2015-04-20 15 views
10

Voglio calcolare la distanza del coseno tra gli autori di un corpus. Prendiamo un corpus di 20 documenti.R: Calcola la distanza del coseno da una matrice di termini e documenti con tm e proxy

require(tm) 
data("crude") 
length(crude) 
# [1] 20 

Voglio scoprire la distanza del coseno (somiglianza) tra questi 20 documenti. Ho creare una matrice termine-documento con

tdm <- TermDocumentMatrix(crude, 
          control = list(removePunctuation = TRUE, 
             stopwords = TRUE)) 

poi devo convertirlo in una matrice di passare alla dist() della delega pacchetto

tdm <- as.matrix(tdm) 
require(proxy) 
cosine_dist_mat <- as.matrix(dist(t(tdm), method = "cosine")) 

Finalmente rimuovere la diagonale del mio coseno matrice a distanza (dal momento che non sono interessato alla distanza tra un documento e se stesso) e calcolare la distanza media tra ogni documento e l'altro documento 19 del corpus

diag(cosine_dist_mat) <- NA 
cosine_dist <- apply(cosine_dist_mat, 2, mean, na.rm=TRUE) 

cosine_dist 
# 127  144  191  194 
# 0.6728505 0.6788326 0.7808791 0.8003223 
# 211  236  237  242 
# 0.8218699 0.6702084 0.8752164 0.7553570 
# 246  248  273  349 
# 0.8205872 0.6495110 0.7064158 0.7494145 
# 352  353  368  489 
# 0.6972964 0.7134836 0.8352642 0.7214411 
# 502  543  704  708 
# 0.7294907 0.7170188 0.8522494 0.8726240 

Fin qui tutto bene (con piccoli corpora). Il problema è che questo metodo non si adatta bene a grandi corpora di documenti. Per una volta sembra inefficiente a causa delle due chiamate a as.matrix(), per passare il tdm da tm a proxy e infine per calcolare la media.

È possibile concepire un modo più intelligente per ottenere lo stesso risultato?

+0

'colMeans' è probabilmente più veloce di' apply'. Tuttavia, dovresti 'Rprof' la chiamata per vedere dove trascorre la maggior parte del tempo. Potrebbe essere la chiamata "dist", nel qual caso non c'è molto che tu possa fare. – James

+0

Penseresti che la libreria 'tm' avrebbe questo built-in ... – wordsforthewise

risposta

12

Dal matrici termine documento tm s' sono solo sparse 'semplici matrici tripletta' dal pacchetto slam, è possibile utilizzare le funzioni di lì a calcolare le distanze direttamente dalla definizione di coseno di similitudine:

library(slam) 
cosine_dist_mat <- 1 - crossprod_simple_triplet_matrix(tdm)/(sqrt(col_sums(tdm^2) %*% t(col_sums(tdm^2)))) 

Questo sfrutta la moltiplicazione con matrice sparsa. Nelle mie mani, un tdm con 2963 termini in 220 documenti e il 97% di scarsità ha impiegato appena un paio di secondi.

Non l'ho profilato, quindi non ho idea se sia più veloce di proxy::dist().

NOTA: affinché funzioni, è necessario non forzare il tdm in una matrice normale, vale a dire non fare tdm <- as.matrix(tdm).

+0

In effetti, usare 'slam' è il modo giusto per procedere. Rende il tempo di esecuzione gestibile anche con corpora di grandi dimensioni (oltre 10.000 documenti). – CptNemo

8

Primo. Grande codice MAndrecPhD! Ma credo che intendesse scrivere:

cosine_dist_mat <- crossprod_simple_triplet_matrix(tdm)/(sqrt(col_sums(tdm^2) %*% t(col_sums(tdm^2)))) 

Il suo codice come scritto restituisce il punteggio di dissimilarità. Vogliamo 1 in diagonale per la somiglianza del coseno, non per 0. https://en.wikipedia.org/wiki/Cosine_similarity. Potrei sbagliarmi, e voi ragazzi volete davvero il punteggio della dissimilarità, ma ho pensato di parlarne, dal momento che mi ci è voluto un po 'di riflessione per risolvere.

Problemi correlati