¿Existe una función R que calcule la matriz de disimilitud del coseno? [cerrado]

20

Me gustaría hacer un mapa de calor con agrupamiento de filas basado en distancias de coseno. Estoy usando R y heatmap.2()para hacer la figura. Puedo ver que hay un distparámetro heatmap.2pero no puedo encontrar una función para generar la matriz de disimilitud del coseno. La distfunción incorporada no admite distancias de coseno, también encontré un paquete llamado arulescon una dissimilarity()función pero solo funciona en datos binarios.

Greg Slodkowicz
fuente
55
Puede ser más rápido escribir su propia función de disimilitud de coseno.
asumido el
2
El coseno es similitud, no disimilitud. Sin embargo, puede convertir el coseno en una distancia euclidiana de datos escalados: d = sqrt (2 * (1-cos)).
ttnphns
La misma pregunta sobre SO: encontrar similitud de coseno entre dos matrices
smci

Respuestas:

29

Como @Max indicó en los comentarios (+1), sería más sencillo "escribir el suyo" que pasar tiempo buscándolo en otro lugar. Como sabemos, la similitud del coseno entre dos vectores de longitud n esUN,sinorte

C=yo=1norteUNyosiyoyo=1norteUNyo2yo=1nortesiyo2

que es fácil de generar R. Sea Xla matriz donde las filas son los valores entre los que queremos calcular la similitud. Luego podemos calcular la matriz de similitud con el siguiente 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)

Entonces la matriz Ces la matriz de similitud de coseno y puede pasarla a la función de mapa de calor que desee (la única con la que estoy familiarizado es image()).

Macro
fuente
Gracias, esto es útil. En realidad, no quiero trazar la matriz en sí, sino tener una función de distancia para agrupar otro mapa de calor que tengo.
Greg Slodkowicz
@GregSlodkowicz, OK, bueno, tal vez puedas pasar esta matriz a la función que estás usando. Además, si ha encontrado útil esta respuesta, considere un voto positivo (o acepte la respuesta si la considera definitiva) :)
Macro
Genial, gracias a tu respuesta y al comentario de ttnphns pude hacer lo que quería. Ahora me gustaría tener una métrica diferente cuando se agrupan filas que cuando se agrupan columnas, pero tal vez eso lo está empujando ...
Greg Slodkowicz
Aparentemente no tengo suficientes puntos para poder comentar. Solo quería ofrecer una versión ligeramente modificada de la buena respuesta de Macro. Aquí está. # Versión de cos.sim () de ChirazB por Macro # donde S = X% *% t (X) cos.sim.2 <- función (S, ix) {i <- ix [1] j <- ix [2 ] return (S [i, j] / sqrt (S [i, i] * S [j, j]))} #test 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 (aplicar (idx.arr, 1, cos.sim, X), n, n) C2 <- matriz (aplicar (idx.arr, 1, cos.sim.2, S), n, n) No me gusta la variable global, por eso incluí S como un parámetro
Chiraz BenAbdelkader
4

La siguiente función puede ser útil cuando se trabaja con matrices, en lugar de vectores 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
fuente
4

Algunas respuestas anteriores son computacionalmente ineficientes, intente esto;


Para la matriz de similitud de coseno

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

Convierta a matriz de disimilaridad de coseno (matriz de distancia).

D_sim <- as.dist(1 - sim)
Puntilla
fuente
0

Acelerando parte del código anterior (de @Macro) sobre este tema, podemos envolverlo en una versión más limpia de la siguiente manera:

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 esto ayude!

bmc
fuente