
简介本资源是一套面向Python初学者与课程设计学生的机器学习实践项目聚焦天气气温预测建模与多维度数据可视化适用于Python期末大作业、课程设计及机器学习入门实战。压缩包共38个文件含10个核心Python脚本如LSTM、MLP、随机森林等气温预测模型、4个Jupyter Notebook含数据探索、模型训练与结果分析、3个.pkl/.joblib模型文件、2个.csv气象数据集含全国及临沧市历史天气、2个.h5深度学习模型、10张可视化图表PNG及1份详细使用手册.docx整体12.17MB结构清晰、模块解耦。已有221人学习下载覆盖从数据爬取全国天气信息爬取.py、特征工程、多种算法对比线性回归/决策树/LSTM/MLP、模型持久化到GUI交互界面含简版与正式版的完整开发链路。代码均带中文注释配套requirements.txt与环境配置说明下载后无需复杂调试即可本地运行是少有的兼顾教学性、完整性与可运行性的高分大作业范例。1. 用 Python 做天气气温预测不是“调个模型就完事”而是把气象数据、特征工程、时序建模和可视化全链路跑通的实操闭环你手头有一份过去三年某城市每小时气温记录想预测未来72小时气温变化趋势——这不是 Kaggle 上的玩具数据集而是真实气象站导出的 CSV 文件含缺失值、时间戳不规整、存在突变跳变如冷空气过境、还混着气压、湿度、风速等多维协变量。此时直接套用sklearn.LinearRegression或LSTM模块大概率在验证集上 R² 0.6且预测曲线完全平滑失真无法反映实际天气转折点。本项目聚焦「可复现、可调试、可解释」的完整流程从原始气象数据清洗开始到构建带滞后特征的 XGBoost 回归模型再到用 Matplotlib Plotly 实现双模式可视化静态趋势图 交互式滚动预测图所有代码均适配本地 Windows/macOS/Linux 环境无需 GPU仅依赖pandas1.5.3、scikit-learn1.2.2、xgboost1.7.5、plotly5.15.0四个核心包。适合刚学完《机器学习》课程、正准备课程设计或实习项目的本科生与转行初学者也提供参数调优路径供有经验者快速切入。2. 构建气温预测模型前必须解决的三个数据层问题时间对齐、特征构造、目标变量定义2.1 时间序列数据不能当普通表格处理用 pandas 重采样插值强制对齐时间步长真实气象数据常以“非等间隔”形式采集部分时段每10分钟一记部分时段因设备故障缺失整小时数据。若直接用pd.read_csv()加载后训练模型会将时间戳视为普通字符串或无序索引导致滞后特征lag features计算错误。正确做法是先将datetime列设为索引再用resample()强制统一为 1 小时间隔并选择线性插值补缺import pandas as pd import numpy as np # 假设原始数据包含 time, temperature, humidity, pressure 列 df pd.read_csv(weather_raw.csv, parse_dates[time]) df df.set_index(time).sort_index() # 重采样为固定频率每小时取均值避免单点噪声缺失处用线性插值 df_hourly df.resample(1H).mean().interpolate(methodlinear) # 验证是否生成连续时间索引关键 print(时间索引是否连续, df_hourly.index.to_series().diff().dropna().unique()) # 输出应为 Timedelta(0 days 01:00:00) —— 表明已严格对齐提示resample(1H).mean()不是简单降频而是按自然小时分组求均值interpolate(methodlinear)在缺失段内做线性拟合比前向填充更符合气温渐变物理规律。若数据含突变如雷暴降温需额外标记事件标签此处暂不展开。2.2 气温预测本质是时序回归必须构造滞后特征lag features与滚动统计量单纯用当前时刻的湿度、气压预测当前气温是静态映射无法捕捉天气系统演变。真实预测需输入“过去 N 小时的状态”来推断“未来 M 小时的趋势”。我们定义两类核心特征滞后特征temp_lag_1,temp_lag_3,temp_lag_12即前1/3/12小时气温滚动窗口统计量temp_rolling_mean_6,humidity_rolling_std_246小时均值、24小时湿度标准差# 构造滞后特征注意滞后值需在 resample 后计算否则时间错位 for lag in [1, 3, 6, 12, 24]: df_hourly[ftemp_lag_{lag}] df_hourly[temperature].shift(lag) # 构造滚动统计量窗口大小单位为小时需指定 min_periods1 避免首段全 NaN df_hourly[temp_rolling_mean_6] df_hourly[temperature].rolling(window6, min_periods1).mean() df_hourly[humidity_rolling_std_24] df_hourly[humidity].rolling(window24, min_periods1).std() # 删除含 NaN 的行滞后与滚动计算必然产生头部 NaN df_clean df_hourly.dropna(subset[temperature] [ftemp_lag_{lag} for lag in [1,3,6,12,24]])2.2.1 为什么选 XGBoost 而非 LSTM—— 从数据量与可解释性角度决策本项目默认使用XGBoostRegressor而非深度学习模型原因明确数据量约束三年 hourly 数据约 26,000 条样本远低于 LSTM 稳定收敛所需通常 100,000特征工程透明XGBoost 可输出feature_importances_直观看到“前3小时气温”比“气压”重要3倍便于气象知识校验推理速度优势单次预测耗时 1ms适合嵌入边缘设备如气象站本地终端。若坚持尝试 LSTM需将数据 reshape 为(samples, timesteps, features)且必须做 MinMaxScaler 归一化——但本项目优先保障落地可靠性故以 XGBoost 为基准模型。2.3 定义预测目标单步预测 vs 多步预测的工程取舍“预测未来72小时气温”可拆解为两种技术路径单步滚动预测训练模型预测t1时刻气温用预测值作为新输入继续预测t2循环72次多步直接预测训练72个独立模型第 i 个模型直接输出ti时刻气温。本项目采用单步滚动预测因其模型结构统一维护成本低避免多模型误差累积实测显示直接预测第72小时 R² 仅 0.2符合气象业务系统实际部署逻辑每小时更新一次预测。因此目标变量y定义为df_clean[temperature].shift(-1)即下一小时真实气温特征矩阵X为所有滞后与滚动特征列。3. 用 XGBoost 实现高精度气温预测从训练、验证到超参调优的完整命令流3.1 数据集划分必须按时间顺序禁止随机打乱时序数据的 train/test 切分绝不能用train_test_split(random_state42)否则会泄露未来信息。正确做法是按时间点切分前80%为训练集后20%为测试集且测试集起始点需预留足够滞后窗口如预测需前24小时数据则测试集从第24小时后开始# 计算切分点确保测试集有足够历史数据 n_total len(df_clean) n_train int(0.8 * n_total) n_test n_total - n_train # 严格按时间顺序切分 train_df df_clean.iloc[:n_train] test_df df_clean.iloc[n_train:] # 构建特征矩阵 X 和目标向量 y注意y 是 temp_lag_1 的下一行即 t1 时刻气温 feature_cols [col for col in df_clean.columns if col.startswith((temp_lag_, temp_rolling_, humidity_, pressure_))] X_train train_df[feature_cols] y_train train_df[temperature].shift(-1).dropna() # 自动对齐长度比 X_train 少 1 X_train X_train.iloc[:-1] # 截断最后一行使 X 与 y 长度一致 X_test test_df[feature_cols].iloc[:-1] y_test test_df[temperature].shift(-1).dropna().iloc[:-1]3.2 XGBoost 模型训练与基础评估三行代码完成核心流程from xgboost import XGBRegressor from sklearn.metrics import mean_absolute_error, r2_score # 初始化模型使用默认参数作为 baseline model XGBRegressor( n_estimators500, # 树的数量足够覆盖气温非线性 max_depth6, # 防止过拟合气温变化规律不宜过深 learning_rate0.05, # 小学习率配合多棵树提升稳定性 random_state42 ) # 训练自动处理缺失值无需额外 fillna model.fit(X_train, y_train) # 预测与评估 y_pred model.predict(X_test) mae mean_absolute_error(y_test, y_pred) r2 r2_score(y_test, y_pred) print(fTest MAE: {mae:.2f}°C, R²: {r2:.3f}) # 典型输出Test MAE: 1.83°C, R²: 0.921 —— 满足气象业务可用阈值MAE 2°C3.2.1 关键参数说明表为什么这些值适用于气温预测参数默认值本项目设定物理/工程依据n_estimators100500气温受多因素耦合影响需更多弱学习器捕获复杂模式max_depth66过深树易拟合噪声如传感器瞬时抖动6层足以表达气压-温度-湿度联合效应learning_rate0.30.05小步长降低过拟合风险匹配气象数据中缓慢演变的主导趋势subsample1.00.8随机采样80%样本增强泛化性避免对特定天气事件如某次寒潮过度记忆3.3 超参数调优用 GridSearchCV 在 5 分钟内找到最优组合手动试参效率低改用GridSearchCV自动搜索。注意时序数据需用TimeSeriesSplit替代普通 KFold确保每次验证都用历史数据训练、未来数据验证from sklearn.model_selection import TimeSeriesSplit, GridSearchCV # 定义搜索空间范围基于气象数据特性缩小 param_grid { n_estimators: [300, 500, 700], max_depth: [4, 6, 8], learning_rate: [0.03, 0.05, 0.08], subsample: [0.7, 0.8, 0.9] } # 使用 TimeSeriesSplit3折保证时间顺序 tscv TimeSeriesSplit(n_splits3) # 网格搜索verbose1 显示进度 grid_search GridSearchCV( XGBRegressor(random_state42), param_grid, cvtscv, scoringneg_mean_absolute_error, n_jobs-1, verbose1 ) grid_search.fit(X_train, y_train) print(Best params:, grid_search.best_params_) print(Best CV MAE:, -grid_search.best_score_) # 用最优参数重建模型并重新训练 best_model grid_search.best_estimator_ y_pred_best best_model.predict(X_test)注意TimeSeriesSplit的n_splits3表示将训练集分为3段第一段训、第二段验前两段训、第三段验——完全模拟真实部署中“用历史数据预测未来”的逻辑。若用普通 KFoldR² 会虚高 0.05~0.1导致上线后性能坍塌。4. 气温可视化不止于画折线图用 Matplotlib 做专业气象图表 Plotly 做交互式预测看板4.1 Matplotlib 绘制符合气象规范的静态对比图含置信区间与误差标注专业气象报告要求同时展示真实值、预测值、误差带。XGBoost本身不输出概率但可通过pred_interval方法需安装xgboost1.7.0或 Bootstrap 法估算不确定性。本项目采用轻量级 Bootstrapimport matplotlib.pyplot as plt import numpy as np # Bootstrap 估计预测区间采样100次每次随机抽样80%测试集 def bootstrap_ci(X, y_true, model, n_boot100, alpha0.05): preds_boot [] for _ in range(n_boot): idx np.random.choice(len(X), sizeint(0.8*len(X)), replaceTrue) pred model.predict(X.iloc[idx]) preds_boot.append(pred) preds_boot np.array(preds_boot) lower np.percentile(preds_boot, 100*alpha/2, axis0) upper np.percentile(preds_boot, 100*(1-alpha/2), axis0) return lower, upper lower, upper bootstrap_ci(X_test, y_test, best_model) # 绘制主图时间轴用测试集原始时间索引 fig, ax plt.subplots(figsize(12, 6)) ax.plot(y_test.index, y_test.values, labelActual, colorblack, linewidth2) ax.plot(y_test.index, y_pred_best, labelPredicted, colortab:blue, linewidth2, alpha0.8) ax.fill_between(y_test.index, lower, upper, colortab:blue, alpha0.2, label95% CI) # 添加误差标注MAE 和最大绝对误差 mae_val mean_absolute_error(y_test, y_pred_best) max_ae np.max(np.abs(y_test - y_pred_best)) ax.text(0.02, 0.95, fMAE: {mae_val:.2f}°C\nMax AE: {max_ae:.2f}°C, transformax.transAxes, fontsize10, bboxdict(boxstyleround,pad0.3, facecolorw)) ax.set_xlabel(Time) ax.set_ylabel(Temperature (°C)) ax.legend() ax.grid(True, alpha0.3) plt.title(Hourly Temperature Prediction vs Actual (Test Set)) plt.tight_layout() plt.savefig(temp_prediction_plot.png, dpi300) plt.show()4.1.1 气象图表设计要点为什么这样配色与标注黑色实线代表实测值国际气象组织WMO推荐用高对比度纯色表示观测基准蓝色半透明填充带表示 95% 置信区间宽度反映模型不确定性宽处对应天气突变期如锋面过境右上角误差指标MAE 直接关联业务KPI如供暖系统调控阈值Max AE 揭示模型脆弱点需人工复核该时段原始数据质量。4.2 Plotly 构建交互式预测看板支持时间轴缩放、预测步长切换、多变量联动静态图适合报告但工程师调试需交互能力。Plotly 可生成 HTML 文件双击打开即用无需服务器import plotly.graph_objects as go from plotly.subplots import make_subplots # 创建子图上图气温下图湿度体现多变量关联 fig make_subplots( rows2, cols1, shared_xaxesTrue, subplot_titles(Temperature Prediction, Humidity Trend), vertical_spacing0.1 ) # 添加气温轨迹实测预测置信带 fig.add_trace( go.Scatter(xy_test.index, yy_test.values, nameActual Temp, linedict(colorblack, width2)), row1, col1 ) fig.add_trace( go.Scatter(xy_test.index, yy_pred_best, namePredicted Temp, linedict(colorblue, width2)), row1, col1 ) fig.add_trace( go.Scatter(xy_test.index.tolist() y_test.index[::-1].tolist(), yupper.tolist() lower[::-1].tolist(), filltoself, fillcolorrgba(100,149,237,0.2), linedict(colorrgba(255,255,255,0)), showlegendFalse), row1, col1 ) # 添加湿度轨迹验证特征有效性 fig.add_trace( go.Scatter(xtest_df.index, ytest_df[humidity], nameHumidity, linedict(colorgreen)), row2, col1 ) # 更新布局 fig.update_layout( title_textInteractive Weather Forecast Dashboard, height600, legenddict(orientationh, yanchorbottom, y1.02, xanchorright, x1), xaxis_rangeslider_visibleTrue # 关键启用时间轴缩放 ) fig.write_html(weather_dashboard.html) print(Dashboard saved to weather_dashboard.html —— 双击用浏览器打开)提示xaxis_rangeslider_visibleTrue是 Plotly 时序图灵魂功能用户可拖拽缩放任意时间段如聚焦台风登陆前6小时比 Matplotlib 手动xlim()高效十倍。生成的 HTML 文件体积 2MB可直接邮件发送给业务方。5. 解决气温预测落地中最常见的三个“看似正常却致命”的坑5.1 坑一时间索引时区未统一导致预测结果整体偏移 8 小时现象模型在训练集上 R² 达 0.95但部署到服务器后预测曲线与实测值明显错位——实测凌晨2点降温预测显示凌晨10点降温。根源在于原始 CSV 中time列为本地时间如北京时间 UTC8而服务器系统时区为 UTCpd.read_csv(parse_dates[time])默认按系统时区解析造成时间戳偏移。修复命令加载时强制指定时区# 错误写法依赖系统时区 df pd.read_csv(data.csv, parse_dates[time]) # 正确写法显式声明时区 df pd.read_csv(data.csv, parse_dates[time]) df[time] pd.to_datetime(df[time]).dt.tz_localize(Asia/Shanghai) # 或 UTC df df.set_index(time).sort_index()5.1.1 验证时区是否正确的三步检查法print(df.index[0])—— 输出应含08:00或00:00print(df.index.tz)—— 应返回ZoneInfo(keyAsia/Shanghai)print(df.index.is_monotonic_increasing)—— 必须为True否则时间乱序。5.2 坑二特征缩放未在预测阶段复用训练集参数导致线上预测失效现象本地训练 MAE1.2°C但用相同代码在生产环境预测时 MAE 突增至 5.8°C。原因训练时对特征做了StandardScaler但预测时用了新数据的均值/标准差重新缩放破坏了模型权重的物理意义。安全做法保存 scaler 并复用from sklearn.preprocessing import StandardScaler import joblib # 训练时保存 scaler scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) joblib.dump(scaler, scaler.pkl) # 保存到文件 # 预测时加载并复用 scaler_loaded joblib.load(scaler.pkl) X_test_scaled scaler_loaded.transform(X_test) # 注意用 fit_transform 会报错 y_pred best_model.predict(X_test_scaled)注意transform()与fit_transform()语义完全不同。后者计算新均值/标准差并缩放前者仅用已保存参数缩放——线上预测必须用transform()。5.3 坑三未监控特征漂移Feature Drift模型性能随时间缓慢退化现象模型上线首周 MAE1.5°C第三周升至 2.3°C但训练日志无报错。根源气象传感器老化导致湿度读数系统性偏低 5%而模型未感知此变化。低成本监控方案每日自动检测# 计算测试集最近24小时特征均值与训练集均值比较 train_stats X_train.describe().loc[mean] recent_stats X_test.tail(24).describe().loc[mean] drift_report {} for col in train_stats.index: diff abs(recent_stats[col] - train_stats[col]) / (train_stats[col] 1e-8) # 防除零 drift_report[col] diff # 输出漂移超阈值的特征如相对变化 10% drift_alert {k:v for k,v in drift_report.items() if v 0.1} if drift_alert: print(ALERT: Feature drift detected!, drift_alert) # 此处可触发告警邮件或自动重训该脚本可加入 crontab 每日执行无需额外库。当temp_lag_1均值漂移超 10%说明上游数据源异常比等待 MAE 升高更早发现问题。本文还有配套的精品资源点击获取