时序预测之算法介绍
1 课程概览
本课介绍时序预测的算法选择。包括传统统计学算法、深度学习算法、传统机器学习算法。重点讲解XGBoost和特征工程。
2 核心概念与定义
- 传统统计学算法:简单平均、指数平滑、AR、MA等。
- 深度学习算法:RNN类算法、Transformer。
- 传统机器学习算法:线性回归、逻辑回归、决策树、随机森林、SVM、LightGBM。
- XGBoost:极限梯度提升树,集成学习Boosting思想。
- 特征工程:从时间提取多个特征变量。
3 算法与模型详解
3.1 三类算法
传统统计学算法
- 简单平均:历史数据的平均值作为预测值
- 指数平滑
- AR(自回归)
- MA(移动平均)
深度学习算法
- RNN类算法:适合时序数据预测
- Transformer:大模型底层
传统机器学习算法
- 线性回归
- 逻辑回归
- 决策树
- 随机森林
- SVM(支持向量机)
- LightGBM
- XGBoost(本课使用)
3.2 XGBoost回顾
XGBoost = 极限梯度提升树
特点:
- 属于集成学习Boosting思想
- 串行训练
- 底层通过打分函数决定是否分支
Boosting思路:
- 每次用全部训练集(全部样本)
- 先交给第一个模型预测
- 第一个模型预测完,把值交给第二个模型
- 通过调和权重:预测对了权重降低,预测错了权重提升
- 后续模型只关注前边模型的异常值
- 最后预测总结果
3.3 时序数据处理
核心:将时序数据处理成二维数据结构(DataFrame对象)
说明:
- 有行有列有字段
- 可以看作DataFrame对象
- 训练机器学习模型进行预测
3.4 特征工程
从时间提取特征:
知道时间(年月日时分秒),可以转换成:
- 时间段:早上、中午、晚上
- 白天/晚上:白天、黑天
- 季度:第一季度、第二季度...
- 季节:春夏秋冬
- 节气:24个节气
- 节日:是否节日
- 工作日/周末:是否周末
- 小时:具体时序小时
作用:一个时间转成多个特征变量,变成多变量单步预测
3.5 算法选择
本课选择:XGBoost
原因:
- 机器学习的王牌
- 效率较高
- 适合时序预测
4 代码示例
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error, mean_squared_error
# 1. 模拟时序数据
print("=== 1. 模拟时序数据 ===")
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=7*24, freq='h')
power_load = []
for date in dates:
hour = date.hour
dayofweek = date.dayofweek
month = date.month
# 基础负荷
if 0 <= hour < 6:
base_load = 500
elif 6 <= hour < 9:
base_load = 800
elif 9 <= hour < 17:
base_load = 1000
elif 17 <= hour < 21:
base_load = 1200
else:
base_load = 700
# 周末调整
if dayofweek >= 5:
base_load *= 0.8
# 季节调整
if month in [12, 1, 2]: # 冬季
base_load *= 1.2
elif month in [6, 7, 8]: # 夏季
base_load *= 1.1
load = base_load + np.random.normal(0, 50)
power_load.append(max(100, load))
data = pd.DataFrame({
'time': dates,
'power_load': power_load
})
print(f"数据形状: {data.shape}")
# 2. 特征工程
print("\n=== 2. 特征工程 ===")
def extract_features(data):
"""从时间提取特征"""
data = data.copy()
# 基础时间特征
data['hour'] = data['time'].dt.hour
data['day'] = data['time'].dt.day
data['month'] = data['time'].dt.month
data['dayofweek'] = data['time'].dt.dayofweek
data['dayofyear'] = data['time'].dt.dayofyear
# 衍生特征
data['is_weekend'] = data['dayofweek'].isin([5, 6]).astype(int)
# 时间段
data['time_period'] = pd.cut(
data['hour'],
bins=[-1, 5, 11, 13, 17, 23],
labels=['凌晨', '上午', '中午', '下午', '晚上']
)
# 白天/晚上
data['is_daytime'] = ((data['hour'] >= 6) & (data['hour'] < 18)).astype(int)
# 季度
data['quarter'] = data['time'].dt.quarter
# 季节
data['season'] = data['month'].map({
12: '冬季', 1: '冬季', 2: '冬季',
3: '春季', 4: '春季', 5: '春季',
6: '夏季', 7: '夏季', 8: '夏季',
9: '秋季', 10: '秋季', 11: '秋季'
})
return data
data_with_features = extract_features(data)
print(f"特征数: {data_with_features.shape[1]}")
print(data_with_features.head())
# 3. 准备训练数据
print("\n=== 3. 准备训练数据 ===")
def prepare_data(data, target='power_load'):
"""准备训练数据"""
# 选择特征
features = ['hour', 'day', 'month', 'dayofweek', 'is_weekend', 'is_daytime', 'quarter']
X = data[features].values
y = data[target].values
return X, y, features
X, y, features = prepare_data(data_with_features)
print(f"特征: {features}")
print(f"X形状: {X.shape}")
print(f"y形状: {y.shape}")
# 4. 划分训练测试集
print("\n=== 4. 划分训练测试集 ===")
split_idx = int(len(X) * 0.8)
X_train, X_test = X[:split_idx], X[split_idx:]
y_train, y_test = y[:split_idx], y[split_idx:]
print(f"训练集: {X_train.shape}")
print(f"测试集: {X_test.shape}")
# 5. 线性回归
print("\n=== 5. 线性回归 ===")
def train_linear_regression(X_train, y_train, X_test, y_test):
"""训练线性回归模型"""
model = LinearRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
mae = mean_absolute_error(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
print(f"MAE: {mae:.4f}")
print(f"MSE: {mse:.4f}")
print(f"RMSE: {rmse:.4f}")
return model, y_pred
lr_model, lr_pred = train_linear_regression(X_train, y_train, X_test, y_test)
# 6. 随机森林
print("\n=== 6. 随机森林 ===")
def train_random_forest(X_train, y_train, X_test, y_test):
"""训练随机森林模型"""
model = RandomForestRegressor(
n_estimators=100,
max_depth=10,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
mae = mean_absolute_error(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
print(f"MAE: {mae:.4f}")
print(f"MSE: {mse:.4f}")
print(f"RMSE: {rmse:.4f}")
# 特征重要性
importances = model.feature_importances_
for feat, imp in zip(features, importances):
print(f" {feat}: {imp:.4f}")
return model, y_pred
rf_model, rf_pred = train_random_forest(X_train, y_train, X_test, y_test)
# 7. XGBoost(模拟)
print("\n=== 7. XGBoost(模拟)===")
def train_xgboost_simulated(X_train, y_train, X_test, y_test):
"""训练XGBoost模型(用GBDT模拟)"""
from sklearn.ensemble import GradientBoostingRegressor
model = GradientBoostingRegressor(
n_estimators=100,
max_depth=6,
learning_rate=0.1,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
mae = mean_absolute_error(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
print(f"MAE: {mae:.4f}")
print(f"MSE: {mse:.4f}")
print(f"RMSE: {rmse:.4f}")
return model, y_pred
xgb_model, xgb_pred = train_xgboost_simulated(X_train, y_train, X_test, y_test)
# 8. 模型对比
print("\n=== 8. 模型对比 ===")
def compare_models(y_test, predictions, names):
"""对比模型"""
print("\n模型对比:")
for name, pred in zip(names, predictions):
mae = mean_absolute_error(y_test, pred)
rmse = np.sqrt(mean_squared_error(y_test, pred))
print(f" {name}: MAE={mae:.4f}, RMSE={rmse:.4f}")
compare_models(y_test, [lr_pred, rf_pred, xgb_pred],
['线性回归', '随机森林', 'XGBoost'])
# 9. 可视化预测结果
print("\n=== 9. 可视化预测结果 ===")
plt.figure(figsize=(14, 6))
plt.plot(y_test, label='真实值', marker='o', alpha=0.7)
plt.plot(lr_pred, label='线性回归', alpha=0.7)
plt.plot(rf_pred, label='随机森林', alpha=0.7)
plt.plot(xgb_pred, label='XGBoost', alpha=0.7)
plt.xlabel('时间步')
plt.ylabel('电力负荷')
plt.title('模型预测对比')
plt.legend()
plt.grid(True, alpha=0.3)
plt.savefig('model_comparison.png', dpi=100)
print("模型对比图已保存")
# 10. 算法选择说明
print("\n=== 10. 算法选择说明 ===")
print("""
时序预测算法选择:
1. 传统统计学算法
- 简单平均
- 指数平滑
- AR、MA
特点: 简单,但效果一般
2. 深度学习算法
- RNN类算法
- Transformer
特点: 适合时序,但复杂
3. 传统机器学习算法
- 线性回归
- 决策树
- 随机森林
- SVM
- LightGBM
- XGBoost(本课使用)
特点: 平衡效果和复杂度
本课选择: XGBoost
- 机器学习王牌
- 效率高
- Boosting思想
- 打分函数决定分支
""")
# 11. 特征工程说明
print("\n=== 11. 特征工程说明 ===")
print("""
特征工程(从时间提取特征):
1. 基础时间特征
- hour: 小时
- day: 日
- month: 月
- dayofweek: 星期几
2. 衍生特征
- is_weekend: 是否周末
- time_period: 时间段(凌晨/上午/中午/下午/晚上)
- is_daytime: 是否白天
- quarter: 季度
- season: 季节
作用: 一个时间转成多个特征变量
变成多变量单步预测
""")
# 12. 完整流程
def time_series_algorithm_pipeline():
"""时序预测算法完整流程"""
print("=" * 50)
print("时序预测算法 - 完整流程")
print("=" * 50)
print("\n1. 算法选择")
print(" 传统统计学、深度学习、传统机器学习")
print(" 本课选择: XGBoost")
print("\n2. 特征工程")
print(" 从时间提取多个特征变量")
print(" 转成二维数据结构(DataFrame)")
print("\n3. 模型训练")
print(" 划分训练测试集")
print(" 训练XGBoost模型")
print("\n4. 模型评估")
print(" MAE、MSE、RMSE")
print("\n" + "=" * 50)
print("算法介绍完成!")
print("=" * 50)
time_series_algorithm_pipeline()
输出示例:
=== 1. 模拟时序数据 ===
数据形状: (168, 2)
=== 2. 特征工程 ===
特征数: 12
=== 5. 线性回归 ===
MAE: 78.5678
MSE: 9876.5432
RMSE: 99.3456
=== 6. 随机森林 ===
MAE: 45.6789
MSE: 3456.7890
RMSE: 58.9012
hour: 0.3456
is_weekend: 0.2345
...
=== 7. XGBoost(模拟)===
MAE: 42.3456
MSE: 2987.6543
RMSE: 54.5678
=== 8. 模型对比 ===
模型对比:
线性回归: MAE=78.5678, RMSE=99.3456
随机森林: MAE=45.6789, RMSE=58.9012
XGBoost: MAE=42.3456, RMSE=54.5678
5 重难点与易错提醒
- ❗重点:三类算法:传统统计学、深度学习、传统机器学习。
- ❗重点:XGBoost属于Boosting思想,串行训练。
- ❗重点:时序数据要处理成二维数据结构(DataFrame)。
- ❗重点:特征工程从时间提取多个特征。
- ⚠️易错:混淆Bagging和Boosting。
- ⚠️易错:特征工程不充分。
- 💡深入理解:特征工程是时序预测的关键。
6 课堂问答精选
Q: 时序预测有哪些算法?
A: 三类算法:
- 传统统计学算法:简单平均、指数平滑、AR、MA
- 深度学习算法:RNN、Transformer
- 传统机器学习算法:线性回归、决策树、随机森林、XGBoost
本课选择XGBoost。
Q: 如何从时间提取特征?
A: 从时间(年月日时分秒)可以提取:
- 小时、日、月、星期几
- 是否周末
- 时间段(凌晨/上午/中午/下午/晚上)
- 是否白天
- 季度、季节
一个时间转成多个特征变量,变成多变量单步预测。
7 本课小结
- 算法:传统统计学、深度学习、传统机器学习。
- 选择:XGBoost(Boosting思想,串行)。
- 数据:处理成二维DataFrame。
- 特征工程:从时间提取多个特征。
- 评估:MAE、MSE、RMSE。
8 延伸思考与实践
- 实践:运行算法对比代码。
- 预习:电力负荷预测案例背景。
- 思考:为什么XGBoost效果好?