Python中DataFrame扣除百分比的累计总额非迭代实现求助
问题
需要在Python中实现累计总额(running total)计算:现有DataFrame,初始值为100,从之前的累计值中扣除take_profit列的百分比数值,维持累计总额。目前仅能通过迭代行实现,希望用向量化方法替代,但尝试的代码逻辑出错,存在自引用问题。
当前尝试的代码:
df = df[['trade_long','close_long','active_trade','take_profit']] df['current_trade_size'] = 0 df.loc[df['trade_long'], 'current_trade_size'] = 100 df.loc[df['close_long'], 'current_trade_size'] = 0 df['trade_ramainder'] = (1 - (df['take_profit']/100)) df['previous_trade_size'] = df['current_trade_size'].shift(1) df['current_trade_size'] = df['previous_trade_size'] * df['trade_ramainder']
当前输出:
| Date | trade_long | close_long | active_trade | take_profit | current_trade_size | trade_ramainder | previous_trade_size |
|---|---|---|---|---|---|---|---|
| 2020-01-07 | True | False | True | 0.00 | NaN | 1.00 | NaN |
| 2020-01-08 | False | False | True | 0.00 | 100.00 | 1.00 | 100.0 |
| 2020-01-09 | False | False | True | 0.68 | 0.00 | 0.99 | 0.0 |
| 2020-01-10 | True | False | True | 0.00 | 0.00 | 1.00 | 0.0 |
| 2020-01-11 | False | False | True | 0.69 | 99.30 | 0.99 | 100.0 |
| 2020-01-12 | True | False | True | 0.00 | 0.00 | 1.00 | 0.0 |
| 2020-01-13 | False | False | True | 0.00 | 100.00 | 1.00 | 100.0 |
期望输出:
| Date | trade_long | close_long | active_trade | take_profit | current_trade_size |
|---|---|---|---|---|---|
| 2020-01-07 | True | False | True | 0.00 | 100.00 |
| 2020-01-08 | False | False | True | 0.00 | 100.00 |
| 2020-01-09 | False | False | True | 0.68 | 99.32 |
| 2020-01-10 | True | False | True | 0.00 | 100.00 |
| 2020-01-11 | False | False | True | 0.69 | 98.63 |
| 2020-01-12 | True | False | True | 0.00 | 100.00 |
| 2020-01-13 | False | False | True | 0.00 | 100.00 |
解决方案
你的核心问题是用shift无法实现实时自引用计算——shift只能取原始列的前一行值,无法获取计算后的实时值。用分组累计乘积可以实现完全向量化的计算,无需迭代。
实现步骤
- 标记重置分组:每当
trade_long为True时,开启一个新的计算分组,自然分隔每次重置为100的逻辑。 - 计算留存比例:将
take_profit转换为每天的资金留存比例1 - take_profit/100。 - 分组计算累计乘积:对每个分组内的留存比例计算累计乘积,再乘以初始值100,得到当天的累计总额。
- 处理
close_long重置:如果close_long触发时需要将数值置0,最后单独修正即可。
完整代码
df = df[['trade_long','close_long','active_trade','take_profit']] # 1. 创建分组标识:trade_long为True时分组编号递增 df['group'] = df['trade_long'].cumsum() # 2. 计算每天的资金留存比例 df['trade_remainder'] = 1 - df['take_profit'] / 100 # 3. 分组计算累计乘积,再乘以初始值100 df['current_trade_size'] = df.groupby('group')['trade_remainder'].cumprod() * 100 # 4. 处理close_long的重置逻辑(若需要) df.loc[df['close_long'], 'current_trade_size'] = 0 # 可选:删除中间辅助列,保留需要的字段 df = df.drop(columns=['group', 'trade_remainder'])
逻辑验证
运行后结果将完全匹配你的期望:
- 2020-01-07:
trade_long=True开启分组1,累计乘积为1,1*100=100 - 2020-01-08:同一分组,留存比例1,累计乘积
1*1=1,1*100=100 - 2020-01-09:同一分组,留存比例
1-0.68/100=0.9932,累计乘积1*0.9932=0.9932,0.9932*100=99.32 - 2020-01-10:
trade_long=True开启分组2,重置为100 - 后续日期按同样逻辑计算,每次
trade_long触发都会重置分组,重新开始累计
内容的提问来源于stack exchange,提问作者James Cabourne
相关产品推荐
相关产品推荐

