2012-12-19 16 views
32

Sto facendo argomento modellazione utilizzando il pacchetto topicmodels in R. Io sono la creazione di un oggetto Corpus, fare un po 'di pre-elaborazione di base, e quindi la creazione di un DocumentTermMatrix:Rimuovere i documenti vuoti da DocumentTermMatrix in mododelle R?

corpus <- Corpus(VectorSource(vec), readerControl=list(language="en")) 
corpus <- tm_map(corpus, tolower) 
corpus <- tm_map(corpus, removePunctuation) 
corpus <- tm_map(corpus, removeWords, stopwords("english")) 
corpus <- tm_map(corpus, stripWhitespace) 
corpus <- tm_map(corpus, removeNumbers) 
...snip removing several custom lists of stopwords... 
corpus <- tm_map(corpus, stemDocument) 
dtm <- DocumentTermMatrix(corpus, control=list(minDocFreq=2, minWordLength=2)) 

E poi eseguire LDA:

LDA(dtm, 30) 

questa chiamata finale per LDA() restituisce l'errore

"Each row of the input matrix needs to contain at least one non-zero entry". 

presumo che ciò significa che c'è almeno un documento t cappello non ha termini in esso dopo la pre-elaborazione. C'è un modo semplice per rimuovere documenti che non contengono termini da DocumentTermMatrix?

Ho esaminato la documentazione per il pacchetto topicmodels e ho trovato la funzione removeSparseTerms, che rimuove i termini che non compaiono in nessun documento, ma non esiste un analogo per la rimozione dei documenti.

+0

Quando si ispeziona (corpus), si vede qualche documento emty? e LDA è in quale pacchetto? – agstudy

+0

Sto usando la funzione LDA dal pacchetto topicmodels. Ho circa 51.000 documenti, quindi non posso controllare manualmente con controlli. Inoltre, è possibile che alcuni termini vengano rimossi dai parametri minDocFreq = 2, minWordLength = 2, quindi quello che voglio veramente controllare è DocumentTermMatrix. C'è un altro modo per trovare i documenti vuoti? –

risposta

45
"Each row of the input matrix needs to contain at least one non-zero entry" 

L'errore indica che la matrice sparsa contiene una riga senza voci (parole). Un'idea è di calcolare la somma di parole per riga

rowTotals <- apply(dtm , 1, sum) #Find the sum of words in each Document 
dtm.new <- dtm[rowTotals> 0, ]   #remove all docs without words 
+1

Funziona bene. Non avevo realizzato che DocumentTermMatrix potesse essere indicizzato in quel modo. Grazie! –

+1

@BillM è una matrice, speciale sì (sparse), ma pur sempre una matrice. – agstudy

+3

Questa soluzione presenta un potenziale problema: la matrice risultante senza documenti a parole zero non corrisponderà più al corpus originale, cioè avrà un numero inferiore di righe. Pertanto non sarà possibile utilizzare il risultato di LDA per classificare il corpus (ad esempio assegnando il cluster migliore a ciascun documento). Qualche idea su come risolvere questo? –

11

Questo è solo per elaborare la risposta data da agstudy.

Invece di rimuovere le righe vuote dalla matrice dtm, possiamo identificare i documenti nel nostro corpus che hanno lunghezza zero e rimuovere i documenti direttamente dal corpus, prima di eseguire un secondo dtm con solo documenti non vuoti.

Ciò è utile per mantenere una corrispondenza 1: 1 tra dtm e corpus.

empty.rows <- dtm[rowTotals == 0, ]$dimnames[1][[1]] corpus <- corpus[-as.numeric(empty.rows)]

+0

Per me la seconda riga del codice ha generato questo errore Errore in '[.VCorpus' (corpus, 1, 1): argomento inutilizzato (1). L'ho modificato in corpus <- corpus [-as.numeric (empty.rows)] – user131476

+1

Un corpus è un elenco in modo da non poter utilizzare la selezione 2D. Volete semplicemente 'corpus [-as.numeric (empty.rows)]' (cioè una dimensione). – neverfox

+0

Grazie, sto modificando la risposta. –

0

Basta piccolo addendum alla risposta di Dario Lacan:

empty.rows <- dtm[rowTotals == 0, ]$dimnames[1][[1]] 

raccoglierà id, piuttosto che numeri d'ordine di record. Prova questo:

library(tm) 
data("crude") 
dtm <- DocumentTermMatrix(crude) 
dtm[1, ]$dimnames[1][[1]] # return "127", not "1" 

Se si preparano da sé corpus con numerazione progressiva, dopo che i dati pulizia alcuni documenti possono essere rimossi e la numerazione saranno rotti. Quindi, è meglio usare id direttamente:

corpus <- tm_filter(
    corpus, 
    FUN = function(doc) !is.element(meta(doc)$id, empty.rows)) 
    # !(meta(doc)$id %in% emptyRows) 
) 
2

rimuovere solo i termini sparse dal DTM e tutto funzionerà bene.

dtm <- DocumentTermMatrix(crude, sparse=TRUE) 
+0

dtm <-removeSparseTerms (dtm, sparse = 0.98) –

17

La risposta di agstudy funziona alla grande, ma utilizzarla su un computer lento si è dimostrata leggermente problematica.

tic() 
row_total = apply(dtm, 1, sum) 
dtm.new = dtm[row_total>0,] 
toc() 
4.859 sec elapsed 

(questo è stato fatto con un 4000x15000 DTM)

Il collo di bottiglia sembra essere applicando sum() ad una matrice sparsa.

Una matrice di termini documento creata dal pacchetto tm contiene i nomi i e j, che sono indici per cui le voci si trovano nella matrice sparsa. Se dtm$i non contiene un particolare indice di riga p, la riga p è vuota.

tic() 
ui = unique(dtm$i) 
dtm.new = dtm[ui,] 
toc() 
0.121 sec elapsed 

ui contiene tutti gli indici non-zero, e poiché dtm$i è già ordinato, dtm.new sarà nello stesso ordine come dtm. Il guadagno in termini di prestazioni potrebbe non avere importanza per le matrici dei termini dei documenti più piccole, ma potrebbe diventare significativo con le matrici più grandi.

Problemi correlati