资讯详情

资讯详情

基于RNN、LSTM与GRU的气象数据预测实战:Python代码解析与避坑指南

简介这份资源围绕循环神经网络RNN、LSTM、GRU在气象数据预测中的应用展开面向本科、硕士阶段从事神经网络预测方向学习与教研的读者也适合希望用Python动手实践时序建模的开发者。压缩包共13个文件约758KB包含5个Python脚本、5张结果图、1份CSV气象数据、1份说明文档和1个模型权重文件脚本覆盖数据处理、模型配置、训练与测试等环节图片则记录了不同学习率与迭代次数下的预测效果对比。资源已积累501人学习说明其在时序预测入门与实验复现方面具有一定参考价值。读者可借助完整代码与数据理解LSTM等结构如何对气象序列建模并通过多组超参数结果图观察训练过程与预测精度的变化为课程设计、论文实验或算法对比提供可运行的实践素材。1. 从一份气象预测代码包说起RNN、LSTM、GRU 到底怎么选去年帮一个做农业气象服务的团队看代码他们用 LSTM 预测未来 24 小时气温结果训练 loss 降到 0.01上线后 MAE 却飙到 4.2℃。翻完代码发现他们把tq.csv里的时间列当成了普通特征喂进去模型学到的是第几行而不是几点钟。这个坑在气象时序预测里极其常见也是我拿到这份基于循环神经网络(RNN, LSTM或GRU)实现气象数据预测附python代码.zip时最先检查的地方。这份资源的核心价值在于它把 RNN、LSTM、GRU 三种循环网络结构放在同一套气象数据管道里做对比实验附带了LSTM.py、data.py、config.py、running.py、test.py五个可执行脚本以及lstm_model.pt权重文件和六张不同超参组合下的训练结果图Res1_M1_lr0.001_eps10.png到Res5_M2_lr0.005_rps6.png。数据文件tq.csv是典型的气象时序表weather_prediction目录下应该还有配套的预处理产物。适合谁如果你正在做气温、湿度、风速这类单变量或多变量时序预测的课程设计、论文实验或者想快速跑通一个 LSTM 基线模型这份代码能省掉你搭数据管道和调参框架的时间。但如果你指望直接拿它上生产环境得先看完后面的避坑章节。2. 拆开代码包数据管道与模型定义的关键实现2.1 气象数据怎么喂进 LSTMdata.py的滑动窗口逻辑气象时序预测的本质是把连续观测值切成输入窗口 → 预测目标的监督学习样本。data.py里通常做三件事读tq.csv、归一化、构造滑动窗口。我按常见实现还原一下核心逻辑你对照包里的代码看是否一致import pandas as pd import numpy as np from sklearn.preprocessing import MinMaxScaler def load_weather_data(csv_path, seq_len24, pred_len1): df pd.read_csv(csv_path) # 假设 tq.csv 包含 time, temp, humidity, pressure 等列 # 关键时间列必须解析成 datetime 并设为索引不能当数值特征 df[time] pd.to_datetime(df[time]) df df.sort_values(time).set_index(time) features df[[temp, humidity, pressure]].values scaler MinMaxScaler(feature_range(0, 1)) scaled scaler.fit_transform(features) X, y [], [] for i in range(len(scaled) - seq_len - pred_len 1): X.append(scaled[i:iseq_len]) y.append(scaled[iseq_len:iseq_lenpred_len, 0]) # 只预测 temp return np.array(X), np.array(y), scaler这段代码有三个参数决定模型上限seq_len24表示用过去 24 个时间步预测下一步对应逐小时数据就是用过去一天预测下一小时pred_len1是单步预测改成 6 就是预测未来 6 小时feature_range(0,1)是 MinMax 归一化气象数据里温度和湿度的量纲差异大不归一化会导致梯度爆炸。注意y只取了第 0 列temp如果你要同时预测多个变量得把pred_len那行改成取所有列。config.py里一般集中管理这些超参常见字段包括SEQ_LEN、PRED_LEN、BATCH_SIZE、EPOCHS、LR、HIDDEN_SIZE、NUM_LAYERS、MODEL_TYPE。从结果图命名Res1_M1_lr0.001_eps10.png能反推出实验矩阵M1/M2 可能代表两种模型结构比如 LSTM vs GRUlr 是学习率eps 是 epoch 数rps 可能是 random seed 或 steps per epoch。这种命名习惯在科研实验里很实用一眼能看出超参组合。2.2 LSTM 模型定义LSTM.py里的层数与隐藏维度LSTM.py是模型主体。PyTorch 实现 LSTM 预测网络的标准写法如下import torch import torch.nn as nn class WeatherLSTM(nn.Module): def __init__(self, input_size3, hidden_size64, num_layers2, output_size1): super(WeatherLSTM, self).__init__() self.hidden_size hidden_size self.num_layers num_layers self.lstm nn.LSTM( input_sizeinput_size, hidden_sizehidden_size, num_layersnum_layers, batch_firstTrue, dropout0.2 if num_layers 1 else 0 ) self.fc nn.Linear(hidden_size, output_size) def forward(self, x): # x shape: (batch, seq_len, input_size) h0 torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device) c0 torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device) out, _ self.lstm(x, (h0, c0)) # 取最后一个时间步的输出做预测 out self.fc(out[:, -1, :]) return outinput_size3对应 temp、humidity、pressure 三个特征hidden_size64是 LSTM 单元内部状态维度太小欠拟合太大过拟合且训练慢气象数据一般 32~128 够用num_layers2是堆叠两层 LSTM第二层能学到更高阶的时序模式但超过 3 层在中小规模气象数据上收益递减dropout0.2只在多层时生效防止过拟合。batch_firstTrue让输入维度是(batch, seq_len, features)这是 PyTorch 里最容易搞混的地方——默认是(seq_len, batch, features)不设这个参数会导致训练时维度对不上。如果你想换成 GRU只需把nn.LSTM替换成nn.GRU同时去掉c0的初始化因为 GRU 只有隐藏状态没有细胞状态。RNN 则更简单nn.RNN只有h0。三种结构的参数量对比RNN 最少GRU 约为 LSTM 的 3/4LSTM 最多。在气象数据这种中等长度序列上LSTM 和 GRU 表现通常接近GRU 训练稍快。2.3 训练与验证running.py和test.py的分工running.py负责训练循环test.py负责加载lstm_model.pt做推理。训练部分的核心是损失函数和优化器选择import torch.optim as optim criterion nn.MSELoss() # 回归任务用 MSE optimizer optim.Adam(model.parameters(), lr0.001) for epoch in range(EPOCHS): model.train() for batch_x, batch_y in train_loader: optimizer.zero_grad() pred model(batch_x) loss criterion(pred, batch_y) loss.backward() # 梯度裁剪防止 LSTM 梯度爆炸 torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm1.0) optimizer.step()MSELoss是回归标准选择如果你更关注相对误差可以换L1Loss或SmoothL1Loss。Adam配合lr0.001是安全起点从结果图看作者试过lr0.05Res2_M1_lr0.05_eps20.png这个学习率对 LSTM 偏大loss 曲线大概率震荡。clip_grad_norm_是 LSTM 训练的后悔药——气象序列长、梯度容易爆炸不加这行 loss 可能突然变 NaN。test.py里要注意的是推理时必须用训练时保存的scaler做反归一化否则输出的预测值永远在 0~1 之间。常见做法是在data.py里把 scaler 存成 pickletest.py加载后调scaler.inverse_transform。另外model.eval()和torch.no_grad()必须加上否则 dropout 和 batch norm 会干扰推理结果。3. 跑通实验从环境配置到结果复现的完整步骤3.1 环境依赖与 Python 版本选择这份代码包基于 PyTorchPython 版本建议 3.8 或 3.9热词里python 3.8出现频率高不是没道理很多深度学习库对 3.10 支持还不稳定。核心依赖pip install torch1.13.1 numpy pandas scikit-learn matplotlib如果你用 GPU 训练去 PyTorch 官网按 CUDA 版本选对应安装命令。CPU 也能跑这份气象数据规模不大tq.csv通常几千到几万行CPU 训练几分钟到十几分钟能出结果。matplotlib用于复现那六张结果图scikit-learn提供MinMaxScaler。常见翻车点pip install torch默认装 CPU 版如果你有 GPU 但没指定版本训练速度差 10 倍以上。另外 Windows 下num_workers设大于 0 可能报错设成 0 最稳。3.2 数据准备tq.csv的格式要求与检查清单tq.csv是这份代码的数据入口。跑之前先确认几件事检查项要求不满足的后果时间列可解析为 datetime格式统一排序错乱滑动窗口切出错误样本缺失值无 NaN 或已插值填充归一化报错或模型输出 NaN采样间隔等间隔逐小时/逐日LSTM 学不到真实周期模式列名与data.py中features列表一致KeyError 或静默取错列数据量至少seq_len * 10行训练集太小验证 loss 不收敛我一般会先跑一段检查脚本df pd.read_csv(tq.csv) print(df.shape) print(df.isnull().sum()) print(df[time].diff().value_counts().head()) # 看采样间隔是否一致如果diff()出现多种间隔说明数据有断档需要重采样或插值。气象数据常见断档是设备离线几小时直接df.interpolate()线性插值最省事但会引入虚假平滑论文里要说明。3.3 训练参数怎么调从结果图反推超参影响包里六张结果图对应不同超参组合我按命名规律还原一下实验设计Res1_M1_lr0.001_eps10.pngLSTM学习率 0.001训练 10 轮。这是基线loss 下降平稳但可能未完全收敛。Res2_M1_lr0.05_eps20.png学习率跳到 0.0520 轮。预期 loss 震荡剧烈验证集可能发散。res3_M1_lr0.01_eps6.png学习率 0.01只训 6 轮。欠拟合loss 还在下降就停了。res4_M2_lr0.01_eps6.png换模型结构可能是 GRU同样 6 轮。对比 M1 看收敛速度差异。Res5_M2_lr0.005_rps6.png学习率 0.005rps6可能是每轮 6 个随机种子取平均降低方差。调参优先级学习率 隐藏层维度 层数 序列长度。气象数据上lr0.001~0.005、hidden_size64~128、num_layers1~2、seq_len24~72是比较稳的区间。batch_size一般 32 或 64太小梯度噪声大太大泛化差。3.4 结果验证MAE、RMSE 与可视化对比test.py跑完后除了看 loss必须算 MAE 和 RMSE 并反归一化到原始量纲from sklearn.metrics import mean_absolute_error, mean_squared_error model.eval() with torch.no_grad(): preds model(X_test_tensor).cpu().numpy() # 反归一化只对 temp 列操作 preds_inv scaler.inverse_transform( np.concatenate([preds, np.zeros((len(preds), 2))], axis1) )[:, 0] true_inv scaler.inverse_transform( np.concatenate([y_test, np.zeros((len(y_test), 2))], axis1) )[:, 0] mae mean_absolute_error(true_inv, preds_inv) rmse np.sqrt(mean_squared_error(true_inv, preds_inv)) print(fMAE: {mae:.2f}℃, RMSE: {rmse:.2f}℃)气温预测的合理 MAE 在 1~2℃ 之间如果超过 3℃ 说明模型没学到有效模式。可视化时把真实值和预测值画在同一张图上重点看峰值和拐点是否跟上——LSTM 常见问题是预测曲线比真实曲线滞后一步这是滑动窗口单步预测的固有缺陷改成多步预测或加注意力机制能缓解。4. 避坑与排查气象时序预测里最容易翻车的五个地方4.1 现象训练 loss 正常下降验证 loss 从第 3 轮开始飙升原因模型过拟合。气象数据如果只有一年左右训练集和验证集分布差异大LSTM 参数量又远大于数据量。解决加 dropout0.2~0.3、减小hidden_size、加 L2 正则optimizer Adam(model.parameters(), lr0.001, weight_decay1e-4)、早停验证 loss 连续 5 轮不降就停。如果数据量少于 5000 行num_layers设 1 层就够。4.2 现象预测值几乎是一条直线不随输入变化原因归一化后目标值方差太小或者模型退化成只输出均值。常见于tq.csv里温度变化平缓的月份。解决检查scaler.inverse_transform后的预测值范围如果始终在均值附近说明模型没学到时序依赖。把seq_len从 24 加大到 72或者换 GRU 试试GRU 对短序列更敏感。另外确认y取的是 temp 列而不是其他变化小的列。4.3 现象RuntimeError: Expected hidden[0] size (2, 64, 64), got (2, 32, 64)原因batch_size在最后一个 batch 不整除LSTM 初始隐藏状态维度对不上。解决h0和c0用x.size(0)动态获取 batch 大小不要硬编码。或者在DataLoader里设drop_lastTrue丢弃最后一个不完整 batch。这个报错在换 batch size 后必现属于血泪经验。4.4 现象tq.csv读取后中文列名乱码原因CSV 编码是 GBK 而 pandas 默认 UTF-8。解决pd.read_csv(tq.csv, encodinggbk)或encodingutf-8-sig。如果列名本身是中文建议在data.py里重命名成英文再喂模型避免后续 matplotlib 画图时字体报错。4.5 现象GPU 显存够但训练速度极慢原因数据加载是瓶颈num_workers0时主进程串行读数据。解决Linux 下设num_workers4、pin_memoryTrueWindows 下num_workers保持 0 但把数据预加载成 tensor 放内存。另外确认model.to(device)和batch_x.to(device)都执行了只转模型不转数据等于白搭。5. 进阶技巧用 GRU 替换 LSTM 并做多步预测的实操跑通基线后最有价值的改动是把单步预测改成多步预测同时对比 GRU 和 LSTM 的推理速度。多步预测有两种策略直接多输出output_sizepred_len和自回归滚动用预测值当下一步输入。前者训练稳定但长程精度差后者精度高但误差累积。我一般先用直接多输出跑基线。改LSTM.py的输出层class WeatherGRU(nn.Module): def __init__(self, input_size3, hidden_size64, num_layers2, output_size6): super(WeatherGRU, self).__init__() self.gru nn.GRU(input_size, hidden_size, num_layers, batch_firstTrue, dropout0.2) self.fc nn.Linear(hidden_size, output_size) # 一次输出未来6步 def forward(self, x): out, _ self.gru(x) # GRU 不需要 c0 return self.fc(out[:, -1, :])output_size6对应预测未来 6 小时气温。训练时y的pred_len也要改成 6data.py里y.append(scaled[iseq_len:iseq_lenpred_len, 0])这行不用动它已经支持多步。损失函数仍用 MSE但评估时要分别算每一步的 MAE通常第 1 步最准第 6 步误差翻倍。GRU 相比 LSTM 的优势在推理速度同样hidden_size64、num_layers2GRU 参数量约为 LSTM 的 75%CPU 推理快 20%~30%。精度上气象数据这种中等长度序列两者差距通常在 5% 以内。如果你要部署到边缘设备GRU 是更务实的选择。验证多步预测效果时我习惯画一张预测步数 vs MAE的曲线step_mae [] for step in range(6): mae mean_absolute_error(true_inv[:, step], preds_inv[:, step]) step_mae.append(mae) plt.plot(range(1, 7), step_mae, markero) plt.xlabel(预测步数 (小时)) plt.ylabel(MAE (℃)) plt.savefig(step_mae.png)如果第 3 步之后 MAE 快速上升说明模型长程依赖没学好可以加一层注意力或改用 Transformer。但在气象预测这个场景里LSTM/GRU 加多步直接输出已经能覆盖大部分课程设计和论文实验的需求。从那以后我每次拿到时序预测代码包都强制先跑一遍df[time].diff().value_counts()确认采样间隔再检查scaler有没有在推理时反归一化。这两个地方翻车过太多次希望帮到你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →