如何编写Python函数动态计算Pandas DataFrame的玩家筹码(stack)?
问题描述
现有如下示例DataFrame:
| hand | player | event | amount | stack_size |
|---|---|---|---|---|
| #345 | paired | win | 144 | 552 |
| #345 | paired | bet returned | 72 | 552 |
| #345 | paired | bets | 72 | 552 |
| #345 | paired | bets | 43 | 552 |
| #345 | paired | raises | 18 | 552 |
| #345 | paired | stack | 0 | 552 |
| #345 | paired | starting hand | 0 | 0 |
需要按照以下逻辑动态计算result列:
- 若
event属于('bets', 'calls', 'big blind', 'small blind', 'raises'):首次计算用stack_size减去amount;后续同类型事件用上一行的result值减去当前行的amount - 若
event属于('bet returned', 'win'):用上一行的result值加上当前行的amount - 所有操作需在
hand和player分组内执行
编写的函数仅考虑当前行,无法得到期望输出:
import pandas as pd data = {'hand': ['#345', '#345', '#345', '#345', '#345', '#345', '#345'], 'player': ['paired', 'paired', 'paired', 'paired', 'paired', 'paired', 'paired'], 'event': ['win', 'bet returned', 'bets', 'bets', 'raises', 'stack', 'starting hand'], 'amount': [144, 72, 72, 43, 18, 0, 0], 'stack_size': [552, 552, 552, 552, 552, 552, 0]} df = pd.DataFrame(data) def adjust_stack(row): if row['event'] in ( 'bets', 'calls', 'big blind', 'small blind', 'raises' ): return row['stack_size'] - row['amount'] elif row['event'] in ('bet_returned', 'win'): return row['stack_size'] + row['amount'] else: return row['stack_size'] df.assign( result = df.apply(adjust_stack, axis=1) ).query('hand=="#345" and player=="paired"')
期望的正确输出:
| hand | player | event | amount | stack_size | result |
|---|---|---|---|---|---|
| #345 | paired | win | 144 | 552 | 635 |
| #345 | paired | bet returned | 72 | 552 | 491 |
| #345 | paired | bets | 72 | 552 | 419 |
| #345 | paired | bets | 43 | 552 | 491 |
| #345 | paired | raises | 18 | 552 | 534 |
| #345 | paired | stack | 0 | 552 | |
| #345 | paired | starting hand | 0 | 0 |
解决方案
问题核心是需要逐行累积计算,而不是仅依赖当前行数据。可以用groupby结合自定义累积函数实现:
import pandas as pd data = {'hand': ['#345', '#345', '#345', '#345', '#345', '#345', '#345'], 'player': ['paired', 'paired', 'paired', 'paired', 'paired', 'paired', 'paired'], 'event': ['win', 'bet returned', 'bets', 'bets', 'raises', 'stack', 'starting hand'], 'amount': [144, 72, 72, 43, 18, 0, 0], 'stack_size': [552, 552, 552, 552, 552, 552, 0]} df = pd.DataFrame(data) def calculate_result(group): result = [] prev_val = None for idx, row in group.iterrows(): event = row['event'] amount = row['amount'] stack_size = row['stack_size'] # 跳过不需要计算的事件 if event in ('stack', 'starting hand'): result.append(None) continue # 初始化首次计算值 if prev_val is None: if event in ('bets', 'calls', 'big blind', 'small blind', 'raises'): current_val = stack_size - amount elif event in ('bet returned', 'win'): current_val = stack_size + amount else: # 基于上一行结果计算当前值 if event in ('bets', 'calls', 'big blind', 'small blind', 'raises'): current_val = prev_val - amount elif event in ('bet returned', 'win'): current_val = prev_val + amount result.append(current_val) prev_val = current_val group['result'] = result return group # 按hand和player分组执行计算 df = df.groupby(['hand', 'player'], group_keys=False).apply(calculate_result) print(df)
代码说明
- 分组隔离:通过
groupby(['hand', 'player'])确保每个玩家每手牌的计算独立进行,互不干扰 - 逐行累积:遍历每组内的每一行,维护上一行的
result值(prev_val),根据当前事件类型更新当前值 - 特殊事件处理:对
stack和starting hand直接返回空值,不参与累积计算
运行后即可得到符合期望的result列。
内容的提问来源于stack exchange,提问作者Ilya Lapshin
相关产品推荐
相关产品推荐

