Обчислення коефіцієнта Жакарда або іншого асоціації для двійкових даних за допомогою множення матриць


9

Я хочу знати, чи є можливий спосіб обчислити коефіцієнт Жакарда за допомогою матричного множення.

Я використав цей код

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

Це цілком нормально втілити в Р. Я зробив схожість на кістки, але застряг із Танімото / Жакардом. Хтось може допомогти?


Схоже, це покривало @ttnphns, але, оскільки ви використовуєте R, я подумав, що я також зазначу, що в veganпакеті вже реалізовано ряд індексів подібності (включаючи Жакарда) . Я думаю, що вони також досить добре оптимізовані для швидкості.
Девід Дж. Харріс

Відповіді:


11

Ми знаємо, що Жакард (обчислений між будь-якими двома стовпцями двійкових даних ) є , тоді як Роджерс-Танімото є , деXaa+b+cа+га+г+2(б+c)

  • a - кількість рядків, де обидва стовпці дорівнюють 1
  • b - кількість рядків, де цей, а не інший стовпець 1
  • c - кількість рядків, де інший, а не цей стовпець 1
  • d - кількість рядків, де обидва стовпці дорівнюють 0

а+б+c+г=н , кількість рядків уХ

Тоді ми маємо:

Х'Х=А є квадратної симетричною матрицею між усіма стовпчиками.а

(нотХ)'(нотХ)=D - квадратна симетрична матриця між усіма стовпцями ("не X" перетворює 1-> 0 і 0-> 1 в X).г

Отже, - квадратна симетрична матриця Жакарда між усіма стовпцями.Ан-D

А+DА+D+2(н-(А+D))=А+D2н-А-D - квадратна симетрична матриця Роджерс-Танімото між усіма колонами.

Я перевіряв чисельно, чи ці формули дають правильний результат. Вони роблять.


Оновити Ви також можете отримати матриці та :БС

Б=[1]'Х-А , де "[1]" позначає матрицю з одиниць, розміром , як . - квадратна асиметрична матриця між усіма стовпцями; його елемент ij - кількість рядків у з 0 у стовпці i та 1 у колонці j .ХБбХ

Отже, .С=Б'

Матриця може бути також обчислена таким чином, звичайно: .Dн-А-Б-С

Знаючи матриці , ви можете обчислити матрицю будь-якого попарного (не) коефіцієнта подібності, винайденого для двійкових даних.А,Б,С,D


Дроби не мають сенсу для матриць, якщо вони не коментують: множення праворуч на обернене інакше дасть інший результат, ніж множення ліворуч. Більше того, зазвичай не так, що добуток двох симетричних матриць є симетричним. Ви, мабуть, маєте на увазі поділ за компонентами? Чи можете ви зафіксувати своє позначення так, щоб відображати правильну формулу, яку ви маєте намір?
whuber

@whuber Я не використовую інверсію і не множення квадратних симетричних матриць. X - матриця двійкових даних, а X'X - її матриця SSCP. not Xє X, де 1-> 0, 0-> 1. І будь-який поділ тут - це елементний поділ. Будь ласка, виправте моє позначення, якщо ви бачите, що це не підходить.
ttnphns

Як обчислити внутрішній добуток (notX) ′ (notX) в R?
user4959

@ user4959, я не знаю R. Тут ! X рекомендується; однак результат булів ПРАВИЛЬНО / ФАЛЬШЕ, а не числовий 1/0. Зауважте, що я оновив свою відповідь там, де кажу, що є також інший спосіб дійти до матриці D.
ttnphns

9

Вищевказане рішення не дуже добре, якщо X є рідким. Тому що прийняття! X складе щільну матрицю, зайнявши величезну кількість пам'яті та обчислення.

Кращим рішенням є використання формули Jaccard [i, j] = #common / (#i + #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

Це може бути або не корисним для вас, залежно від ваших потреб. Припустимо, що вас цікавить схожість між завданнями кластеризації:

Коефіцієнт подібності Жакарда або індекс Жакарда можна використовувати для обчислення подібності двох призначень кластеризації.

Враховуючи маркування L1та L2, Бен-Хур, Еліссефф та Гайон (2002) показали, що індекс Жакарда можна обчислити, використовуючи крапкові продукти проміжної матриці. Наведений нижче код використовує це для швидкого обчислення індексу Жакарда без необхідності зберігання проміжних матриць у пам'яті.

Код написаний на 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));
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.