使用 Python 和 NLP 的 Jaccard 相似度和 Jaccard 索引

杰卡德距离和杰卡德相似度(也称为杰卡德指数)是集合论中两个集合之间相似性的度量。杰卡德相似度在自然语言处理中非常有用,因为它们可以在一定程度上给出两个单词或句子之间的相似性度量。杰卡德相似度是两个集合之间相似性的度量,这意味着杰卡德相似度的值越高,两个集合越相似。另一方面,杰卡德距离与杰卡德相似度相对应,它是对两个集合的相似程度的度量。它计算两组之间的距离。因此,值越低,两个集合彼此越接近或越相似。

杰卡德相似度和杰卡德距离的概念完全基于集合论,并使用基本的集合运算来计算。计算方法如下:

杰卡德相似度公式

上式中,分子为集合A和B中共有元素的个数,即集合A和B的交集。分母为集合A和B中元素的总数,即集合A和B的并集。应该注意的是,这里使用的是集合,因此也需要遵循集合的规则。在获取序数之前,重复元素会从交集和并集中删除。杰卡德距离计算如下:

杰卡德距离公式

上式中,分子中的运算符为对称差。从这篇文章中可以看出,Symmetric Difference 中的元素个数基本上就是 Union 中元素个数与 Intersection 中元素个数之差。将其作为上式中对称差值的值,得到以下结果:

代入对称差值后的杰卡德距离公式

可以简单地写为:

杰卡德距离简化公式 1

所以基本上,杰卡德距离是两个集合的杰卡德相似度减去 1。但是这个基本公式不足以计算自然语言处理中两个单词/句子之间的相似度。要理解其中的原因,需要用Python实现Jaccard Distance,然后几句话的结果就描述了低效的输出。更严格版本的杰卡德相似度和杰卡德距离将用于计算自然语言处理中两个单词/句子之间的相似度。

杰卡德相似度和杰卡德距离的实现

这里将使用Python数据结构集来实现。集合是列表,但它们没有重复的元素。可以使用 set() 函数将列表转换为集合。Jaccard相似度的实现如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def JaccardSimilarity(firstset,secondset):
  list1=list(firstset)
  list2=list(secondset)
  union=0
  intersection=0
  set1=set(list1)
  set2=set(list2)
  for element in set1:
    if element in set2:
      intersection=intersection+1
  unionlist=list1+list2
  unionset=set(unionlist)
  union=len(unionset)
  js=intersection/union
  return js

从上面的代码片段中可以看出,函数 JaccardSimilarity() 的输入,即firstset和secondset,首先被转换为列表,然后对列表进行处理。这样做是为了在继续之前将任何类型的其他数据结构(例如字符串或元组)转换为列表。并集和交集变量保存并集和交集中的项目数。需要注意的是,Set数据结构的union()和intersection()函数也可以用来达到目的,但这里为了更好的解释而将它们单独实现。两个列表都被转换为集合,并且这些列表中的重复元素被消除。现在迭代第一个集合中的每个元素,如果在第二个集合中找到,则交集变量递增 1。创建另一个集合,称为并集,这是两个列表组合的集合。其长度被指定为联合变量。杰卡德相似度是交集变量除以并集变量。

如上所述,杰卡德距离只不过是杰卡德相似度减去 1。因此,杰卡德距离的实现如下:

1
2
def JaccardDistance(word1,word2):
  return 1-JaccardSimilarity(word1,word2)

上面的函数使用了已经实现的 JaccardSimialrity() 函数。现在,以下两个列表将作为 JaccardSimilarity() 和 JaccardDistance() 函数的输入提供,以检查其输出:

1
2
3
4
set1=[1,1,4,5,7,9,0,6,5]
set2=[9,6,3,6,4,0,1,2,1]
print('Jaccard Similarity: '+str( JaccardSimilarity(set1,set2)))
print('Jaccard Distance: '+ str(JaccardDistance(set1,set2)))

它产生以下输出:

集合上的杰卡德相似度和杰卡德距离输出

输出如预期。转换为集合后的列表变为{1,4,7,5,9,0,6}和{1,2,3,4,0,6,9}。并集有 9 个元素 {1,4,7,5,9,0,6,2,3} ,它们的交集有 5 个元素 {1,4,6,9,0} 。因此 JaccardSimilarity() 的输出为 5/9=0.555556,JaccardDistance() 的输出为 4/9=0.4444444444。

但是当使用 JaccardSimilarity() 函数计算两个单词/句子之间的相似度时,就会出现问题。为了说明这一事实,使用了几句话作为例子。运行以下代码时:

1
2
3
4
listofwords=['list','set','tuple','jaccard','jackal','distance','index','article','python','mobile','computer','square']
for word in listofwords:
  print(word)
  print(JaccardSimilarity(word,word))

产生以下输出:

相同输入词的 Jaccard 相似度输出

这是预期的输出,因为相同的单词将产生 1.0 JaccardSimilairty()。但如果其中一些单词故意拼写错误,会发生什么情况呢?以下代码执行相同的操作:

1
2
3
4
5
listofwords=['list','set','tuple','jaccard','jackal','distance','index','article','python','mobile','computer','square']
fakewords=['lits','set','tulp','jakard','jakal','ditsance','idnex','articel','typhoon','mobeel','computer','sqaure']
for i in range(len(listofwords)):
  print(listofwords[i]+' '+fakewords[i])
  print(JaccardSimilarity(listofwords[i],fakewords[i]))

