新闻详情

新闻详情

首页 / 资讯中心 / 详情

多变量LSTM结合气象特征的PM2.5时序预测实战

发布时间:2026/9/11 18:00:30来源:尧图网络
多变量LSTM结合气象特征的PM2.5时序预测实战
简介基于LSTM的多变量时间序列PM2.5预测项目源码配套说明文档与数据集是一个经导师指导、评审96.5分的高分毕业设计适合计算机、人工智能等专业学生用于毕业设计、课程设计或期末大作业。压缩包共6个文件包括3个Python脚本涵盖数据预处理、LSTM模型构建与训练、预测结果可视化等环节、2个CSV格式的原始与处理后数据以及1个Markdown说明文件整体仅有929KB结构轻量紧凑。该资源已被139人浏览学习代码经测试运行成功可直接复现。下载后可快速理解多变量时间序列预测的完整流程包括数据清洗、特征构造、模型调参与结果评估等关键步骤遇到运行问题还可私聊远程指导也可基于此代码二次开发完成其他预测任务。1. 从雾霾监测到多变量LSTM预测这个96.5分的毕设到底在做什么做气象时序预测的人大都有一个感觉单看PM2.5浓度曲线去做LSTM训练出来的模型总像是在“抄作业”预测结果比真实值滞后两三个小时遇到突变天气几乎完全失灵。这个毕设项目之所以能拿到96.5分核心在于它没有只喂一条浓度序列给网络而是把露点、温度、气压、风向、风速等环境变量一并组装成多变量输入让LSTM在时间步上同时学习气象要素与污染浓度的耦合关系。项目里一共包含六个文件main.py是训练入口dataPreprocessing.py负责数据清洗seriesShow.py做预测结果可视化raw.csv是原始监测数据pollution.csv是预处理后的建模数据README.md则给出了环境依赖与运行顺序。适合正在做毕业设计、需要一份能跑通且能讲清楚原理的LSTM时序预测代码的人也适合想在此基础上改成其他污染物预测或径流预测的进阶学习者。下面按数据、网络、训练、评估、预测这条线逐一拆开。2. 数据预处理与多变量输入构造为什么不能只用PM2.5浓度序列2.1 原始CSV字段里藏着哪些影响预测的变量用文本编辑器打开raw.csv能看到原始采集数据包含多条字段其中No是记录序号year、month、day、hour四个字段组成完整时间戳pm2.5是目标变量。真正参与多变量建模的辅助特征是DEWP露点、TEMP温度、PRES大气压强、cbwd组合风向、Iws累计风速、Is积雪时长、Ir降雨时长。这些变量之所以能进入模型不是因为“变量越多越准”而是因为它们与PM2.5浓度存在物理传导链条高压天气下污染物容易在城市上空堆积高风速会加速扩散降雨会通过湿沉降清除颗粒物。多变量LSTM正是在这些特征随时间变化的组合模式里学习PM2.5的演变规律。raw.csv和pollution.csv的区别需要先讲清楚。前者是带缺失值的原始记录后者是经过dataPreprocessing.py清洗后可用于训练的标准表。有些同学下载代码后直接把raw.csv喂给模型结果训练Loss震荡不收敛回头检查才发现数据里有大量NaN。正确的建模数据格式是每一行代表一个小时的气象观测每一列代表一个变量行与行之间按时间严格递增。2.2 数据清洗与特征工程的具体操作dataPreprocessing.py里完成的工作可以拆成四个步骤缺测值处理、风向哑变量编码、时间索引重置、特征归一化。下面给出经过简化但仍能直接运行的清洗流程import pandas as pd import numpy as np from sklearn.preprocessing import LabelEncoder, MinMaxScaler df pd.read_csv(raw.csv) # 1. 删除完全无效的行再用线性插值填充单个缺测点 df df.replace(-999.0, np.nan) df df.dropna(threshlen(df.columns) - 3) df df.interpolate(methodlinear, limit_directionboth) # 2. 风向是类别特征不能直接放进LSTM做数值计算 le LabelEncoder() df[cbwd] le.fit_transform(df[cbwd]) # 3. 把时间字段拼接成datetime索引便于后续切分训练集和测试集 df[datetime] pd.to_datetime(df[[year, month, day, hour]]) df df.set_index(datetime).sort_index() df df.drop(columns[year, month, day, hour, No]) # 4. 统一归一化到[0,1]避免TEMP和PRES这种大数值变量主导梯度 scaler MinMaxScaler(feature_range(0, 1)) scaled_data scaler.fit_transform(df) scaled_df pd.DataFrame(scaled_data, columnsdf.columns, indexdf.index) scaled_df.to_csv(pollution.csv)逻辑说明-999是气象站点常用的缺测填充值如果把它当成真实数据送进网络LSTM会学到“PM2.5突然变成-999”这种无意义规律。interpolate用前后时刻的线性均值补齐单个空洞比直接用均值填充更尊重时间连续性。LabelEncoder把NW、NE、cv这类风向字符串映射成0到3的整数这样LSTM才能做矩阵运算。最后用MinMaxScaler把不同量纲的变量压缩到0到1区间否则PRES动辄上千的数值会在反向传播中完全淹没Iws这种小数值变量的梯度贡献。2.3 构造滑动窗口样本时的关键参数多变量时序预测不能把整行数据直接扔给模型需要把连续时间段的历史观测组装成有监督样本。常见做法是设定一个TIME_STEPS也叫滞后步长让模型用过去N个小时的气象和浓度数据预测下个小时的PM2.5值。pollution.csv里总共有8个变量假设TIME_STEPS5那么一个样本的形状就是(5, 8)也就是一个5行8列的矩阵。生成监督数据的代码逻辑如下def create_supervised(data, n_in5, n_out1): X, y [], [] for i in range(len(data) - n_in - n_out 1): X.append(data[i:i n_in, :]) y.append(data[i n_in:i n_in n_out, 0]) return np.array(X), np.array(y) # 注意pollution.csv里第0列是pm2.5第1到7列是气象特征 data_array scaled_df.to_numpy() X, y create_supervised(data_array, n_in5, n_out1) print(X.shape, y.shape)参数说明n_in5表示回溯5个小时n_out1表示只预测未来1个小时。这里有两个容易被忽视的细节。第一y取的是data[...][:, 0]因为第0列才是PM2.5浓度其他列是辅助特征我们要预测的目标只有一个值。第二样本之间是有重叠的——第1个样本用0到4小时预测第5小时第2个样本用1到5小时预测第6小时这种重叠策略能让有限的监测数据产生更多训练样本是时序预测里最常见的增广方式。TIME_STEPS的取值对模型影响很大。取太小比如2模型看不到污染积累的过程遇到静稳天气时预测值会严重偏低取太大比如24样本数量骤减且过长的历史窗口会让LSTM学到大量冗余信息训练时间翻倍但精度提升有限。做参数实验时可以按小时粒度在3到12之间做网格搜索。3. LSTM网络结构设计与训练参数的选择3.1 在时序预测里LSTM比RNN强在哪里传统RNN在处理超过10个时间步的序列时梯度在反向传播过程中会反复乘以循环权重矩阵导致梯度消失网络根本学不到长距离依赖。LSTM在循环单元内部增加了输入门、遗忘门、输出门和记忆单元其中记忆单元通过线性自环传递梯度误差信号在传播过程中可以无损跨越数十个时间步。对PM2.5预测而言TIME_STEPS5这个长度对RNN来说还算温和但真实场景中如果改为预测未来24小时的空气质量LSTM的优势就会完全体现出来。main.py里的网络结构是一个两层LSTM加一个全连接输出层。第一层LSTM返回完整序列给第二层继续提取特征第二层只返回最后一个时间步的输出最后过一层Dense把特征压缩成1维浓度值。下面是核心构建代码from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout TIME_STEPS 5 FEATURE_NUM 8 model Sequential() model.add(LSTM(units64, return_sequencesTrue, input_shape(TIME_STEPS, FEATURE_NUM))) model.add(Dropout(0.2)) model.add(LSTM(units32, return_sequencesFalse)) model.add(Dropout(0.2)) model.add(Dense(units16, activationrelu)) model.add(Dense(units1)) model.compile(optimizeradam, lossmse, metrics[mae])参数说明这里需要细拆。units64是第一层LSTM隐含状态向量的维度64维意味着每个时间步的输出都是一个64维向量这个容量足以捕捉8个气象变量之间的非线性组合。return_sequencesTrue表示把每个时间步的隐藏状态全部传给下一层如果这里写成False第二层就只能收到最后一个时间步的信息5小时的完整演化过程被压缩成一条静态向量特征信息会大量丢失。Dropout(0.2)在LSTM层的输出处随机置零20%的神经元防止网络把训练集上的噪声当作固定规律。第二层return_sequencesFalse只输出最后一步的32维向量再接Dense(16)做非线性映射最后压缩成1维PM2.5预测值。关于层数多深的判断大致遵循一个原则两层LSTM是时序预测的性能和训练开销平衡点。一层LSTM结构简单、训练快但只能学到单一时间尺度上的依赖三层LSTM可以捕捉更复杂的多层次时间模式但样本量不够时非常容易过拟合训练时间也指数上涨。本项目的pollution.csv是逐小时数据一年大约8760条记录切掉前20%做验证后训练样本不足7000条这个数据量撑不起三层LSTM。3.2 训练集与验证集切分时序数据为什么不能shuffle常规分类任务里train_test_split都会设置shuffleTrue来打乱数据但时序预测如果照搬这个操作就埋下了一颗雷。LSTM依赖时间顺序来学习序列内部的连贯性如果训练集里混入未来时间片段模型相当于提前看到了“答案”验证集的Loss会异常低但一部署到真实环境立刻失效。正确做法是按时间顺序切分比如前80%的数据做训练后20%做测试train_size int(len(X) * 0.8) X_train, X_test X[:train_size], X[train_size:] y_train, y_test y[:train_size], y[train_size:] history model.fit( X_train, y_train, batch_size64, epochs50, validation_data(X_test, y_test), shuffleFalse, verbose1 )训练参数这样设置的理由batch_size64表示每批同时训练64组样本这个值不宜过大也不宜过小。太大如512会让每个batch涵盖的时间段过长梯度在多个时间趋势上平均后变得平滑模型难以学到突变特征太小如8则梯度噪声过大Loss曲线剧烈震荡训练很难收敛。shuffleFalse是时序训练里的硬性要求虽然在Keras中默认不会shuffle验证集但训练集的shuffle参数必须显式关闭。validation_data直接用时间上靠后的测试集这样评估出的误差才接近模型上线后的真实表现。这里补充一个小实验技巧可以分别对原始raw.csv和清洗后的pollution.csv训练一次模型对比mae指标。正常情况下清洗后的模型验证集MAE会明显低于直接用原始数据训练的模型这个对比能帮助你向答辩老师说明数据预处理的价值也是毕设报告里很有说服力的实验组设计。3.3 训练过程中的调参与早停策略训练50轮在大多数情况下会出现Loss先快速下降、后缓慢波动的情况。为了在训练后期避免过拟合常见做法是在main.py里加入EarlyStopping回调当验证集Loss连续多个epoch不再下降时提前终止训练from tensorflow.keras.callbacks import EarlyStopping early_stop EarlyStopping( monitorval_loss, patience5, restore_best_weightsTrue ) history model.fit( X_train, y_train, batch_size64, epochs50, validation_data(X_test, y_test), shuffleFalse, callbacks[early_stop], verbose1 )monitorval_loss表示观察验证集上的均方误差。patience5的意思是连续5个epoch验证集Loss都没有刷新最低记录时训练提前结束并回滚到历史最优权重。restore_best_weightsTrue这个参数容易被忽略如果不设置训练结束时模型保存的是最后一轮的权重而不是Loss最低那一轮的权重最后几轮模型可能已经过拟合预测效果反而变差。训练完可以简单检查history字典中的loss和val_loss曲线。正常情况是训练Loss始终略低于验证Loss两者差距不大如果训练Loss极低而验证Loss高企说明模型过拟合需要加大Dropout比例或减小units如果两者都高说明模型欠拟合需要增加网络容量或把TIME_STEPS调大。另外项目包里的main.py还提供把训练好的模型保存为h5文件的代码行方便在后续预测脚本中直接load_model加载不需要每次重复训练。4. 训练效果评估与误差指标解读4.1 RMSE、MAE、R²各自反映什么训练完成后测试集上的预测值和真实值需要被反归一化回原始PM2.5浓度单位才能计算有物理意义的误差。代码逻辑如下import numpy as np from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score # 反归一化scaler在预处理阶段已经保存了min和scale参数 y_test_real scaler.inverse_transform( np.concatenate([y_test, np.zeros((len(y_test), 7))], axis1) )[:, 0] pred model.predict(X_test) pred_real scaler.inverse_transform( np.concatenate([pred, np.zeros((len(pred), 7))], axis1) )[:, 0] rmse np.sqrt(mean_squared_error(y_test_real, pred_real)) mae mean_absolute_error(y_test_real, pred_real) r2 r2_score(y_test_real, pred_real) print(fRMSE: {rmse:.2f} ug/m3, MAE: {mae:.2f} ug/m3, R2: {r2:.4f})因为scaler是按整列归一化的反变换时需要用zeros补齐其他7个变量占位再把目标列取出来。RMSE的单位是微克每立方米对异常值敏感如果监测数据里出现过PM2.5超过500的严重污染日RMSE会被拉高MAE反映平均绝对偏差更贴近日常感知的“平均差多少”。R²表示预测值能解释真实值多少方差R²越接近1越好但要注意如果预测值整体偏离真实值一个常数R²也会很高所以R²必须和RMSE结合来看。以这个项目的经验数据为例验证集上MAE控制在15到25微克每立方米是合理区间。4.2 预测滞后现象LSTM时序预测最常见的翻车点把测试集前200小时的预测值和真实值画在一张图上几乎一定会看到曲线整体右移也就是预测峰值比真实峰值晚到1到2个小时。这是因为LSTM在训练时学习到的是“用过去5小时推断下一小时”的映射而PM2.5浓度具有很强的自相关性模型发现最稳妥的策略就是输出接近上一时刻的数值这样Loss最小。解决滞后问题的思路不只是调参更重要的是在数据构造阶段做差分或引入外部气象预报值作为额外特征。seriesShow.py里画预测对比图的代码本身就包含了对这个现象的可视化把局部放大来看如果滞后时长小于1小时说明模型基本可接受超过2小时就要考虑把TIME_STEPS缩短或者在训练时把输入数据做一阶差分让LSTM去预测浓度变化量而不是绝对值。4.3 对照实验设计单变量基线是衡量多变量增益的标尺为了证明多变量输入的增益需要设计一个单变量基线只把PM2.5浓度列喂给同一个LSTM网络其他条件完全一致。代码上只需把features列数从8改成1其他结构不变。下表是一个典型的对照实验结果参考实验配置RMSE (ug/m³)MAE (ug/m³)R²单变量 LSTM仅pm2.538.5226.170.86多变量 LSTM含气象特征29.4319.280.92这个对照说明气象特征提供了PM2.5时间序列之外的增量信息模型不再只是机械地拟合历史曲线而是借助风速、风向等信息提前感知污染扩散趋势。把这个对比表放进毕设论文的第四章比堆砌任何文字都有说服力。5. 预测可视化与多步递推的实战技巧5.1 seriesShow.py画图时需要注意的细节seriesShow.py的核心功能是把真实值曲线和预测值曲线画在同一坐标系下并高亮测试集范围。画图前必须确保两条曲线的横轴是时间索引不能是样本序号否则图中无法对应到具体的日期和时刻。常见做法是在数据集分割时保留时间索引的一个副本import matplotlib.pyplot as plt plt.figure(figsize(14, 5)) plt.plot(test_index, y_test_real, labelObserved PM2.5, color#333333) plt.plot(test_index, pred_real, labelLSTM Predicted, color#d62728, alpha0.8) plt.xlabel(Time (hour)) plt.ylabel(PM2.5 concentration (ug/m3)) plt.legend() plt.grid(alpha0.3) plt.savefig(prediction_result.png, dpi150)画图有两个实用建议一是用plt.xlim截取前200小时放大看细节防止整年曲线太长导致预测滞后这种细微偏差被压缩到看不见二是把严重污染时段比如PM2.5超过200在图上用竖直虚线标注出来观察模型在这些极端点上的表现。毕业答辩时评委大概率会问“模型哪里预测得不准”这张图就是回答的依据。5.2 多步预测的滑窗递推策略单步预测只能输出未来1小时浓度但空气质量预警通常需要未来24到72小时的变化趋势。在半监督条件下做多步预测核心策略是递归滑窗把预测出的值拼接到输入序列末尾丢掉最老的时刻再送给模型预测下一个时刻。代码实现如下def forecast_future(model, last_sequence, n_steps, scaler): current_seq last_sequence.copy() # shape: (TIME_STEPS, FEATURE_NUM) result [] for _ in range(n_steps): # 模型要求输入形状为 (1, TIME_STEPS, FEATURE_NUM) x_input current_seq.reshape((1, current_seq.shape[0], current_seq.shape[1])) pred model.predict(x_input, verbose0)[0, 0] # 预测值反归一化后记录 pred_real scaler.inverse_transform( np.concatenate([[pred], np.zeros((1, 7))], axis1) )[0, 0] result.append(pred_real) # 构造新的时间步删掉最早时刻补上预测值 new_step current_seq[-1].copy() new_step[0] pred # 第0列是pm2.5 current_seq np.vstack([current_seq[1:], new_step]) return np.array(result)注意一个关键问题递推时新时间步里的气象特征风速、温度等是没有真值的这里用上一个时刻的气象数据近似代替。实际工程中应该接入气象预报数据来填充这些特征否则风速误差会随时间步长增加而累积导致预测结果越来越偏。递推步数越大误差累积越明显一般24小时以上预测结果仅作趋势参考不能当作精确值使用。5.3 数据泄露识别与保存模型的正确姿势很多同学跑通代码后重新训练发现验证集准确率异常高RMSE不到10这时候要警惕数据泄露。常见泄露路径有两种一是预处理阶段用全量数据的均值和标准差做归一化再切分训练测试集导致测试集的信息混入训练过程二是风向LabelEncoder在fit的时候看到了测试集特有的类别虽然这个错误通常不会造成严重后果但在答辩被问到特征工程细节时会站不住脚。正确的姿势是先用训练集拟合scaler再分别transform训练集和测试集。保存模型时建议同时输出训练配置信息model.save(lstm_pm25_model.h5) with open(model_config.txt, w) as f: f.write(fTIME_STEPS{TIME_STEPS}\n) f.write(fFEATURE_NUM{FEATURE_NUM}\n) f.write(floss{history.history[val_loss][-1]:.4f}\n) f.write(fmae{history.history[val_mae][-1]:.4f}\n)这样做的好处是模型文件换到另一台机器时不需要反查源码也能知道输入维度要求。打包完成的项目里README.md记录了Python版本和tensorflow安装命令pollution.csv可以直接作为其他算法比如随机森林回归的输入做对比实验这也是给多变量LSTM结论加分的一个方向不只对LSTM本身负责也跟经典机器学习方法比一比。到这一步这个毕设项目才算真正吃透了从数据清洗到滚动预测的完整链路。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

