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