多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Python机器学习天气预测实战:LSTM时间序列与可视化大作业全流程

Python机器学习天气预测实战:LSTM时间序列与可视化大作业全流程 简介这份资源是面向计算机相关专业学生与项目实战学习者的机器学习天气预测完整项目适用于期末大作业、毕业设计及课程实践场景难度适中。项目以Python为核心围绕气温预测与数据可视化展开涵盖数据爬取、数据探索、特征处理、模型训练与GUI展示等环节涉及线性回归、决策树、随机森林、三层MLP及LSTM等多种算法并配有模型文件与可视化图表便于对照理解建模流程与结果呈现。压缩包共38个文件约12.17MB包含py源码、ipynb笔记本、png图表、pkl与joblib模型文件、h5权重文件、csv与json数据以及docx说明文档结构清晰覆盖从数据到模型再到界面的完整链路。目前已有117人学习下载适合需要完整项目方案、可运行源码与文档参考的学习者使用。1. 从一份天气预测大作业说起Python 机器学习到底能做出什么每年期末季总有一批人对着「天气预测」这四个字发愁。选题看起来简单数据好像也找得到但真动手才发现拿到的气象数据字段一大堆时间戳、温度、湿度、气压、风速、风向混在一起缺失值和异常值藏在各个角落想用 LSTM 做时间序列预测代码跑起来了 loss 却不降想加个可视化大屏ECharts 和 Matplotlib 的图拼在一起风格割裂。这份「Python 机器学习天气预测与可视化源码全套数据文档说明」瞄准的就是这个场景——它不是一个玩具 demo而是一套从数据清洗、特征工程、模型训练到可视化呈现的完整链路。适合正在做机器学习期末大作业的本科生、想用 LSTM 练手时间序列预测的入门者以及需要一份可复现基线方案的从业者。接下来我会按真实落地顺序把这条链路拆开讲清楚数据怎么处理、模型怎么选、参数怎么调、可视化怎么做、坑在哪里。2. 数据准备与特征工程天气预测的地基怎么打2.1 气象数据的典型结构与清洗策略天气预测用的原始数据通常来自公开气象数据集常见字段包括时间戳date/time、温度temperature、相对湿度humidity、气压pressure、风速wind_speed、风向wind_direction、降水量precipitation、能见度visibility等。不同来源的字段命名和单位可能不同第一步永远是统一格式。我一般会先把数据读进来做三件事统一时间索引、处理缺失值、检测异常值。下面是一个典型的清洗脚本import pandas as pd import numpy as np # 读取原始气象数据假设是 CSV 格式 df pd.read_csv(weather_raw.csv) # 统一时间列并设为索引 df[datetime] pd.to_datetime(df[datetime]) df df.set_index(datetime).sort_index() # 按小时重采样避免时间间隔不均匀 df df.resample(1h).mean() # 缺失值处理温度用线性插值湿度用前向填充 df[temperature] df[temperature].interpolate(methodlinear) df[humidity] df[humidity].ffill() # 异常值检测温度超出 -50~60 摄氏度的视为异常 df.loc[df[temperature] 60, temperature] np.nan df.loc[df[temperature] -50, temperature] np.nan df[temperature] df[temperature].interpolate(methodlinear) print(df.describe())这段代码的逻辑是先把时间列转成标准 datetime 并排序保证后续时间序列操作不会乱序然后用resample(1h).mean()把数据统一到小时粒度因为很多气象站原始数据是分钟级或不定间隔的缺失值方面温度这种连续变量用线性插值更合理湿度用前向填充可以保留最近的有效观测异常值先置为 NaN 再插值避免极端错误值污染模型。参数说明resample的频率可以根据你的预测目标调整如果做日级预测就用1D插值方法linear适合变化平缓的变量time方法适合时间间隔不均匀的场景。注意不要用均值填充温度那会抹掉日变化规律。2.2 时间序列特征构造从原始字段到模型输入LSTM 这类时间序列模型不会直接吃原始字段需要构造滑动窗口特征。常见做法是用过去 N 个小时的温度、湿度、气压等作为输入预测未来 M 个小时的温度。下面是一个构造监督学习样本的函数def create_sequences(data, input_len24, output_len1, target_coltemperature): data: 清洗后的 DataFrame input_len: 输入窗口长度小时 output_len: 预测步长小时 target_col: 预测目标列 X, y [], [] values data.values target_idx data.columns.get_loc(target_col) for i in range(len(values) - input_len - output_len 1): X.append(values[i : i input_len]) y.append(values[i input_len : i input_len output_len, target_idx]) return np.array(X), np.array(y) # 只保留数值列并做归一化 feature_cols [temperature, humidity, pressure, wind_speed] data_norm (df[feature_cols] - df[feature_cols].mean()) / df[feature_cols].std() X, y create_sequences(data_norm, input_len24, output_len1) print(X.shape, y.shape) # 例如 (8760, 24, 4) 和 (8760, 1)逻辑说明create_sequences把时间序列切成一个个窗口每个窗口包含input_len个时间步每个时间步有多个特征标签是窗口之后output_len步的目标值。归一化用 z-score因为 LSTM 对输入尺度敏感不做归一化容易导致梯度爆炸或收敛慢。参数说明input_len24表示用过去 24 小时预测下一小时这个值可以根据数据周期调整——如果温度有明显日周期24 是合理起点output_len1是单步预测如果想做多步预测可以改成 6 或 12。注意归一化要用训练集的均值和方差验证集和测试集用同样的参数变换否则会引入未来信息。3. LSTM 模型搭建与训练从 Keras 到 PyTorch 的选型与调参3.1 框架选型Keras 快速验证 vs PyTorch 灵活调试做天气预测的 LSTM常见框架就两个KerasTensorFlow 后端和 PyTorch。Keras 的优势是代码短、上手快适合期末大作业这种时间紧的场景PyTorch 的优势是调试灵活、自定义层方便适合想深入理解 LSTM 内部机制的。我一般会先用 Keras 搭一个基线确认数据管道没问题再决定要不要转 PyTorch。Keras 版本的核心代码from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout from tensorflow.keras.callbacks import EarlyStopping model Sequential([ LSTM(64, return_sequencesTrue, input_shape(24, 4)), Dropout(0.2), LSTM(32, return_sequencesFalse), Dropout(0.2), Dense(1) ]) model.compile(optimizeradam, lossmse, metrics[mae]) early_stop EarlyStopping(monitorval_loss, patience5, restore_best_weightsTrue) history model.fit( X_train, y_train, validation_split0.2, epochs100, batch_size32, callbacks[early_stop], verbose1 )逻辑说明第一层 LSTM 设return_sequencesTrue把每个时间步的隐藏状态传给下一层第二层 LSTM 设return_sequencesFalse只输出最后一个时间步的状态Dropout 放在 LSTM 之后可以缓解过拟合最后 Dense(1) 输出预测值。EarlyStopping 监控验证集 loss连续 5 个 epoch 不下降就停止并恢复最佳权重。参数说明LSTM(64)和LSTM(32)是隐藏单元数数据量小的时候可以降到 32/16数据量大可以升到 128/64Dropout(0.2)是丢弃率过拟合严重时调到 0.3~0.5batch_size32是常见起点显存不够就降到 16patience5可以根据训练曲线调整波动大就设 8~10。3.2 训练过程中的关键监控指标与调参方向训练 LSTM 做天气预测不能只看 loss 降没降还要看验证集和训练集的差距。如果训练 loss 一直降但验证 loss 先降后升说明过拟合了如果两个都降不下去说明欠拟合或者数据有问题。我一般会画三条曲线训练 loss、验证 loss、验证 MAE。MAE 比 MSE 更直观因为它的单位和温度一样。下面是一个监控脚本import matplotlib.pyplot as plt fig, axes plt.subplots(1, 2, figsize(12, 4)) axes[0].plot(history.history[loss], labeltrain_loss) axes[0].plot(history.history[val_loss], labelval_loss) axes[0].set_title(Loss Curve) axes[0].legend() axes[1].plot(history.history[mae], labeltrain_mae) axes[1].plot(history.history[val_mae], labelval_mae) axes[1].set_title(MAE Curve) axes[1].legend() plt.tight_layout() plt.savefig(training_curve.png, dpi150)如果验证 loss 在某个 epoch 后开始上升可以降低模型复杂度减少 LSTM 层数或隐藏单元、增大 Dropout、加 L2 正则化、或者增加训练数据。如果训练 loss 下降很慢可以提高学习率但不要超过 1e-3、检查输入是否归一化、确认时间窗口是否合理。还有一个容易被忽略的点天气数据有季节性如果训练集和验证集是按时间顺序切的验证集可能落在不同季节导致验证 loss 偏高。常见做法是按时间 8:2 切分而不是随机切分。如果数据跨年最好确保每个季节都有样本。4. 可视化落地从 Matplotlib 静态图到 ECharts 交互大屏4.1 预测结果对比图让误差一眼可见模型训完之后最直观的验证方式是把预测值和真实值画在同一张图上。下面是一个对比图脚本import matplotlib.pyplot as plt import matplotlib.dates as mdates # 反归一化 y_pred_inv y_pred * y_std y_mean y_true_inv y_test * y_std y_mean plt.figure(figsize(14, 5)) plt.plot(dates_test, y_true_inv, labelActual, linewidth1.5) plt.plot(dates_test, y_pred_inv, labelPredicted, linewidth1.5, linestyle--) plt.xlabel(Date) plt.ylabel(Temperature (°C)) plt.title(Weather Prediction: Actual vs Predicted) plt.legend() plt.gca().xaxis.set_major_formatter(mdates.DateFormatter(%m-%d)) plt.gca().xaxis.set_major_locator(mdates.DayLocator(interval3)) plt.tight_layout() plt.savefig(prediction_vs_actual.png, dpi150)逻辑说明反归一化是把模型输出的标准化值还原成真实温度方便肉眼判断误差linestyle--让预测线更容易和真实线区分日期格式化避免 x 轴标签重叠。参数说明figsize根据输出用途调整论文里用 (12, 4)大屏用 (16, 6)dpi150适合屏幕展示打印可以设 300。如果预测线整体偏高或偏低检查归一化参数是否用错如果预测线比真实线平滑很多说明模型欠拟合需要增加隐藏单元或训练轮数。4.2 用 ECharts 做交互式可视化大屏如果大作业要求「可视化大屏」Matplotlib 的静态图就不够了。ECharts 是常见选择可以做出可缩放、可悬停查看数值的交互图表。下面是一个最小可用的 HTML 模板!DOCTYPE html html head meta charsetutf-8 script srchttps://cdn.jsdelivr.net/npm/echarts5/dist/echarts.min.js/script /head body div idmain stylewidth: 100%; height: 500px;/div script var chart echarts.init(document.getElementById(main)); var option { title: { text: 天气预测趋势 }, tooltip: { trigger: axis }, legend: { data: [实际温度, 预测温度] }, xAxis: { type: category, data: dates }, yAxis: { type: value, name: 温度 (°C) }, series: [ { name: 实际温度, type: line, data: actual }, { name: 预测温度, type: line, data: predicted, lineStyle: { type: dashed } } ] }; chart.setOption(option); /script /body /html逻辑说明dates、actual、predicted是从 Python 导出的 JSON 数组可以用json.dump写进 HTML 或者通过接口传给前端tooltip开启悬停提示legend允许切换显示lineStyle的虚线样式和 Matplotlib 保持一致。参数说明ECharts 的 CDN 地址建议用固定版本号避免版本更新导致 API 变化如果数据量大开启sampling: lttb降采样大屏场景可以加dataZoom组件让用户拖动时间轴。注意ECharts 的 CDN 引用需要网络环境支持如果部署在离线环境需要把 echarts.min.js 下载到本地。5. 避坑与排查天气预测项目里最容易翻车的 5 个地方5.1 数据泄漏归一化用了全量数据现象模型在验证集上表现异常好但换一批数据预测就崩了。 原因归一化时用了整个数据集的均值和方差验证集的信息泄漏到了训练过程。 解决先切分训练集和测试集只用训练集的均值和方差做归一化测试集用同样的参数变换。5.2 时间顺序打乱随机切分导致验证集失真现象验证 loss 比训练 loss 还低或者波动极大。 原因用train_test_split随机切分时间序列验证集里混入了未来信息。 解决按时间顺序切分前 80% 做训练后 20% 做测试如果数据跨年确保每个季节都有样本。5.3 LSTM 输入形状错误三维数组搞混现象报错ValueError: Input 0 of layer lstm is incompatible。 原因LSTM 要求输入是(样本数, 时间步, 特征数)三维数组常见错误是传了二维或者把时间步和特征数搞反。 解决用X.shape确认维度input_shape(input_len, n_features)要和数据一致。5.4 预测值全是一条直线模型没学到东西现象预测曲线几乎不变MAE 和直接取均值差不多。 原因学习率太大导致梯度爆炸或者输入特征没有归一化或者 LSTM 隐藏单元太少。 解决检查 loss 曲线如果 loss 是 NaN 就降低学习率确认输入归一化把隐藏单元从 32 升到 64 或 128。5.5 可视化中文乱码Matplotlib 字体没设现象图表标题和标签里的中文变成方框。 原因Matplotlib 默认字体不支持中文。 解决在绘图前设置plt.rcParams[font.sans-serif] [SimHei]和plt.rcParams[axes.unicode_minus] FalseLinux 环境下如果没有 SimHei可以换成WenQuanYi Micro Hei。6. 进阶技巧用多步预测和误差分析把大作业做出区分度单步预测只能预测下一小时温度想让大作业更有亮点可以改成多步预测用过去 24 小时预测未来 6 小时或 12 小时。做法是把output_len从 1 改成 6模型最后一层 Dense 的输出维度也改成 6。训练时 loss 用 MSE评估时分别算每一步的 MAE画一张「预测步长 vs MAE」的曲线能直观看出误差随步长增加的速度。另一个加分项是误差分析。不要只报一个总体 MAE按时间段拆开看白天和夜间的误差有没有差异雨天和晴天的误差有没有差异下面是一个分组统计的示例import pandas as pd results pd.DataFrame({ actual: y_true_inv.flatten(), predicted: y_pred_inv.flatten(), hour: dates_test.hour, is_rainy: df.loc[dates_test, precipitation].values 0 }) results[abs_error] abs(results[actual] - results[predicted]) # 按小时统计平均绝对误差 hourly_mae results.groupby(hour)[abs_error].mean() print(hourly_mae) # 按是否下雨统计 rainy_mae results.groupby(is_rainy)[abs_error].mean() print(rainy_mae)如果发现夜间误差明显大于白天说明模型对温度日变化的捕捉不够可以加入「小时」作为额外特征或者用两个模型分别预测白天和夜间。如果雨天误差大说明降水相关的特征没用好可以加入云量、气压变化率等衍生特征。还有一个实用技巧把预测结果和真实值的残差画成直方图看误差分布是否对称。如果残差有明显偏斜说明模型系统性高估或低估可以在输出层加一个偏置修正或者对目标变量做差分再预测。我自己做这类项目最大的教训是不要一上来就堆 LSTM 层数先把数据管道和基线模型跑通确认每一步的输入输出形状和数值范围都符合预期再逐步加复杂度。很多「模型不收敛」的问题最后查出来都是数据清洗阶段埋的雷。希望帮到你。本文还有配套的精品资源点击获取
返回列表