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('温度(℃)')
[此处为图片1]
plt.subplot(1, 2, 2)
plt.plot(range(1440), temperature[:1440])
plt.title("前10天温度变化")
plt.xlabel('时间点(10分钟间隔)')
plt.ylabel('温度(℃)')
plt.tight_layout()
plt.show()
通过图像可以观察到以下特征:
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即:
mean = raw_data[:num_train_samples].mean(axis=0) raw_data -= mean std = raw_data[:num_train_samples].std(axis=0) raw_data /= std此操作确保各特征处于相近的数量级,有利于梯度优化过程。
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}℃")
运行结果显示,该方法在测试集上的平均绝对误差(MAE)为 2.62℃。这一结果将成为后续模型改进的参照标准。
def build_dense_model():
"""搭建基础全连接网络结构"""
该模型将展平输入序列并送入若干全连接层,用以捕捉非线性关系。尽管结构简单,但其表现通常优于纯启发式方法,并为后续更高级模型提供对比依据。
[此处为图片2]
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 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℃,与基准方法相当。这表明该模型未能有效捕捉时间序列中的动态依赖关系,因其忽略了输入数据的时间顺序特性。
[此处为图片1]尝试利用卷积层提取局部时序模式:
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℃,结果甚至劣于基准方法。主要原因包括:
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℃,测试集为2.55℃,首次超越基准方法!
[此处为图片3]| 模型类型 | 验证MAE | 测试MAE | 特点 | 适用场景 |
|---|---|---|---|---|
| 基准方法 | 2.44℃ | 2.62℃ | 简单快速 | 快速验证、基线参考 |
| 密集连接 | ~2.44℃ | 需测试 | 忽略时序 | 特征间关系简单 |
| 一维卷积 | ~2.9℃ | 需测试 | 提取局部特征 | 具有局部模式的序列 |
| LSTM | 2.36℃ | 2.55℃ | 建模时序依赖 | 复杂时序关系 |
以下函数用于绘制训练过程中MAE的变化曲线:
def plot_training_history(history, title):
"""绘制训练和验证的MAE曲线"""
plt.figure(figsize=(8, 5))
loss = history.history["mae"]
val_loss = history.history["val_mae"]
该函数将帮助直观评估模型收敛情况及是否存在过拟合现象。
[此处为图片4]时间序列数据在实际中有着广泛的应用,除了预测任务外,还包括以下几类典型问题:
随着模型复杂度的提升,可以引入更先进的结构来增强对时序特征的捕捉能力:
本案例以温度预测为主线,系统展示了时间序列建模的关键环节。我们从中可以提炼出以下几个核心经验:
时间序列预测虽具挑战性,但在工业、金融、医疗等领域具有极高的应用价值。随着深度学习的发展,我们拥有了更多强有力的工具来应对复杂的时序建模任务。希望本文能为你开启通往这一领域的大门。
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()
[此处为图片1]
扫码加好友,拉您进群



收藏
