การคำนวณ Jaccard หรือสัมประสิทธิ์การเชื่อมโยงอื่น ๆ สำหรับข้อมูลไบนารีโดยใช้การคูณเมทริกซ์


9

ฉันต้องการทราบว่ามีวิธีใดที่เป็นไปได้ในการคำนวณสัมประสิทธิ์ Jaccard โดยใช้การคูณเมทริกซ์

ฉันใช้รหัสนี้

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

มันค่อนข้างโอเคที่จะนำไปใช้ในอาร์ฉันได้ทำลูกเต๋าที่มีความคล้ายคลึงกัน แต่ติดกับ Tanimoto / Jaccard ใครช่วยได้บ้าง


ดูเหมือน @ttnphns ได้ครอบคลุมสิ่งนี้ แต่เนื่องจากคุณใช้ R ฉันคิดว่าฉันยังชี้ให้เห็นว่ามีดัชนีความคล้ายคลึงกันจำนวนมาก (รวมถึง Jaccard) ถูกนำไปใช้ในveganแพ็คเกจแล้ว ฉันคิดว่าพวกเขามีแนวโน้มที่จะได้รับการปรับให้เหมาะสมกับความเร็วด้วย
David J. Harris

คำตอบ:


11

เรารู้ว่า Jaccard (คำนวณระหว่างสองคอลัมน์ของข้อมูลไบนารี ) คือขณะที่ Rogers-Tanimoto คือโดยที่Xaa+b+ca+da+d+2(b+c)

  • a - จำนวนแถวที่ทั้งสองคอลัมน์เป็น 1
  • b - จำนวนแถวโดยที่ไม่ใช่คอลัมน์อื่นคือ 1
  • c - จำนวนแถวที่อื่น ๆ และไม่ใช่คอลัมน์นี้คือ 1
  • d - จำนวนแถวที่ทั้งสองคอลัมน์เป็น 0

a+b+c+d=n , จำนวนแถวในX

จากนั้นเรามี:

XX=Aคือเมทริกซ์สมมาตรแบบจัตุรัสของระหว่างคอลัมน์ทั้งหมดa

(notX)(notX)=Dคือเมทริกซ์จตุรัสสมมาตรของระหว่างคอลัมน์ทั้งหมด ("ไม่ใช่ X" กำลังแปลง 1-> 0 และ 0-> 1 ใน X)d

ดังนั้นคือเมทริกซ์สมมาตรแบบสี่เหลี่ยมจัตุรัสของ Jaccard ระหว่างคอลัมน์ทั้งหมดAnD

A+DA+D+2(n(A+D))=A+D2nADเป็นเมทริกซ์สมมาตรแบบสมมาตรของ Rogers-Tanimoto ระหว่างคอลัมน์ทั้งหมด

ฉันตรวจสอบตัวเลขถ้าสูตรเหล่านี้ให้ผลลัพธ์ที่ถูกต้อง พวกเขาทำ.


UPD นอกจากนี้คุณยังสามารถรับเมทริกซ์และ :BC

B=[1]XAที่ไหน "[1]" หมายถึงเมทริกซ์ของคนขนาดเป็นX คือเมทริกซ์จตุรัสไม่สมมาตรของระหว่างคอลัมน์ทั้งหมด; องค์ประกอบของIJเป็นจำนวนแถวในด้วย 0 ในคอลัมน์ฉันและ 1 ในคอลัมน์JXBbX

ดังนั้นB'C=B

เมทริกซ์ยังสามารถคำนวณด้วยวิธีนี้ของหลักสูตร:-ABCDnABC

การรู้เมทริกซ์ , คุณสามารถคำนวณเมทริกซ์ของสัมประสิทธิ์ความคล้ายคลึงกันของคู่ (dis) ใด ๆ ที่คิดค้นขึ้นสำหรับข้อมูลไบนารีA,B,C,D


เศษส่วนไม่สมเหตุสมผลสำหรับการฝึกอบรมเว้นแต่ว่าพวกเขาจะเดินทาง: การคูณด้านขวาด้วยการกลับกันจะให้ผลลัพธ์ที่แตกต่างจากการคูณทางซ้าย ยิ่งไปกว่านั้นมันมักจะไม่ใช่กรณีที่ผลิตภัณฑ์ของเมทริกซ์สมมาตรสองตัวคือสมมาตร คุณอาจหมายถึงการแบ่งส่วนประกอบตามส่วนประกอบ? คุณสามารถแก้ไขสัญกรณ์ของคุณให้สะท้อนถึงสิ่งที่คุณต้องการเป็นสูตรที่ถูกต้องได้หรือไม่?
whuber

@whuber ฉันไม่ได้ใช้การผกผันหรือการคูณเมทริกซ์สมมาตรแบบจัตุรัส X คือเมทริกซ์ข้อมูลไบนารีและ X'X เป็นเมทริกซ์ SSCP not Xคือ X โดยที่ 1-> 0, 0-> 1 และการหารใด ๆ ที่นี่คือการหารองค์ประกอบ โปรดแก้ไขสัญลักษณ์ของฉันหากคุณเห็นว่าไม่เหมาะสม
ttnphns

วิธีการคำนวณผลิตภัณฑ์ด้านใน (notX) ′(notX) ใน R
user4959

@ user4959 ฉันไม่ทราบว่าอาร์ที่นี่ ! X แนะนำ; อย่างไรก็ตามผลลัพธ์คือบูลีน TRUE / FALSE ไม่ใช่ตัวเลข 1/0 โปรดทราบว่าฉันได้อัปเดตคำตอบโดยที่ฉันบอกว่ายังมีอีกวิธีหนึ่งที่จะมาถึง D matrix
ttnphns

9

การแก้ปัญหาข้างต้นไม่ดีมากถ้า X กระจัดกระจาย เพราะการทำ! X จะสร้างเมทริกซ์ที่หนาแน่นใช้หน่วยความจำและการคำนวณจำนวนมาก

ทางออกที่ดีคือการใช้สูตรJaccard [ฉัน j] = #common / (# ฉัน + #J - #common) ด้วยเมทริกซ์กระจัดกระจายคุณสามารถทำดังต่อไปนี้ (หมายเหตุรหัสยังใช้งานได้สำหรับเมทริกซ์ที่ไม่กระจัดกระจาย):

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

สิ่งนี้อาจเป็นประโยชน์กับคุณหรือไม่ก็ได้ขึ้นอยู่กับความต้องการของคุณ สมมติว่าคุณสนใจในความคล้ายคลึงกันระหว่างการกำหนดกลุ่ม:

ค่าสัมประสิทธิ์ความคล้ายกันของ Jaccard หรือดัชนี Jaccardสามารถนำมาใช้ในการคำนวณความคล้ายคลึงกันของการมอบหมายการทำคลัสเตอร์สองครั้ง

ได้รับการ labelings L1และL2, เบนเฮอร์, Elisseeff และ Guyon (2002)แสดงให้เห็นว่าดัชนี Jaccard สามารถคำนวณโดยใช้จุดผลิตภัณฑ์ของเมทริกซ์กลาง โค้ดด้านล่างใช้ประโยชน์จากสิ่งนี้เพื่อคำนวณดัชนี Jaccard อย่างรวดเร็วโดยไม่ต้องจัดเก็บเมทริกซ์กลางในหน่วยความจำ

รหัสถูกเขียนใน C ++ แต่สามารถโหลดลงใน R โดยใช้sourceCppคำสั่ง

/**
 * 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));
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.