自学教程 学编程从这里开始

Pandas 窗口函数 rolling

承接《Pandas apply / map / applymap》,本篇讲解 rolling 滑动窗口,包含移动平均、滑动求和、窗口统计、窗口参数、扩展窗口expanding、指数加权ewm、分组滚动,是时序指标、行情、订单滚动统计核心工具,保持系列教程统一风格。
前置导入与示例数据

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "date": pd.date_range(start="2025-01-01", periods=10, freq="D"),
    "sales": [120, 90, 150, 130, 180, 160, 200, 170, 140, 190]
})
df = df.set_index("date")
print(df)

一、rolling 基础概念

滚动窗口(滑动窗口):设置窗口大小 window,沿着序列向前滑动,在窗口内做聚合计算。

窗口必须是有序序列,时序数据一般以时间为索引;顺序乱了结果完全错误。

# 语法:df["sales"].rolling(window=N)
roll = df["sales"].rolling(window=3)
# 窗口内求和
df["roll_sum_3"] = roll.sum()
# 窗口内平均值(移动平均MA3)
df["roll_mean_3"] = roll.mean()

window=3:每次取当前行 + 前面2行,一共3条数据。
前两行数据窗口不足,默认返回 NaN。

二、常用聚合函数

s = df["sales"].rolling(window=3)
df["roll_max"] = s.max()    # 窗口最大值
df["roll_min"] = s.min()    # 窗口最小值
df["roll_std"] = s.std()    # 窗口标准差
df["roll_count"] = s.count()# 窗口内非空数量
df["roll_median"] = s.median() # 窗口中位数

三、核心参数详解

1. window

  • 数字:行数窗口(固定条数)
  • 时间字符串(如 5D、2H):时间窗口,索引必须是DatetimeIndex
# 时间窗口:最近5天的滚动统计
df["sales"].rolling(window="5D").sum()

2. min_periods

最小有效观测数,窗口内满足多少条数据才输出结果,默认等于window

# window=3,min_periods=1:只要>=1条就计算,不足3条不再是NaN
df["roll_mean_3p1"] = df["sales"].rolling(window=3, min_periods=1).mean()

3. center

窗口居中对齐,默认 center=False(窗口靠右,当前行是窗口最后一个)
center=True:当前行放在窗口中间

df["roll_center"] = df["sales"].rolling(window=3, center=True).mean()

居中窗口适合平滑绘图,不适合业务回溯统计(报表、回测一般不用center)

4. closed

窗口区间闭合方式,时序窗口高频参数

  • right(默认):包含右端,不包含左端
  • left:包含左端,不包含右端
  • both:两端都包含
  • neither:两端都不包含

四、自定义窗口函数 apply

rolling 内置函数不够用时,可以传入自定义函数

# 窗口内极差(最大值-最小值)
def peak_range(x):
    return x.max() - x.min()

df["roll_range"] = df["sales"].rolling(window=3).apply(peak_range)

⚠️ 自定义rolling.apply性能较差,大数据慎用。

五、expanding 扩展窗口(累计窗口)

expanding 是从第一条一直累积到当前行,窗口不断变大,又叫累计窗口

# 累计平均值
df["exp_mean"] = df["sales"].expanding().mean()
# 累计总和
df["exp_sum"] = df["sales"].expanding().sum()

区别 rolling:rolling是固定大小滑动;expanding持续扩大。

六、ewm 指数加权窗口(EWMA)

指数加权移动平均,越近的数据权重越高,适合行情、传感器平滑

# alpha=0.3 衰减系数
df["ewm_mean"] = df["sales"].ewm(alpha=0.3, adjust=False).mean()

七、分组滚动(groupby + rolling,业务高频)

多分组时序,每个分组独立滚动,比如每个商品、每个渠道单独算3日滚动销售额

df2 = pd.DataFrame({
    "date": pd.date_range("2025-01-01", periods=12, freq="D"),
    "cate": ["A","A","A","A","B","B","B","B","A","A","B","B"],
    "sales": [120,90,150,130,180,160,200,170,140,190,110,135]
})
# 按品类分组,每组独立3日滚动平均
df2["roll_3_cate"] = df2.groupby("cate")["sales"].rolling(window=3, min_periods=1).mean().reset_index(drop=True)
print(df2)

重点:groupby后rolling返回多层索引,记得 reset_index(drop=True) 再接回原df。

八、滚动窗口 + shift 搭配(前N期指标)

# 3日滚动均值,整体向后偏移1行,代表上一周期的滚动均值
df["roll_mean_3_last"] = df["sales"].rolling(3).mean().shift(1)

九、高频坑清单

  1. 索引无序,rolling直接算出错误结果,时序数据先排序 df.sort_index()
  2. 时间窗口window=”5D”,索引不是datetime会报错
  3. min_periods忘记设置,前面大量NaN
  4. groupby rolling 多层索引,直接赋值会报长度不匹配
  5. center=True 用于统计时容易理解错窗口含义
  6. rolling.apply 自定义函数速度慢,优先内置sum/mean/std
  7. 缺失值会被窗口自动忽略,配合min_periods控制输出

十、综合实战模板

def add_rolling_feature(df, col, window=3):
    """增加滚动指标:均值、求和、最大值"""
    df = df.sort_index()
    roll = df[col].rolling(window=window, min_periods=1)
    df[f"{col}_roll_mean_{window}"] = roll.mean()
    df[f"{col}_roll_sum_{window}"] = roll.sum()
    df[f"{col}_roll_max_{window}"] = roll.max()
    return df

df = add_rolling_feature(df, "sales", window=3)
print(df)

十一、窗口函数速查表

API类型特点
rolling(window)滑动窗口固定窗口大小,向前滑动
expanding()扩展窗口从第一条开始不断累积
ewm(alpha)指数加权近值权重更高,平滑时序
groupby + rolling分组滚动每个分组独立计算窗口
标签:

0 条笔记