Pandas apply函数如何引用前序行递推计算结果
问题核心
时序递推类计算(当前行计算依赖上一行的计算输出)无法直接用apply(axis=1)实现:apply执行时不会实时将单行计算结果写回原DataFrame,函数内读取原df的end列只能拿到初始化的0值,无法获取上一步的计算结果。同时iterrows()作为Python层行迭代方案,在大规模数据集上性能极差。
性能最优实现(Numba 编译方案)
这类强递推逻辑的最高效实现方式是用Numba将Python循环编译为机器码执行,性能比iterrows()/apply高2~3个数量级,百万行级数据可在毫秒级完成计算,代码逻辑和原生循环完全一致,可读性强。
import pandas as pd import numpy as np from numba import njit # 测试数据 df = pd.DataFrame(data = {'NetPosition': [-10, -5, 10], 'row_no': [0,1,2]}) starting_value = 20 max_rating = 4 # 递推逻辑加numba编译装饰器,入参出参统一用numpy数组避免Pandas对象开销 @njit def calc_dispatch(net_position_arr, init_soc, max_power): n = len(net_position_arr) start = np.zeros(n, dtype=np.float64) end = np.zeros(n, dtype=np.float64) dispatch = np.zeros(n, dtype=np.float64) for i in range(n): # 第一步取初始值,后续步直接取上一步计算得到的end值 start[i] = init_soc if i == 0 else end[i-1] if net_position_arr[i] < 0: dispatch[i] = min(np.abs(net_position_arr[i]), max_power, start[i]) end[i] = start[i] - dispatch[i] else: dispatch[i] = 0 end[i] = start[i] return start, end, dispatch # 执行计算并赋值回df df['start'], df['end'], df['dispatch'] = calc_dispatch( df['NetPosition'].to_numpy(), starting_value, max_rating )
执行后得到的结果完全符合预期:
| NetPosition | row_no | start | end | dispatch | |
|---|---|---|---|---|---|
| 0 | -10 | 0 | 20 | 16 | 4 |
| 1 | -5 | 1 | 16 | 12 | 4 |
| 2 | 10 | 2 | 12 | 12 | 0 |
其他可选方案
如果无法安装Numba依赖,可替换为itertuples()迭代,相比iterrows()性能可提升5~10倍,但本质仍是Python层循环,仅适合十万行以内的中小规模数据集:
df = df.reset_index(drop=True) prev_end = starting_value for row in df.itertuples(): idx = row.Index curr_start = prev_end if row.NetPosition < 0: curr_dispatch = min(abs(row.NetPosition), max_rating, curr_start) curr_end = curr_start - curr_dispatch else: curr_dispatch = 0 curr_end = curr_start df.loc[idx, ['start', 'end', 'dispatch']] = [curr_start, curr_end, curr_dispatch] prev_end = curr_end
注意事项
不要尝试用全局变量、临时列表等trick让apply实现递推逻辑:apply本身的行迭代开销极高,哪怕实现了功能,性能也远低于Numba方案,且代码可维护性极差。
内容的提问来源于stack exchange,提问作者c10all
相关产品推荐
相关产品推荐

