如何基于Pandas列条件构建网球选手对手映射字典?
网球选手对手字典生成方案
问题描述
给出的网球数据集如下:
tourney_id = ['French Open 2018','French Open 2018','Wimbledon 2018','Wimbledon 2018','Australian Open 2019','Australian Open 2019','US Open 2019','US Open 2019'] player_name = ['Novak Djokovic','Roger Federer','Andy Murray','Rafael Nadal','John Isner','Novak Djokovic','Andy Murray','Roger Federer'] match_num = [103, 103, 217, 217, 104, 104, 243, 243] df = pd.DataFrame(list(zip(tourney_id, player_name, match_num)), columns =['TournamentID','Name','MatchID'])
需要生成一个字典,键为选手姓名,值是该选手的所有对手列表(对手定义为同一TournamentID和MatchID下的其他选手),目标格式如下:
{'Novak Djokovic': ['Roger Federer','John Isner'], 'Roger Federer': ['Novak Djokovic','Andy Murray'], 'Andy Murray': ['Rafael Nadal','Roger Federer'], 'Rafael Nadal': ['Andy Murray'], 'John Isner': ['Novak Djokovic']}
尝试过df.set_index(['TournamentID','MatchID'])['Name'].to_dict(),但未得到预期结果,需实现正确的生成逻辑。
解决方案
可以通过分组遍历的方式实现,核心逻辑是把同一赛事同一场比赛的选手归为一组,组内选手互为对手,再逐个整理到字典中。
实现代码
import pandas as pd # 初始化数据集 tourney_id = ['French Open 2018','French Open 2018','Wimbledon 2018','Wimbledon 2018','Australian Open 2019','Australian Open 2019','US Open 2019','US Open 2019'] player_name = ['Novak Djokovic','Roger Federer','Andy Murray','Rafael Nadal','John Isner','Novak Djokovic','Andy Murray','Roger Federer'] match_num = [103, 103, 217, 217, 104, 104, 243, 243] df = pd.DataFrame(list(zip(tourney_id, player_name, match_num)), columns =['TournamentID','Name','MatchID']) # 初始化空字典存储结果 opponent_dict = {} # 按赛事+比赛ID分组,遍历每个分组 for _, group in df.groupby(['TournamentID', 'MatchID']): current_players = group['Name'].tolist() # 给组内每个选手添加对手 for player in current_players: # 筛选出组内除自己外的其他选手作为对手 opponents = [p for p in current_players if p != player] # 字典中无该选手则初始化列表,再添加对手 if player not in opponent_dict: opponent_dict[player] = [] opponent_dict[player].extend(opponents) print(opponent_dict)
代码说明
groupby(['TournamentID', 'MatchID']):将同一赛事、同一场比赛的选手归为一组,确保每组内的选手都是直接对手关系。- 遍历每个分组,取出该组的选手列表,对每个选手筛选出除自身外的其他成员作为对手。
- 用字典存储每个选手的对手列表,若选手首次出现则初始化空列表,再将对手添加进去。
简洁版实现
也可以用apply和字典推导简化代码:
# 分组后获取每组的选手列表 match_groups = df.groupby(['TournamentID', 'MatchID'])['Name'].apply(list).tolist() # 构建对手字典 opponent_dict = {} for players in match_groups: for player in players: # setdefault自动初始化空列表,避免判断 opponent_dict.setdefault(player, []).extend([p for p in players if p != player])
内容的提问来源于stack exchange,提问作者user2813606
相关产品推荐
相关产品推荐

