ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Python机器学习天气预测项目源码解析:数据处理、模型训练与可视化

2026/10/3 2:50:30 拓冰建站 浏览量
Python机器学习天气预测项目源码解析:数据处理、模型训练与可视化 简介面向计算机相关专业正在完成课程设计或期末大作业的学生以及需要项目实战的 Python 学习者这套基于机器学习ML的天气预测与可视化资源提供了完整可运行的实践样例。压缩包共 24 个文件大小 1.42MB包含 4 个 Python 脚本、4 个 CSV 数据集、12 张效果展示图、1 份 HTML 说明页和 1 个模型文件脚本覆盖数据获取、清理、建模、预测与可视化五大核心环节GetData.py 采集天气数据ProcessData.py 完成清洗与特征转换GetModel.py 训练模型main.py 串联输出天气趋势。CSV 数据包含训练集、验证集与测试集Model.pkl 保存已训练模型12 张图片直观展示预测拟合和多种气象图表readme 提供详细项目说明目录结构清晰便于快速定位。源码经严格调试下载后即可运行适合快速完成课程设计或复现完整的机器学习流程也可将思路迁移至其他时间序列预测任务。目前已有 249 人学习/下载。1. 天气预测大作业源码值不值得跑先看它解决什么问题你从课程群或网盘里下载到的“基于python机器学习(ml)的天气预测和天气可视化源码全部数据95分以上大作业.zip”本质是一个把数据清洗、特征构造、模型训练、结果可视化完整串起来的小项目。对正在学 python 和机器学习的人来说它比零散的 python 教程更接近真实工作流给你一份历史气象数据让你预测明天温度并把预测效果画成图。对准备交期末大作业的人来说它意味着一个可以复现、改参数、换数据集的起点。我的建议是不要把它当黑匣子直接交上去先拆开看三个问题数据是什么格式、模型预测什么目标、图表展示了哪些结论。搞懂这三件事后面所有步骤都不会走歪。2. 天气数据准备先别运行 main.py把数据格式和缺失值理清楚从网上下载的天气预测项目十个里有八个死在数据读取这一步。很多“免费python源码大全”里挂着的天气预测压缩包解压后看着很完整但直接运行 main.py 跑出来的不是 KeyError 就是 UnicodeDecodeError。原因不外乎列名对不上、编码不是 UTF-8、日期列没有解析成时间类型。这个标题里写了“全部数据”意味着数据量不是问题问题是你是否真正了解这份数据的结构。下面三步是拿到数据后最优先做的做完再谈模型。2.1 数据格式识别与缺失值处理先解决读不进来的问题天气数据最常见的存储格式是 CSV列名要么是 date、temperature_max、temperature_min、humidity、pressure、wind_speed 这类英文要么是带上中文表头的“日期、最高温度、最低温度、湿度、气压、风向”。第一步永远是 df.head() 和 df.info()确认列名、类型和缺失量。import pandas as pd # 默认按 utf-8 读如果报错就改成 encodinggbk 或 encodinggb18030 df pd.read_csv(data/weather.csv, encodingutf-8, parse_dates[date]) print(df.head(5)) print(df.info()) # 看一下哪些列有缺失缺失量有多大 missing df.isnull().sum() print(missing[missing 0]) # 数值列用前向填充天气文本列用众数填充 num_cols [temperature_max, temperature_min, humidity, pressure, wind_speed] for col in num_cols: if col in df.columns: df[col] df[col].ffill() if weather_condition in df.columns: df[weather_condition] df[weather_condition].fillna(晴)这段代码的逻辑是先用 pandas 把 CSV 读进来parse_dates[date] 会把日期列转成 datetime 类型这是后面所有时间特征的基础。ffill() 是前向填充适合气象数据连续缺失的情况——昨天缺失的温度用前天补上比直接用均值填充更符合天气的惯性。weather_condition 是文本列缺失时填“晴”是最稳妥的方案因为大多数天气数据集里晴天占比最高。要注意的是ffill 会把文件开头的缺失值留在那儿所以 df.info() 里如果发现前面几行还有 NaN需要用 dropna() 删掉或者把填充方向改成 bfill() 在开头用后一个值补。读进来之后还要做一次脏数据检查。常见的有两类一类是重复日期比如同一天出现两行这会让 time shift 序列错位另一类是物理上不可能的值比如温度达到 70℃、湿度大于 100 或小于 0。重复日期用 drop_duplicates(subset[date]) 处理异常值可以按列做上下限截断也可以在训练时直接当作缺失值填充。2.2 日期特征与滞后特征让模型“看到”时间原始日期列是 datetime 类型不能直接丢给线性模型。你需要把它拆成年、月、日、星期几否则模型只能把它当数值或字符串处理。对天气预测来说真正影响预测效果的是滞后特征今天的最高温大概率接近昨天的最高温过去三天的平均湿度决定未来会不会下雨。所以构造滞后特征是比调模型参数更重要的提升手段。# 必须先按时间排序否则 shift 拿到的可能是“未来”或乱序数据 df df.sort_values(date).reset_index(dropTrue) # 日期特征模型能学到月度趋势和星期规律 df[year] df[date].dt.year df[month] df[date].dt.month df[day] df[date].dt.day df[weekday] df[date].dt.weekday # 滞后特征预测当天最高温时把前一天的最高温、最低温、湿度、气压作为输入 for col in [temperature_max, temperature_min, humidity, pressure]: df[f{col}_lag1] df[col].shift(1) df[f{col}_lag2] df[col].shift(2) # 滚动平均过去 3 天最高温的均值平滑短期波动 df[temp_max_rolling3] df[temperature_max].rolling(window3).mean() # 删除头部因为滞后和滚动平均产生的 NaN df df.dropna().reset_index(dropTrue)参数说明shift(1) 代表取上一条记录的值shift(2) 取上两条。如果数据是按天记录shift(1) 就是昨天shift(2) 是前天。rolling(window3).mean() 计算的是包含当天在内最近 3 天的平均值。这里有一个容易忽略的细节如果你只想用“过去”的信息预测“今天”那么 rolling(3) 里包含今天的 temperature_max 其实是不合理的更严格的做法是先把今天的数据删掉或者用 shift(1).rolling(3)。写成 df[temperature_max].shift(1).rolling(3).mean() 才能完全避开当天信息。很多源码在这里偷懒导致验证集分数虚高。滞后阶数怎么定我的经验是数据量在 300 行以内lag1 和 lag2 足够有 3 年以上日数据可以尝试 lag7 做“上周同期”特征比如上周二的温度对本周二的温度有参考价值。滞后特征不是越多越好每多一列都会增加过拟合风险还会让时间序列交叉验证的“干净窗口”变短。2.3 训练集与测试集按时间切分别用随机切分天气预测是时间序列任务如果还是用 sklearn 默认的 train_test_split 随机打乱模型就会在训练时见到未来数据。举个例子训练集里包含了 1 月 5 日测试集里随机抽到 1 月 4 日模型认得出相邻几天的温度模式验证 R2 高得离谱但真正去预测未来时立刻失效。正确的切分方法是按时间顺序前 80% 训练后 20% 验证。# 按位置切分保持时间顺序 split_idx int(len(df) * 0.8) train_df df.iloc[:split_idx].reset_index(dropTrue) test_df df.iloc[split_idx:].reset_index(dropTrue) feature_cols [ month, day, weekday, temperature_max_lag1, temperature_min_lag1, humidity_lag1, pressure_lag1, temperature_max_lag2, humidity_lag2, temp_max_rolling3 ] target_col temperature_max X_train train_df[feature_cols].values y_train train_df[target_col].values X_test test_df[feature_cols].values y_test test_df[target_col].values如果你在压缩包里看到代码里直接写 from sklearn.model_selection import train_test_split; train_test_split(X, y, test_size0.2)基本可以断定这份源码的验证分数有水分。改成分段切分之后评分才会接近真实水平。对于调参阶段的交叉验证我会用 TimeSeriesSplit 而不是 KFold原因是一样的KFold 会把未来的样本混进训练集TimeSeriesSplit 每次都在训练集后面加一段新数据符合时间序列的逻辑。from sklearn.model_selection import TimeSeriesSplit tscv TimeSeriesSplit(n_splits5) for train_index, val_index in tscv.split(X_train): print(f训练样本 {len(train_index)} 条验证样本 {len(val_index)} 条)参数说明n_splits5 表示做 5 次前向验证第一次用前 1/5 训练第二次用前 2/5依此类推。这样每次验证都只用过去预测未来得到的分数才是可信的。到这里数据部分已经准备好。特征列里包含离散的 month、day、weekday也包含连续的滞后温度和湿度。这里没有做标准化因为后面的随机森林和 XGBoost 都是基于树模型对量纲不敏感如果你换用线性回归或神经网络就必须在切分之后用训练集的均值和标准差做归一化避免测试集信息提前进入训练。3. 机器学习模型怎么选先定任务再选算法和参数数据准备好了下一步就是选择机器学习算法。很多人上来就调 XGBoost结果特征没构造对精度照样上不去。这个项目里“天气预测”包含两个不同的任务预测“最高温度”是回归预测“明天是否下雨”是分类。如果只做其中一个大作业会显得单薄两个都做再用多张图表展示结果就符合“95 分以上大作业”的体量。下面按照从简单到复杂的顺序把选型和训练流程拆开。3.1 先定任务回归、分类还是时间序列在动手训练之前你要先明确模型输出的到底是什么。最高温、最低温、湿度这些连续值输出是一个实数属于回归任务评估指标用 MAE、RMSE 和 R2。天气状况晴、雨、阴、雪是离散标签属于分类任务评估指标用准确率、F1 分数和混淆矩阵。如果你要预测的是“未来七天的温度曲线”那就变成时间序列预测可以在回归基础上加滚动预测。课程大作业里最常见的组合是“温度预测用回归 降雨预测用分类”因为既能展示机器学习算法又能画两种不同类型的图。3.2 模型对比线性回归、随机森林、XGBoost 怎么选对这份天气数据我的建议是做三档对比先用线性回归作为 baseline再用随机森林作为主力模型最后尝试 XGBoost 争取提升。为什么这样排线性回归训练快、可解释性强能让老师一眼看出“特征和预测值的基本关系”随机森林几乎不需要对特征做太复杂的预处理抗过拟合效果不错适合 300~3000 行的气象数据XGBoost 精度上限更高但参数多容易过拟合而且如果环境里没有 xgboost 库安装和版本兼容又会花掉不少时间。模型优点缺点在这个项目里的定位线性回归稳定、可解释对非线性关系拟合差baseline必须跑随机森林抗过拟合、不用标准化预测值不会超出训练范围主力XGBoost精度高、有正则化参数多、需要额外安装加分项LSTM能建模长期依赖需要序列样本、训练慢不推荐课程作业使用我用过的项目里随机森林基本上能把温度预测的 R2 做到 0.85 左右XGBoost 能再提升 0.02~0.05。如果数据量只有几十行两个模型差别不大干脆选随机森林少一个包就少一个坑。3.3 训练与评估核心代码与参数说明训练随机森林回归器只需要十行代码。关键在于参数要合理不能全用默认值。from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score import numpy as np model_rf RandomForestRegressor( n_estimators200, max_depth8, min_samples_leaf5, n_jobs-1, random_state42 ) model_rf.fit(X_train, y_train) y_pred_rf model_rf.predict(X_test) print(fMAE {mean_absolute_error(y_test, y_pred_rf):.2f} ℃) print(fRMSE {np.sqrt(mean_squared_error(y_test, y_pred_rf)):.2f} ℃) print(fR2 {r2_score(y_test, y_pred_rf):.3f})参数说明n_estimators200 是树的数量太少会欠拟合太多训练变慢200 是折中max_depth8 限制每棵树的最大深度默认值不限制容易在少量数据上过拟合min_samples_leaf5 表示叶子节点至少要有 5 个样本防止树把噪声也学进去n_jobs-1 让所有 CPU 核心参与训练。random_state42 保证结果可复现交作业时老师能跑出和你报告里一致的分数。评估时看三个指标MAE 告诉你平均偏差几度RMSE 对大的偏差更敏感R2 是老师最常看的分数0.85 以上就算不错。如果 R2 在 0.7 以下先别急着换模型回头检查滞后特征和切分方式大概率是信息泄露的反向问题——特征没构造够。3.4 调参与时间序列交叉验证让分数可信地涨上去如果要写在报告里建议用 GridSearchCV 配合 TimeSeriesSplit 调一遍主要参数。注意这里的 cv 参数不能填 KFold。from sklearn.model_selection import GridSearchCV, TimeSeriesSplit param_grid { n_estimators: [100, 200, 300], max_depth: [6, 8, 10, 12], min_samples_leaf: [3, 5, 7] } tscv TimeSeriesSplit(n_splits4) grid GridSearchCV( RandomForestRegressor(random_state42, n_jobs-1), param_grid, cvtscv, scoringr2, verbose0 ) grid.fit(X_train, y_train) print(grid.best_params_) print(grid.best_score_)GridSearchCV 会遍历 param_grid 里的组合在每一折上训练并验证cvtscv 是关键它保证每一折都是“过去训练、未来验证”。best_params_ 是得分最高的一组参数best_score_ 是交叉验证平均 R2。这里有一个很容易犯的错误GridSearchCV 只对训练集又做了一次内部切分所以不要再用 X_test 去参与调参只能最后评估一次否则测试集信息又混进去了。调参后的随机森林再加上 XGBoosttry: from xgboost import XGBRegressor model_xgb XGBRegressor( n_estimators300, learning_rate0.05, max_depth5, subsample0.8, colsample_bytree0.8, random_state42 ) model_xgb.fit(X_train, y_train) y_pred_xgb model_xgb.predict(X_test) print(fXGBoost R2 {r2_score(y_test, y_pred_xgb):.3f}) except ImportError: print(未安装 xgboost跳过对比)XGBoost 常用的参数和随机森林含义不完全一样。learning_rate0.05 是每棵树的贡献权重学得太快容易过拟合subsample0.8 表示每轮只用 80% 的样本来训练类似随机森林的抽样colsample_bytree0.8 表示每棵树只用 80% 的特征。这些参数组合起来能有效压制过拟合。如果发现 XGBoost 在验证集上的分数明显低于随机森林优先把学习率调低比如 0.03并把 n_estimators 提到 500。特征重要性也是报告里的常见加分点。随机森林训练完可以直接读取 feature_importances_排序后你会发现 lag1 特征几乎总是排在最前面这说明天气预测里“昨天的值”比“月份”更有信息量。4. 天气可视化把预测结果用四张图画清楚模型输出了一堆数字老师要的不是数字而是结论。天气可视化的目标是把真实值、预测值、特征关系用图表讲清楚。我一般会固定输出四类图预测对比折线图、残差散点图、特征相关性热力图、天气状况分布图。前三张用 Matplotlib 和 Seaborn 就能完成最后一张可以升级成 Pyecharts 的交互日历图。图表质量直接影响大作业观感下面按顺序说。4.1 用 Matplotlib 画预测值与真实值折线图折线图是展示回归效果最直观的图。横轴是日期纵轴是温度画两条线一条真实值一条预测值。import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False plt.figure(figsize(14, 5)) plt.plot(test_df[date], y_test, label真实最高温, color#333333, linewidth1.5) plt.plot(test_df[date], y_pred_rf, label预测最高温, color#e67e22, linewidth1.5, linestyle--) plt.title(随机森林预测最高温度测试集表现) plt.xlabel(日期) plt.ylabel(温度℃) plt.legend() plt.grid(alpha0.3) plt.tight_layout() plt.savefig(visual/温度预测对比图.png, dpi150) plt.show()逻辑说明先把 Matplotlib 的默认字体改成 SimHei否则图里中文会变成方块figsize(14, 5) 把图拉长压扁折线在横向上更舒展linewidth 设成 1.5既清楚又不至于太粗linestyle-- 让预测线有区分度。savefig 里的 dpi150 是为了保证放大后不糊课程报告里需要打印的话可以提到 200。如果系统里没有 SimHei可以换成 Noto Sans CJK SC 或 Microsoft YaHei这取决于你的操作系统。4.2 用 Seaborn 画残差散点图和相关性热力图残差是真实值减预测值。残差随机分布在 0 附近说明模型没系统偏差如果残差在高温段明显偏大说明模型对极端温度拟合不好这也是报告里值得写的一句分析。import seaborn as sns import pandas as pd residual y_test - y_pred_rf plt.figure(figsize(14, 4)) plt.scatter(range(len(residual)), residual, s12, alpha0.5, color#c0392b) plt.axhline(y0, color#333333, linewidth0.8) plt.title(测试集残差分布) plt.xlabel(样本序号按时间排序) plt.ylabel(真实值 - 预测值℃) plt.savefig(visual/残差图.png, dpi150) plt.show()这里是散点图而不是线图因为样本之间没有连续关系。点大小 s12、透明度 alpha0.5主要是防止点太密变成一团黑。接着用 Seaborn 画特征相关性热力图这一步能回答“哪些特征对温度影响最大”。# 从待训练的数据里取一列特征做相关性分析 corr_df df[[temperature_max, temperature_max_lag1, temperature_min_lag1, humidity_lag1, pressure_lag1, month, weekday]].copy() plt.figure(figsize(9, 7)) sns.heatmap(corr_df.corr(), annotTrue, fmt.2f, cmapcoolwarm, cbarTrue) plt.title(特征相关系数热力图) plt.savefig(visual/相关性热力图.png, dpi150) plt.show()annotTrue 会把相关系数数值直接标在格子里fmt.2f 保留两位小数cmapcoolwarm 用红蓝渐变色一眼就能看出正相关还是负相关。你会看到 temperature_max 和 temperature_max_lag1 的相关系数通常超过 0.8这正好验证了滞后特征的必要性。4.3 用 Pyecharts 生成可交互 HTML 图如果想让大作业看起来更完整可以加一张 Pyecharts 的日历图或仪表盘。温度日历图能在一个页面里展示全年的温度分布鼠标悬停能看到具体日期和数值。from pyecharts import options as opts from pyecharts.charts import Calendar calendar ( Calendar() .add( series_name最高温度, yaxis_data[[str(d), v] for d, v in zip(df[date], df[temperature_max])], calendar_optsopts.CalendarOpts(range_[2023-01-01, 2023-12-31]), ) .set_global_opts( title_optsopts.TitleOpts(title2023 年最高温度日历图), visualmap_optsopts.VisualMapOpts(max_40, min_-10, orienthorizontal) ) ) calendar.render(visual/温度日历图.html)Pyecharts 的图表会渲染成一个 HTML 文件render 之后用浏览器打开不需要在 Jupyter 里内联显示。visualmap_opts 控制右侧颜色条的范围min_-10、max_40 要根据你的数据范围调整不然颜色映射会失真。要注意 Pyecharts 的版本差异我用的是 2.x 的 API1.x 的导入方式完全不同如果运行报错先检查 pyecharts 版本。4.4 图表输出规范大作业拿分的隐藏细节很多人的代码能跑但图表一看就没花心思。这里有几个低成本改进第一所有图统一命名比如“温度预测对比图.png”“残差图.png”“相关性热力图.png”别出现 figure_1.png 这种第二每张图标题都要带具体信息比如“随机森林预测最高温度测试集表现”而不是“result”第三坐标轴必须带单位温度写 ℃湿度写 %日期格式写 2023-01-01第四图例位置统一放在右上或图内空白处。这些细节在老师眼里就是“专业感”的来源也是源码里“95 分以上大作业”标题里最值钱的部分。5. 避坑排查天气预测源码最容易翻车的 5 个地方这一章写的是我在复现类似天气预测项目时真实遇到过的坑。每一条都是“现象 → 原因 → 解决”的结构希望能帮你把踩坑时间从一下午压缩到十分钟。5.1 中文乱码图标题变成方块或问号现象代码跑完Matplotlib 弹出的窗口里标题、图例全部显示成方块□或者保存成 PNG 后中文是乱码。原因Matplotlib 默认字体是 DejaVu Sans不支持中文字符。这是所有 Python 可视化项目都会遇到的经典问题不是你的代码逻辑错了。解决在导入 Matplotlib 后立刻设置字体plt.rcParams[font.sans-serif] [SimHei, Noto Sans CJK SC, Microsoft YaHei] plt.rcParams[axes.unicode_minus] Falseaxes.unicode_minus 是另一个容易漏的点它解决的是坐标轴负号显示成方块的问题。如果系统里没有这些字体先用 plt.rcParams[font.sans-serif] 查看可用字体或者下载一个开源中文字体放到系统字体目录里。这条经验几乎适用于所有 Python 数据分析项目不只是天气预测。5.2 CSV 编码错误读文件报 UnicodeDecodeError现象pd.read_csv(data/weather.csv) 报错 UnicodeDecodeError: utf-8 codec cant decode byte xxx。原因数据文件是用 Excel 或旧版气象站软件导出的编码是 GBK/GB18030不是 UTF-8。解决读文件时指定编码df pd.read_csv(data/weather.csv, encodinggb18030)如果仍然不行先尝试 encodinggbk再不行就用 encodinglatin1 读进来之后单独处理中文列。这里有个技巧用 with open(data/weather.csv, rb) as f: print(f.read(100)) 打印前 100 个字节能看到到底是哪种编码两三分钟就能定位不用一个个试。5.3 信息泄露训练分数虚高验证分数崩盘现象交叉验证 R2 高达 0.95但把训练好的模型拿去做未来一天的预测误差非常大几乎等于乱猜。原因常见两个。一是切分用了随机 train_test_split模型见过未来数据二是构造滞后特征时没有先排序shift 拿到的是乱序后的“前后行”。后者比前者更隐蔽。解决先 df df.sort_values(date) 再 shift切分用 df.iloc[:split_idx] 而不是随机打乱。改完之后分数会降到合理范围这很正常宁可要一个诚实低分不要一个虚假高分。检查方法是打印 train_df 的最大日期和 test_df 的最小日期确认验证集日期严格晚于训练集。# 信息泄露快速自检 print(训练集截止日期, train_df[date].max()) print(测试集起始日期, test_df[date].min()) assert test_df[date].min() train_df[date].max(), 切分异常测试集出现了早于训练集的数据这段断言代码可以在训练前跑一次如果数据顺序被意外打乱它会直接抛出异常提醒你。我第一次做这个项目时训练集 R2 到了 0.95心理美滋滋结果验证集一测只有 0.6后来才发现是随机切分的问题。改完切分方式之后分数降到 0.86但那个分数才是真实可用的。5.4 预测未来一周时误差越来越大现象模型单步预测效果不错但用 predict 直接预测未来第 2 天、第 3 天时温度预测值逐渐偏离甚至出现“预测温度一直降”的情况。原因模型训练时使用的是真实滞后特征而实际预测未来时前一天的真实值是不存在的。如果直接把 NaN 或 0 填进去预测自然越来越乱。这是递归预测的误差累积。解决写一个滚动预测循环把上一步的预测值作为下一步的滞后特征。这类问题的核心不是模型而是输入特征的回填方式。简单框架是这样的for step in range(7): pred model.predict([current_features])[0] future.append(pred) # 更新 current_features预测值进入 lag1 位置旧 lag1 移到 lag2 current_features[lag1_index] pred current_features[lag2_index] old_lag1完整的可运行代码放在下一章展开。这里先记住一个原则预测未来 K 步必须循环 K 次每次都要把上一步的输出拼回特征向量。5.5 Pyecharts 和 Matplotlib 环境冲突现象Pyecharts 画的图在浏览器里打开是一片空白或者报错 ModuleNotFoundError: No module named pyecharts还有明明装了 pyecharts但 from pyecharts.charts import Calendar 报错。原因Pyecharts 1.x 和 2.x 的导入路径完全不一样很多旧教程还在教你 from pyecharts import Bar这在 2.x 里已经废了。另外如果是在 Jupyter Notebook 里运行Pyecharts 默认输出到 notebook 内联模式可能被某些安全设置拦掉。解决统一使用新版 APIfrom pyecharts.charts import Calendar并调用 .render(xxx.html) 输出到文件。如果一定要在 Notebook 里显示需要 from pyecharts.globals import CurrentConfig, NotebookType 之类的前置设置不如直接开 HTML 省心。检查版本用 pip show pyecharts2.0 以上基本都是这样。如果 Matplotlib 和 Pyecharts 同时使用建议两个库的导入顺序固定避免 Matplotlib 后端切换干扰尤其是 Linux 服务器上用 Agg 后端时Pyecharts 反而没问题因为它是独立渲染的 HTML。6. 进阶给天气预测加一个滚动预测让大作业体现真正的预测能力前面所有内容都是“单步预测”也就是用昨天预测今天。但实际使用中老师更喜欢看到你能预测未来 3 天或 7 天的温度曲线。滚动预测的思想很简单预测出第 N 天的值之后把预测值当作第 N1 天的滞后特征而不是等真实值。from datetime import timedelta # 为了展示滚动逻辑重新定义一个简化特征集 lag_feats [temperature_max_lag1, humidity_lag1, pressure_lag1, temperature_max_lag2] date_feats [month, day, weekday] X_train_r train_df[date_feats lag_feats].values X_test_r test_df[date_feats lag_feats].values model_roll RandomForestRegressor(n_estimators200, max_depth8, min_samples_leaf5, random_state42) model_roll.fit(X_train_r, y_train) # 从测试集最后一条记录的真实滞后值启动 current [ test_df[temperature_max_lag1].iloc[-1], test_df[humidity_lag1].iloc[-1], test_df[pressure_lag1].iloc[-1], test_df[temperature_max_lag2].iloc[-1] ] last_date test_df[date].iloc[-1] future_pred [] d last_date for _ in range(7): d d timedelta(days1) feats [[d.month, d.day, d.weekday()] current] pred model_roll.predict(feats)[0] future_pred.append(pred) # 预测出的最高温进入 lag1旧 lag1 变成 lag2湿度和气压用最近的真实值近似 current [pred, current[1], current[2], current[0]]这段代码的关键是 current 列表的更新顺序预测值先进入 lag1 位置原来的 lag1 退到 lag2温度项按这个规则滚动。湿度和气压的滞后值沿用最后已知值这是简化处理真正多变量滚动预测需要对每个特征各建一个模型但课程作业里用这个近似已经能说明问题。滚动预测的误差分析同样重要。把 7 天的预测结果与真实值画在同一张图上你会发现随着步数增加误差先小后大这正是递归预测的典型特征。在报告里写一句“前 3 日预测误差在 2℃ 以内第 7 日误差扩大到 4℃后续可以考虑直接多步预测或序列模型”会让你的分析深度明显高出普通大作业。我第一次做这个项目时就吃过亏看着训练集 R2 0.95 以为稳了结果在验证集上只有 0.6后来才发现是随机切分和 shift 顺序两个问题叠加。改完这两个坑加上滚动预测分数才真正可信。这个教训让我后来做任何时间序列项目都先检查数据顺序再检查切分方式。希望帮到你。本文还有配套的精品资源点击获取