ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

LSTM空气质量预测:期末大作业从数据预处理到模型评估全攻略

LSTM空气质量预测:期末大作业从数据预处理到模型评估全攻略 简介基于长短期记忆网络LSTM的空气质量数据可视化分析预测项目是面向计算机专业学生的期末大作业完整源码适用于课程设计、毕业设计与项目实战训练。项目经导师认可并通过评审得分99分代码完整可运行基础薄弱的学习者也能按注释理解并上手。压缩包中共260个文件大小约7.03MB涵盖Python脚本、HTML页面、SCSS与CSS样式文件、CSV空气监测数据、SQLite数据库及说明文档等各类文件按功能分层存放便于定位模型训练、数据可视化与结果展示模块。项目完整演示了从数据预处理、LSTM模型构建训练到预测结果可视化呈现的整套流程可直接用于大作业提交、答辩展示或后续扩展学习。目前已有99人学习下载适合需要高质量参考模板的在校学生。1. 期末大作业选 LSTM 预测空气质量划算在哪期末周最磨人的不是复习而是手里握着一份从监测站导出的空气质量表格却不知道该拿它做什么才算“像样的结课作品”。直接做描述性统计撑不住页面用线性回归猜 PM2.5答辩时老师一句“非线性呢”就会卡住。空气质量预测恰好卡在性价比最高的位置数据是公开的逐小时监测记录任务本质是时间序列预测尾声再配几张图就是一个完整的故事线。LSTM 模型对这类带周期和延迟效应的序列数据贴合度高源代码量可控可视化分析又能撑起报告篇幅很多“期末大作业”选它就是看中这三点数据不用爬、模型不是调包完事、图表能证明工作量。这篇按“数据处理 → 模型 → 评估 → 答辩”展开每一步写到能直接抄的程度。2. 空气质量数据预处理从时间表到 LSTM 输入张量LSTM 吃的是有先后顺序的序列不是散着的表格行。期末作业里最常见的翻车点不是模型写错而是数据没有按时间排序、时间列有重复、缺失值直接 dropna 导致序列断档。空气质量监测是按小时采样的夜间到清晨容易出现设备离线造成的空洞所以“读进来直接训练”大概率会在 loss 上表现得莫名其妙。2.1 时间解析与缺失值处理监测数据的第一个坑先确认时间列能不能被 pandas 正确识别。常见做法是parse_dates读入后立刻 sort再设为索引这一步决定了后面所有滑窗切片的顺序是否正确。import pandas as pd df pd.read_csv(air_quality.csv, parse_dates[time]) df df.sort_values(time).set_index(time) print(df.info()) print(df.isnull().sum()) df[pm2_5] df[pm2_5].interpolate(methodlinear) df df.dropna(subset[pm2_5])interpolate(methodlinear)按前后观测值做线性插补比ffill()能保留更多浓度变化细节适合设备短时掉线。若某一列缺失超过 3%插值意义不大建议直接丢列并在报告里注明。做完这两步后再检查两件事索引是否严格递增、时间步长是否均匀。若出现重复时间戳需要先groupby(level0).mean()聚合成单条记录否则滑窗时同一个小时会被重复采样。提示监测数据里的 PM2.5 单位通常是 μg/m³量纲对后续归一化没有影响但写报告时一定要标单位。2.2 训练/测试切分与归一化别把未来信息带进训练时间序列不能像普通回归那样随机切分。随机打乱会破坏前后相关性更严重的是如果用全量数据做fit_transform测试集的极大极小值已经掺进了归一化参数等于测试时偷看了未来信息评估出来的 RMSE 虚低答辩时被追问必露馅。from sklearn.preprocessing import MinMaxScaler n_train int(len(df) * 0.7) train_df df.iloc[:n_train] test_df df.iloc[n_train:] sc MinMaxScaler(feature_range(0, 1)) train_scaled sc.fit_transform(train_df[[pm2_5]]) test_scaled sc.transform(test_df[[pm2_5]])fit_transform只用在训练集上transform只对测试集做同样映射。如果引入温度、风速等多个特征就把它们的列一起传进去LSTM 输入张量的最后一个维度对应特征数后续模型代码无需大改。这里还有一个容易被忽略的细节MinMaxScaler对异常值不稳健若某天监测设备爆表记录到极高浓度归一化后正常值会被压缩到很小区间训练反而变难。若数据长尾明显可以先用np.log1p对浓度做对数变换再归一化这个改进可以在报告里单独写成一个小实验。2.3 滑窗序列构造lookback 是期末答辩必问参数LSTM 的输入不是单条记录而是一段连续历史。假设用过去 72 小时预测当前小时那么每一条训练样本形状是(72, 1)72 就是 lookback 窗口。窗口太短学不到日周期太长又把噪声也装进记忆72 小时是多数空气质量预测作业的稳妥起点。import numpy as np def create_sequences(data, lookback): X, y [], [] for i in range(lookback, len(data)): X.append(data[i - lookback:i]) y.append(data[i]) return np.array(X, dtypenp.float32), np.array(y, dtypenp.float32) X_train, y_train create_sequences(train_scaled, lookback72) X_test, y_test create_sequences(test_scaled, lookback72)data[i - lookback:i]取的是连续切片y是对应切片之后的那个时间点数值。循环实现简单直观数据量在几万条以内完全够用不需要绕道TimeseriesGenerator。X_train的形状是(样本数, 72, 1)y_train是(样本数,)这个形状直接对接 Keras 的 LSTM 输入要求。参数示例值作用与影响lookback72控制记忆长度覆盖 24 小时周期并留出跨天余量features1单特征时只喂 PM2.5多特征时传多列训练占比70%顺序切分不打乱测试集留在时间轴末端窗口与预测目标的关系值得多想一层这里做的是“未来 1 小时”单步预测。若作业要求预测未来 24 小时浓度曲线常见做法是用预测输出递归地接回输入但误差会逐步累积期末展示时主动说明这个限制比等老师点破更显专业。3. LSTM 模型构建与训练从门控机制到可复现的 Keras 代码空气质量序列本身是非线性的早晚高峰抬升、雨天下降、前一日高浓度会延续到次日上午。RNN 理论上能处理序列但训练时梯度在长序列上容易消失。LSTM 加入门控单元让信息可以选择性写入记忆或遗忘这让它成为时间序列预测作业里最容易出稳定结果的初始选择。3.1 为什么序列建模选 LSTM记住并遗忘的边界LSTM 的核心是单元状态 C_t它像一条传送带横穿整个网络。遗忘门决定上一时刻的状态保留多少输入门决定新信息写入多少输出门决定最终输出什么。若只记住传送带概念或只记得“它比 RNN 强”答辩时很容易被细节问住。遗忘门的输入是什么数据是当前时刻输入 x_t 与上一时刻隐状态 h_{t-1} 拼接后的向量经过 sigmoid 输出 0 到 1 的系数。这个系数与上一时刻单元状态 C_{t-1} 逐元素相乘完成“遗忘”。对应公式为f_t σ(W_f · [h_{t-1}, x_t] b_f)空气质量场景里遗忘门学到的东西往往是“今天凌晨 3 点的浓度对下午 3 点的预测没那么重要”而前一天的相同时刻反而权重更高。这就是 LSTM 处理这种带日周期数据的直觉逻辑它不把整个历史等权看待而是学出一套动态权重这一点写进报告比贴网络结构图更有说服力。3.2 两层 LSTM 模型骨架return_sequences 与 Dropout 的位置Keras 是期末作业里复现成本最低的选择原因在于它不需要像 PyTorch 那样手动管理隐状态初始化LSTM 层的循环逻辑封装在内部刚接触深度学习的人不容易在状态重置上出错。我更推荐先跑通 Keras若后续想改自定义损失或做多步采样再换 PyTorch 也不迟。from tensorflow import keras from tensorflow.keras import layers model keras.Sequential([ layers.Input(shape(X_train.shape[1], X_train.shape[2])), layers.LSTM(64, return_sequencesTrue), layers.Dropout(0.2), layers.LSTM(32), layers.Dense(1) ]) model.compile( optimizerkeras.optimizers.Adam(learning_rate1e-3), lossmse, metrics[mae] ) model.summary()第一层 LSTM 必须设return_sequencesTrue否则它只输出最后一个时间步的状态形状变成(None, 64)第二层 LSTM 拿到的就不是序列而是单点维度直接对不上。Input里的X_train.shape[2]是特征数单变量为 1多变量时会自动适配。Dropout 放在两层之间而不是输出层之后目的是让第二层看到的是被随机置零的序列特征这比在 Dense 后加正则更能抵抗时间序列过拟合。提示model.summary()会显示每层参数量截图放进报告可以直观展示网络规模是期末作业常见的素材。3.3 训练参数与回调EarlyStopping 让 100 轮变成“够了就停”深度学习作业最容易犯的错是把epochs固定写死比如训练 100 轮后直接取最后一个权重。模型在第 60 轮已经收敛时后面 40 轮只是在过拟合训练集。正确做法是用回调监控val_loss连续若干轮不降就提前停止并恢复到最佳权重。from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau early_stop EarlyStopping( monitorval_loss, patience15, restore_best_weightsTrue ) reduce_lr ReduceLROnPlateau( monitorval_loss, factor0.5, patience5, min_lr1e-5 ) history model.fit( X_train, y_train, validation_split0.2, epochs100, batch_size64, callbacks[early_stop, reduce_lr], verbose1 )validation_split0.2是在训练集末尾再切出 20% 作为验证集不会穿透到测试集。patience15意味着验证损失连续 15 轮没有更优就停ReduceLROnPlateau在连续 5 轮平台期时把学习率减半帮助模型跳出局部极小。训练完成后注意一件事history里保存的是归一化空间下的 loss不能直接写进报告说“loss 是 0.003”要反归一化后按浓度单位计算误差。超参数推荐值调参方向第一层 units64数据量小时从 32 起步第二层 units32两层结构比单层多层更稳dropout0.2过拟合明显时升到 0.3batch_size64显存小就降到 32learning_rate1e-3loss 震荡时降到 5e-4关于“模型越深越好”的误解这里顺便纠正空气质量数据集通常在几万条量级两层 LSTM 是实践中的上限。堆到三层以上参数量变大训练集 loss 好看测试集反而变差期末报告里写“两层足够了”反而体现你对模型容量有判断力。4. 可视化分析与预测评估把模型结果变成报告的图表模型跑完只完成一半期末大作业的评分标准里“可视化分析”往往占大头。可视化不是把训练曲线贴一遍而是要让老师能从图里读出三个结论模型收敛没有、预测准不准、失效场景在哪。下面的图和指标都围绕这三点展开。4.1 训练/验证损失曲线过拟合要从图上看出来损失曲线是判断训练过程是否健康的第一个证据。把 loss 和 val_loss 画在一起如果两者同步下降后走平说明训练充分如果 val_loss 在某轮之后反弹上升而 loss 还在降就是过拟合的典型信号此时应提高 dropout 或提前停止。import matplotlib.pyplot as plt plt.figure(figsize(10, 4)) plt.plot(history.history[loss], labeltrain_mse) plt.plot(history.history[val_loss], labelval_mse) plt.yscale(log) plt.xlabel(epoch) plt.ylabel(MSE loss) plt.title(训练与验证损失曲线) plt.legend() plt.tight_layout() plt.savefig(loss_curve.png, dpi200)plt.yscale(log)是常用技巧loss 从 0.01 降到 0.0001 时线性坐标下后半段会被压成一条直线对数坐标才能看出收敛细节。图片用savefig保存而不是截图dpi 设 200 以上放进报告才不会被老师说“看不清”。4.2 预测值与真实值对比评估指标怎么算、怎么写进报告损失函数是归一化空间的 MSE不能直接对外汇报。测试集预测结果要反归一化回原始浓度单位再重新计算指标。注意y_test在create_sequences后是二维数组变一维数组反归一化前需要 reshape。from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score pred_test model.predict(X_test, verbose0) pred_real sc.inverse_transform(pred_test) y_real sc.inverse_transform(y_test.reshape(-1, 1)) mae mean_absolute_error(y_real, pred_real) rmse mean_squared_error(y_real, pred_real, squaredFalse) r2 r2_score(y_real, pred_real) print(fMAE: {mae:.2f} μg/m³) print(fRMSE: {rmse:.2f} μg/m³) print(fR2: {r2:.3f})指标含义报告里怎么解读RMSE误差的均方根对重污染时段的大误差更敏感取值大于 MAEMAE平均绝对误差与“平均差多少 μg/m³”直接挂钩R²决定系数接近 1 说明模型捕捉到了大部分波动趋势RMSE 大于 MAE 是正常的因为平方运算放大了极端误差两者差得越多说明模型在重污染时段的偏移越明显这正好可以作为 4.3 节的分析入口。R² 的计算在 sklearn 新版中直接返回标量值不推荐手写公式手写容易出现负值时解释不清楚的情况。4.3 误差分布与重污染时段挖出模型失效的规律对比图谁都会画加一张误差分布图就能拉开差距。以真实值减预测值为横轴画直方图观察误差是否集中在 0 附近。若直方图明显左偏说明模型系统性低估右侧长尾则说明偶发的高浓度漏报严重。residuals y_real[:, 0] - pred_real[:, 0] plt.figure(figsize(8, 4)) plt.hist(residuals, bins30, edgecolorwhite, alpha0.8) plt.xlabel(真实值 - 预测值 (μg/m³)) plt.ylabel(样本数) plt.title(测试集预测残差分布) plt.tight_layout() plt.savefig(residual_hist.png, dpi200)更进一步的漏斗图是把y_real按浓度分桶比如 0-50、50-100、100 以上分别计算每个桶的平均绝对误差。结果大概率显示浓度越高的桶误差越大。这不是模型 bug而是 LSTM 在训练集里见过的高浓度样本本身就少且重污染过程的突变性更强。把这张图放进报告并解释“模型擅长日常浓度预测重污染事件是边界场景”比只放一张对比图显得更有分析深度。5. 期末答辩现场把源代码、模型和可视化讲成一个闭环答辩演示和写代码是两种能力。代码能跑只是底线老师更想看到的是“你知道自己在做什么、模型哪部分最脆弱、还能怎么改”。期末大作业的评分锚点往往就在最后十分钟的追问里。5.1 老师爱问的三个追问的应答方向“为什么用 LSTM 而不是 ARIMA”是出现频率最高的问题。应答主线是ARIMA 是线性模型对 PM2.5 这种受排放、气象、地形共同影响的非线性序列拟合能力有限LSTM 通过门控机制学习长期依赖不需要手动指定滞后阶数。如果老师追问“你怎么证明 LSTM 比 ARIMA 好”回应方式是“我没做对比实验但从文献和课程讨论中做了一个选型判断”。诚实承认边界远比编造对比结果安全。“lookback 为什么设 72”也有固定答法24 小时是日周期48 小时覆盖前一天同潮汐72 小时留出跨两天的余量可以补充一句“我还试过 168但训练样本变少验证损失没有改善”。这句话说明你做过敏感性分析是实打实的加分项。“模型什么时候预测得最差”是压力最大的追问。直接展示 4.3 的残差桶状图说出“高浓度样本少模型倾向于向均值回归所以重污染时段会低估”。老师会接着问“那怎么改”答案不必做出来说出思路即可对高浓度样本加权损失、把对数变换加入预处理、或改用分位数损失。5.2 演示前值得做的三件小事第一把训练入口封装成命令行参数。用argparse暴露--lookback、--epochs、--batch_size三个参数答辩现场老师问“换一个窗口试试”时你只需要改一个数字重新跑而不是改代码。第二在测试集预测图上用红框标出一次重污染事件框出模型低估区间并截两张局部放大图这会让分析环节从“我画了图”变成“我发现了问题”。第三把model.load_weights的保存路径写清楚答辩前直接加载权重出图不要现场训练浪费五分钟。空气质量预测类作业的答辩节奏应该是数据怎么清洗、窗口怎么选、网络怎么搭、误差在哪、下一步怎么改。这五步讲全源代码本身是否完美反而不那么重要。下次再面对类似的时间序列预测小项目先做周周期观察再看预测残差的分布比反复堆训练轮数更能提前发现问题。本文还有配套的精品资源点击获取
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表