如何不使用for循环在Pandas中填充网球对战的last_winner字段?
用apply替代for loop填充网球对战历史胜者
需求说明
给定网球比赛数据集,需为每条记录填充对战双方此前的最后一位胜者,无历史对战则填"none"。
原始数据
| player_1 | player_2 | winner | last_winner |
|---|---|---|---|
| Federer | Nadal | Federer | |
| Djoko | Federer | Djoko | |
| Nadal | Federer | Nadal | |
| Djoko | Federer | Federer | |
| Murray | Djoko | Murray | |
| Djoko | Federer | Djoko |
目标输出
| player_1 | player_2 | winner | last_winner |
|---|---|---|---|
| Federer | Nadal | Federer | none |
| Djoko | Federer | Djoko | none |
| Nadal | Federer | Nadal | Federer |
| Djoko | Federer | Federer | Djoko |
| Murray | Djoko | Murray | none |
| Djoko | Federer | Djoko | Federer |
现有for loop实现
for i,j in tennis.iterrows() : try : tennis.loc[i, 'last_winner'] = tennis.iloc[:i].loc[(tennis.player_1.isin([j.player_1, j.player_2]) & tennis.player_2.isin([j.player_1, j.player_2])), "winner"].iloc[-1] except: tennis.loc[i, 'last_winner'] = "none"
用apply实现的替代方案
当然可以用apply结合自定义函数实现,核心是先为每对对战组合生成唯一标识(忽略球员顺序),再针对每行回溯历史记录:
步骤1:生成对战组合唯一键
为了统一A vs B和B vs A的对战标识,将两位球员按字母排序后拼接:
def create_match_key(row): return '-'.join(sorted([row['player_1'], row['player_2']])) tennis['match_key'] = tennis.apply(create_match_key, axis=1)
步骤2:自定义函数获取历史最后胜者
遍历每行,筛选当前行之前的同组合记录,取最后一个胜者:
def get_previous_winner(row): # 取当前行之前的所有记录,筛选同对战组合的条目 prior_matches = tennis.loc[:row.name - 1][tennis['match_key'] == row['match_key']] return prior_matches['winner'].iloc[-1] if not prior_matches.empty else 'none' # 应用函数填充last_winner列 tennis['last_winner'] = tennis.apply(get_previous_winner, axis=1) # 可选:删除临时生成的match_key列 tennis = tennis.drop(columns=['match_key'])
方案优势
- 代码结构更清晰,逻辑拆分明确;
- 相比
iterrows()的逐行循环,apply更贴合pandas的API设计,可读性更强; - 对战组合的唯一键避免了重复判断
player_1和player_2的双向匹配,减少逻辑冗余。
内容的提问来源于stack exchange,提问作者iordanoffff
相关产品推荐
相关产品推荐

