深度学习时间序列预测全攻略:从基线到LSTM实战
·
深度学习时间序列预测全攻略:从基线到LSTM实战
引言:时间序列预测的挑战与机遇
时间序列数据在我们生活中无处不在:股票价格、天气变化、用电量、网站流量……这些数据都按时间顺序记录,蕴含着丰富的时序规律。
今天,我们将通过一个实际的气温预测案例,带大家深入了解时间序列预测的完整流程,从最简单的基准方法到先进的LSTM模型,一步步揭开时间序列预测的神秘面纱。
数据集介绍:耶拿气象站数据
我们使用的是德国耶拿气象站2009-2016年的数据,包含:
- 时间跨度:2009年1月1日 - 2016年12月31日
- 记录频率:每10分钟记录一次
- 数据维度:14个气象指标(温度、气压、湿度、风速等)
- 数据总量:420,451个时间点
任务目标:基于过去5天的气象数据,预测24小时后的温度
数据探索与可视化
# 查看数据基本信息
print("表头:", header)
print("数据行数:", len(lines))
print("数据形状:", raw_data.shape)
# 绘制温度变化趋势
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(range(len(temperature)), temperature)
plt.title("8年温度变化趋势")
plt.xlabel('时间点')
plt.ylabel('温度(℃)')
plt.subplot(1, 2, 2)
plt.plot(range(1440), temperature[:1440])
plt.title("前10天温度变化")
plt.xlabel('时间点(10分钟间隔)')
plt.ylabel('温度(℃)')
plt.tight_layout()
plt.show()
从图中我们可以清晰看到:
- 年度周期性:温度呈现明显的年度循环
- 日周期性:每天的温度变化也有规律可循
- 数据复杂性:在短期尺度上,温度变化较为复杂
数据预处理关键步骤
1. 数据划分策略
# 按时间顺序划分:训练集(50%) -> 验证集(25%) -> 测试集(25%)
num_train_samples = int(0.5 * len(raw_data))
num_val_samples = int(0.25 * len(raw_data))
num_test_samples = len(raw_data) - num_train_samples - num_val_samples
重要原则:时间序列数据必须按时间顺序划分,不能随机打乱!
2. 数据标准化
# 使用训练集的统计量进行标准化
mean = raw_data[:num_train_samples].mean(axis=0)
raw_data -= mean
std = raw_data[:num_train_samples].std(axis=0)
raw_data /= std
3. 创建时间序列数据集
# 定义关键参数
sampling_rate = 6 # 每小时取一个点(每6个点取1个)
sequence_length = 120 # 5天的数据(120小时)
delay = sampling_rate * (sequence_length + 24 - 1) # 预测24小时后
# 创建数据集
train_dataset = keras.utils.timeseries_dataset_from_array(
raw_data[:-delay],
targets=temperature[delay:],
sampling_rate=sampling_rate,
sequence_length=sequence_length,
shuffle=True,
batch_size=256
)
基线模型:常识的力量
在应用复杂的深度学习模型前,我们先建立一个简单的基准:
def evaluate_naive_method():
"""最简单的预测方法:预测24小时后温度等于现在温度"""
batch_maes = []
for samples, targets in test_dataset:
preds = samples[:, -1, 1] * std[1] + mean[1] # 获取当前温度
mae = np.mean(np.abs(preds - targets))
batch_maes.append(mae)
print(f"基准方法MAE: {np.mean(batch_maes):.2f}℃")
结果:这个简单的基准方法在测试集上达到了 2.62℃ 的平均绝对误差(MAE)。
机器学习模型初探
1. 密集连接网络
def build_dense_model():
"""构建简单的全连接网络"""
inputs = keras.Input(shape=(sequence_length, raw_data.shape[-1]))
x = layers.Flatten()(inputs) # 展平时间维度
x = layers.Dense(16, activation="relu")(x)
outputs = layers.Dense(1)(x) # 回归输出,无激活函数
return keras.Model(inputs, outputs)
表现:验证MAE约2.44℃,与基准方法相当。这说明简单的全连接网络难以捕捉时间序列的时序依赖关系。
2. 一维卷积神经网络
def build_conv1d_model():
"""构建一维卷积网络,适合捕捉局部时序模式"""
inputs = keras.Input(shape=(sequence_length, raw_data.shape[-1]))
x = layers.Conv1D(8, 24, activation="relu")(inputs) # 24小时窗口
x = layers.MaxPooling1D(2)(x)
x = layers.Conv1D(8, 12, activation="relu")(x) # 12小时窗口
x = layers.MaxPooling1D(2)(x)
x = layers.Conv1D(8, 6, activation="relu")(x) # 6小时窗口
x = layers.GlobalAveragePooling1D()(x)
outputs = layers.Dense(1)(x)
return keras.Model(inputs, outputs)
表现:验证MAE约2.9℃,反而不如基准方法。原因在于:
- 天气数据的平移不变性假设不成立
- 池化操作破坏了顺序信息
王者登场:循环神经网络(RNN)
LSTM模型实现
def build_lstm_model():
"""构建LSTM模型,专门处理序列数据"""
inputs = keras.Input(shape=(sequence_length, raw_data.shape[-1]))
x = layers.LSTM(16)(inputs) # LSTM层,16个单元
outputs = layers.Dense(1)(x)
return keras.Model(inputs, outputs)
# 训练配置
model.compile(optimizer="rmsprop", loss="mse", metrics=["mae"])
callbacks = [
keras.callbacks.ModelCheckpoint("jena_lstm.keras", save_best_only=True)
]
表现:验证MAE 2.36℃,测试MAE 2.55℃,首次超越了基准方法!
LSTM为什么有效?
- 记忆能力:LSTM有专门的门控机制,可以记住长期依赖
- 顺序处理:按时间顺序处理数据,保留完整的时序信息
- 状态传递:每个时间步的状态传递到下一步,形成"记忆"
模型对比与深度思考
| 模型类型 | 验证MAE | 测试MAE | 特点 | 适用场景 |
|---|---|---|---|---|
| 基准方法 | 2.44℃ | 2.62℃ | 简单快速 | 快速验证、基线 |
| 密集连接 | ~2.44℃ | 需要测试 | 忽略时序 | 特征间关系简单 |
| 一维卷积 | ~2.9℃ | 需要测试 | 局部特征 | 具有局部模式的序列 |
| LSTM | 2.36℃ | 2.55℃ | 时序依赖 | 复杂时序关系 |
关键洞察
- 基准方法的重要性:在尝试复杂模型前,一定要建立简单基准
- 模型不是越复杂越好:一维卷积在这个任务上表现不佳
- 选择合适的架构:针对序列数据,RNN/LSTM通常是更好的选择
- 数据的本质决定方法:时间序列的核心是时序依赖关系
完整代码实践
import os
import numpy as np
import matplotlib.pyplot as plt
from tensorflow import keras
from tensorflow.keras import layers
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
# 数据加载和预处理(见上文)
# 模型构建和训练(见上文)
# 可视化训练过程
def plot_training_history(history, title):
"""绘制训练和验证的MAE曲线"""
plt.figure(figsize=(8, 5))
loss = history.history["mae"]
val_loss = history.history["val_mae"]
epochs = range(1, len(loss) + 1)
plt.plot(epochs, loss, "bo", label="训练MAE")
plt.plot(epochs, val_loss, "b", label="验证MAE")
plt.title(title)
plt.xlabel("训练轮次")
plt.ylabel("MAE")
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
扩展应用与进阶思考
其他时间序列任务
- 时间序列分类:识别序列模式(如心电图分类)
- 异常检测:发现数据中的异常点
- 事件检测:检测特定事件的发生
进阶技术方向
- 双向LSTM:同时考虑过去和未来信息
- 注意力机制:关注重要的时间点
- Transformer:在长时间序列上表现优异
- 多变量预测:预测多个变量而不仅仅是温度
总结
通过这个完整的温度预测案例,我们学到了:
- 数据预处理是关键,特别是时间序列的划分策略
- 建立基准是评估模型性能的必要步骤
- 模型选择需要基于数据特性:对于时间序列,RNN/LSTM通常更合适
- 实践出真知:只有通过实验才能知道哪种方法最有效
时间序列预测是一个充满挑战但也极具价值的领域。随着深度学习技术的发展,我们有了更多强大的工具来处理复杂的时序数据。希望这篇文章能为你打开时间序列预测的大门!
更多推荐
所有评论(0)