代码之家  ›  专栏  ›  技术社区  ›  AKKA

nltk中Jaccard距离度量的实现。指标。距离与数学定义不一致?

  •  2
  • AKKA  · 技术社区  · 6 年前

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

    当我检查 jaccard\u距离() online source ,我注意到它与 mathematical definition 用于Jaccard索引。

    具体而言,在 nltk 是:

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

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

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

    当我使用后者编写自己的函数时,我确实得到了我的作业的正确答案。例如,我的任务是为拼写错误的单词推荐正确的拼写建议 粗纤维 ,来自全面的词汇库(内置 nltk公司 ),在单词的三角形上使用Jaccard距离。

    当我使用 jaccard\u距离() 从…起 nltk公司 ,我反而获得了如此多的完美匹配(距离函数的结果是 1.0 )这根本不正确。

    当我使用自己的函数(后一种实现)时,我能够得到拼写建议 发福的 ,Jaccard距离为0.4 粗纤维 ,一个不错的建议。

    会不会有bug jaccard\u距离() 在里面 nltk公司 ?

    2 回复  |  直到 6 年前
        1
  •  2
  •   cs95 abhishek58g    6 年前

    你引用的两个公式做的事情并不完全相同,但它们在数学上是相关的。从NLTK包中引用的第一个定义称为Jaccard距离(D 贾卡德 )。您引用的第二个称为Jaccard相似性(Sim 贾卡德 )。

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

        2
  •  1
  •   sophros    6 年前

    你确定你没有混淆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))