Pandas rolling可变窗口报错及金额按周期向前回填方案求解
解决方案
pandas 原生 rolling 方法的 window 参数仅支持固定整数或固定时间偏移量,不支持传入序列实现逐行动态窗口,因此你之前的写法会抛出数值类型错误。
针对3000万级别的大数据量,推荐使用以下高性能实现方案,完全匹配你的需求:
前置预处理
首先确保数据按ID分组、日期升序排列,并完成格式转换:
import pandas as pd import numpy as np # 日期格式转换 + 排序 df['DATE'] = pd.to_datetime(df['DATE'], format='%d-%m-%Y') df = df.sort_values(['ID', 'DATE']).reset_index(drop=True) # 空金额转为0,避免计算报错 df['AMOUNT'] = pd.to_numeric(df['AMOUNT'], errors='coerce').fillna(0)
核心计算逻辑
你的需求本质是:每个非空的AMOUNT值,会覆盖从当前行往前数VARIABLE_DISTRIBUTION - 1行到当前行的区间,区间内的REPEAT_AMOUNT统一取该AMOUNT值,后出现的有效值会覆盖前面的重叠区间。
我们通过向量化区间赋值实现,性能远高于逐行apply或循环:
def calc_repeat_amount(group): group_len = len(group) res = np.full(group_len, np.nan) # 提取当前分组的数值数组 amt_arr = group['AMOUNT'].values dist_arr = group['VARIABLE_DISTRIBUTION'].values # 筛选有有效值的位置 valid_idx = np.where(amt_arr > 0)[0] if valid_idx.size == 0: group['REPEAT_AMOUNT'] = res return group # 计算每个有效值的覆盖区间 start_pos = np.maximum(0, valid_idx - dist_arr[valid_idx] + 1) end_pos = valid_idx + 1 valid_amt = amt_arr[valid_idx] # 批量赋值,后值自动覆盖前值重叠部分 for s, e, val in zip(start_pos, end_pos, valid_amt): res[s:e] = val group['REPEAT_AMOUNT'] = res return group # 按ID分组计算 df = df.groupby('ID', group_keys=False).apply(calc_repeat_amount) # 可选:将空值转为示例中的'-'格式 df['REPEAT_AMOUNT'] = df['REPEAT_AMOUNT'].fillna('-')
超大数据量优化
如果单节点内存无法承载全量数据,可以替换为Dask框架分块计算,逻辑和上述代码完全一致,仅需将pandas接口替换为Dask对应接口即可,无需调整核心逻辑。
内容的提问来源于stack exchange,提问作者Ricardo Romero
相关产品推荐
相关产品推荐

