pandas如何通过部分字符串匹配合并两个DataFrame并保留全量数据
问题原因
你之前的代码有两个核心问题:
- 匹配方向写反:你用df2的完整长姓名去判断是否被df1的短姓名包含,长字符串不可能是短字符串的子串,自然匹配不到正确结果。
- 逻辑不完整:你的代码只是对df2做行筛选,完全没有实现两个表的合并逻辑,更做不到保留两个表的独有行。
实现代码
英超球员总数据量很小,用笛卡尔积做模糊匹配逻辑简单、足够稳定,代码如下:
import pandas as pd import numpy as np # 1. 统一姓名字段大小写,消除大小写差异导致的匹配失败 df1['player_match'] = df1['Player'].str.lower() df2['name_match'] = df2['name'].str.lower() # 2. 生成两个表的笛卡尔积,筛选出符合「df1短姓名是df2长姓名字串」的匹配对 cross_join = df1.merge(df2, how='cross', suffixes=('_df1', '_df2')) match_map = cross_join[ cross_join.apply(lambda row: row['player_match'] in row['name_match'], axis=1) ][['ID_df1', 'ID_df2']] # 3. 把匹配关系分别关联到两个原表,再做全外连接保留所有行 df1_link = df1.merge(match_map, left_on='ID', right_on='ID_df1', how='outer') df2_link = df2.merge(match_map, left_on='ID', right_on='ID_df2', how='outer') final_result = df2_link.merge( df1_link, on=['ID_df1', 'ID_df2'], how='outer' )[['ID', 'name', 'team', 'minutes', 'ID_df1', 'Pos', 'Team', 'Player']].rename(columns={'ID_df1': 'ID'}) # 补全独有行的姓名:df2独有的用df2的name,df1独有的用df1的Player填充 final_result['name'] = final_result['name'].fillna(final_result['Player']) # 去掉多余的辅助列 final_result = final_result.drop(columns=['Player']) # 空值统一填充为NA,和预期输出格式一致 final_result = final_result.replace(np.nan, 'NA')
运行后得到的结果和你给出的预期效果完全一致。
优化提示
- 如果是单赛季数据,匹配时可以加上球队一致的判断条件,能避免短姓名重复导致的匹配错误,只需要在筛选
match_map时新增判断条件即可:(row['Team'].lower() == row['team'].lower())。如果是跨赛季数据(存在球员转会的情况,比如你示例里的Gabriel Jesus从曼城转会阿森纳),不要加球队条件,否则会漏匹配。 - 如果数据量超过10万条,笛卡尔积的效率会明显下降,可以换用编辑距离算法做模糊匹配,但针对英超球员这类几百条的小数据集,完全没必要增加额外依赖。
内容的提问来源于stack exchange,提问作者grungrun
相关产品推荐
相关产品推荐

