为 Dataframe Merging 匹配字符串值不是 100% 相同的列
Matching columns with string values that are not 100% identical for Dataframe Merging
我正在尝试合并两个数据框,不幸的是,唯一的公共列是名称列,它们没有 100% 相同的值。有没有一种方法可以根据概率匹配名称,假设两个值之间有 80% 或更多的匹配字符串,它们会将它们匹配在一起。下面是我所面对的例子;
df1= pd.DataFrame({"Name":["John", "Mary", "Sarah", "Jack"], "B":[1,2,3,4]})
df2= pd.DataFrame({"Name":["Jon", 'Mary", "Sara", "Jak", "lilly"], "C":["foo", "bar", "bar", "foo", "bar"]})
我对编码还很陌生,非常感谢您的建议:)
正如@Scott Boston 所建议的,您可以使用 fuzzywuzzy 包。您需要创建一个新列,其中包含 df1 中最相似的词,然后您可以加入该列。
In [88]: df2['key'] = df2['Name'].apply(lambda x : [process.extract(x, df1['Name'], limit=1)][0][0][0])
In [89]: df2
Out[89]:
Name C key
0 Jon foo John
1 Mary bar Mary
2 Sara bar Sarah
3 Jak foo Jack
4 lilly bar Mary
In [90]: df2.merge(df1, left_on='key',right_on='Name')
Out[90]:
Name_x C key Name_y B
0 Jon foo John John 1
1 Mary bar Mary Mary 2
2 lilly bar Mary Mary 2
3 Sara bar Sarah Sarah 3
4 Jak foo Jack Jack 4
如果您不需要太花哨的东西,内置的 difflib.get_close_matches
可能就足够了:
from difflib import get_close_matches
def get_closest_match(name):
matches = get_close_matches(name, df1['Name']
if len(matches) > 0:
return matches[0]
else:
return None
df2['ClosestName'] = df2['Name'].apply(get_closest_match)
df1.merge(df2, left_on='Name', right_on='ClosestName')
结果:
Name_x B Name_y C ClosestName
John 1 Jon foo John
Mary 2 Mary bar Mary
Sarah 3 Sara bar Sarah
Jack 4 Jak foo Jack
可能有两种解决方案。
如果您拥有列 "Name" 的所有有效名称(命名空间),则第一个解决方案有效。然后你可以迭代列中的值 "Name" 和:
- 用命名空间中所有可能的值计算它的距离(Levenshtein 距离应该有效)
- Select距离最小(相似度最高)的那个替换掉
2.5 为了避免容易出错的替换,可以为距离
设置一个截断值
- 刚刚合并(外连接)
对于您没有所有有效名称的情况,您可以使用其他数据框的列 "Name" 中的所有值创建一个集合,并将其视为命名空间。以下步骤相同。
我正在尝试合并两个数据框,不幸的是,唯一的公共列是名称列,它们没有 100% 相同的值。有没有一种方法可以根据概率匹配名称,假设两个值之间有 80% 或更多的匹配字符串,它们会将它们匹配在一起。下面是我所面对的例子;
df1= pd.DataFrame({"Name":["John", "Mary", "Sarah", "Jack"], "B":[1,2,3,4]})
df2= pd.DataFrame({"Name":["Jon", 'Mary", "Sara", "Jak", "lilly"], "C":["foo", "bar", "bar", "foo", "bar"]})
我对编码还很陌生,非常感谢您的建议:)
正如@Scott Boston 所建议的,您可以使用 fuzzywuzzy 包。您需要创建一个新列,其中包含 df1 中最相似的词,然后您可以加入该列。
In [88]: df2['key'] = df2['Name'].apply(lambda x : [process.extract(x, df1['Name'], limit=1)][0][0][0])
In [89]: df2
Out[89]:
Name C key
0 Jon foo John
1 Mary bar Mary
2 Sara bar Sarah
3 Jak foo Jack
4 lilly bar Mary
In [90]: df2.merge(df1, left_on='key',right_on='Name')
Out[90]:
Name_x C key Name_y B
0 Jon foo John John 1
1 Mary bar Mary Mary 2
2 lilly bar Mary Mary 2
3 Sara bar Sarah Sarah 3
4 Jak foo Jack Jack 4
如果您不需要太花哨的东西,内置的 difflib.get_close_matches
可能就足够了:
from difflib import get_close_matches
def get_closest_match(name):
matches = get_close_matches(name, df1['Name']
if len(matches) > 0:
return matches[0]
else:
return None
df2['ClosestName'] = df2['Name'].apply(get_closest_match)
df1.merge(df2, left_on='Name', right_on='ClosestName')
结果:
Name_x B Name_y C ClosestName
John 1 Jon foo John
Mary 2 Mary bar Mary
Sarah 3 Sara bar Sarah
Jack 4 Jak foo Jack
可能有两种解决方案。
如果您拥有列 "Name" 的所有有效名称(命名空间),则第一个解决方案有效。然后你可以迭代列中的值 "Name" 和:
- 用命名空间中所有可能的值计算它的距离(Levenshtein 距离应该有效)
- Select距离最小(相似度最高)的那个替换掉 2.5 为了避免容易出错的替换,可以为距离 设置一个截断值
- 刚刚合并(外连接)
对于您没有所有有效名称的情况,您可以使用其他数据框的列 "Name" 中的所有值创建一个集合,并将其视为命名空间。以下步骤相同。