nltk.metrics.distance中Jaccard Distance度量的实现不符合数学定义?
Implementation of Jaccard Distance metric in nltk.metrics.distance not consistent with the mathematical definition?
我试图使用 nltk.metrics.distance
中内置的 Jaccard 距离度量函数 jaccard_distance()
完成 NLP 作业,当我注意到它的结果在我期望的上下文中没有意义时.
当我在 Jaccard 索引的 online source, I noticed that it was not consistent with the mathematical definition 中检查 jaccard_distance()
的实现时。
具体来说,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 距离的话。
当我使用 nltk
中的 jaccard_distance()
时,我反而获得了如此多的完美匹配(距离函数的结果是 1.0
),但离正确还差得很远。
当我在后一个实现中使用自己的函数时,我能够在 cormulent[ 的 Jaccard 距离为 0.4 的情况下获得 corpulent 的拼写建议=43=],不错的推荐。
nltk
中的 jaccard_distance()
是否存在错误?
您引用的两个公式并不完全相同,但它们在数学上是相关的。您从 NLTK 包中引用的第一个定义称为 Jaccard 距离 (DJaccard)。您引用的第二个称为 Jaccard 相似度 (SimJaccard).
在数学上,DJaccard = 1 - SimJaccard。这里的直觉是它们越相似(SimJaccard 越高),距离越小(因此,DJaccard) .
您确定没有将 Jaccard 的 index 与 Jaccard 的 distance 混淆吗?
第一个确实应该按照您的建议进行计算,而第二个是 1-Jaccard_index(A,B)
,这与 NLTK 实现中的完全一样。
执行速度更快(0.83 对 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))
我试图使用 nltk.metrics.distance
中内置的 Jaccard 距离度量函数 jaccard_distance()
完成 NLP 作业,当我注意到它的结果在我期望的上下文中没有意义时.
当我在 Jaccard 索引的 online source, I noticed that it was not consistent with the mathematical definition 中检查 jaccard_distance()
的实现时。
具体来说,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 距离的话。
当我使用 nltk
中的 jaccard_distance()
时,我反而获得了如此多的完美匹配(距离函数的结果是 1.0
),但离正确还差得很远。
当我在后一个实现中使用自己的函数时,我能够在 cormulent[ 的 Jaccard 距离为 0.4 的情况下获得 corpulent 的拼写建议=43=],不错的推荐。
nltk
中的 jaccard_distance()
是否存在错误?
您引用的两个公式并不完全相同,但它们在数学上是相关的。您从 NLTK 包中引用的第一个定义称为 Jaccard 距离 (DJaccard)。您引用的第二个称为 Jaccard 相似度 (SimJaccard).
在数学上,DJaccard = 1 - SimJaccard。这里的直觉是它们越相似(SimJaccard 越高),距离越小(因此,DJaccard) .
您确定没有将 Jaccard 的 index 与 Jaccard 的 distance 混淆吗?
第一个确实应该按照您的建议进行计算,而第二个是 1-Jaccard_index(A,B)
,这与 NLTK 实现中的完全一样。
执行速度更快(0.83 对 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))