在nltk.metrics.distance中实现Jaccard Distance度量与数学定义不一致?



我试图使用内置在nltk.metrics.distance中的杰卡德距离度量jaccard_distance()函数完成NLP分配,当时我注意到它的结果在我期望的上下文中没有意义。

当我检查在线资源中jaccard_distance()的实现时,我注意到它与Jaccard指数的数学定义不一致。

具体来说,nltk中的实现是:

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

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

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

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

当我使用nltkjaccard_distance()时,我得到了如此多的完美匹配(距离函数的结果是1.0),而这些匹配远非正确。

当我使用自己的函数进行后一种实现时,我能够获得corpulent的拼写建议,在 Jaccard 距离cormulent0.4 处,这是一个不错的建议。

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

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

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

你确定你没有把杰卡德的索引和杰卡德的距离混淆吗?

第一个确实应该按照您的建议进行计算,而第二个是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))

最新更新