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

Pandas expanding /ewm 窗口详解

承接上一篇《Pandas 窗口函数 rolling》,本篇专门讲解 expanding 扩展窗口、ewm 指数加权窗口,对比 rolling,包含参数、代码示例、分组用法、业务场景、坑点,是时序指标、金融回测、数据平滑的常用工具,保持系列教程统一风格。
前置导入与示例数据

import pandas as pd
import numpy as np

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

一、三者核心区别快速回顾

  • rolling:固定窗口大小,向前滑动,窗口重叠(3日移动平均)
  • expanding:扩展窗口,从第一条数据一直包含到当前行,窗口持续变大
  • ewm:指数加权窗口,距离当前越近的数据权重越高,权重指数衰减

rolling 是“固定长度滑动”;expanding 是“不断扩大的全集”;ewm 是“带权重衰减的平滑”

二、expanding 扩展窗口

2.1 基础语法

exp = df["value"].expanding(min_periods=1)
df["exp_sum"] = exp.sum()
df["exp_mean"] = exp.mean()
df["exp_max"] = exp.max()
df["exp_min"] = exp.min()

参数说明:

  • min_periods:最少有效样本数量,默认 1;达到这个数量才输出结果
  • axis:维度方向,默认0(按列)
  • method:计算方式,single 单进程,table 全表(新版pandas)

支持的聚合函数和 rolling 几乎一致:sum, mean, max, min, std, var, median, skew, corr, cov

2.2 和 cumsum 的关系

# 下面两行等价
df["value"].expanding().sum()
df["value"].cumsum()

cumsum/cummax/cummin 是 expanding 部分场景的简写;但 expanding 可以做均值、标准差、偏度等复杂统计,cumsum 只能做累计求和。

2.3 分组 expanding(groupby + expanding)

业务高频场景:每个品类、每个用户独立累计统计

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]
})

df2["exp_mean_cate"] = df2.groupby("cate")["sales"].expanding(min_periods=1).mean().reset_index(drop=True)
print(df2)

注意:groupby + expanding 返回 MultiIndex,需要 reset_index(drop=True) 才能直接赋值回原DataFrame。

2.4 expanding 适用场景

累计收益率、累计最高水位、累计平均转化率、用户累计消费、累计最大回撤。

三、ewm 指数加权窗口(Exponentially Weighted Moving)

EWM,常用来计算 EWMA 指数加权移动平均,降噪、趋势平滑,股票、传感器时序非常常用。

核心思想:历史数据权重随时间指数衰减,越新的数据权重越高。

3.1 基础语法

# span=5 代表5周期EWMA
df["ewm_span5"] = df["value"].ewm(span=5, adjust=False).mean()

3.2 四大参数(四选一,控制衰减速度)

你只需要指定其中一个:

  1. span:跨度,等效N周期,alpha = 2/(span+1)
  2. com:质心,alpha = 1/(com+1)
  3. halflife:半衰期,权重衰减到一半的时间
  4. alpha:直接指定衰减系数,范围 0 < alpha ≤ 1
# alpha=0.3,最新数据权重0.3
df["ewm_alpha03"] = df["value"].ewm(alpha=0.3, adjust=False).mean()

3.3 adjust 参数(非常关键,很多人踩坑)

  • adjust=True(默认):使用递归标准EWM公式,适合理论计算
  • adjust=False:简化公式,和金融软件(同花顺、通达信EWMA)对齐,做回测优先 False

3.4 支持的聚合

ewm 原生支持:mean, var, std, corr, cov,不支持max/min/median,这点和 rolling/expanding 不一样。

3.5 分组 ewm(groupby + ewm)

Pandas 1.2.0 之后支持分组指数加权

df2["ewm_span3"] = df2.groupby("cate")["sales"].ewm(span=3, adjust=False).mean().reset_index(drop=True)
print(df2)

3.6 ewm 适用场景

时序平滑降噪、波动率EWMA、行情均线、传感器信号过滤、在线指标平滑。

四、自定义函数:expanding.apply / ewm 说明

  • expanding.apply(func):支持传入自定义函数,用法和 rolling.apply 一致,但是性能同样偏弱
def range_func(x):
    return x.max() - x.min()
df["exp_range"] = df["value"].expanding(min_periods=2).apply(range_func)
  • ewm 没有 .apply(),ewm 只能使用内置的 mean/std/cov/corr,不能自定义函数。

五、三者对比汇总表

窗口类型窗口形态权重典型输出能否时间窗口分组支持
rolling固定长度滑动,重叠窗口默认等权,支持win_type加权MA、滚动分位数、滚动极值✅ 支持 5D、1H✅
expanding从首行持续扩大到当前行等权累计均值、累计最大、累计标准差❌ 仅按行数✅
ewm全量历史,指数衰减近大远小EWMA、指数波动率❌ 仅按行数✅

六、高频坑清单

  1. expanding 不支持时间窗口(”5D”),只能按行数;想要时间范围累计,只能用rolling时间窗口
  2. ewm 没有 max/min 聚合,不能用来求指数加权最大值
  3. adjust=True 和 adjust=False 结果差异很大,对接金融指标要固定为False
  4. groupby + expanding / ewm 会返回多层索引,直接赋值会报长度不匹配,必须 reset_index(drop=True)
  5. expanding 前几行 min_periods 设置不当会大量出现NaN
  6. ewm 对缺失值敏感,NaN会中断权重链,建议先填充时序缺失

七、综合实战模板

def add_exp_ewm_feature(df, col, span=5):
    """批量增加扩展窗口、EWM指标"""
    df = df.sort_index()
    # expanding
    exp = df[col].expanding(min_periods=1)
    df[f"{col}_exp_mean"] = exp.mean()
    df[f"{col}_exp_max"] = exp.max()
    # ewm
    df[f"{col}_ewm_{span}"] = df[col].ewm(span=span, adjust=False).mean()
    return df

df = add_exp_ewm_feature(df, "value", span=5)
print(df)

八、配套速记

  • 需要N天滑动指标 → rolling
  • 需要从开始到现在累计统计 → expanding
  • 需要平滑、近期数据权重更高 → ewm
标签:

0 条笔记