这是我的看法。
如果我将余弦相似度定义为
coss <- function(x) {crossprod(x)/(sqrt(tcrossprod(colSums(x^2))))}
(我认为这大约是我用基本 R 函数和经常被监督的函数所能达到的最快速度crossprod
这是一个小宝石)。如果我将它与使用 RCppArmadillo 的 RCpp 函数进行比较(按照@f-privé的建议稍微更新)
NumericMatrix cosine_similarity(NumericMatrix x) {
arma::mat X(x.begin(), x.nrow(), x.ncol(), false);
// Compute the crossprod
arma::mat res = X.t() * X;
int n = x.ncol();
arma::vec diag(n);
int i, j;
for (i=0; i<n; i++) {
diag(i) = sqrt(res(i,i));
}
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
res(i, j) /= diag(i)*diag(j);
return(wrap(res));
}
(这可能可以通过犰狳库中的一些专用函数进行优化 - 只是想获得一些计时测量)。
比较这些产量
> XX <- matrix(rnorm(120*1600), ncol=1600)
> microbenchmark::microbenchmark(cosine_similarity(XX), coss(XX), coss2(XX), times=50)
> microbenchmark::microbenchmark(coss(x), coss2(x), cosine_similarity(x), cosine_similarity2(x), coss3(x), times=50)
Unit: milliseconds
expr min lq mean median uq max
coss(x) 173.0975 183.0606 192.8333 187.6082 193.2885 331.9206
coss2(x) 162.4193 171.3178 183.7533 178.8296 184.9762 319.7934
cosine_similarity2(x) 169.6075 175.5601 191.4402 181.3405 186.4769 319.8792
neval cld
50 a
50 b
50 a
这确实没那么糟糕。使用 C++ 计算余弦相似度的增益非常小(@ f-privé 的解决方案是最快的),所以我猜你的计时问题是由于你正在将文本从单词转换为数字而不是计算时造成的余弦相似度。如果不了解您的具体代码的更多信息,我们很难为您提供帮助。