如何通过一次groupby调用创建Pandas多列不同滞后值
分组生成命名滞后特征的高效实现
核心需求
- 最终目标:给Pandas DataFrame按分组生成n个带命名的滞后特征(每行对应分组内的历史值)
- 次要目标:减少Pandas API调用次数,避免嵌套for循环
朴素实现(低效)
下面是常规的嵌套循环写法,需要调用len(features)*n次API,效率偏低:
n = 7 for feature in features: for i in range(1, n + 1): df[feature + "_" + str(i)] = df.groupby(["a", "b"])[feature].shift(i)
失败的优化尝试
想用agg方法批量生成滞后特征,但agg要求聚合函数返回单个值,不支持shift这类保留原行数的操作,运行后会报错ValueError: Must produce aggregated value:
lagged_features = {} n = 7 for feature in features: for i in range(1, n + 1): key = feature + "_" + str(i) lagged_features[key] = pd.NamedAgg(feature, lambda x: x.shift(i)) df_lagged = df.groupby(["a", "b"]).agg(**lagged_features)
高效实现方案(仅1次API调用)
利用groupby.shift的向量化特性,一次性生成所有滞后特征,再整理列名即可:
import pandas as pd n = 7 # 按分组批量生成1到n阶滞后 lagged_df = df.groupby(["a", "b"])[features].shift(range(1, n+1)) # 重命名列:格式为「原特征名_滞后阶数」 lagged_df.columns = [f"{col}_{i+1}" for col in features for i in range(n)] # 合并到原DataFrame df = pd.concat([df, lagged_df], axis=1)
原理说明
shift(range(1, n+1))会对每个特征同时生成1到n阶的滞后结果,返回的DataFrame会有多层列索引(第一层是原特征名,第二层是滞后阶数)- 通过列表推导式把多层索引转换成直观的命名格式
- 最后用
concat把滞后特征拼回原表,全程只调用一次groupby.shift,完全避免嵌套循环
内容的提问来源于stack exchange,提问作者teejk
相关产品推荐
相关产品推荐

