时间序列预测中的特征工程与机器学习应用
1. 时间序列预测中的特征工程挑战
在时间序列预测任务中,原始数据通常只包含按时间顺序排列的观测值序列。这种单变量时间序列无法直接用于监督学习算法,因为机器学习模型需要明确的输入特征和输出目标。这就是特征工程的核心挑战所在——我们需要从原始时间序列中构造出有预测价值的特征。
传统时间序列分析工具(如自相关图)可以帮助评估滞后变量的相关性,但对于其他类型的特征(如时间戳衍生的年月日特征、移动统计量等)选择帮助有限。当面对以下情况时,这个问题尤为突出:
- 季节性模式复杂的数据集
- 存在多个潜在预测因子的场景
- 需要组合不同类型特征的情况
2. 数据集准备与平稳化处理
2.1 汽车销售数据集概览
我们使用1960-1968年加拿大魁北克地区的月度汽车销售数据集。这个经典数据集包含108个观测值,具有明显的季节性和增长趋势。
# 加载并可视化数据集 from pandas import read_csv from matplotlib import pyplot series = read_csv('car-sales.csv', header=0, index_col=0) print(series.head(5)) series.plot() pyplot.show()2.2 数据平稳化处理
原始数据中的趋势和季节性成分会掩盖其他预测信号。我们通过季节性差分(周期为12个月)来获得平稳时间序列:
# 季节性差分处理 differenced = series.diff(12) differenced = differenced[12:] # 丢弃前12个NaN值 differenced.to_csv('seasonally_adjusted.csv', index=False) differenced.plot() pyplot.show()关键提示:差分阶数的选择应基于数据特性。对于同时存在趋势和季节性的数据,通常需要先做一阶普通差分再做季节性差分。
3. 传统特征选择方法:自相关分析
3.1 自相关图解读
自相关函数(ACF)图显示各滞后项与当前值的相关性:
from statsmodels.graphics.tsaplots import plot_acf series = read_csv('seasonally_adjusted.csv', header=0) plot_acf(series) pyplot.show()ACF图中:
- x轴表示滞后阶数
- y轴表示相关系数(-1到1)
- 蓝色区域外的点表示统计显著性
本例中,滞后1、2、12和17个月显示出显著相关性,这为特征选择提供了基线参考。
3.2 转换为监督学习格式
将单变量时间序列转化为监督学习问题:
from pandas import DataFrame # 创建12个月的滞后特征 dataframe = DataFrame() for i in range(12,0,-1): dataframe[f't-{i}'] = series.shift(i).values[:,0] dataframe['t'] = series.values[:,0] # 移除包含NaN的前12行 dataframe = dataframe[13:] dataframe.to_csv('lags_12months_features.csv', index=False)4. 基于机器学习的特征重要性评估
4.1 随机森林特征重要性
随机森林可以计算各特征的相对重要性分数:
from sklearn.ensemble import RandomForestRegressor # 加载特征数据 dataframe = read_csv('lags_12months_features.csv', header=0) X, y = dataframe.iloc[:,:-1], dataframe.iloc[:,-1] # 训练模型并获取重要性 model = RandomForestRegressor(n_estimators=500, random_state=1) model.fit(X, y) # 可视化重要性 features = dataframe.columns[:-1] pyplot.bar(range(len(features)), model.feature_importances_) pyplot.xticks(range(len(features)), features, rotation=90) pyplot.show()结果显示t-12、t-2和t-4滞后项最为重要,这与ACF分析结果部分一致但也有差异,说明两种方法可以互补。
4.2 不同模型的重要性比较
实践中建议尝试多种模型:
- 梯度提升树(GBRT)
- 极端随机树(ExtraTrees)
- 正则化线性模型
不同模型可能会突出不同特征的重要性,这能提供更全面的特征评估。
5. 递归特征消除(RFE)实战
5.1 RFE基础实现
RFE通过递归剔除不重要特征来选择最优特征子集:
from sklearn.feature_selection import RFE # 初始化RFE rfe = RFE(RandomForestRegressor(n_estimators=500, random_state=1), n_features_to_select=4) fit = rfe.fit(X, y) # 输出选择结果 print("Selected Features:") for i, col in enumerate(X.columns): if fit.support_[i]: print(col) # 可视化特征排名 pyplot.bar(range(len(fit.ranking_)), fit.ranking_) pyplot.xticks(range(len(X.columns)), X.columns, rotation=90) pyplot.show()5.2 RFE参数调优
关键参数需要考虑:
n_features_to_select:目标特征数step:每次迭代剔除的特征数- 基评估器选择:不同模型会产生不同结果
建议使用交叉验证评估不同参数组合的效果。
6. 高级特征工程技术
6.1 时间戳特征扩展
除滞后项外,还可从时间戳提取有用特征:
# 提取时间特征 dataframe['month'] = dataframe.index.month dataframe['quarter'] = dataframe.index.quarter dataframe['year'] = dataframe.index.year6.2 移动统计特征
计算滚动统计量作为新特征:
# 添加移动平均和标准差 dataframe['rolling_mean_3'] = dataframe['t'].rolling(3).mean() dataframe['rolling_std_3'] = dataframe['t'].rolling(3).std()6.3 特征组合与交互
创建特征间的交互项有时能提升模型性能:
# 创建交互特征 dataframe['t-1_t-12'] = dataframe['t-1'] * dataframe['t-12'] dataframe['t-1_div_t-12'] = dataframe['t-1'] / dataframe['t-12']7. 实战建议与常见问题
7.1 特征选择流程建议
- 从简单方法开始(如ACF分析)
- 使用多种特征重要性评估方法
- 尝试不同的特征子集大小
- 通过交叉验证评估选择效果
- 最终模型使用最优特征组合
7.2 常见问题解决方案
问题1:特征重要性结果不稳定
- 增加树模型的estimators数量
- 使用不同的随机种子多次运行取平均
- 尝试更稳定的特征选择方法
问题2:选择的特征过多
- 提高RFE中的选择阈值
- 使用正则化方法筛选
- 考虑特征间的相关性
问题3:新特征没有提升效果
- 检查特征与目标的实际相关性
- 确保没有数据泄露
- 尝试不同的特征组合方式
7.3 性能优化技巧
- 对于大数据集,使用
SelectFromModel替代RFE - 并行化特征选择过程
- 对类别特征进行适当编码
- 定期重新评估特征重要性,特别是数据分布变化时
8. 完整项目示例
以下是一个整合了上述技术的完整示例:
from pandas import read_csv, DataFrame from sklearn.ensemble import RandomForestRegressor from sklearn.feature_selection import RFE from matplotlib import pyplot # 1. 数据加载与预处理 series = read_csv('car-sales.csv', header=0, index_col=0, parse_dates=True) differenced = series.diff(12).dropna() # 2. 特征工程 def create_features(df, lags=12): # 滞后特征 for i in range(1, lags+1): df[f't-{i}'] = df['Sales'].shift(i) # 时间特征 df['month'] = df.index.month df['quarter'] = df.index.quarter # 移动统计量 df['rolling_mean_3'] = df['Sales'].rolling(3).mean() df['rolling_std_3'] = df['Sales'].rolling(3).std() return df.dropna() features_df = create_features(DataFrame(differenced, columns=['Sales'])) # 3. 特征选择 X, y = features_df.drop('Sales', axis=1), features_df['Sales'] # 方法1:特征重要性 model = RandomForestRegressor(n_estimators=500, random_state=1) model.fit(X, y) importance = model.feature_importances_ # 方法2:RFE rfe = RFE(RandomForestRegressor(n_estimators=500, random_state=1), n_features_to_select=5) rfe.fit(X, y) # 4. 结果可视化 fig, (ax1, ax2) = pyplot.subplots(2, 1, figsize=(10, 8)) ax1.bar(X.columns, importance) ax1.set_title('Feature Importance') ax2.bar(X.columns, rfe.ranking_) ax2.set_title('RFE Ranking') pyplot.tight_layout() pyplot.show()这个完整流程展示了从原始数据到特征选择的端到端处理,可以作为实际项目的模板。
