Matris çarpımı kullanarak ikili veri için Jaccard veya diğer ilişkilendirme katsayısının hesaplanması


9

Matris çarpımı kullanarak Jaccard katsayısını hesaplamanın olası bir yolu olup olmadığını bilmek istiyorum.

Bu kodu kullandım

    jaccard_sim <- function(x) {
    # initialize similarity matrix
    m <- matrix(NA, nrow=ncol(x),ncol=ncol(x),dimnames=list(colnames(x),colnames(x)))
    jaccard <- as.data.frame(m)

    for(i in 1:ncol(x)) {
     for(j in i:ncol(x)) {
        jaccard[i,j]= length(which(x[,i] & x[,j])) / length(which(x[,i] | x[,j]))
        jaccard[j,i]=jaccard[i,j]        
       }
     }

Bu R de uygulamak için tamam. Ben zar benzerlik bir yaptım, ama Tanimoto / Jaccard ile sıkışmış var. Herkes yardım edebilir mi?


@Ttnphns bunu kapsıyor gibi görünüyor, ancak R kullandığınızdan, veganpakette zaten bir dizi benzerlik endeksinin (Jaccard'lar dahil) uygulandığını da işaret ettiğimi düşündüm . Bence hız için de oldukça iyi optimize edilmişler.
David J. Harris

Yanıtlar:


11

Jaccard'ın ( ikili verilerin herhangi iki sütunu arasında hesaplandığını biliyoruz.X) dır-dir aa+b+c, Rogers-Tanimoto ise a+da+d+2(b+c), nerede

  • a - her iki sütunun da 1 olduğu satır sayısı
  • b - diğer sütunun değil, bunun olduğu satır sayısı 1
  • c - bu sütunun değil, diğerinin olduğu satır sayısı 1
  • d - her iki sütunun da 0 olduğu satır sayısı

a+b+c+d=n, içindeki satır sayısı X

Sonra elimizde:

XX=A kare simetrik matrisidir a tüm sütunlar arasında.

(notX)(notX)=D kare simetrik matrisidir d Tüm sütunlar arasında ("X değil" X'te 1-> 0 ve 0-> 1'i dönüştürüyor).

Yani, AnD tüm sütunlar arasındaki Jaccard'ın kare simetrik matrisidir.

A+DA+D+2(n(A+D))=A+D2nAD tüm sütunlar arasındaki Rogers-Tanimoto'nun kare simetrik matrisidir.

Bu formüllerin doğru sonuç verip vermediğini sayısal olarak kontrol ettim. Onlar yapar.


Post. Matrisler de elde edebilirsinizB ve C:

B=[1]XA, burada "[1]", X. B kare asimetrik matrisi btüm sütunlar arasında; ij öğesi , içindeki satır sayısıdırXi sütununda 0 ve j sütununda 1 .

Sonuç olarak, C=B.

Matris D tabii ki bu şekilde de hesaplanabilir: nABC.

Matrisleri bilmek A,B,C,D, ikili veriler için icat edilen herhangi bir çift (dis) benzerlik katsayısının bir matrisini hesaplayabilirsiniz.


Kesirler matrisler için işe gidip gelmedikleri sürece bir anlam ifade etmezler: sağda ters ile çarpmak, aksi takdirde solda çarpmaktan farklı bir sonuç verecektir. Ayrıca, genellikle iki simetrik matrisli bir ürünün simetrik olduğu durum söz konusu değildir. Belki de bileşenlere göre bölünmeyi mi kastediyorsunuz? Gösterimlerinizi doğru formül olduğunu düşündüğünüzü yansıtacak şekilde düzeltebilir misiniz?
whuber

@whuber Kare simetrik matrislerin tersini veya çoğalmasını kullanmıyorum . X ikili veri matrisidir ve X'X SSCP matrisidir. not Xburadaki X, 1-> 0, 0-> 1'dir. Ve buradaki herhangi bir bölünme, elementen bölünmedir. Uygun olmadığını görürseniz lütfen gösterimi düzeltin.
ttnphns

R'de iç ürün (notX) ′ (notX) nasıl hesaplanır?
user4959

@ user4959, R bilmiyorum. İşte ! X önerilir; ancak sonuç boole doğru DOĞRU / YANLIŞ, sayısal değil 1/0. D matrisine gelmenin başka bir yolu olduğunu söylediğimde cevabımı güncellediğimi unutmayın.
ttnphns

9

X seyrek ise yukarıdaki çözelti çok iyi değildir. Çünkü! X almak yoğun bir matris oluşturacak, büyük miktarda bellek ve hesaplama alacak.

Daha iyi bir çözüm Jaccard [i, j] = #common / (#i + #j - #common) formülünü kullanmaktır . Seyrek matrislerle aşağıdaki gibi yapabilirsiniz (kodun seyrek olmayan matrisler için de çalıştığını unutmayın):

library(Matrix)
jaccard <- function(m) {
    ## common values:
    A = tcrossprod(m)
    ## indexes for non-zero common values
    im = which(A > 0, arr.ind=TRUE)
    ## counts for each row
    b = rowSums(m)

    ## only non-zero values of common
    Aim = A[im]

    ## Jacard formula: #common / (#i + #j - #common)
    J = sparseMatrix(
          i = im[,1],
          j = im[,2],
          x = Aim / (b[im[,1]] + b[im[,2]] - Aim),
          dims = dim(A)
    )

    return( J )
}

1

Bu, ihtiyaçlarınızın ne olduğuna bağlı olarak sizin için yararlı olabilir veya olmayabilir. Kümeleme atamaları arasındaki benzerlikle ilgilendiğinizi varsayarsak:

Jaccard Benzerlik Katsayısı veya Jaccard Dizini , iki kümeleme ödevinin benzerliğini hesaplamak için kullanılabilir.

Verilen labelings L1ve L2, Ben-Hur, Elisseeff ve Guyon (2002) Jaccard göstergesi bir ara matrisin nokta ürünler kullanılarak hesaplanabilir göstermiştir. Aşağıdaki kod , ara matrisleri bellekte saklamak zorunda kalmadan, Jaccard Endeksini hızlı bir şekilde hesaplamak için bunu kullanır .

Kod C ++ ile yazılmıştır, ancak sourceCppkomut kullanılarak R'ye yüklenebilir .

/**
 * The Jaccard Similarity Coefficient or Jaccard Index is used to compare the
 * similarity/diversity of sample sets. It is defined as the size of the
 * intersection of the sets divided by the size of the union of the sets. Here,
 * it is used to determine how similar to clustering assignments are.
 *
 * INPUTS:
 *    L1: A list. Each element of the list is a number indicating the cluster
 *        assignment of that number.
 *    L2: The same as L1. Must be the same length as L1.
 *
 * RETURNS:
 *    The Jaccard Similarity Index
 *
 * SIDE-EFFECTS:
 *    None
 *
 * COMPLEXITY:
 *    Time:  O(K^2+n), where K = number of clusters
 *    Space: O(K^2)
 *
 * SOURCES:
 *    Asa Ben-Hur, Andre Elisseeff, and Isabelle Guyon (2001) A stability based
 *    method for discovering structure in clustered data. Biocomputing 2002: pp.
 *    6-17. 
 */
// [[Rcpp::export]]
NumericVector JaccardIndex(const NumericVector L1, const NumericVector L2){
  int n = L1.size();
  int K = max(L1);

  int overlaps[K][K];
  int cluster_sizes1[K], cluster_sizes2[K];

  for(int i = 0; i < K; i++){    // We can use NumericMatrix (default 0) 
    cluster_sizes1[i] = 0;
    cluster_sizes2[i] = 0;
    for(int j = 0; j < K; j++)
      overlaps[i][j] = 0;
  }

  //O(n) time. O(K^2) space. Determine the size of each cluster as well as the
  //size of the overlaps between the clusters.
  for(int i = 0; i < n; i++){
    cluster_sizes1[(int)L1[i] - 1]++; // -1's account for zero-based indexing
    cluster_sizes2[(int)L2[i] - 1]++;
    overlaps[(int)L1[i] - 1][(int)L2[i] - 1]++;
  }

  // O(K^2) time. O(1) space. Square the overlap values.
  int C1dotC2 = 0;
  for(int j = 0; j < K; j++){
    for(int k = 0; k < K; k++){
      C1dotC2 += pow(overlaps[j][k], 2);
    }
  }

  // O(K) time. O(1) space. Square the cluster sizes
  int C1dotC1 = 0, C2dotC2 = 0;
  for(int i = 0; i < K; i++){
    C1dotC1 += pow(cluster_sizes1[i], 2);
    C2dotC2 += pow(cluster_sizes2[i], 2);
  }

  return NumericVector::create((double)C1dotC2/(double)(C1dotC1+C2dotC2-C1dotC2));
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.