基于日期与分组的tot_value增量计算问题求助
问题
我有一个以date为索引的DataFrame,每个日期对应4个symbol。需要按日期和symbol循环计算:
quantity列基于前一日的tot_valuetot_value为当日所有symbol的共用值value列随每个symbol变化
当前代码使用shift方法时,无法正确引用前一日的tot_value,而是使用DataFrame初始化时的默认值,但最终tot_value计算正确。恳请修正该循环逻辑。
原代码:
import pandas as pd # create the dataframe data = {'symbol': ['A', 'B', 'C', 'D','A', 'B', 'C', 'D','A', 'B', 'C', 'D','A', 'B', 'C', 'D'], 'date':['05/06/2024','05/06/2024','05/06/2024','05/06/2024', '05/07/2024','05/07/2024','05/07/2024','05/07/2024', '05/08/2024','05/08/2024','05/08/2024','05/08/2024', '05/09/2024','05/09/2024','05/09/2024','05/09/2024'], 'tot_value': [1000, 1000, 1000, 1000,1000, 1000, 1000, 1000,1000, 1000, 1000, 1000,1000, 1000, 1000, 1000], 'mult': [1, 1.1, 1.2, 1.3,1.4, 1.5, 1.6, 1.7,1.8, 1.9, 2, 2.1,2.2, 2.3, 2.4, 2.5], 'quantity': [0, 0, 0, 0,0, 0, 0, 0,0, 0, 0, 0,0, 0, 0, 0], 'value': [0, 0, 0, 0,0, 0, 0, 0,0, 0, 0, 0,0, 0, 0, 0], } df = pd.DataFrame(data) df.set_index(['date'], inplace = True) symbols = df['symbol'].unique() # loop by date index and symbol for ind in df.index.unique(): for symbol in symbols: df['quantity'][ind] = df['tot_value'][ind].shift(1) * df['mult'][ind] df['value'][ind] = df['quantity'][ind] * 5 g = df.groupby('date')['value'].sum() df['tot_value'][ind] = g.sum() df
修正后的代码与逻辑
原代码问题在于:
df['tot_value'][ind].shift(1)无法正确获取前一日的全局tot_value,shift是对列的整体操作,而非单值引用- 循环单个symbol的方式效率低,且容易引发DataFrame赋值警告
修正思路:
- 用变量单独维护前一日的
tot_value,避免依赖DataFrame的shift操作 - 按时间顺序循环日期,确保每一步都能拿到正确的前置值
- 批量处理当日所有symbol的计算,再统一更新
tot_value
修正后的代码:
import pandas as pd # 创建初始DataFrame data = {'symbol': ['A', 'B', 'C', 'D','A', 'B', 'C', 'D','A', 'B', 'C', 'D','A', 'B', 'C', 'D'], 'date':['05/06/2024','05/06/2024','05/06/2024','05/06/2024', '05/07/2024','05/07/2024','05/07/2024','05/07/2024', '05/08/2024','05/08/2024','05/08/2024','05/08/2024', '05/09/2024','05/09/2024','05/09/2024','05/09/2024'], 'tot_value': [1000, 1000, 1000, 1000,1000, 1000, 1000, 1000,1000, 1000, 1000, 1000,1000, 1000, 1000, 1000], 'mult': [1, 1.1, 1.2, 1.3,1.4, 1.5, 1.6, 1.7,1.8, 1.9, 2, 2.1,2.2, 2.3, 2.4, 2.5], 'quantity': [0, 0, 0, 0,0, 0, 0, 0,0, 0, 0, 0,0, 0, 0, 0], 'value': [0, 0, 0, 0,0, 0, 0, 0,0, 0, 0, 0,0, 0, 0, 0], } df = pd.DataFrame(data) # 转换日期格式并排序,确保按时间顺序计算 df['date'] = pd.to_datetime(df['date'], format='%m/%d/%Y') df.set_index(['date'], inplace=True) df.sort_index(inplace=True) # 获取按时间排序的日期列表 dates = df.index.unique().sort_values() # 初始化前一日的tot_value,取第一天的初始值 prev_tot_value = df.loc[dates[0], 'tot_value'].iloc[0] for date in dates: mask = df.index == date if date == dates[0]: # 第一天无前置数据,设置quantity和value为NaN df.loc[mask, 'quantity'] = pd.NA df.loc[mask, 'value'] = pd.NA else: # 用前一日tot_value计算当日所有symbol的quantity df.loc[mask, 'quantity'] = prev_tot_value * df.loc[mask, 'mult'] # 计算value df.loc[mask, 'value'] = df.loc[mask, 'quantity'] * 5 # 计算当日value总和,更新tot_value daily_value_sum = df.loc[mask, 'value'].sum() new_tot_value = prev_tot_value + daily_value_sum df.loc[mask, 'tot_value'] = new_tot_value # 更新前置值,供下一日使用 prev_tot_value = new_tot_value # 格式化数字显示(可选) pd.options.display.float_format = '{:,.0f}'.format print(df)
关键修正点
- 日期排序:确保循环顺序与时间一致,避免计算混乱
- 单值维护:用
prev_tot_value存储前一天的tot_value,每次循环后更新,保证下一日能正确引用 - 批量操作:用
loc批量处理当日所有行,避免循环单个symbol,提升效率并避免赋值警告 - 首日处理:直接设置首日的
quantity和value为NaN,符合预期逻辑
预期结果
| date | symbol | tot_value | mult | quantity | value |
|---|---|---|---|---|---|
| 2024-05-06 | A | 1,000 | 1 | NaN | NaN |
| 2024-05-06 | B | 1,000 | 1.1 | NaN | NaN |
| 2024-05-06 | C | 1,000 | 1.2 | NaN | NaN |
| 2024-05-06 | D | 1,000 | 1.3 | NaN | NaN |
| 2024-05-07 | A | 32,000 | 1.4 | 1,400 | 7,000 |
| 2024-05-07 | B | 32,000 | 1.5 | 1,500 | 7,500 |
| 2024-05-07 | C | 32,000 | 1.6 | 1,600 | 8,000 |
| 2024-05-07 | D | 32,000 | 1.7 | 1,700 | 8,500 |
| 2024-05-08 | A | 1,280,000 | 1.8 | 57,600 | 288,000 |
| 2024-05-08 | B | 1,280,000 | 1.9 | 60,800 | 304,000 |
| 2024-05-08 | C | 1,280,000 | 2 | 64,000 | 320,000 |
| 2024-05-08 | D | 1,280,000 | 2.1 | 67,200 | 336,000 |
| 2024-05-09 | A | 61,440,000 | 2.2 | 2,816,000 | 14,080,000 |
| 2024-05-09 | B | 61,440,000 | 2.3 | 2,944,000 | 14,720,000 |
| 2024-05-09 | C | 61,440,000 | 2.4 | 3,072,000 | 15,360,000 |
| 2024-05-09 | D | 61,440,000 | 2.5 | 3,200,000 | 16,000,000 |
内容的提问来源于stack exchange,提问作者rumkey
相关产品推荐
相关产品推荐

