如何高效合并Pandas网球赛事DataFrame重复行并补全对手信息
问题背景
我有一个包含70000行网球赛事数据的Pandas DataFrame,存在两个核心问题:
- 每场比赛重复记录:选手A对阵选手B的比赛,同时存在「A为Player A、B为Player B」和「B为Player A、A为Player B」两行数据,这是从每位选手页面提取数据导致的。
- 每行仅包含Player A的信息:比如纳达尔对阵费德勒的比赛,纳达尔作为Player A的行只有纳达尔的Rank、Height、Age,缺少费德勒的对应数据;反之亦然。
数据示例:
| Player A | Rank | Height | Age | Tourn. | Year | Round | Player B | Result |
|---|---|---|---|---|---|---|---|---|
| Nadal | 3 | 185 | 37 | US Open | 2019 | Finals | Federer | W |
| Federer | 7 | 183 | 40 | US Open | 2019 | Finals | Nadal | L |
目标是将每场比赛合并为一行,补全双方信息,最终格式如下:
| Player A | Rank | Height | Age | Tourn. | Year | Round | Player B | Rank_B | Height_B | Age_B | Result |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Nadal | 3 | 185 | 37 | US Open | 2019 | Finals | Federer | 7 | 183 | 40 | W |
目前用嵌套for循环处理70000行耗时12小时,无法适配百万级数据,需要更高效的解决方案。
高效解决方案
核心思路是利用Pandas的向量化合并与分组去重,彻底摒弃嵌套循环,将时间复杂度从O(n²)降至O(n log n),大幅提升处理效率。
步骤1:生成唯一比赛标识
为精准匹配同一场比赛的两条记录,为每场比赛生成唯一「比赛键」:将对阵双方按字母排序后拼接,再结合赛事、年份、轮次,确保该键能唯一标识同一场比赛。例如Nadal vs Federer的比赛,排序后得到Federer_Nadal,再拼接赛事信息形成Federer_Nadal_US Open_2019_Finals。
步骤2:自合并关联数据
将DataFrame与自身合并,匹配条件为「相同比赛键」且「对阵双方互换」,从而将双方的信息关联到同一行。
步骤3:筛选有效行并整理格式
合并后会产生重复匹配结果,仅保留一组有效数据,整理成目标格式后删除重复行。
完整代码实现
import pandas as pd # 读取原始数据 games = pd.read_csv("games.csv") # 步骤1:生成唯一比赛键 def create_match_key(row): # 将对阵双方按字母排序,避免因顺序不同导致键不匹配 sorted_players = sorted([row["Player A"], row["Player B"]]) return f"{sorted_players[0]}_{sorted_players[1]}_{row['Tourn.']}_{row['Year']}_{row['Round']}" games["match_key"] = games.apply(create_match_key, axis=1) # 步骤2:自合并数据,匹配同一场比赛的两条记录 merged_df = pd.merge( games, games, left_on=["match_key", "Player A"], right_on=["match_key", "Player B"], suffixes=("", "_opponent") # 区分原数据和对手数据的列名 ) # 步骤3:筛选有效行并整理目标格式 # 过滤掉自身匹配的无效行,并重命名对手信息列 final_df = merged_df[merged_df["Player A"] != merged_df["Player A_opponent"]].rename(columns={ "Rank_opponent": "Rank_B", "Height_opponent": "Height_B", "Age_opponent": "Age_B" }) # 保留目标列并删除重复行 target_columns = [ "Player A", "Rank", "Height", "Age", "Tourn.", "Year", "Round", "Player B", "Rank_B", "Height_B", "Age_B", "Result" ] final_df = final_df[target_columns].drop_duplicates() # 保存处理后的数据 final_df.to_csv("merged_tennis_games.csv", index=False)
方案优势
- 效率飞跃:利用Pandas底层的C语言实现的合并算法,处理70000行数据仅需几秒,完全支持百万级数据集。
- 逻辑简洁:通过唯一键精准匹配,避免循环中的复杂条件判断,代码易读易维护。
- 兼容性强:若存在选手名称大小写不一致等小问题,只需调整排序前的字符串格式化逻辑即可兼容。
内容的提问来源于stack exchange,提问作者Gil Ramos
相关产品推荐
相关产品推荐

