pandas 数据框中的匹配(fuzzywuzzy)

Posted

技术标签:

【中文标题】pandas 数据框中的匹配(fuzzywuzzy)【英文标题】:Matching in pandas dataframe (fuzzywuzzy) 【发布时间】:2021-10-22 00:50:06 【问题描述】:

我有一个数据框,其中一列包含公司名称(数据框大约有 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']

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

【问题讨论】:

这里检查的名称是什么?您是否将所有公司名称与所有其他公司名称进行核对? 【参考方案1】:

如果你要匹配所有字符串对,你可以从生成所有这些你想要比较的字符串对开始,然后在出现两次相同的单词时删除:

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

然后你可以使用你的 fuzz 库进行比较,我将使用 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()

【讨论】:

感谢辛巴利。我收到此错误:ValueError:fill_value 必须是标量。你知道我该如何解决它或者我应该看什么来解决它吗? @LdM 我已经更新了,fillna 不接受列表作为参数。

以上是关于pandas 数据框中的匹配(fuzzywuzzy)的主要内容,如果未能解决你的问题,请参考以下文章

将语料库中的名称部分匹配到 Pandas 数据框中另一列中的名称

遍历 pandas 数据框中的行并匹配列表中的元组并创建一个新的 df 列

如何从数据框中返回最常用的名称?

Python中实现模糊匹配的魔法库:FuzzyWuzzy

在 Pandas 中模糊搜索列

在 Pandas 数据框中高效、快速地查找和匹配唯一值