Pandas实现网球选手赛前对阵战绩统计(含场地维度)
网球比赛选手历史对战战绩统计实现方案
需求说明
需要基于网球比赛DataFrame完成以下统计:
- 统计选手作为p1或p2时的head to head历史对战战绩
- 最终新增
p1_h2h(当前p1的历史胜率)和p2_h2h(当前p2的历史胜率)字段 - 使用
shift(1)获取当前比赛开始前的历史战绩
原始数据
| p1_name | p2_name | Surface | p1_win | p2_win |
|---|---|---|---|---|
| Murray | Nadal | Hard | 1 | 0 |
| Nadal | Murray | Clay | 1 | 0 |
| Nadal | Murray | Hard | 0 | 1 |
| Murray | Federer | Clay | 1 | 0 |
期望输出结果
| p1_name | p2_name | Surface | p1_win | p2_win | p1_h2h | p2_h2h |
|---|---|---|---|---|---|---|
| Murray | Nadal | Hard | 1 | 0 | na | na |
| Nadal | Murray | Clay | 1 | 0 | 0% | 100% |
| Nadal | Murray | Hard | 0 | 1 | 50% | 50% |
| Murray | Federer | Clay | 1 | 0 | na | na |
实现代码
import pandas as pd # 构造原始数据(实际使用时可替换为你的DataFrame) data = { 'p1_name': ['Murray', 'Nadal', 'Nadal', 'Murray'], 'p2_name': ['Nadal', 'Murray', 'Murray', 'Federer'], 'Surface': ['Hard', 'Clay', 'Hard', 'Clay'], 'p1_win': [1, 1, 0, 1], 'p2_win': [0, 0, 1, 0] } df = pd.DataFrame(data) # 生成唯一对战组合键(排序选手名拼接,确保同一对战对统一分组) df['match_pair'] = df.apply(lambda x: '-'.join(sorted([x['p1_name'], x['p2_name']])), axis=1) df['player_a'] = df['match_pair'].str.split('-').str[0] df['player_b'] = df['match_pair'].str.split('-').str[1] # 标记每场比赛中对战双方的胜场情况 df['a_win'] = df.apply( lambda x: 1 if (x['p1_name'] == x['player_a'] and x['p1_win'] == 1) or (x['p2_name'] == x['player_a'] and x['p2_win'] == 1) else 0, axis=1 ) df['b_win'] = df.apply( lambda x: 1 if (x['p1_name'] == x['player_b'] and x['p1_win'] == 1) or (x['p2_name'] == x['player_b'] and x['p2_win'] == 1) else 0, axis=1 ) # 按对战组合分组,累计双方历史胜场,shift(1)得到当前比赛前的战绩 df['a_cum_win'] = df.groupby('match_pair')['a_win'].cumsum().shift(1) df['b_cum_win'] = df.groupby('match_pair')['b_win'].cumsum().shift(1) # 计算当前p1和p2的历史胜率 def calculate_h2h(row): total_matches = row['a_cum_win'] + row['b_cum_win'] if pd.isna(total_matches) or total_matches == 0: return ('na', 'na') # 根据当前p1属于player_a还是player_b,匹配对应的累计胜场计算胜率 if row['p1_name'] == row['player_a']: p1_rate = f"{round(row['a_cum_win'] / total_matches * 100)}%" p2_rate = f"{round(row['b_cum_win'] / total_matches * 100)}%" else: p1_rate = f"{round(row['b_cum_win'] / total_matches * 100)}%" p2_rate = f"{round(row['a_cum_win'] / total_matches * 100)}%" return (p1_rate, p2_rate) df[['p1_h2h', 'p2_h2h']] = df.apply(calculate_h2h, axis=1, result_type='expand') # 移除中间辅助字段,保留目标列 df = df.drop(['match_pair', 'player_a', 'player_b', 'a_win', 'b_win', 'a_cum_win', 'b_cum_win'], axis=1) # 输出结果 print(df)
代码逻辑说明
- 统一对战分组:通过排序选手名称生成唯一组合键,确保同一对选手无论谁是p1/p2,都被归为同一统计组。
- 标记双方胜场:针对每场比赛,判断对战双方(player_a/player_b)各自是否获胜,为后续累计做准备。
- 累计历史战绩:按对战组合分组后,用
cumsum()累计胜场,再通过shift(1)获取当前比赛开始前的历史数据。 - 计算胜率:根据当前p1/p2对应的对战方,匹配累计胜场计算胜率,无历史对战时返回
na。 - 清理结果:移除中间辅助字段,得到符合期望的最终DataFrame。
内容的提问来源于stack exchange,提问作者user19446980
相关产品推荐
相关产品推荐

