仅具有首字母

时间:2017-09-12 22:11:29

标签: python fuzzywuzzy

我有一个案例需要将给定字符串中的名称与名称数据库进行匹配。下面我给出了一个我遇到的问题的一个非常简单的例子,我不清楚为什么一个案例比另一个案例有效?如果我没弄错的话,extractOne()的Python默认算法是Levenshtein距离算法。是因为克莱门斯'名字提供前两个首字母,与冈萨雷斯案中只有一个相对应?

from fuzzywuzzy import fuzz
from fuzzywuzzy import process

s = ['Gonzalez, E. walked down the street.', 'Gonzalez, R. went to the market.', 'Clemens, Ko. reach the intersection; Clemens, Ka. did not.']

names = []

for i in s:

    name = [] #clear name
    for k in i.split():
        if k[0].isupper(): name.append(k)
        else: break
    names.append(' '.join(name))

    if ';' in i:
        for each in i.split(';')[1:]:
            name = [] #clear name
            for k in each.split():
                if k[0].isupper(): name.append(k)
                else: break
            names.append(' '.join(name))

print(names)

choices = ['Kody Clemens','Kacy Clemens','Gonzalez Ryan', 'Gonzalez Eddy']

for i in names:
    s = process.extractOne(i, choices)
    print(s, i)

输出:

['Gonzalez, E.', 'Gonzalez, R.', 'Clemens, Ko.', 'Clemens, Ka.']
('Gonzalez Ryan', 85) Gonzalez, E.
('Gonzalez Ryan', 85) Gonzalez, R.
('Kody Clemens', 86) Clemens, Ko.
('Kacy Clemens', 86) Clemens, Ka.

1 个答案:

答案 0 :(得分:4)

虽然@ Igle的提交确实解决了这个具体问题,但我想强调的是,这是一个狭隘的解决方案,并不一定能解决所有问题。 Fuzzywuzzy有多个得分者,他们使用Levenshtein距离算法结合不同的逻辑来比较字符串。默认记分员fuzz.WRatio将直接Levenshtein距离算法(fuzz.ratio)的匹配得分与其他变量进行比较,并返回所有得分者的最佳匹配。除此之外还有更多内容,包括围绕权衡不同方法得分的其他逻辑,如果您有兴趣,我建议您查看the source code for fuzz.WRatio

要查看您的案例中发生了什么,您可以通过略微调整代码的最后几行来比较得分者的所有选择的得分:

对于token_set_ratio:

for i in names:
   s = process.extract(i, choices,scorer=fuzz.token_set_ratio)
   print(s, i)

[('Gonzalez Ryan', 89), ('Gonzalez Eddy', 89), ('Kody Clemens', 27), ('Kacy Clemens', 27)] Gonzalez, E.
[('Gonzalez Ryan', 89), ('Gonzalez Eddy', 89), ('Kody Clemens', 27), ('Kacy Clemens', 27)] Gonzalez, R.
[('Kody Clemens', 91), ('Kacy Clemens', 82), ('Gonzalez Ryan', 26), ('Gonzalez Eddy', 26)] Clemens, Ko.
[('Kacy Clemens', 91), ('Kody Clemens', 82), ('Gonzalez Ryan', 35), ('Gonzalez Eddy', 26)] Clemens, Ka.

对于token_sort_ratio:

for i in names:
   s = process.extract(i, choices,scorer=fuzz.token_sort_ratio)
   print(s, i)

[('Gonzalez Eddy', 87), ('Gonzalez Ryan', 70), ('Kody Clemens', 27), ('Kacy Clemens', 27)] Gonzalez, E.
[('Gonzalez Ryan', 87), ('Gonzalez Eddy', 70), ('Kody Clemens', 27), ('Kacy Clemens', 27)] Gonzalez, R.
[('Kody Clemens', 91), ('Kacy Clemens', 82), ('Gonzalez Ryan', 26), ('Gonzalez Eddy', 26)] Clemens, Ko.
[('Kacy Clemens', 91), ('Kody Clemens', 82), ('Gonzalez Ryan', 35), ('Gonzalez Eddy', 26)] Clemens, Ka.

尽管token_sort_ratio显示了明显的获胜匹配,但token_set_ratio返回更高的分数,这就是fuzz.WRatio选择返回结果的方式。另一个主要问题是,当您有类似的查询和选择时,它们的比较顺序开始变得重要。例如,当我运行与上面完全相同的代码,但是反转选择列表的顺序时,我们得到'Gonzalez Eddy':

for i in names:
   s = process.extract(i, choices[::-1],scorer=fuzz.token_set_ratio)
   print(s, i)
[('Gonzalez Eddy', 89), ('Gonzalez Ryan', 89), ('Kacy Clemens', 27), ('Kody Clemens', 27)] Gonzalez, E.
[('Gonzalez Eddy', 89), ('Gonzalez Ryan', 89), ('Kacy Clemens', 27), ('Kody Clemens', 27)] Gonzalez, R.
[('Kody Clemens', 91), ('Kacy Clemens', 82), ('Gonzalez Eddy', 26), ('Gonzalez Ryan', 26)] Clemens, Ko.
[('Kacy Clemens', 91), ('Kody Clemens', 82), ('Gonzalez Ryan', 35), ('Gonzalez Eddy', 26)] Clemens, Ka.

我猜测正确的比赛实际上有更高的分数,但是'Eddy'和'Ryan'足够接近以达到相同的最终分数。

过去我处理类似问题的方式是:

  1. 使用extract而不是extractOne(就像我在上面的示例中所做的那样)
  2. 使用多个得分者(ratio,token_set_ratio,token_sort_ratio)处理相同的查询/选择,并使用这些得分的加权平均值来选择最佳匹配。
  3. 调整fuzzywuzzy源代码以包含自定义权重或删除舍入。