如何在Pandas合并两个DataFrame时实现Name列模糊匹配?
解决Pandas基于差异字符串列合并的问题
嘿,这种字符串匹配合并的坑我可太熟了!别发愁,咱们根据你的情况一步步来解决——毕竟这种因为字符串格式、变体导致合并失败的场景在数据处理里真的超常见。
先假设你的两个DataFrame大概是这样的(方便对应你的场景):
import pandas as pd df1 = pd.DataFrame({ 'Name': ['Ian Ford', 'mike smith', 'Sarah-Jones', 'Bob taylor'], 'Age': [30, 28, 35, 42] }) df2 = pd.DataFrame({ 'Name': ['Ian Ford', 'Mike Smith', 'Sarah Jones', 'Robert Taylor'], 'City': ['London', 'New York', 'Paris', 'Sydney'] })
直接merge的话确实只有Ian Ford能匹配,下面给你几个实用的解决方案:
方法1:字符串标准化预处理(最常用,解决格式类差异)
绝大多数情况下,字符串差异都是格式不统一导致的:比如大小写不一致、多余空格、特殊符号(连字符/下划线)替换,先对Name列做清洗就能解决问题。
我们可以写一个清洗函数,对两个DataFrame的Name列做统一处理:
def clean_name(name): # 统一转为小写(避免大小写差异) name = name.lower() # 把连字符替换成空格(处理Sarah-Jones vs Sarah Jones这种情况) name = name.replace('-', ' ') # 去除首尾空格,同时把中间多个连续空格换成单个 name = ' '.join(name.split()) return name # 给两个DataFrame添加清洗后的标准化列 df1['clean_name'] = df1['Name'].apply(clean_name) df2['clean_name'] = df2['Name'].apply(clean_name) # 基于标准化后的列执行合并 merged_df = pd.merge(df1, df2, on='clean_name', how='outer')
处理后,mike smith和Mike Smith、Sarah-Jones和Sarah Jones都会变成完全一致的字符串,就能成功匹配了。
方法2:模糊匹配处理名字变体差异
如果你的字符串差异是名字变体(比如Bob vs Robert、Mike vs Michael这种),单纯的格式清洗就不够用了,这时候可以用模糊匹配工具fuzzywuzzy来计算字符串相似度。
首先安装依赖库:
pip install fuzzywuzzy python-Levenshtein
然后编写匹配逻辑:
from fuzzywuzzy import fuzz from fuzzywuzzy import process # 定义匹配函数:从df2的Name中找到与目标名字相似度最高的条目 def match_name(name, target_names, threshold=80): # 获取最高相似度的匹配结果和分数 match_result, similarity_score = process.extractOne(name, target_names) # 设定相似度阈值,超过阈值才认为匹配成功 if similarity_score >= threshold: return match_result return None # 给df1添加匹配到的df2的Name列 df1['matched_name'] = df1['Name'].apply(lambda x: match_name(x, df2['Name'].tolist())) # 基于匹配后的列执行合并 merged_df = pd.merge(df1, df2, left_on='matched_name', right_on='Name', how='outer')
你可以根据实际情况调整threshold参数(比如90分要求更严格,70分更宽松),这个方法能解决大部分名字变体的匹配问题。
方法3:手动映射(适合已知的固定差异)
如果你明确知道哪些名字是一一对应的(比如只有几个固定的差异),直接做一个映射字典是最精准的方法:
# 定义名字映射规则:key是df1里的名字,value是df2里对应的名字 name_mapping = { 'mike smith': 'Mike Smith', 'Sarah-Jones': 'Sarah Jones', 'Bob taylor': 'Robert Taylor' } # 对df1的Name列进行替换,得到标准化后的列 df1['standardized_name'] = df1['Name'].replace(name_mapping) # 执行合并 merged_df = pd.merge(df1, df2, left_on='standardized_name', right_on='Name', how='outer')
这个方法没有计算开销,结果完全可控,适合差异少且明确的场景。
总结一下优先级:先试试方法1(解决90%的格式类问题),如果是名字变体用方法2,固定差异用方法3。
内容的提问来源于stack exchange,提问作者zesla




