Tính toán Jaccard hoặc hệ số liên kết khác cho dữ liệu nhị phân bằng cách nhân ma trận


9

Tôi muốn biết liệu có cách nào để tính hệ số Jaccard bằng cách nhân ma trận hay không.

Tôi đã sử dụng mã này

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

Điều này khá ok để thực hiện trong R. Tôi đã thực hiện tương tự súc sắc, nhưng bị mắc kẹt với Tanimoto / Jaccard. Bất cứ ai có thể giúp đỡ?


Có vẻ như @ttnphns có nội dung này, nhưng vì bạn đang sử dụng R, tôi nghĩ tôi cũng chỉ ra rằng một số chỉ số tương tự (bao gồm cả Jaccard) đã được triển khai trong vegangói. Tôi nghĩ rằng họ cũng có xu hướng được tối ưu hóa tốt cho tốc độ.
David J. Harris

Câu trả lời:


11

Chúng tôi biết rằng Jaccard (được tính giữa hai cột dữ liệu nhị phân bất kỳ ) là , trong khi Rogers-Tanimoto là , trong đóaX a+daa+b+ca+da+d+2(b+c)

  • a - số hàng trong đó cả hai cột là 1
  • b - số hàng trong đó hàng này và không phải cột khác là 1
  • c - số hàng trong đó hàng khác và không phải cột này là 1
  • d - số hàng trong đó cả hai cột bằng 0

Xa+b+c+d=n , số lượng hàng trongX

Sau đó chúng tôi có:

aXX=A là ma trận đối xứng vuông của giữa tất cả các cột.a

d(notX)(notX)=D là ma trận đối xứng vuông của giữa tất cả các cột ("không phải X" đang chuyển đổi 1-> 0 và 0-> 1 trong X).d

Vì vậy, là ma trận đối xứng vuông của Jaccard giữa tất cả các cột.AnD

A+DA+D+2(n(A+D))=A+D2nAD là ma trận đối xứng vuông của Rogers-Tanimoto giữa tất cả các cột.

Tôi đã kiểm tra số lượng nếu các công thức này cho kết quả chính xác. Họ làm.


Cập nhật. Bạn cũng có thể nhận được ma trận và :CBC

X B b XB=[1]XA , trong đó "[1]" biểu thị ma trận của những người thân, có kích thước như . là ma trận bất đối xứng vuông của giữa tất cả các cột; phần tử ij của nó là số hàng trong với 0 trong cột i và 1 trong cột j .XBbX

Do đó, .C=B

Tất nhiên, ma trận cũng có thể được tính theo cách này: .n - A - B - CDnABC

Biết các ma trận , bạn có thể tính toán một ma trận của bất kỳ hệ số tương tự cặp (dis) nào được phát minh cho dữ liệu nhị phân.A,B,C,D


Phân số không có ý nghĩa đối với ma trận trừ khi chúng đi lại: nhân bên phải bằng nghịch đảo sẽ cho kết quả khác so với nhân bên trái. Hơn nữa, thông thường không phải là một sản phẩm của hai ma trận đối xứng là đối xứng. Bạn có thể có nghĩa là phân chia từng thành phần? Bạn có thể sửa chữa ký hiệu của bạn để phản ánh những gì bạn dự định là công thức chính xác?
whuber

@whuber Tôi không sử dụng phép đảo ngược cũng như nhân các ma trận đối xứng vuông . X là ma trận dữ liệu nhị phân và X'X là ma trận SSCP của nó. not Xlà X trong đó 1-> 0, 0-> 1. Và bất kỳ phân chia ở đây là phân chia nguyên tố. Vui lòng sửa ký hiệu của tôi nếu bạn thấy nó không phù hợp.
ttnphns

Làm thế nào để tính sản phẩm bên trong (notX) (notX) trong R?
dùng4959

@ user4959, tôi không biết R. Ở đây ! X được khuyến nghị; tuy nhiên kết quả là Boolean TRUE / FALSE, không phải là số 1/0. Lưu ý rằng tôi đã cập nhật câu trả lời của mình khi tôi nói rằng cũng có một cách khác để đến ma trận D.
ttnphns

9

Giải pháp trên không tốt lắm nếu X thưa thớt. Bởi vì lấy! X sẽ tạo ra một ma trận dày đặc, chiếm số lượng lớn bộ nhớ và tính toán.

Một giải pháp tốt hơn là sử dụng công thức Jaccard [i, j] = #common / (#i + #j - #common) . Với các ma trận thưa thớt, bạn có thể thực hiện như sau (lưu ý mã cũng hoạt động cho các ma trận không thưa thớt):

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

Điều này có thể hoặc có thể không hữu ích cho bạn, tùy thuộc vào nhu cầu của bạn là gì. Giả sử rằng bạn quan tâm đến sự giống nhau giữa các bài tập phân cụm:

Chỉ số tương tự Jaccard hoặc chỉ số Jaccard có thể được sử dụng để tính toán độ tương tự của hai phép gán phân cụm.

Đưa ra các nhãn L1L2, Ben-Hur, Elisseeff và Guyon (2002) đã chỉ ra rằng chỉ số Jaccard có thể được tính bằng cách sử dụng các sản phẩm chấm của ma trận trung gian. Mã dưới đây tận dụng điều này để nhanh chóng tính toán Chỉ số Jaccard mà không phải lưu trữ các ma trận trung gian trong bộ nhớ.

Mã được viết bằng C ++, nhưng có thể được tải vào R bằng sourceCpplệnh.

/**
 * 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));
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.