Existe uma função R que calculará a matriz de dissimilaridade de cosseno? [fechadas]

20

Eu gostaria de fazer um mapa de calor com agrupamento de linhas com base nas distâncias do cosseno. Estou usando R e heatmap.2()para fazer a figura. Percebo que existe um distparâmetro, heatmap.2mas não consigo encontrar uma função para gerar a matriz de dissimilaridade de cosseno. A distfunção embutida não suporta distâncias de cosseno, também encontrei um pacote chamado arulescom uma dissimilarity()função, mas funciona apenas em dados binários.

Greg Slodkowicz
fonte
5
Pode ser mais rápido escrever sua própria função de dissimilaridade de cosseno.
assumednormal
2
O cosseno é similaridade, não dissimilaridade. No entanto, você pode transformar o cosseno na distância euclidiana dos dados em escala: d = sqrt (2 * (1-cos)).
ttnphns

Respostas:

29

UMA,Bn

C=Eu=1nUMAEuBEuEu=1nUMAEu2Eu=1nBEu2

que é simples de gerar R. Let XSer a matriz onde as linhas são os valores que queremos calcular a semelhança entre. Em seguida, podemos calcular a matriz de similaridade com o seguinte Rcódigo:

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)

Então a matriz Cé a matriz de semelhança de cosseno e você pode passá-la para qualquer função de mapa de calor que você gosta (a única com a qual estou familiarizado image()).

Macro
fonte
Obrigado, isso é útil. Na verdade, não quero plotar a matriz em si, mas sim ter uma função de distância para agrupar outro mapa de calor que possuo.
Greg Slodkowicz
@ GregSlodkowicz, OK, bem, talvez você possa passar essa matriz para a função que está usando. Além disso, se você encontrou esta resposta útil por favor considere um upvote (ou aceitar a resposta se você considerá-lo definitiva) :)
Macro
Ótimo, graças à sua resposta e ao comentário de ttnphns, consegui fazer o que queria. Agora eu gostaria de ter uma métrica diferente ao agrupar linhas do que ao agrupar colunas, mas talvez seja isso que está pressionando ...
Greg Slodkowicz
Aparentemente, não tenho pontos suficientes para poder comentar. Eu só queria oferecer uma versão ligeiramente modificada da boa resposta de Macro. Aqui está. # Versão do ChirazB de cos.sim () pela macro # em que S = X% *% t (X) cos.sim.2 <- função (S, ix) {i <- ix [1] j <- ix [2 ] return (S [i, j] / sqrt (S [i, i] * S [j, j]))} teste X <- matriz (rnorm (20), nrow = 5, ncol = 4) S < - X% *% t (X) n <- nrow (X) idx.arr <- expand.grid (i = 1: n, j = 1: n) C <- matriz (aplica-se (idx.arr, 1, cos.sim, X), n, n) C2 <- matriz (apply (idx.arr, 1, cos.sim.2, S), n, n) Eu não gosto de variável global, é por isso que incluí S como um parâmetro.
você precisa saber é o seguinte
4

A função a seguir pode ser útil ao trabalhar com matrizes, em vez de vetores 1-d:

# 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)
}
Kimsche
fonte
4

Algumas respostas acima são computacionalmente ineficientes, tente isso;


Para matriz de semelhança de cosseno

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

Converta para matriz de dissimilaridade de cosseno (matriz de distância).

D_sim <- as.dist(1 - sim)
Brad
fonte
0

Ampliando parte do código anterior (do @Macro) sobre esse problema, podemos agrupá-lo em uma versão mais limpa, a seguir:

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)

Espero que isto ajude!

bmc
fonte