如何为Pandas DataFrame添加含历史行条件求和的列?附网球示例
给网球比赛DataFrame添加“之前行条件求和”列的实现方案
嘿,我来帮你搞定这个需求!看起来你想给这份网球比赛结果的DataFrame新增一列,用来计算当前行之前满足条件的求和值——我猜你大概率是想统计每个选手在当前这场比赛前已经赢了多少场对吧?下面我给你两种实现方案,从简洁到灵活都有,你可以按需选择:
先回顾你的数据集
首先先把你的数据初始化代码放出来,方便后续操作:
import pandas as pd tennis_cols = ['Year','TourNo','MatchNo','Round','Winner','Loser'] tennis_rslts = [ [2018, 1, 1, 'QF', 'PlayerA', 'PlayerB'], [2018, 1, 2, 'QF', 'PlayerC', 'PlayerD'], [2018, 1, 3, 'QF', 'PlayerE', 'PlayerF'], [2018, 1, 4, 'QF', 'PlayerG', 'PlayerH'], [2018, 1, 5, 'SF', 'PlayerA', 'PlayerC'], [2018, 1, 6, 'SF', 'PlayerE', 'PlayerG'], [2018, 1, 7, 'F', 'PlayerA', 'PlayerE'] ] dfTennis = pd.DataFrame(tennis_rslts, columns=tennis_cols)
方案1:仅统计获胜者的此前胜场(最简洁)
如果你的需求只是统计当前获胜选手在同一赛事(Year+TourNo)里,在这场比赛之前已经赢了多少场,那用cumcount()就能轻松搞定:
# 按年份、赛事编号、获胜者分组,cumcount()会给每组的行从0开始编号,正好对应此前胜场数 dfTennis['Winner_Previous_Wins'] = dfTennis.groupby(['Year', 'TourNo', 'Winner']).cumcount()
运行后你会得到这样的结果(截取核心列):
| Year | Winner | Winner_Previous_Wins |
|---|---|---|
| 2018 | PlayerA | 0 |
| 2018 | PlayerC | 0 |
| 2018 | PlayerE | 0 |
| 2018 | PlayerG | 0 |
| 2018 | PlayerA | 1 |
| 2018 | PlayerE | 1 |
| 2018 | PlayerA | 2 |
完全符合预期:PlayerA第一次赢球时此前胜场为0,第二次赢球时已经赢过1场,第三次赢球时已经赢过2场。
方案2:同时统计获胜者和失利者的此前胜场(更灵活)
如果你还想统计失利者在这场比赛之前的胜场数,或者需要更灵活的条件求和,那可以先把数据转成长格式再处理:
# 把每场比赛拆成两行,分别记录获胜者和失利者的参赛情况,标记是否获胜 df_long = pd.concat([ dfTennis.assign(Player=dfTennis['Winner'], Win=1), dfTennis.assign(Player=dfTennis['Loser'], Win=0) ]).sort_values(['Year', 'TourNo', 'MatchNo']).reset_index(drop=True) # 计算每个选手到当前比赛之前的累计获胜次数,shift(1)排除当前这场,fillna(0)处理第一次参赛的情况 df_long['Previous_Wins'] = df_long.groupby(['Year', 'TourNo', 'Player'])['Win'].cumsum().shift(1).fillna(0) # 把结果合并回原DataFrame,分别给获胜者和失利者添加此前胜场列 dfTennis = dfTennis.merge( df_long[['Year', 'TourNo', 'MatchNo', 'Player', 'Previous_Wins']].rename(columns={'Player': 'Winner', 'Previous_Wins': 'Winner_Previous_Wins'}), on=['Year', 'TourNo', 'MatchNo', 'Winner'], how='left' ).merge( df_long[['Year', 'TourNo', 'MatchNo', 'Player', 'Previous_Wins']].rename(columns={'Player': 'Loser', 'Previous_Wins': 'Loser_Previous_Wins'}), on=['Year', 'TourNo', 'MatchNo', 'Loser'], how='left' )
最终的dfTennis会新增两列:Winner_Previous_Wins和Loser_Previous_Wins,比如第5场比赛(PlayerA vs PlayerC)里,PlayerC的此前胜场是1(他赢过第2场QF),完全正确。
扩展说明
如果你的“条件求和”是其他维度(比如统计所有赛事里的此前胜场,或者统计其他指标),只需要调整groupby的分组键或者求和的列就可以了。比如要统计所有年份赛事的此前胜场,把groupby里的Year和TourNo去掉就行。
内容的提问来源于stack exchange,提问作者AndyMas78
相关产品推荐
相关产品推荐

