比 FuzzyWuzzy 更好的方法?

Better Approach than FuzzyWuzzy?

我在 fuzzywuzzy 中得到的结果不如预期的那样有效。如果中间多了一个词,由于levenshtein的差异,得分较低。

示例:

from fuzzywuzzy import fuzz

score = fuzz.ratio('DANIEL CARTWRIGHT', 'DANIEL WILLIAM CARTWRIGHT')
print(score)
score = fuzz.ratio('DANIEL CARTWRIGHT', 'DAVID CARTWRIGHT')
print(score)

score = fuzz.partial_ratio('DANIEL CARTWRIGHT', 'DANIEL WILLIAM CARTWRIGHT')
print(score)
score = fuzz.partial_ratio('DANIEL CARTWRIGHT', 'DAVID CARTWRIGHT')
print(score)

结果: 81 85 71 81

我正在寻找第一对(Daniel vs. Daniel William)比第二对(Daniel vs. David)更好的比赛。

这里有比 fuzzywuzzy 更好的方法吗?

对于您的示例,您可以使用 token_set_ratio。代码文档说它采用令牌与剩余令牌的交集的比率。

from fuzzywuzzy import fuzz

score = fuzz.token_set_ratio('DANIEL CARTWRIGHT', 'DANIEL WILLIAM CARTWRIGHT')
print(score)
score = fuzz.token_set_ratio('DANIEL CARTWRIGHT', 'DAVID CARTWRIGHT')
print(score)

结果:

100
85

我在使用 FuzzyWuzzy 将一个名称列表与另一个名称列表进行比较以识别列表之间的匹配时遇到了类似的挑战。 FuzzyWuzzy token_set_ratio 记分器对我不起作用,因为使用您的示例,将“DANIEL CARTWRIGHT”与“DANIEL WILLIAM CARTWRIGHT”以及“DANIEL WILLIAM CARTWRIGHT”与“DANIEL WILLIAM CARTWRIGHT”进行比较(部分匹配 2 3 个词与 3 个词中的 3 个的身份匹配)都产生 100% 的分数。对我来说,3 个单词的匹配比 3 个中的 2 个匹配需要更高的分数。

我最终在类似词袋的方法中使用了 nltk。下面代码中的算法将多词名称转换为不同词(标记)的列表,并计算一个列表中的词与另一个列表中的词的匹配项,并将计数归一化为每个列表中的词数。因为 True = 1 和 False = 0,所以 sum() 过度测试元素是否在列表中可以很好地工作 count the elements of one list in another list.

所有单词的身份匹配得分为 1 (100%)。您的比较得分如下:

  • 丹尼尔·卡特赖特与丹尼尔·威廉·卡特赖特 = (2/2 + 2/3)/2 = (5/3)/2 = 0.83
  • 丹尼尔卡特赖特与大卫卡特赖特 = (1/2 + 1/2)/2 = 1/2 = 0.5
    请注意,我的方法忽略了词序,这在我的案例中不需要。
    import nltk
    
    s1 = 'DANIEL CARTWRIGHT'
    s2 = ['DANIEL WILLIAM CARTWRIGHT', 'DAVID CARTWRIGHT']
    
    def myScore(lst1, lst2):
        # calculate score for comparing lists of words
        c = sum(el in lst1 for el in lst2)
        if (len(lst1) == 0 or len(lst2) == 0):
            retval = 0.0
        else:
            retval = 0.5 * (c/len(lst1) + c/len(lst2))
        
        return retval
    
    tokens1 = nltk.word_tokenize(s1)
    
    for s in s2:
        tokens2 = nltk.word_tokenize(s)
        score = myScore(tokens1, tokens2)
        print(' vs. '.join([s1, s]), ":", str(score))
    

    输出:

    DANIEL CARTWRIGHT vs. DANIEL WILLIAM CARTWRIGHT : 0.8333333333333333
    DANIEL CARTWRIGHT vs. DAVID CARTWRIGHT : 0.5