Ich möchte eine Möglichkeit, Jaccard Ähnlichkeit zwischen Dokumenten einer tm::DocumentTermMatrix
effizient zu berechnen. Ich kann etwas ähnliches für Kosinusähnlichkeit über die Slam Paket wie in this answer. gezeigt Ich stieß auf CrossValidated another question and response, die R spezifisch war, aber über Matrixalgebra nicht unbedingt der effizienteste Weg. Ich habe versucht, diese Lösung mit effizienteren Slam Funktionen zu implementieren, aber bekomme nicht die selbe Lösung wie wenn ich einen weniger effizienten Ansatz verwende, um den DTM zu einer Matrix zu zwingen und proxy::dist
zu verwenden.Effiziente Jaccardähnlichkeit DocumentTermMatrix
Wie kann ich die Jaccard-Ähnlichkeit zwischen Dokumenten einer großen DocumentTermMatrix in R effizient berechnen?
#Data & pacages
library(Matrix);library(proxy);library(tm);library(slam);library(Matrix)
mat <- structure(list(i = c(1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 3L, 1L,
2L, 3L, 3L, 3L, 4L, 4L, 4L, 4L), j = c(1L, 1L, 2L, 2L, 3L, 3L,
4L, 4L, 4L, 5L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L), v = c(1,
1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1), nrow = 4L,
ncol = 12L, dimnames = structure(list(Docs = c("1", "2",
"3", "4"), Terms = c("computer", "is", "fun", "not", "too",
"no", "it's", "dumb", "what", "should", "we", "do")), .Names = c("Docs",
"Terms"))), .Names = c("i", "j", "v", "nrow", "ncol", "dimnames"
), class = c("DocumentTermMatrix", "simple_triplet_matrix"), weighting = c("term frequency",
"tf"))
#Inefficient Berechnung (erwartete Ausgabe)
proxy::dist(as.matrix(mat), method = 'jaccard')
## 1 2 3
## 2 0.000
## 3 0.875 0.875
## 4 1.000 1.000 1.000
#My Attempt
A <- slam::tcrossprod_simple_triplet_matrix(mat)
im <- which(A > 0, arr.ind=TRUE)
b <- slam::row_sums(mat)
Aim <- A[im]
stats::as.dist(Matrix::sparseMatrix(
i = im[,1],
j = im[,2],
x = Aim/(b[im[,1]] + b[im[,2]] - Aim),
dims = dim(A)
))
## 1 2 3
## 2 2.0
## 3 0.1 0.1
## 4 0.0 0.0 0.0
Ausgänge stimmen nicht überein.
FYI Hier ist der Originaltext:
c("Computer is fun. Not too fun.", "Computer is fun. Not too fun.",
"No it's not, it's dumb.", "What should we do?")
I erwarten würde Elemente 1 & 2 0 Entfernung und das Element auf 3 zu Element näher an 1 als das Element 1 und 4 (I erwarten würde weitesten Abstand, da keine Wörter geteilt werden), wie in der proxy::dist
Lösung gesehen.
EDIT
Beachten Sie, dass auch auf einem mittelgroßen DTM die Matrix riesig wird. Hier ist ein Beispiel mit dem veganen Paket. Hinweis 4 Minuten zu lösen, wo die Kosinusähnlichkeit ~ 5 Sekunden ist.
library(qdap); library(quanteda);library(vegan);library(slam)
x <- quanteda::convert(quanteda::dfm(rep(pres_debates2012$dialogue), stem = FALSE,
verbose = FALSE, removeNumbers = FALSE), to = 'tm')
## <<DocumentTermMatrix (documents: 2912, terms: 3368)>>
## Non-/sparse entries: 37836/9769780
## Sparsity : 100%
## Maximal term length: 16
## Weighting : term frequency (tf)
tic <- Sys.time()
jaccard_dist_mat <- vegan::vegdist(as.matrix(x), method = 'jaccard')
Sys.time() - tiC#Time difference of 4.01837 mins
tic <- Sys.time()
tdm <- t(x)
cosine_dist_mat <- 1 - crossprod_simple_triplet_matrix(tdm)/(sqrt(col_sums(tdm^2) %*% t(col_sums(tdm^2))))
Sys.time() - tiC#Time difference of 5.024992 secs
Ich bin mir nicht sicher, ob ich Ihren Kommentar verstanden habe. Was genau stimmt in meiner Antwort nicht? Es erzeugt korrekte jaccard Ähnlichkeiten und funktioniert ziemlich schnell. –
Entschuldigung, wenn mein Kommentar zu unhöflich aussieht. Angepasste Antwort. –
danke sehr hilfreich, PS mögen die neuen Ergänzungen zu text2vec –