nltk.metrics.distance中Jaccard距离度量的实现与数学定义不一致?

时间:2018-03-11 06:55:58

标签: python nlp nltk distance metric

我试图使用jaccard_distance()中内置的Jaccard距离度量函数nltk.metrics.distance来完成NLP赋值,当我注意到它的结果在我期望的上下文中没有意义。 / p>

当我检查online sourcejaccard_distance()的实现时,我注意到它与Jaccard索引的mathematical definition不一致。

具体而言,nltk中的实施是:

return (len(label1.union(label2)) - len(label1.intersection(label2)))/len(label1.union(label2))

但是根据定义,分子术语应该只涉及两组的交集,这意味着正确的实现应该是:

return len(label1.intersection(label2))/len(label1.union(label2))

当我使用后者编写自己的函数时,我确实获得了正确的答案。例如,我的任务是使用单词三元组中的Jaccard Distance,从一个全面的单词语料库(内置nltk)中为拼写错误的单词 cormulent 推荐正确的拼写建议。

当我使用jaccard_distance()中的nltk时,我获得了很多完美的匹配(距离函数的结果是1.0),而这些匹配远远不够正确。

当我使用我自己的函数后一个实现时,我能够得到肥胖的拼写推荐,距离 cormulent 的Jaccard距离为0.4,这是一个不错的推荐

jaccard_distance()中的nltk可能存在错误吗?

2 个答案:

答案 0 :(得分:1)

您引用的两个公式并不完全相同,但它们在数学上是相关的。您从NLTK包中引用的第一个定义称为Jaccard Distance(D Jaccard )。你引用的第二个叫做Jaccard Similarity(Sim Jaccard )。

数学上,D Jaccard = 1 - Sim Jaccard 。这里的直觉是它们越相似(Sim Jaccard 越高),距离越低(因此,D Jaccard )。

答案 1 :(得分:1)

您确定不会将Jaccard的索引与Jaccard的距离混淆吗?

第一个确实应该按照你的建议计算,而第二个确实是1-Jaccard_index(A,B),这与NLTK实现完全一样。

实施速度更快(0.83 vs. 1.29s = ~35%),具有以下变化:

def jaccard_distance(label1, label2):
    len_union = len(label1.union(label2))
    return (len_union - len(label1.intersection(label2)))/len_union

您可以通过以下方式重复我的测试(集合的结构将改变时间 - 这只是一个例子):

from timeit import timeit

a = {1,4,6,7,5,7,9,234}
b = {1,43,66,7,85,7,89,234}

def jaccard_distance(label1, label2):
    len_union = len(label1.union(label2))
    return (len_union - len(label1.intersection(label2))) / len_union

def jaccard_distance2(label1, label2):
    return (len(label1.union(label2)) - len(label1.intersection(label2))) / len(label1.union(label2))


s1 = """a = {1,4,6,7,5,7,9,234}
b = {1,43,66,7,85,7,89,234}
def jaccard_distance(label1, label2):
     len_union = len(label1.union(label2))
     return (len_union - len(label1.intersection(label2))) / len_union
for i in range(100000):
     jaccard_distance(a,b)"""

s2 = """a = {1,4,6,7,5,7,9,234}
b = {1,43,66,7,85,7,89,234}
def jaccard_distance2(label1, label2):
     return (len(label1.union(label2)) - len(label1.intersection(label2))) / len(label1.union(label2))
for i in range(100000):
     jaccard_distance2(a,b)"""

print(timeit(stmt=s1, number=10))
print(timeit(stmt=s2, number=10))