R中的Jaccard相似度

机器算法验证 r 杰卡相似度
2022-04-10 19:54:10

我想比较 2 个长度为 43 的向量;它们的值为 0(不存在)和 1(存在)。我将称为同时存在 1 的情况,将称为仅存在一个 1 而另一个值为 0 的情况。M1,1M1,0M0,1

data3$IDS  1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 
       0 0 0 0 0 0 0 0 0 0
data3$CESD 1 1 1 0 1 1 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1
           1 1 1 1 1 1 1 1 1 1 

我想了解这两个向量的相关性。阅读该主题,Jaccard索引似乎是要走的路。在这种特定情况下,Jaccard 索引将是(请注意,我使用的是 Wikipedia 上第二个数字旁边给出的公式): 在我的例子中:

M1,1(M1,0+M0,1M1,1)
8/(23+128)=0.2962963

使用:

library('clusteval')
cluster_similarity(data3$IDS, data3$CESD, similarity="jaccard", method="independence")

回报:

0.553429

我不太明白为什么,以及我犯的错误在哪里。

我不明白的另一件事是在高度重叠的情况下。想象一下中只有这将导致 Jaccard 指数为M1,1=302M1,0M0,130/(2+230)=1.153846

但是J指数只定义在0到1之间。我的误解在哪里?

4个回答

查看 Wikipedia 页面的编辑历史,似乎问题是由于对用于表示索引的两种数学符号的混淆造成的。使用集合论的符号,我们有: 其中,表示交集表示并表示基数

J(A,B)=|AB||AB|=|AB||A|+|B||AB|
| |

再往下看,公式是使用矩阵/列联表中的计数以代数方式呈现的: 这对编辑来说似乎是矛盾的谁评论说“公式中的错误[原文如此]。应该减去交叉点”。 M

J=M11M10+M01+M11

这两个公式实际上是一致的,因为尽管代数公式可以这样表示(以一种更麻烦的方式,但更清楚地与上面的公式平行):|AB|=M11|A|M10|B|M01

J=M11jM1j+iMi1M11

这个公式确实是错误的。

它应该是 m11 / (m01 + m10 + m11),因为 Jaccard 索引是两个集合之间的交集的大小除以这些集合之间的并集的大小。

正确的值是 8 / (12 + 23 + 8) = 0.186。不过我觉得很奇怪,这与您从 R 包中获得的值不同。

您正确理解 Jaccard 索引是介于 0 和 1 之间的值。例如,您给出的正确索引是 30 / (2 + 2 + 30) = 0.882。

我写了一个简单的函数来计算二元属性的 Jaccard 指数(相似系数)和互补 Jaccard 距离:

# Your dataset
df2 <- data.frame(
  IDS = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 
  CESD = c(1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1))

# Function returns the Jaccard index and Jaccard distance
jaccard <- function(df, margin) {
  if (margin == 1 | margin == 2) {
    M_00 <- apply(df, margin, sum) == 0
    M_11 <- apply(df, margin, sum) == 2
    if (margin == 1) {
      df <- df[!M_00, ]
      JSim <- sum(M_11) / nrow(df)
    } else {
      df <- df[, !M_00]
      JSim <- sum(M_11) / length(df)
    }
    JDist <- 1 - JSim
    return(c(JSim = JSim, JDist = JDist))
  } else break
}

该函数有两个参数:x一个数据框或矩阵对象,以及函数中使用的m参数如果您的数据采用宽格式设置为应用于列。如果您的数据采用长格式设置为应用于行。 MARGINapplym = 2summ = 1sum

> jaccard(df2, 1)
     JSim     JDist 
0.1860465 0.8139535 

解决了。问题是维基百科实际上是错误的,特别是公式:

m11/(m10+m01-m11)