1. 特征工程:从原始数据中挖掘黄金
做时间序列预测就像炒菜,特征工程就是准备食材的过程。我处理过不少用电量预测项目,发现特征质量直接决定模型上限。那个法国用电量数据集有7个原始变量,但真正用起来能玩出几十种花样。
1.1 时序特征构建实战
滞后特征是最基础的招式。比如预测明天用电量,最近7天的数据肯定比一个月前的有用。用pandas生成滞后特征特别简单:
# 生成1-7阶滞后特征 for i in range(1, 8): dataset[f'lag_{i}'] = dataset['Global_active_power'].shift(i)但要注意处理缺失值,我一般用.fillna(method='bfill')向后填充。滑动窗口统计量更厉害,它能捕捉短期波动规律:
# 7天滑动窗口的均值和标准差 dataset['rolling_mean_7'] = dataset['Global_active_power'].rolling(window=7).mean() dataset['rolling_std_7'] = dataset['Global_active_power'].rolling(window=7).std()周期性特征是电力数据的灵魂。法国人工作日和周末用电模式差异很大,我通常会这样处理:
# 提取星期几特征(0-6对应周一到周日) dataset['day_of_week'] = dataset.index.dayofweek # 是否为周末 dataset['is_weekend'] = dataset['day_of_week'].apply(lambda x: 1 if x >=5 else 0)1.2 外部特征融合技巧
温度对用电量影响巨大,特别是空调使用率高的地区。我曾在一个项目中发现,气温每升高1℃,用电量增加5%。处理外部数据要注意三点:
- 时间对齐:确保温度数据的时间戳与用电量数据完全匹配
- 缺失处理:用线性插值补全缺失的温度数据
- 非线性转换:尝试温度平方项捕捉极端天气影响
节假日特征也很关键。法国人圣诞节用电模式很特殊,我通常会手动标注重要节日:
holidays = ['2007-12-25', '2008-12-25',...] dataset['is_holiday'] = dataset.index.isin(pd.to_datetime(holidays)).astype(int)1.3 数据标准化那些坑
电力数据量纲差异大,比如电压单位是伏特,功率是千瓦。我吃过没做标准化的亏,模型完全跑偏。现在固定用这两种方法:
- MinMaxScaler:当数据分布较均匀时
from sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler(feature_range=(0, 1)) scaled_data = scaler.fit_transform(dataset[['Global_active_power', 'Voltage']])- RobustScaler:当存在异常值时
from sklearn.preprocessing import RobustScaler scaler = RobustScaler() scaled_data = scaler.fit_transform(dataset[['Global_reactive_power']])特别注意:要先用训练集fit,再用相同的scaler转换验证集和测试集,否则会数据泄露。
2. 模型选择:没有银弹,只有合适
2.1 SARIMA:传统方法依然能打
SARIMA适合有明显季节性的数据。配置一个基础模型:
from statsmodels.tsa.statespace.sarimax import SARIMAX model = SARIMAX(train_data, order=(1,1,1), # (p,d,q) seasonal_order=(1,1,1,24)) # (P,D,Q,s) results = model.fit() print(results.summary())调参时我常用网格搜索找最优参数组合,但要注意:
- 差分阶数d一般不超过2
- 季节性周期s要根据数据定(电力数据常用24小时/7天)
- 用AIC/BIC指标比较模型,值越小越好
2.2 XGBoost:特征工程的好搭档
XGBoost对特征质量要求高,但效果惊人。这是我的标配参数:
from xgboost import XGBRegressor model = XGBRegressor( n_estimators=200, max_depth=5, learning_rate=0.1, subsample=0.8, colsample_bytree=0.8, early_stopping_rounds=20, random_state=42 ) model.fit(X_train, y_train, eval_set=[(X_val, y_val)], verbose=10)特征重要性分析能帮我们优化特征工程:
import matplotlib.pyplot as plt plt.barh(feature_names, model.feature_importances_)2.3 LSTM/GRU:深度学习的双刃剑
LSTM处理时序数据确实强,但调参难度也大。一个实用的网络结构:
from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense model = Sequential([ LSTM(64, input_shape=(look_back, n_features), return_sequences=True), LSTM(32), Dense(16, activation='relu'), Dense(1) ]) model.compile(loss='mse', optimizer='adam')几个血泪教训:
- 数据量小于1万条时慎用
- Batch_size建议设为24/48等周期值
- 用EarlyStopping防止过拟合
- 输出层不要用激活函数
3. 模型调优:从能用变好用
3.1 交叉验证的特殊姿势
时间序列不能随机打乱,要用TimeSeriesSplit:
from sklearn.model_selection import TimeSeriesSplit tscv = TimeSeriesSplit(n_splits=5) for train_index, test_index in tscv.split(X): X_train, X_test = X[train_index], X[test_index] y_train, y_test = y[train_index], y[test_index]我习惯保留最后20%数据作为独立测试集,用前80%做交叉验证。
3.2 超参数搜索实战
网格搜索太耗时,我改用贝叶斯优化:
from skopt import BayesSearchCV search_space = { 'n_estimators': (100, 500), 'max_depth': (3, 10), 'learning_rate': (0.01, 0.3, 'log-uniform') } opt = BayesSearchCV( XGBRegressor(), search_space, n_iter=20, cv=tscv, scoring='neg_mean_squared_error' ) opt.fit(X_train, y_train)3.3 集成策略提升鲁棒性
单一模型总有局限,我常用三种集成方式:
- 加权平均:给不同模型分配不同权重
- Stacking:用第二层模型整合基模型输出
- 残差学习:用LSTM学习其他模型的预测残差
一个简单的加权平均实现:
final_pred = 0.4*lstm_pred + 0.3*xgb_pred + 0.3*sarima_pred4. 部署落地:模型上线那些坑
4.1 实时预测架构设计
生产环境要考虑延迟和吞吐量。我常用的架构:
[数据流] -> [特征工程微服务] -> [模型预测集群] -> [结果缓存Redis] -> [API网关]4.2 模型监控与迭代
上线才是开始,要监控这些指标:
- 预测偏差(实际值-预测值)
- 特征分布变化(用KL散度检测)
- 预测延迟(P99<100ms)
我设置了一个自动retrain机制:当误差连续3天超过阈值时触发。
4.3 业务指标对齐
技术指标好不等于业务效果好。曾经有个项目MSE降了但调度成本反而上升,后来才发现要优化的是负荷峰谷差。建议:
- 与业务方共同定义损失函数
- 在测试环境跑业务模拟
- 做AB测试验证实际效果
用电量预测看似简单,但想做好需要不断迭代。我现在的项目已经迭代到第7版,每次以为到天花板时,总能发现新的优化空间。最近在试验Transformer模型,效果还有待验证。