4. 金融时序滚动统计特征提取
任务与数据
用一段模拟的日频收盘价序列,计算滚动窗口内的均值、标准差、偏度和峰度,拼成特征矩阵,供后续建模使用。滚动统计量能刻画局部趋势、波动率和分布形态,是金融时序特征工程的基础。
实现要点
- 窗口
window=20,min_periods=window保证每个统计量都由完整窗口计算,避免前 19 行出现不完整估计。 - 均值/标准差用
pandas.rolling;偏度/峰度用rolling().skew()与rolling().kurt()(Fisher 定义,正态为 0)。 - 对价格先取对数收益率
log(price).diff(),再对收益率做滚动统计,量纲更稳定。 - 丢弃含 NaN 的前
window行,得到对齐的特征矩阵。
完整代码
import numpy as np
import pandas as pd
# 1. 构造模拟日频收盘价(几何随机游走)
rng = np.random.default_rng(42)
n = 200
ret = rng.normal(0.0005, 0.02, size=n)
price = 100 * np.exp(np.cumsum(ret))
dates = pd.date_range("2023-01-02", periods=n, freq="B")
df = pd.DataFrame({"close": price}, index=dates)
# 2. 对数收益率
df["log_ret"] = np.log(df["close"]).diff()
# 3. 滚动统计特征
w = 20
roll = df["log_ret"].rolling(window=w, min_periods=w)
feat = pd.DataFrame({
"roll_mean": roll.mean(),
"roll_std": roll.std(),
"roll_skew": roll.skew(),
"roll_kurt": roll.kurt(),
})
# 4. 对齐并输出特征矩阵
features = feat.dropna()
print("特征矩阵形状:", features.shape)
print(features.head())
print("列名:", list(features.columns))
# 5. 简单验证:窗口内统计量与手工计算一致
i = w # 第一个完整窗口结束位置
manual_mean = df["log_ret"].iloc[i - w + 1:i + 1].mean()
manual_std = df["log_ret"].iloc[i - w + 1:i + 1].std()
assert np.isclose(features["roll_mean"].iloc[0], manual_mean)
assert np.isclose(features["roll_std"].iloc[0], manual_std)
print("验证通过:滚动均值/标准差与手工计算一致")
运行与验证
- 依赖:
pip install numpy pandas,Python 3.9+。 - 运行脚本,观察输出形状应为
(180, 4)(200 行减去 1 行 diff 与 19 行窗口预热)。 - 通过条件:脚本无异常退出,且断言通过,说明滚动均值与标准差与手工窗口计算一致;偏度、峰度由 pandas 同一窗口机制产出,列名与顺序符合预期。
特征计算流程
常见问题
- 若
min_periods小于window,前几行统计量基于不完整窗口,会引入偏差,建模前需注意。 - 偏度/峰度对异常值敏感,可先对收益率做缩尾(winsorize)再滚动。
- 若需多窗口(如 5/20/60),对同一
log_ret循环不同w并横向拼接即可。