【问题标题】:Implementation of Jaccard Distance metric in nltk.metrics.distance not consistent with the mathematical definition?nltk.metrics.distance中Jaccard距离度量的实现与数学定义不一致?
【发布时间】:2018-03-11 06:55:58
【问题描述】:

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

当我检查 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))

当我使用后者编写自己的函数时,我确实得到了正确答案。例如,我的任务是为拼写错误的单词 cormulent 推荐一个正确的拼写建议,该建议来自一个综合的单词语料库(内置于nltk),对单词的三元组使用 Jaccard 距离。

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

当我使用我自己的函数进行后一种实现时,我能够在与 cormulent 的 Jaccard 距离为 0.4 处获得 corpulent 的拼写推荐,这是一个不错的推荐.

jaccard_distance()nltk 中会不会有错误?

【问题讨论】:

  • 感谢大家的帮助!我现在也理解了jaccard_distance()nltk 实现中的分子项,它来自执行 1 - Jaccard Similarity。

标签: python nlp nltk distance metric


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    您确定没有将 Jaccard 的 index 与 Jaccard 的 distance 混淆吗?

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

    【讨论】:

      猜你喜欢
      • 2019-08-21
      • 1970-01-01
      • 2020-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多