在 pandas 数据框中匹配(fuzzywuzzy)

Matching in pandas dataframe (fuzzywuzzy)

我有一个数据框,其中一列包含公司名称(数据框大约有 50 列)。例如

Name
byname_tt
standing_re
mystandying_tz
mouse_x
mousepad_db

我正在尝试再创建一个列,其中列出了选中名称中的相似名称。为了比较我使用 fuzzywuzzy 的名称。

def check_name(name):
    check = df.apply(lambda row: ((fuzz.partial_ratio(row['Name'], name)) >= 50), axis=1)
    return [df.Name[i] for i, x in enumerate(check) if x]

如果匹配高于阈值,我的预期输出应该类似于

 Name           Checked
    byname_tt      []
    standing_re    ['mystandying_tz']
    mystandying_tz ['standing_re']
    mouse_x        ['mousepad_db']
    mousepad_db    ['mouse_x']

目前,我的输出是错误的:

 Name           Checked
    byname_tt      ['byname_tt']
    standing_re    ['standing_re']
    mystandying_tz ['mystandying_tz']
    mouse_x        ['mouse_x']
    mousepad_db    ['mousepad_db']

对于名称中的每个名称,我应该检查与名称列中其他名称的相似性。 知道出了什么问题吗?

如果你无论如何都要匹配所有的字符串对,你可以首先生成所有你想要比较的字符串对,并在出现两次相同的单词时删除:

>>> pairs = pd.merge(df['Name'], df['Name'].rename('Checked'), how='cross', suffixes=('', ''))
>>> pairs = pairs[pairs['Name'] != pairs['Checked']]

然后你可以使用你的模糊库进行比较,我将在这个例子中使用 python 的 difflib - 它不一定更好但它会避免安装另一个包,因为它大致一样。

>>> pairs['ratio'] = pairs.agg(lambda s: difflib.SequenceMatcher(None, s['Name'], s['Checked']).ratio(), axis='columns')
>>> pairs
              Name         Checked     ratio
1        byname_tt     standing_re  0.200000
2        byname_tt  mystandying_tz  0.347826
3        byname_tt         mouse_x  0.375000
4        byname_tt     mousepad_db  0.100000
5      standing_re       byname_tt  0.100000
7      standing_re  mystandying_tz  0.720000
8      standing_re         mouse_x  0.222222
9      standing_re     mousepad_db  0.363636
10  mystandying_tz       byname_tt  0.260870
11  mystandying_tz     standing_re  0.720000
13  mystandying_tz         mouse_x  0.285714
14  mystandying_tz     mousepad_db  0.400000
15         mouse_x       byname_tt  0.375000
16         mouse_x     standing_re  0.222222
17         mouse_x  mystandying_tz  0.285714
19         mouse_x     mousepad_db  0.666667
20     mousepad_db       byname_tt  0.300000
21     mousepad_db     standing_re  0.181818
22     mousepad_db  mystandying_tz  0.400000
23     mousepad_db         mouse_x  0.666667

最后我们可以简单地过滤比率并使用简单的 groupby 生成列表:

>>> similar = pairs[pairs['ratio'] > .5].groupby('Name')['Checked'].agg(list)
>>> similar
Name
mouse_x              [mousepad_db]
mousepad_db              [mouse_x]
mystandying_tz       [standing_re]
standing_re       [mystandying_tz]
Name: Checked, dtype: object
>>> df.merge(similar.reindex(pairs['Name'].unique(), fill_value=[]), on='Name', how='outer')
             Name           Checked
0       byname_tt                []
1     standing_re  [mystandying_tz]
2  mystandying_tz     [standing_re]
3         mouse_x     [mousepad_db]
4     mousepad_db         [mouse_x]

最后的 reindex 是一个小的解决方法,可以在没有匹配的行上获得 [] 的 fillna,因为您不能将列表作为参数传递给 fillna() .