第1章:滞后特征与差分——时序特征工程的基石

大家好,我是你们这趟旅程的向导。今天咱们聊聊时序特征工程里最基础、也最核心的两个操作:滞后特征和差分。说实话,这两个东西看着简单,但用好了,能让你的模型效果提升一大截。我在量化交易这行摸爬滚打这么多年,见过太多人一上来就上复杂模型,结果连最基本的滞后结构都没搞清楚,最后模型效果还不如一个简单的ARIMA。

好,咱们直接进入正题。

1.1 滞后算子(Lag Operator)——时间序列的“时间机器”

滞后算子,符号是 L,也叫延迟算子。它的作用很简单:把时间序列往回推。

定义上,L * y_t = y_{t-1}。你想想看,这就像给数据装了个“时间机器”,让当前时刻的数据回到过去。更一般地,L^k * y_t = y_{t-k},表示滞后k期。

我个人习惯把滞后算子看作一个“移位指令”。在代码里,它对应pandas的shift()函数。比如:

import pandas as pd
import numpy as np

# 生成示例数据
dates = pd.date_range('2024-01-01', periods=10, freq='D')
data = pd.Series(np.random.randn(10), index=dates, name='price')

# 滞后1期
data_lag1 = data.shift(1)
print(pd.concat([data, data_lag1], axis=1).head())

输出结果:

               price      price_lag1
2024-01-01  0.123456           NaN
2024-01-02 -0.789012      0.123456
2024-01-03  0.456789     -0.789012
2024-01-04 -0.234567      0.456789
2024-01-05  0.890123     -0.234567

嗯,这里要注意:滞后一期后,第一行会变成NaN。因为t=1时刻没有t=0的数据。这个NaN在建模时要么删掉,要么填充。我建议直接删掉,因为填充会引入偏差。

核心要点:滞后算子本质上是将时间序列的“记忆”显式地表达为特征。在金融时序中,过去的价格、成交量、波动率等信息,往往对当前时刻有预测能力。

1.2 差分运算——让非平稳序列“变乖”

差分,说白了就是计算相邻时刻的差值。一阶差分:Δy_t = y_t - y_{t-1}。季节性差分:Δ_s y_t = y_t - y_{t-s},s是季节周期。

为什么需要差分?因为很多金融时间序列是非平稳的,比如股票价格。非平稳序列的均值和方差会随时间变化,直接建模会出问题。差分之后,序列通常会变得平稳。我个人习惯在建模前,先用ADF检验看序列是否平稳,如果不平稳,就做一阶差分。

举个例子:

# 一阶差分
diff_1 = data.diff(1)
print(diff_1.head())

# 季节性差分(假设周期为7天)
diff_s = data.diff(7)
print(diff_s.head())

输出:

               price_diff_1
2024-01-01           NaN
2024-01-02     -0.912468
2024-01-03      1.245801
2024-01-04     -0.691356
2024-01-05      1.124690

我在项目中遇到过一个问题:有些序列需要做二阶差分才能平稳。但要注意,差分阶数越高,信息损失越大。一般一阶差分就够了,最多二阶。千万别为了追求平稳性而过度差分,否则会丢失长期趋势信息。

避坑指南:我曾经在一个高频交易项目中,对价格序列做了三阶差分,结果模型预测效果极差。后来发现,过度差分把价格中的趋势和季节性信息全抹掉了,只剩下噪声。记住:差分是为了让序列平稳,不是为了“干净”。

1.3 收益率计算——金融时序的“通用语言”

在金融领域,我们很少直接对价格建模,而是对收益率建模。原因很简单:价格是非平稳的,收益率通常是平稳的。而且收益率具有可加性,方便跨资产比较。

两种最常见的收益率:

  • 简单收益率R_t = (P_t - P_{t-1}) / P_{t-1}
  • 对数收益率r_t = ln(P_t / P_{t-1})

对数收益率有个好处:它近似等于简单收益率(当收益率很小时),而且具有时间可加性。比如,一周的对数收益率等于每天对数收益率之和。这在多期收益计算中非常方便。

代码实现:

# 简单收益率
simple_return = data.pct_change()
print(simple_return.head())

# 对数收益率
log_return = np.log(data / data.shift(1))
print(log_return.head())

输出:

               simple_return  log_return
2024-01-01           NaN         NaN
2024-01-02     -7.392857   -7.692308
2024-01-03      1.578947    0.947368
2024-01-04     -0.513514   -0.720720
2024-01-05      1.944444    0.666667

你想想看,当收益率很小时,比如0.1%,简单收益率和对数收益率几乎相等。但当收益率很大时,比如10%,两者就有明显差异了。我个人习惯在回测和风险管理中用对数收益率,因为它更符合正态分布假设,而且计算多期收益时不会出现负价格的问题。

小技巧:如果你需要计算多期累计收益,用对数收益率相加再取指数,比用简单收益率连乘更稳定。比如:cum_return = np.exp(log_return.sum()) - 1

1.4 知识体系总览

下面这张图,是我自己画的本章知识结构。你可以把它当作一个“地图”,随时回来看看。

滞后特征与差分:知识体系 滞后算子 (Lag Operator) • 定义:L*y_t = y_{t-1} • 高阶滞后:L^k*y_t = y_{t-k} • 代码实现:shift() • 应用:自回归特征 • 注意:NaN处理 差分运算 (Differencing) • 一阶差分:Δy_t = y_t - y_{t-1} • 季节性差分:Δ_s y_t = y_t - y_{t-s} • 目的:使序列平稳 • 代码实现:diff() • 注意:避免过度差分 • 检验:ADF检验 收益率计算 (Returns) • 简单收益率:R_t • 对数收益率:r_t • 代码实现:pct_change() • 对数收益率的可加性 • 应用:多期收益计算 • 注意:大收益率时的差异 核心思想:将时间序列的“记忆”和“变化”转化为可建模的特征 滞后特征捕捉历史信息,差分和收益率捕捉动态变化 典型应用场景 • 股票价格预测:滞后价格 + 收益率特征 • 波动率建模:滞后波动率 + 差分 • 宏观经济指标:季节性差分去除周期 • 高频交易:毫秒级滞后特征

1.5 实战中的选择建议

好了,理论讲完了,咱们聊聊实战中怎么选。

场景 推荐操作 原因
价格预测(日频) 对数收益率 + 滞后1-5期 价格非平稳,收益率平稳;短期记忆足够
波动率预测 滞后波动率 + 一阶差分 波动率有聚集效应,差分去除趋势
季节性数据(如天气) 季节性差分 + 滞后1期 去除年周期,保留短期波动
高频数据(毫秒级) 简单收益率 + 大量滞后特征 高频下对数收益率近似简单收益率,滞后阶数需更多

我个人习惯是:先用对数收益率做基础特征,然后根据ACF/PACF图选择滞后阶数。如果序列有明显季节性,再加季节性差分。记住,特征不是越多越好,而是越有效越好。

最后说一句:滞后特征和差分是时序特征工程的“基本功”。别小看它们,很多复杂的模型(比如LSTM、Transformer)本质上也是在学习这些滞后和差分关系。把基础打牢,后面的路才能走稳。


公众号:蓝海数据掘金营,微信deep3321