How to efficiently retrieve top K-similar vectors by cosine similarity using R?

大城市里の小女人 提交于 2019-11-29 11:02:13

No need to compute the similarity for every row. You can use this instead:

coSim2<-function(mat1, mat2, topK){
    #similarity computation:

    xy <- tcrossprod(mat1, mat2)
    xx <- rowSums(mat1^2)
    yy <- rowSums(mat2^2)
    result <- xy/sqrt(outer(xx,yy))

    #top similar rows from train (per row in test):

    top <- apply(result, 2, order, decreasing=TRUE)[1:topK,]
    result_df <- data.frame(testRowId=c(col(top)), trainRowId=c(top))
    result_df$CosineSimilarity <- result[as.matrix(result_df[,2:1])]
    list(similarity=result_df, index=t(top))
}

Test data (I've reduced your train matrix)

set.seed(123)
train<-matrix(round(runif(100000),0),nrow=500,ncol=200)
set.seed(987)
test<-matrix(round(runif(400000),0),nrow=2000,ncol=200)

Result:

> system.time(cosineSim<-coSim(train, test, topK=50)) #380secs
   user  system elapsed 
  41.71    1.59   43.72 

> system.time(cosineSim2<-coSim2(train, test, topK=50)) #380secs
   user  system elapsed 
   0.46    0.02    0.49 

Using your full 5000 x 200 train matrix, coSim2 runs in 7.8 sec.

Also note:

> any(cosineSim$similarity != cosineSim2$similarity)
[1] FALSE
> any(cosineSim$index != cosineSim2$index)
[1] FALSE

You can't use identical because my function returns integers instead of doubles for row IDs.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!