You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pandas实现网球选手赛前对阵战绩统计(含场地维度)

网球比赛选手历史对战战绩统计实现方案

需求说明

需要基于网球比赛DataFrame完成以下统计:

  • 统计选手作为p1或p2时的head to head历史对战战绩
  • 最终新增p1_h2h(当前p1的历史胜率)和p2_h2h(当前p2的历史胜率)字段
  • 使用shift(1)获取当前比赛开始前的历史战绩

原始数据

p1_namep2_nameSurfacep1_winp2_win
MurrayNadalHard10
NadalMurrayClay10
NadalMurrayHard01
MurrayFedererClay10

期望输出结果

p1_namep2_nameSurfacep1_winp2_winp1_h2hp2_h2h
MurrayNadalHard10nana
NadalMurrayClay100%100%
NadalMurrayHard0150%50%
MurrayFedererClay10nana

实现代码

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)

代码逻辑说明

  1. 统一对战分组:通过排序选手名称生成唯一组合键,确保同一对选手无论谁是p1/p2,都被归为同一统计组。
  2. 标记双方胜场:针对每场比赛,判断对战双方(player_a/player_b)各自是否获胜,为后续累计做准备。
  3. 累计历史战绩:按对战组合分组后,用cumsum()累计胜场,再通过shift(1)获取当前比赛开始前的历史数据。
  4. 计算胜率:根据当前p1/p2对应的对战方,匹配累计胜场计算胜率,无历史对战时返回na。
  5. 清理结果:移除中间辅助字段,得到符合期望的最终DataFrame。

内容的提问来源于stack exchange,提问作者user19446980

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 20:35:18