2013-05-19 16 views
5

Supponiamo che disponga di dati di addestramento basati su testo e dati di test. Per essere più precisi, ho due set di dati - addestramento e test - e entrambi hanno una colonna che contiene del testo ed è interessante per il lavoro da svolgere.Come ricreare DocumentTermMatrix con nuovi dati (test)

Ho usato il pacchetto tm in R per elaborare la colonna di testo nel set di dati di allenamento. Dopo aver rimosso gli spazi bianchi, la punteggiatura e le parole di stop, ho arginato il corpus e finalmente creato una matrice di termini di documento di 1 grammo contenente la frequenza/il conteggio delle parole in ciascun documento. Ho quindi preso un limite predeterminato di, diciamo, 50 e ho mantenuto solo quei termini con un conteggio superiore a 50.

In seguito, alleno un modello GLMNET utilizzando il DTM e il dipendente variabile (che era presente nei dati di addestramento). Tutto funziona liscio e facile fino ad ora.

Tuttavia, come procedo quando voglio segnare/prevedere il modello sui dati di test o eventuali nuovi dati che potrebbero arrivare in futuro?

In particolare, quello che sto cercando di scoprire è come faccio a creare il DTM esatto sui nuovi dati?

Se il nuovo set di dati non contiene parole simili ai dati di allenamento originali, tutti i termini devono avere un conteggio pari a zero (che va bene). Ma voglio essere in grado di replicare esattamente lo stesso DTM (in termini di struttura) su qualsiasi nuovo corpus.

Qualche idea/pensiero?

+0

Se ho capito bene la tua domanda (e io non sono sicuro di avere, senza un esempio riproducibile che dimostra quello che si sta provando a fare.), sembra che il modo più semplice per farlo sarebbe quello di creare la matrice term-documento usando tutti i dati, e quindi dividere quella matrice in un set di test e addestramento. In questo modo, hai tutti i termini rappresentati in entrambe le matrici, anche se una matrice ha solo zeri per diversi termini. Stai riscontrando problemi perché stai dividendo i dati prima di creare le matrici dei documenti termine. – SchaunW

+1

Sono d'accordo Schaun, ma posso farlo solo con i dati di test che ho attualmente. Sto cercando una soluzione che funzionerà quando avrò nuovi dati domani. Altrimenti, sarebbe un problema aggiungere sempre nuovi dati a quelli esistenti, ricreare il DTM e riqualificare il modello ogni volta. – Godel

+1

Anche in questo caso, disporre di dati di esempio con cui lavorare potrebbe rendere più semplice la risposta alla domanda. Che ne dici di questo: trasforma i tuoi nuovi dati in una matrice di term-document, quindi legalo ai vecchi dati usando la funzione 'rbind.fill' del pacchetto' plyr', che creerebbe una nuova matrice con tutte le colonne di entrambe le matrici originali. I tuoi dati di allenamento avrebbero colonne di NA per qualsiasi termine nei tuoi nuovi dati che non erano nei tuoi dati di allenamento. Potresti quindi eliminare quelle colonne. I tuoi nuovi dati avrebbero colonne di NA per qualsiasi termine nei tuoi dati di allenamento, ma non nei tuoi nuovi dati, Potresti sostituire questi NA con zeri. – SchaunW

risposta

7

Se ho capito correttamente, hai fatto un dtm e vuoi creare un nuovo dtm da nuovi documenti che hanno le stesse colonne (es. Termini) del primo dtm. Se questo è il caso, allora dovrebbe essere una questione di sub-setting il secondo DTM dai termini nella prima, forse qualcosa di simile:

innanzitutto impostare alcuni dati riproducibili ...

Questa è la vostra dati di allenamento ...

library(tm) 
# make corpus for text mining (data comes from package, for reproducibility) 
data("crude") 
corpus1 <- Corpus(VectorSource(crude[1:10]))  
# process text (your methods may differ) 
skipWords <- function(x) removeWords(x, stopwords("english")) 
funcs <- list(tolower, removePunctuation, removeNumbers, 
       stripWhitespace, skipWords) 
crude1 <- tm_map(corpus1, FUN = tm_reduce, tmFuns = funcs) 
crude1.dtm <- DocumentTermMatrix(crude1, control = list(wordLengths = c(3,10))) 

E questo è il tuo dati di test ...

corpus2 <- Corpus(VectorSource(crude[15:20])) 
# process text (your methods may differ) 
skipWords <- function(x) removeWords(x, stopwords("english")) 
funcs <- list(tolower, removePunctuation, removeNumbers, 
       stripWhitespace, skipWords) 
crude2 <- tm_map(corpus2, FUN = tm_reduce, tmFuns = funcs) 
crude2.dtm <- DocumentTermMatrix(crude2, control = list(wordLengths = c(3,10))) 

Ecco il bit che fa quello che si vuole:

Ora abbiamo solo mantenere i termini i dati di test che sono presenti nei dati di addestramento ...

# convert to matrices for subsetting 
crude1.dtm.mat <- as.matrix(crude1.dtm) # training 
crude2.dtm.mat <- as.matrix(crude2.dtm) # testing 

# subset testing data by colnames (ie. terms) or training data 
xx <- data.frame(crude2.dtm.mat[,intersect(colnames(crude2.dtm.mat), 
              colnames(crude1.dtm.mat))]) 

Infine aggiungere ai dati di prova tutte le colonne vuote per i termini nei dati di addestramento che sono non nei dati di test ...

# make an empty data frame with the colnames of the training data 
yy <- read.table(textConnection(""), col.names = colnames(crude1.dtm.mat), 
       colClasses = "integer") 

# add incols of NAs for terms absent in the 
# testing data but present # in the training data 
# following SchaunW's suggestion in the comments above 
library(plyr) 
zz <- rbind.fill(xx, yy) 

Così zz è un frame di dati dei documenti di prova, ma ha la stessa struttura dei documenti di formazione (es. stesse colonne, sebbene molte di esse contengano NA, come nota SchaunW).

E 'questo il concetto di quello che vuoi?

+0

Sì Ben. Questo aiuta parecchio. Molte grazie. :) – Godel

+0

Nessun problema! E ora sai come creare dati di esempio da includere in eventuali domande correlate che potresti voler porre. – Ben

+0

Ho cercato una soluzione per un po ', grazie, anche se proverò anche uno di seguito mostrato da Dmitriy – Tetlanesh

12

tm ha così tante insidie ​​... Vedi molto più efficiente text2vec e vectorization vignette che risponde pienamente alla domanda.

Per tm qui è probabilmente un altro modo semplice per ricostruire matrice DTM per il secondo corpus:

crude2.dtm <- DocumentTermMatrix(crude2, control = list 
       (dictionary=Terms(crude1.dtm), wordLengths = c(3,10))) 
+3

Funziona anche molto bene, ma 'Dictionary()' non è più supportato e devi usare invece 'Terms()'. – Khozzy

+0

Un ottimo esempio, lo proverò sicuramente, ho cercato un modo nativo per farlo. Suppongo che dovrei effettivamente leggere le versioni di pacchetti che uso :) – Tetlanesh

+1

Penso che questa soluzione sia molto meglio dato che non converte dalla matrice sparsa – elactic

Problemi correlati