合并匹配含球员姓名的Pandas DataFrame:解决merge结果为空问题
Pandas球员数据合并为空问题解决方法
问题背景
现有两个Pandas DataFrame:
- df1:包含「Player(球员姓名)」和「Rating」列
- df2:包含「Player」及「Team」「Age」「Value」等多列
需求是将df1的Rating数据合并到df2中,保留df2全部字段。尝试带正则替换的merge代码后,合并结果为空,需排查解决。
数据示例
df1数据:
| Player | Rating |
|---|---|
| O. Fuglsang | 53 |
| J. Jensen-Abbew | 53 |
| M. Enggård | 53 |
| J. Liburd | 53 |
df2数据:
| Player | Team | Age | Value |
|---|---|---|---|
| R. Mudražija | a1 | a2 | a3 |
| J. Gomez | b1 | b2 | b3 |
| T. Mølgaard | c1 | c2 | c2 |
| J. Liburd | d1 | d2 | d3 |
尝试的错误代码
dfmerged = df1.merge(df2, left_on=df1['Player'].str.replace(r'^(.)\w+', r'\1.', regex=True), right_on='Player' )
问题分析
你写的正则表达式r'^(.)\w+'逻辑错误:
^(\.)匹配字符串第一个字符,\w+匹配后续字母/数字,但\w不匹配点号(.),所以对于df1中O. Fuglsang这类带点的名字,正则只能匹配到O,替换后结果还是O.,和df2的Player字段完全无法匹配,导致合并结果为空。
正确解决步骤
步骤1:基础左合并(优先匹配一致姓名)
先直接用how='left'执行左合并,保留df2所有行,自动匹配格式完全一致的球员:
df_merged = df2.merge(df1, on='Player', how='left')
这一步会先搞定大部分格式一致的球员,未匹配到的Rating会显示为NaN。
步骤2:排查未匹配的球员
找出df2中未匹配的球员,分析格式差异:
# 提取df2中未匹配Rating的球员姓名 unmatched_players = df_merged[df_merged['Rating'].isna()]['Player'].tolist() print("未匹配的球员:", unmatched_players) print("df1中的姓名样本:", df1['Player'].sample(5).tolist())
通过对比可以发现具体格式差异(比如首字母位置、大小写、特殊字符、缩写方式等)。
步骤3:针对性处理格式差异
场景1:姓名缩写顺序不同
如果df1是「首字母. 姓氏」格式,df2是「姓氏, 首字母.」格式,可生成统一匹配键合并:
# 给df1生成匹配键:首字母_姓氏 df1['match_key'] = df1['Player'].str.split('. ', expand=True)[0] + '_' + df1['Player'].str.split('. ', expand=True)[1] # 给df2生成匹配键:首字母_姓氏 df2['match_key'] = df2['Player'].str.split(', ', expand=True)[1].str.replace('.', '') + '_' + df2['Player'].str.split(', ', expand=True)[0] # 用匹配键合并,保留df2全部字段 df_merged = df2.merge(df1, on='match_key', how='left') # 清理临时列,重命名字段 df_merged = df_merged[['Player_x', 'Team', 'Age', 'Value', 'Rating']].rename(columns={'Player_x': 'Player'})
场景2:特殊字符差异(如å/a、ø/o)
统一转换为普通字符后再匹配:
import unicodedata def normalize_name(name): # 去除特殊字符并转小写 return unicodedata.normalize('NFKD', name).encode('ascii', 'ignore').decode('utf-8').lower() # 生成标准化匹配键 df1['match_key'] = df1['Player'].apply(normalize_name) df2['match_key'] = df2['Player'].apply(normalize_name) # 合并并清理临时列 df_merged = df2.merge(df1, on='match_key', how='left') df_merged = df_merged[['Player_x', 'Team', 'Age', 'Value', 'Rating']].rename(columns={'Player_x': 'Player'})
总结
- 先通过基础左合并解决大部分匹配需求;
- 针对少数格式差异的球员,先排查差异类型,再生成统一匹配键进行合并;
- 避免盲目使用不熟悉的正则,优先从数据样本入手分析格式规律。
内容的提问来源于stack exchange,提问作者fr3dr1k
相关产品推荐
相关产品推荐

