
本文介绍如何高效地为 DataFrame 添加一列,其值为前 N 行(如 3 行)的滑动窗口列表,避免低效的 Python 循环和 apply 的类型限制问题。
本文介绍如何高效地为 dataframe 添加一列,其值为前 n 行(如 3 行)的滑动窗口列表,避免低效的 python 循环和 `apply` 的类型限制问题。
在 Pandas 中,尝试用 rolling().apply() 返回列表(如 lambda x: list(x))会失败,根本原因在于:rolling.apply() 要求聚合函数必须返回标量数值(如 int, float),而 list 是非标量对象,触发 TypeError: must be real number, not list。这不是 apply 的使用错误,而是滚动窗口聚合的设计约束——它面向数值计算(均值、标准差等),不支持构造复合对象。
因此,正确解法是绕过 rolling().apply(),改用底层向量化滑动窗口工具。自 NumPy 1.20 起,numpy.lib.stride_tricks.sliding_window_view 提供了零拷贝、高性能的滑动窗口视图,完美适配此类需求。
以下为完整实现步骤:
import pandas as pd
import numpy as np
# 构造示例数据
np.random.seed(150)
df = pd.DataFrame(np.random.randint(0, 10, size=(10, 2)), columns=['A', 'B'])
# ✅ 推荐方案:使用 sliding_window_view(高效、简洁、向量化)
from numpy.lib.stride_tricks import sliding_window_view as swv
N = 3
windowed_arrays = swv(df['B'], window_shape=N) # 形状为 (len-2, 3) 的 2D 数组
df['C'] = pd.Series([row.tolist() for row in windowed_arrays],
index=df.index[N-1:]) # 对齐索引:前 N-1 行为 NaN
输出结果与预期一致:
A B C 0 4 9 NaN 1 0 2 NaN 2 4 5 [9, 2, 5] 3 7 9 [2, 5, 9] 4 8 3 [5, 9, 3] 5 8 1 [9, 3, 1] 6 1 4 [3, 1, 4] 7 4 1 [1, 4, 1] 8 1 9 [4, 1, 9] 9 3 7 [1, 9, 7]
⚠️ 注意事项:
-
sliding_window_view返回的是只读视图,.tolist()会创建新列表,确保结果可修改; - 新列
C的前N-1行自动为NaN(而非None),符合 Pandas 缺失值规范,便于后续dropna()或fillna()处理; - 若需兼容旧版 NumPy(df['B'].to_numpy()[i:i+N] 配合列表推导,但性能显著下降;
- 切勿使用
df.apply(lambda x: ..., axis=1)实现滑动逻辑——它逐行调用,复杂度 O(n²),大数据下极慢。
总结:当目标是生成滑动窗口列表时,优先选择 sliding_window_view + pd.Series 构造,兼顾性能、可读性与健壮性;放弃 rolling().apply() 的尝试,因其设计本就不支持非标量返回。










