R:使用 tm 和代理计算术语文档矩阵的余弦距离
R: Calculate cosine distance from a term-document matrix with tm and proxy
我想计算语料库作者之间的余弦距离。让我们取一个包含 20 个文档的语料库。
require(tm)
data("crude")
length(crude)
# [1] 20
我想找出这20个文档之间的余弦距离(相似度)。我用
创建了一个术语文档矩阵
tdm <- TermDocumentMatrix(crude,
control = list(removePunctuation = TRUE,
stopwords = TRUE))
然后我必须将其转换为矩阵以将其传递给 proxy 包
的 dist()
tdm <- as.matrix(tdm)
require(proxy)
cosine_dist_mat <- as.matrix(dist(t(tdm), method = "cosine"))
最后我删除余弦距离矩阵的对角线(因为我对文档与其自身之间的距离不感兴趣)并计算每个文档与语料库中其他 19 个文档之间的平均距离
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
到目前为止一切顺利(语料库较小)。问题是这种方法不能很好地扩展到更大的文档语料库。这一次似乎效率低下,因为两次调用 as.matrix()
,将 tdm
从 tm 传递给 proxy 和最后计算平均值。
是否可以想出更聪明的方法来获得相同的结果?
由于 tm
的术语文档矩阵只是来自 slam
包的稀疏 "simple triplet matrices",您可以使用那里的函数直接根据余弦相似度的定义计算距离:
library(slam)
cosine_dist_mat <- 1 - crossprod_simple_triplet_matrix(tdm)/(sqrt(col_sums(tdm^2) %*% t(col_sums(tdm^2))))
这利用了稀疏矩阵乘法。在我手中,220 个文档中有 2963 个术语且稀疏度为 97% 的 tdm 仅用了几秒钟。
我没有分析过这个,所以我不知道它是否比 proxy::dist()
.
快
注意:要使其正常工作,您应该不 将 tdm 强制转换为规则矩阵,即不要执行 tdm <- as.matrix(tdm)
.
首先。伟大的代码 MAndrecPhD!但我相信他是想写:
cosine_dist_mat <- crossprod_simple_triplet_matrix(tdm)/(sqrt(col_sums(tdm^2) %*% t(col_sums(tdm^2))))
他写的代码 returns 差异分数。我们希望对角线上的余弦相似度为 1,而不是 0。 https://en.wikipedia.org/wiki/Cosine_similarity。我可能弄错了,你们实际上想要差异分数,但我想我会提到它,因为我花了一点时间来整理。
我想计算语料库作者之间的余弦距离。让我们取一个包含 20 个文档的语料库。
require(tm)
data("crude")
length(crude)
# [1] 20
我想找出这20个文档之间的余弦距离(相似度)。我用
创建了一个术语文档矩阵tdm <- TermDocumentMatrix(crude,
control = list(removePunctuation = TRUE,
stopwords = TRUE))
然后我必须将其转换为矩阵以将其传递给 proxy 包
的dist()
tdm <- as.matrix(tdm)
require(proxy)
cosine_dist_mat <- as.matrix(dist(t(tdm), method = "cosine"))
最后我删除余弦距离矩阵的对角线(因为我对文档与其自身之间的距离不感兴趣)并计算每个文档与语料库中其他 19 个文档之间的平均距离
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
到目前为止一切顺利(语料库较小)。问题是这种方法不能很好地扩展到更大的文档语料库。这一次似乎效率低下,因为两次调用 as.matrix()
,将 tdm
从 tm 传递给 proxy 和最后计算平均值。
是否可以想出更聪明的方法来获得相同的结果?
由于 tm
的术语文档矩阵只是来自 slam
包的稀疏 "simple triplet matrices",您可以使用那里的函数直接根据余弦相似度的定义计算距离:
library(slam)
cosine_dist_mat <- 1 - crossprod_simple_triplet_matrix(tdm)/(sqrt(col_sums(tdm^2) %*% t(col_sums(tdm^2))))
这利用了稀疏矩阵乘法。在我手中,220 个文档中有 2963 个术语且稀疏度为 97% 的 tdm 仅用了几秒钟。
我没有分析过这个,所以我不知道它是否比 proxy::dist()
.
注意:要使其正常工作,您应该不 将 tdm 强制转换为规则矩阵,即不要执行 tdm <- as.matrix(tdm)
.
首先。伟大的代码 MAndrecPhD!但我相信他是想写:
cosine_dist_mat <- crossprod_simple_triplet_matrix(tdm)/(sqrt(col_sums(tdm^2) %*% t(col_sums(tdm^2))))
他写的代码 returns 差异分数。我们希望对角线上的余弦相似度为 1,而不是 0。 https://en.wikipedia.org/wiki/Cosine_similarity。我可能弄错了,你们实际上想要差异分数,但我想我会提到它,因为我花了一点时间来整理。