是否有一个R函数可以计算余弦相似度矩阵?[关闭]


20

我想通过基于余弦距离的行聚类制作一个热图。我正在使用R并heatmap.2()制作数字。我可以看到其中有一个dist参数,heatmap.2但是找不到用于生成余弦相异度矩阵的函数。内置dist函数不支持余弦距离,我还发现了一个arules带有dissimilarity()函数的包,但仅适用于二进制数据。


5
编写自己的余弦不相似函数可能会更快。
假定是正常的2012年

2
余弦是相似的,而不是相似的。但是,您可以将余弦转换为缩放数据的欧氏距离:d = sqrt(2 *(1-cos))。
ttnphns 2012年

Answers:


29

正如@Max在注释(+1)中指出的那样,“花自己的时间写”比花时间在其他地方查找要简单得多。众所周知,长度为两个向量之间的余弦相似度Ñ一种ñ

C=一世=1个ñ一种一世一世一世=1个ñ一种一世2一世=1个ñ一世2

这很容易在中生成R。设X矩阵,其中行是我们要计算它们之间相似度的值。然后,我们可以使用以下R代码计算相似度矩阵:

cos.sim <- function(ix) 
{
    A = X[ix[1],]
    B = X[ix[2],]
    return( sum(A*B)/sqrt(sum(A^2)*sum(B^2)) )
}   
n <- nrow(X) 
cmb <- expand.grid(i=1:n, j=1:n) 
C <- matrix(apply(cmb,1,cos.sim),n,n)

然后,该矩阵C就是余弦相似度矩阵,您可以将其传递给您喜欢的任何热图函数(我所熟悉的唯一函数是image())。


谢谢,这是有帮助的。实际上,我不想绘制矩阵本身,而是拥有一个距离函数来聚类另一个热图。
格雷格·斯洛德科维奇

@GregSlodkowicz,好的,也许您可​​以将此矩阵传递给您使用的函数。此外,如果您认为此答案有帮助,请考虑接受投票(如果您认为是确定的,请接受答案):)
Macro

太好了,多亏您的回复和ttnphns的评论,我才能做到自己想要的。现在,我希望在对行进行聚簇时与对列对聚簇时使用不同的度量标准,但这也许正在推动它...
Greg Slodkowicz

显然我没有足够的意见要发表意见。我只是想提供一个对Macro的很好回答的稍微修改的版本。这里是。#Macros的ChirazB版本的cos.sim(),其中S = X%*%t(X)cos.sim.2 <-function(S,ix){i <-ix [1] j <-ix [2 ] return(S [i,j] / sqrt(S [i,i] * S [j,j]))} #test X <-matrix(rnorm(20),nrow = 5,ncol = 4)S < -X%*%t(X)n <-nrow(X)idx.arr <-expand.grid(i = 1:n,j = 1:n)C <-matrix(apply(idx.arr,1, cos.sim,X),n,n)C2 <-matrix(apply(idx.arr,1,cos.sim.2,S),n,n)我不喜欢全局变量,这就是为什么我包括S作为参数。
Chiraz BenAbdelkader 2015年


4

在处理矩阵而不是一维向量时,以下函数可能会很有用:

# input: row matrices 'ma' and 'mb' (with compatible dimensions)
# output: cosine similarity matrix

cos.sim=function(ma, mb){
  mat=tcrossprod(ma, mb)
  t1=sqrt(apply(ma, 1, crossprod))
  t2=sqrt(apply(mb, 1, crossprod))
  mat / outer(t1,t2)
}

4

上面的一些答案在计算上效率低下,请尝试一下;


对于余弦相似度矩阵

Matrix <- as.matrix(DF)
sim <- Matrix / sqrt(rowSums(Matrix * Matrix))
sim <- sim %*% t(sim)

转换为余弦相异矩阵(距离矩阵)。

D_sim <- as.dist(1 - sim)

0

在此问题上加强一些先前的代码(来自@Macro),我们可以将其包装为以下更干净的版本:

df <- data.frame(t(data.frame(c1=rnorm(100),
                              c2=rnorm(100),
                              c3=rnorm(100),
                              c4=rnorm(100),
                              c5=rnorm(100),
                              c6=rnorm(100))))

#df[df > 0] <- 1
#df[df <= 0] <- 0



apply_cosine_similarity <- function(df){
  cos.sim <- function(df, ix) 
  {
    A = df[ix[1],]
    B = df[ix[2],]
    return( sum(A*B)/sqrt(sum(A^2)*sum(B^2)) )
  }   
  n <- nrow(df) 
  cmb <- expand.grid(i=1:n, j=1:n) 
  C <- matrix(apply(cmb,1,function(cmb){ cos.sim(df, cmb) }),n,n)
  C
}
apply_cosine_similarity(df)

希望这可以帮助!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.