Есть ли R-функция, которая будет вычислять матрицу косинусных различий? [закрыто]

20

Я хотел бы сделать тепловую карту с кластеризацией строк на основе косинусных расстояний. Я использую R и heatmap.2()для создания фигуры. Я вижу, что есть distпараметр, heatmap.2но я не могу найти функцию для генерации косинусной матрицы различий. Встроенная distфункция не поддерживает косинус расстояния, я также нашел пакет , называемый arulesс dissimilarity()функцией , но он работает только на двоичных данных.

Грег Слодкович
источник
5
Может быть быстрее написать свою собственную функцию различий косинусов.
принято нормальным
2
Косинус - это сходство, а не различие. Однако вы можете превратить косинус в евклидово расстояние масштабированных данных: d = sqrt (2 * (1-cos)).
ttnphns

Ответы:

29

A,ВN

Сзнак равноΣязнак равно1NAяВяΣязнак равно1NAя2Σязнак равно1NВя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, хорошо, возможно, вы можете передать эту матрицу функции, которую вы используете. Кроме того, если вы нашли этот ответ полезным, рассмотрите возможность повышения (или принятия ответа, если вы считаете его окончательным) :)
Макрос
Отлично, благодаря вашему ответу и комментарию ttnphns я смог сделать то, что хочу. Теперь я хотел бы иметь другую метрику при кластеризации строк, чем при кластеризации столбцов, но, возможно, это подталкивает ...
Грег Слодкович
Видимо, у меня недостаточно очков, чтобы комментировать. Я просто хотел предложить слегка измененную версию хорошего ответа Макро. Вот. # Версия cos.sim () в ChirazB для Macro #, где S = X% *% t (X) cos.sim.2 <- функция (S, ix) {i <- ix [1] j <- ix [2 ] return (S [i, j] / sqrt (S [i, i] * S [j, j]))} #test X <- матрица (rnorm (20), nrow = 5, ncol = 4) S < - X% *% t (X) n <- nrow (X) idx.arr <- expand.grid (i = 1: n, j = 1: n) C <- матрица (применить (idx.arr, 1, cos.sim, X), n, n) C2 <- матрица (применить (idx.arr, 1, cos.sim.2, S), n, n) Мне не нравится глобальная переменная, поэтому я включил S в качестве параметра.
Chiraz BenAbdelkader
4

Следующая функция может быть полезна при работе с матрицами вместо 1-мерных векторов:

# 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
источник
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)

Надеюсь это поможет!

BMC
источник