时间序列特征构建:滞后、窗口与频域指标
时间序列特征构建:从滞后、窗口到频域
时间序列建模的核心在于将原始序列转化为可供机器学习算法理解的特征矩阵。手工特征工程能够注入领域知识,而滞后、窗口和频域指标是最经典的三大构建模块。本教程面向初学者,以直观解释配合可运行代码,带你逐步掌握这些技术。
滞后特征:捕捉自相关结构
滞后特征是将当前时刻的值与过去某时刻的值对齐,使模型能看到历史信号。对于具有周期性和记忆效应的序列,滞后是首先要尝试的特征。
单变量滞后
假设我们有序列 y_t,滞后k的特征就是 y_{t-k}。在Python中,pandas的shift()可以方便生成滞后列。
import pandas as pd
import numpy as np
# 示例序列
df = pd.DataFrame({'y': [10, 20, 30, 40, 50, 60]})
df['lag_1'] = df['y'].shift(1)
df['lag_2'] = df['y'].shift(2)
print(df)
滞后列开头的缺失值需要处理,常用方法有丢弃或填充。选择滞后阶数可依据偏自相关函数(PACF)或领域经验。
多步预测的滞后
若预测目标是未来h步,特征中可包含滞后h+1, h+2等,避免使用未来信息。例如预测t+3时刻,特征集不能包含t+3的任何信息,滞后阶数至少从3开始。
季节滞后
对于有固定周期的数据(如小时级数据的日周期24,月数据的年周期12),构建季节滞后至关重要。季节滞后直接捕捉周期重复模式。
# 假设日频数据,周周期7
df['lag_7'] = df['y'].shift(7)
滞后特征能保留序列的时序依赖,但也增加了维度,存在多重共线性风险,通常需配合正则化或特征选择。
窗口特征:汇总局部统计量
窗口特征通过在一个滑动窗口内计算统计量,将原始序列压缩为反映局部水平、波动和形态的指标。窗口可以是固定长度(滚动)或随时间累积扩张(扩展)。
滚动窗口统计
最常见的窗口特征包括移动平均、移动标准差、移动最大值/最小值等。它们能平滑噪声并刻画趋势强度。
# 窗口大小为3的滚动统计量
df['roll_mean_3'] = df['y'].rolling(window=3).mean()
df['roll_std_3'] = df['y'].rolling(window=3).std()
df['roll_min_3'] = df['y'].rolling(window=3).min()
df['roll_max_3'] = df['y'].rolling(window=3).max()
窗口大小决定了统计量的平滑程度——窗口越大,滞后越多,但延迟也越明显。需根据序列频率和任务平衡。
扩展窗口统计
扩展窗口从序列起点一直累加到当前时刻,适合表示历史累积水平,如至今总均值、至今最大值等。
df['expand_mean'] = df['y'].expanding().mean()
df['expand_max'] = df['y'].expanding().max()
高级窗口特征
除基础统计量外,还可以构建:
- 移动分位数:如滚动窗口的5%、95%分位,用于表示区间。
- 窗口内差分/变化率:
y_t - y_{t-window},直接表示窗口变化。 - 窗口自相关:在窗口内计算滞后1的自相关系数,衡量局部记忆强度。
- 窗口斜率:对窗口内序列拟合线性回归,取斜率作为趋势强度特征。
滚动特征通常会产生多重共线性和冗余,建议组合不同窗口大小(短、中、长),并辅以领域知识筛选。
频域特征:从周期角度分解序列
时域特征有时难以捕捉精确的周期成分,频域分析通过傅里叶变换将序列分解为不同频率的正弦波,提供“频谱特征”。这些特征对周期性规律、异常节奏特别有效。
傅里叶变换与频谱
离散傅里叶变换(DFT)输出复数,包含幅度和相位。幅度谱表示各频率成分的强度,相位谱表示起始偏移。通常仅使用幅度信息作为特征。
from scipy.fft import fft, fftfreq
n = len(df)
y_fft = fft(df['y'].values)
amplitude = np.abs(y_fft) # 幅度谱
freqs = fftfreq(n, d=1) # 频率(假设采样间隔=1)
# 仅保留正频率部分
pos_mask = freqs > 0
freqs_pos = freqs[pos_mask]
amp_pos = amplitude[pos_mask]
常用频域特征
我们并不直接把整个频谱作为特征(维度过高),而是汇总成若干指标:
- 主频率:幅度最大的频率,反映最强周期成分。
- 主幅度:主频率对应的幅度值。
- 谱质心:幅度的加权平均频率,表示“能量中心”所在。
- 谱带宽:频率分布的二阶中心矩,反映周期性的集中程度。
- 谱熵:基于幅度归一化后计算的信息熵,熵越高频谱越平坦(混乱),越低则周期性越强。
- 频段能量比:将频率分成低频、中频、高频段,计算各段能量占比。例如低频能量比高说明趋势或长周期主导。
# 计算谱质心和谱熵示例
def spectral_centroid(freqs, amp):
return np.sum(freqs * amp) / np.sum(amp)
def spectral_entropy(amp):
prob = amp / np.sum(amp)
prob = prob[prob > 0] # 避免log(0)
return -np.sum(prob * np.log(prob))
频域特征的应用时机
频域特征特别适合:
- 存在强周期性且周期未知时,主频率可自动发现周期。
- 需要区分类别:平稳周期序列与噪声序列的谱熵差异很大。
- 作为全局特征,补充窗口统计量的局部视角。
注意:傅里叶变换假设信号是平稳的,对于非平稳序列,可先在差分或去趋势后计算频谱,或采用小波变换等时频分析工具。
特征组合实践建议
- 基础滞后:依据ACF/PACF选取重要滞后阶,优先考虑周期滞后。
- 多尺度窗口:使用短窗口(捕捉瞬时变化)、中窗口(捕捉近期行为)、长窗口(捕捉长期水平)构建滚动均值和标准差。
- 频域摘要:对整个历史或滑动窗口计算频域特征,作为补充的全局或局部周期性指标。
- 差分与变换:除原始序列外,对其一阶差分、对数变换、季节性差分等也构建同样特征,增加稳定性。
- 避免泄漏:所有特征构建必须在时间点t之前进行,杜绝使用未来信息。滚动窗口中使用
closed='left'或shift对齐。
掌握滞后、窗口和频域这三个维度,你就拥有了时间序列特征工程最核心的武器库。在此基础上可延伸出时序卷积特征、熵特征、基于模型的隐含状态特征等,但万变不离其宗。现在你可以使用提供的代码片段在真实数据上实验,感受不同特征对预测性能的提升。