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.


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=1nUMAEuBEu∑Eu=1nUMAEu2⋅∑Eu=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()).


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)
}

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)

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!

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.