应该注意的是,其中一些单词(例如“square”和“sqaure”)存在细微差别,但“sqaure”是错误的拼写,因此 JaccardSimilarity() 不应返回 1.0 。但这是从代码中观察到的输出:

Jaccard相似度输出

它对某些单词(如“jaccard”和“jakard”)效果很好,但对于大多数拼写错误的单词(如“index”和“idnex”或“article”和“articel”),JaccardSimilarity() 返回值 1.0;这是不可接受的。因此,需要为自然语言处理实现更严格版本的 JaccardSimilarity()。

NLP 的杰卡德相似度和杰卡德距离

NLP 的 Jaccard 相似性背后的基本思想是,单词字符串不会转换为集合,并且当且仅当这些单词的字母出现在两个列表中的相同位置时,这些单词的字母才会包含在交集集中。使用这些更严格的条件,JaccardSimilarity() 在匹配单词相似度方面提供了比原始想法更准确的结果。如下面的代码所示:

1
2
3
4
5
6
7
8
9
10
11
def JaccardSimilarityforNLP(word1,word2):
  list1=list(word1)
  list2=list(word2)
  iter=min(len(list1),len(list2))
  union=len(set(list1+list2))
  intersection=0
  for i in range(iter):
    if list1[i]==list2[i]:
      intersection=intersection+1
  ji=intersection/union
  return ji

在上面的代码片段中,代码运行 for 循环多次迭代,其中数字是较小单词的长度。如果某个字母出现在两个列表中的同一位置,则该字母被视为处于交集集中。并集的计算方法与之前使用的方法相同。使用该算法,Jaccard Comparison 可以提供两个单词之间更清晰的相似度。运行以下代码可以看到:

1
2
3
4
5
listofwords=['list','set','tuple','jaccard','jackal','distance','index','article','python','mobile','computer','square']
fakewords=['lits','set','tulpe','jakkard','jakcal','ditsance','idnex','articel','typhon','mobeel','computer','sqaure']
for i in range(len(listofwords)):
  print(listofwords[i]+' '+fakewords[i])
  print(JaccardSimilarityforNLP(listofwords[i],fakewords[i]))

它提供以下输出:

NLP Jaccard相似度输出

这提供了关于两个不同单词之间相似性的更清晰的基础想法。但应该注意的是,杰卡德距离对于具有相同长度的单词/句子效果更好。编辑距离是衡量两个不同长度单词之间相似性的更好指标。

还应该注意的是,Jaccard 相似度并不总是为相同的单词提供精确的 1.0。有时,该值可能大于 1。发生这种情况是因为定义的交集中的元素数量可能多于两个单词的并集中的元素数量。两个不同的单词的 Jaccard 相似度(在本例中)肯定小于 1,但两个相同的单词的 Jaccard 相似度可以等于或大于 1。可以在以下示例中看到:

listofwords=['list','set','tuple','jaccard','jackal','distance','index','article','python','mobile','computer','square']
for word in listofwords:
  print(word)
  print(JaccardSimilarityforNLP(word,word))

它产生以下输出:

NLP Jaccard 相同单词的相似度输出

两个相同的单词的 Jaccard 相似度(在本例中)永远不会小于 1。

Jaccard 距离和 Jaccard 相似度等指标在不同的 Python 自然语言处理库(如 NLTK 和 SpaCy)中也得到了更准确的实现。他们的实现还掩盖了该实现中遗漏的不准确之处。他们的官方文档的链接是NLTKSpaCy

结论

基于单词的相似性匹配在自然语言处理中非常重要。杰卡德距离和杰卡德相似度对于测量两个集合之间的相似性非常有用。由于NLP中的单词和句子可以被视为集合,因此Jaccard距离和Jaccard相似度也提供了衡量单词/句子相似度的度量。为了成功实施,他们的规则必须更加严格,因为正常的 Jaccard 相似度将无法衡量 NLP 中的相似度。检查两个相同长的单词/句子中的同一位置是否存在字母,并仅考虑交集集中的那些元素,可以提供比正常 Jaccard 相似度更好的输出。

相似性匹配可以带来一些有用的基于 NLP 的应用程序,例如聊天机器人和翻译器。本文介绍如何使用 SpaCy 的相似性匹配在 Python 中制作聊天机器人。

关于杰卡德相似度和杰卡德距离的常见问题

如何计算杰卡德相似度?

杰卡德相似度是两个集合之间相似度的度量。它是通过集合交集中的元素数量除以并集中的元素数量来衡量的。其得分介于 0 到 1 之间。如果两个集合没有交集的元素,即 Jaccard 相似度为 0,则两个集合完全不相似,而如果两个集合中的所有元素都存在交集,即 Number,则两个集合完全相似交集的元素个数等于并集的元素个数,即杰卡德相似度为1。

如何计算杰卡德距离

杰卡德距离是两个集合之间差异的度量,与杰卡德相似度相反。计算方法为杰卡德相似度减去 1。其值也介于 0 到 1 之间。杰卡德距离越低,两个集合越相似

Jaccard相似度在NLP中如何使用?

Jaccard 相似度在 NLP 中非常有用,因为它可以衡量两个单词或句子之间的相似度。它用于聊天机器人实现、翻译、搜索引擎创建等。 Jaccard 相似度提供了两个相同长度的单词或句子之间相似性测量的良好指标,但编辑距离对于不同长度的单词或句子来说是一个更准确的指标。

什么是杰卡德相似指数?

杰卡德相似度指数是根据杰卡德相似度本身计算得出的。它是 Jaccard 相似度乘以 100,它给出了两个集合之间相似度的百分比表示。