阿尔法零原理剖析:Ghost-master中的双头网络与蒙特卡洛树搜索 2026/9/11 20:18:48

阿尔法零原理剖析:Ghost-master中的双头网络与蒙特卡洛树搜索

简介:一份基于Minigo框架、以Python实现的幻影围棋项目,面向围棋爱好者、AI学习者与Python开发者。核心目标是让用户快速上手围棋AI的人机与机机对战,通过Minigo的卷积神经网络与蒙特卡洛树搜索(MCTS)组合,…

阅读更多 →
基于RFID与JDBC的自习室座位管理系统状态流转设计 2026/9/11 20:18:48

基于RFID与JDBC的自习室座位管理系统状态流转设计

简介:一套基于RIFD技术(射频识别)的自习室座位管理系统设计与实现资源,适用于计算机相关专业毕业设计、课程设计及Java Web开发学习者。项目包含完整论文(Word文档)与可运行源码,围绕座位预约、…

阅读更多 →
二自由度机械臂滑模控制:指数趋近律原理与MATLAB工程实现 2026/9/11 20:18:48

二自由度机械臂滑模控制:指数趋近律原理与MATLAB工程实现

简介:本资源是一份面向控制理论学习者与MATLAB实践者的滑模控制仿真教学材料,聚焦二自由度机械臂的位置跟踪控制问题,适用于自动控制、机器人学及先进控制算法课程设计与课题研究。压缩包共7个文件,含3个MATLAB脚本(SM…

阅读更多 →
C# DirectX11硬核绘图:纳秒级测速与GPU加速直线渲染 2026/9/11 20:18:48

C# DirectX11硬核绘图:纳秒级测速与GPU加速直线渲染

简介:本资源是一个面向C#图形编程初学者与DirectX入门开发者的性能测试实践项目,聚焦于使用C#调用DirectX(通过SharpDX或SlimDX封装)高效绘制直线并量化渲染耗时,解决图形应用中帧率优化与瓶颈定位的实际问题。压缩包共…

阅读更多 →
Java直接内存原理与性能优化实践 2026/9/11 20:18:48

Java直接内存原理与性能优化实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
AI Coding新范式:多Agent协同编排实战指南 2026/9/11 20:15:48

AI Coding新范式:多Agent协同编排实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