如何在Pandas中实现基于前一行的截断累积和(Clipped Cumsum)
高效实现依赖前值的截断累积和(Clipped Cumsum)
需求明确
先通过energy_pv - energy_consumption生成spare_pv列,再生成cumsum_spare_pv列,规则为:
- 首行:若
spare_pv[0] <= 0则取0,否则取spare_pv[0] - 后续行:计算
当前spare_pv + 上一行cumsum_spare_pv,结果<=0则取0,否则取该结果
普通的pd.Series.cumsum()无法实现这种带截断且依赖前序计算结果的逻辑,纯Python循环处理数十万行效率极低,以下是高效解决方案:
最优方案:用Numba编译加速循环
Numba能将Python循环编译为机器码,速度比纯Python循环快几十倍甚至上百倍,完全适配数十万行的数据集。
步骤1:计算spare_pv列
import pandas as pd import numpy as np from numba import jit df['spare_pv'] = df['energy_pv'] - df['energy_consumption']
步骤2:定义Numba编译的截断累积和函数
@jit(nopython=True) def clipped_cumsum(arr): result = np.empty_like(arr) current = 0.0 for i in range(len(arr)): current += arr[i] # 截断逻辑:小于等于0则重置为0 current = max(current, 0.0) result[i] = current return result
步骤3:应用函数生成目标列
df['cumsum_spare_pv'] = clipped_cumsum(df['spare_pv'].values)
备选方案:Pandas Expanding Apply(仅适合小数据集)
如果不想引入Numba依赖,可使用Pandas的expanding().apply(),但速度远不如Numba,仅建议用于万级以内的数据集:
def calc_clipped_window(window): # 窗口最后一个值是当前spare_pv,前面的累积结果是窗口倒数第二个值(如果存在) prev_cumsum = window.iloc[-2] if len(window) > 1 else 0 current_val = window.iloc[-1] + prev_cumsum return max(current_val, 0) df['cumsum_spare_pv'] = df['spare_pv'].expanding().apply(calc_clipped_window)
结果验证
比如以下测试数据:
| energy_consumption | energy_pv | spare_pv | cumsum_spare_pv |
|---|---|---|---|
| 10 | 15 | 5 | 5 |
| 10 | 7 | -3 | 2 |
| 10 | 7 | -3 | 0 |
| 10 | 14 | 4 | 4 |
计算结果完全匹配Excel公式=IF((E2+F1)<=0, 0, E2+F1)的逻辑。
内容的提问来源于stack exchange,提问作者GalacticPonderer
相关产品推荐
相关产品推荐

