news 2026/10/12 20:34:15

气温预测机器学习课设全流程:数据清洗、特征工程与模型对比实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
气温预测机器学习课设全流程:数据清洗、特征工程与模型对比实战

简介:面向Python课程设计与期末大作业的机器学习综合项目,以气温预测与可视化为核心场景,覆盖数据采集、数据探索、特征处理、模型训练、效果评估与结果展示的完整流程,适合需要一份可运行、可讲解高分方案的初学者与进阶学习者。项目实现了三层MLP、LSTM、随机森林、决策树与线性回归五种回归模型,基于真实天气数据集进行系统训练与对比,实验结果表明LSTM在预测准确率和综合表现上最佳,并配套图形化用户界面(GUI)便于直观查看预测结果,操作简单、界面友好。资源包共38个文件,py源码可直接运行,ipynb记录建模与可视化过程,csv与json保存原始及中间气象数据,h5、joblib、pkl保存训练好的模型权重,docx为使用文档,png为效果示意图,整体约12.17MB,目录按功能划分,部署简单、结构清晰。目前已有426人学习下载,除完整代码注释外,还提供全国天气信息爬取、临沧历史天气爬取与数据探索脚本,可快速复现五模型对比实验并理解数据到模型的完整链路,适合课程答辩、期末展示或在此基础上二次扩展。

1. 气温预测这个机器学习课设题:为什么人人都能拿高分

如果你正在为课程设计选题发愁,气温预测是少有的、从数据到答辩都能让你稳住的机器学习方向。它的任务本质很单纯:把历史气温、季节、滞后窗口这些特征喂给模型,预测未来某天的最高气温。数据可以从公开历史气象网站下载,模型有 sklearn 一家就够,图表能一路画成 Pyecharts 的可视化大屏——项目完整、工作量看得见、老师也好提问。这篇笔记按我实际做课设辅导时最常用的路径来写:先讲数据清洗和特征工程,再给三个能直接跑的回归模型,然后谈可视化和一套六条踩坑记录。无论你是刚装完 Python 还分不清 DataFrame 的新手,还是想让课设从“能跑”变得“能讲”的准毕业生,照着下面章节做,都能交出一份解释得清的源码与文档。

2. 从 CSV 到特征矩阵:气温预测的数据清洗和特征工程怎么做

课程设计里大部分人第一步就栽在数据上:下载下来的气温表要么是 GBK 编码读不出来,要么日期变成字符串,要么某几天气温是空值。这一章我把从原始 CSV 到 sklearn 能吃的特征矩阵全流程拆开,每一步都给出能直接跑的代码。你在网上搜“机器学习中的数据处理是什么”时看到的抽象名词,在这里全部落到具体操作上。

2.1 数据从哪来:历史天气 CSV 的常见字段和编码

常见做法是去历史天气网站按城市、按月手工导出。这类站点导出的 CSV 一般包含这些列:日期、最高温度、最低温度、天气、风向、风力。字段名可能叫“最高温度”也可能叫“最高气温”,下载后用 Excel 打开确认一眼最稳妥。

这里有个隐藏坑:这类网站的中文页面大多按 GBK/GB2312 编码输出,而 pandas 的read_csv默认按 UTF-8 读,一读就报UnicodeDecodeError。解决办法是显式指定编码,或者直接用gb18030这种兼容更广的编码兜底。

import pandas as pd # 从历史天气网站导出的 CSV,中文列名 + GBK 编码是常态 # 先试 gbk,报错就换 gb18030,再不行就用 errors="ignore" 先看看结构 df = pd.read_csv("weather_data.csv", encoding="gbk") print(df.head()) print(df.dtypes)

代码逻辑说明:第一行用gbk编码读取,是最常见的情况;print(df.dtypes)用来确认“日期”“最高温度”这些字段是不是被读成了字符串。如果这里的日期列是object类型,后面 2.2 节就必须做转换;如果最高温度是“-3℃”这种带符号的字符串,后面也得先用正则把单位和符号剥掉。

参数说明:encoding参数在 Windows 上导出文件时经常需要设成gbk;把gbk改成gb18030可以覆盖到极少数生僻字,这是我在 macOS 上读同一份文件时常用的后备方案。不要迷信utf-8,课程设计里最省时间的办法就是两种编码都试一遍。

2.2 清洗气温数据:日期解析、缺失值、异常值

拿到原始表之后,我的固定顺序是:日期转时间索引、数值列去单位、缺失值填充、异常值肉眼确认。你后面画图、切分训练集、做滞后特征,全部依赖这几步的正确性,顺序错了后面全是脏数据。

import pandas as pd import numpy as np df = pd.read_csv("weather_data.csv", encoding="gbk") # 1. 日期列转成 pandas 的时间类型,并排成时间顺序 df["日期"] = pd.to_datetime(df["日期"], format="%Y-%m-%d") df = df.sort_values("日期").set_index("日期") # 2. 把 "8℃" 这类带单位的字符串变成纯数字 df["最高温度"] = df["最高温度"].astype(str).str.replace("℃", "").astype(float) df["最低温度"] = pd.to_numeric(df["最低温度"], errors="coerce") # 3. 缺失值:最低温用前向填充,最高温用线性插值,两端边界也补上 df["最低温度"] = df["最低温度"].ffill() df["最高温度"] = df["最高温度"].interpolate(limit_direction="both") # 4. 异常值排查:相邻两天最高温差超过 15℃,先画出来看再决定删不删 df["temp_diff"] = df["最高温度"].diff().abs() print(df.loc[df["temp_diff"] > 15, ["最高温度", "temp_diff"]])

代码逻辑说明:sort_values("日期")必须放在set_index之前,否则后面所有滞后特征和画图都会因为顺序错乱而出现锯齿线。astype(str).str.replace这一步是清理“℃”符号的通用做法,删掉这行,后面模型全部报could not convert string to float。最低温用ffill()是因为气温是连续时间序列,前一天的值是最近最合理的估计;最高温用interpolate(limit_direction="both")是应对连续两三天缺失的情况,在两端补上边界值,避免前向填充后测试集里仍然带 NaN。

使用注意:这里temp_diff是排查用的临时列,确认完异常值之后要在建模前删掉;如果发现某天最高温从 5℃ 猛跳到 28℃,大概率是站点维护或者人工录入错误,直接把这行剔除比强行填充更合理。此外,不要用平均值填气温缺失——气温有强季节性,均值填充会把冬季和夏季的特征糊在一起。

2.3 特征工程:滞后项、星期、滑动窗口

很多课设拿到 80 分但没到满分,差就差在特征上。如果你只把“前一天温度”丢进模型,那本质上是在做一个最朴素的持久性预测;加上月、日、星期、滑动窗口这些特征后,模型才真正开始“学习”气温变化的规律。

# 基于 2.2 清洗完的 df,构造特征列 df["最高温度_滞后1天"] = df["最高温度"].shift(1) df["最高温度_滞后7天"] = df["最高温度"].shift(7) # 时间循环特征:月、日、星期会在后续可视化里也用到 df["月"] = df.index.month df["日"] = df.index.day df["星期"] = df.index.dayofweek # 0 代表周一,6 代表周日 # 滑动窗口:近 3 天和近 7 天的历史最高温均值 df["最高温度_近3日均值"] = df["最高温度"].rolling(3).mean() df["最高温度_近7日均值"] = df["最高温度"].rolling(7).mean() # 删除造特征期间产生的空行,时间序列建模必须在特征构造完成后再 dropna df = df.dropna() print(df.tail())

代码逻辑说明:shift(1)是把这一列整体下移一行,让模型看到“昨天的温度”;shift(7)对应的是一周前的温度。为什么要这两个滞后项?因为气温同时受“惯性”和“季节周期”控制:今天温度大概率接近昨天,但也大概率接近去年今天或一周前同一季节的水平。rolling(3).mean()是三天滑动平均,用来平滑寒潮或暖流带来的突跳。

参数说明:shift的天数不是越大越好,滞后 1 天和滞后 7 天是气象时间序列里性价比最高的两个窗口,再往上加滞后 30 天会和月特征高度重复,造成特征冗余。rolling窗口大小同理,3 天和 7 天是常见默认值;如果数据量只有一年,建议只保留近3日均值,7 天窗口会让前 6 行全部变成 NaN。

这一阶段的目标是把原始的三四列变成模型能直接消费的 8 列左右,特征矩阵和预测目标的对应关系保持在“用当天之前的信息预测当天的最高温”,这一点务必记牢,后面第 5 章的数据泄漏坑全靠这个原则来避。

3. 三个机器学习模型跑通气温预测:线性回归、决策树与随机森林

数据就绪后,接下来就是模型环节。我一般会让课设方案里至少出现三个模型:一个线性基线、一个非线性基线、一个集成模型。这样模型对比表才写得满,答辩时老师问“你为什么用这个模型”你也有得讲。本章所有代码都只依赖 sklearn,不需要额外装任何深度学习框架。

3.1 回归任务的评价指标:MAE、RMSE、R² 怎么解释

气温预测是回归问题,不是分类问题,“准确率”这个概念在这里不成立。你要预测的是一个连续温度值,模型不可能每次都跟真实值完全一致,所以课程设计里主要用下面三个指标来衡量好坏:

指标含义课设答辩一句话说法
MAE平均绝对误差平均每天预测差几度
RMSE均方根误差放大大误差的惩罚,看模型在极端天气上稳不稳
R²决定系数模型能解释气温波动的百分之多少,越接近 1 越好

答辩时最怕的就是只丢出一句“随机森林正确率 90%”——这是典型的外行话。温度预测里 RMSE 2.5℃ 和 3.2℃ 看着差别不大,但在寒潮天气里,差 0.7℃ 就可能预示着模型对极端值的捕捉能力完全不同。所以我在课设文档里一般会强调:MAE 是“日常表现”,RMSE 是“极端表现”,R² 是“整体解释力”,三个指标要一起看。

3.2 第一个基线:线性回归 5 行代码出结果

线性回归在气温预测里通常表现不差,因为气温和滞后温度之间本身就近似线性关系。它在这里的作用是当基线:后面随机森林如果比线性回归提升不到 5%,那说明问题出在特征上,而不是模型复杂度上。

from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score import numpy as np # 特征列必须和 2.3 节构造的列名完全一致 feature_cols = ["最高温度_滞后1天", "最高温度_滞后7天", "月", "日", "星期", "最高温度_近3日均值", "最高温度_近7日均值"] X = df[feature_cols].values y = df["最高温度"].values # 时间序列必须按顺序切分,前 80% 训练,后 20% 测试 split = int(len(X) * 0.8) X_train, X_test = X[:split], X[split:] y_train, y_test = y[:split], y[split:] model = LinearRegression() model.fit(X_train, y_train) y_pred = model.predict(X_test) rmse = float(np.sqrt(mean_squared_error(y_test, y_pred))) print("LinearRegression RMSE:", round(rmse, 2)) print("R2:", round(r2_score(y_test, y_pred), 3))

代码逻辑说明:X = df[feature_cols].values把 DataFrame 转成 numpy 二维数组,sklearn 对 pandas DataFrame 也能直接处理,但转成 values 可以减少版本兼容性问题。split = int(len(X) * 0.8)是按时间顺序硬切分,第 5 章会详细讲,如果这里用train_test_split默认打乱切分,模型会把未来数据塞进训练集,R² 会虚高到 0.9 以上,答辩一问就穿帮。

参数说明:线性回归几乎没有需要调的参数,默认值即可。真正要关注的是切分比例:数据量 700 行左右时,0.8/0.2是课设里最常用的比例;如果数据只有 300 行,建议改成0.75/0.25,测试集至少要有 50 个样本,否则评估指标波动极大。

3.3 上非线性:决策树和随机森林的参数怎么调

决策树在这个场景里几乎必然过拟合:不去限制树的深度,树会为训练集里每个样本单独长出一个叶子节点,测试集上一塌糊涂。所以决策树我只用来做“过拟合演示”,真正交给老师的模型是随机森林,相关热搜词里“机器学习模型”和“机器学习检测”指向的也都是这类树模型集成。

from sklearn.tree import DecisionTreeRegressor from sklearn.ensemble import RandomForestRegressor # 决策树:故意不剪枝,让它在训练集上疯狂生长 dt = DecisionTreeRegressor(random_state=42) dt.fit(X_train, y_train) dt_pred = dt.predict(X_test) dt_rmse = float(np.sqrt(mean_squared_error(y_test, dt_pred))) print("DecisionTree RMSE:", round(dt_rmse, 2)) # 随机森林:限制树深度和叶子大小,是能交作业的配置 rf = RandomForestRegressor( n_estimators=200, max_depth=8, min_samples_leaf=5, random_state=42 ) rf.fit(X_train, y_train) rf_pred = rf.predict(X_test) rf_rmse = float(np.sqrt(mean_squared_error(y_test, rf_pred))) print("RandomForest RMSE:", round(rf_rmse, 2)) print("RandomForest R2:", round(r2_score(y_test, rf_pred), 3))

代码逻辑说明:DecisionTreeRegressor(random_state=42)不设任何限制,它会在训练集上构造出一棵极深树,RMSE 肉眼可见地变差,这段代码的作用是让文档里的对比表多一个“反例”。RandomForestRegressor的n_estimators=200表示 200 棵树,max_depth=8限制每棵树最多 8 层,min_samples_leaf=5让每个叶子节点至少包含 5 个样本,这是防止随机森林过拟合的三板斧。

参数说明:n_estimators从 100 加到 200 对精度提升很小,但训练时间翻倍,课设数据量下 200 是甜点值;max_depth建议从 5 到 15 逐个试一轮,气温预测里 8 是常见拐点——低于 8 欠拟合,高于 15 开始过拟合;min_samples_leaf在数据量小时千万别设成 1,设成 5 左右模型会平滑很多。这三个参数足够答辩时解释十分钟,不要再往上堆参数了。

3.4 三模型对比:结果表与结论句怎么写

跑完三个模型后,把结果整理成表格贴进使用文档,配上两三句分析,这个项目的“机器学习”部分就算完整了。下面表格的数字是示意值,务必拿你自己跑出来的结果替换,不要照抄。

模型MAE(℃)RMSE(℃)R²一句话结论
线性回归2.312.980.84能抓住整体趋势,但对寒潮等极端天反应迟钝
决策树(不剪枝)2.553.460.78明显过拟合,训练集 R² 接近 1.0
随机森林1.922.470.90综合表现最好,对气温突变更敏感

结论句切忌只写“随机森林最好”。我一般会补一段:“气温受昨天温度、季节周期、连续几日冷暖空气共同影响,随机森林能自动组合这些特征并做非线性切分,而线性回归只能对它们做线性加权,因此在寒潮这种非线性波动下随机森林表现更好。”这段话背下来,答辩时直接就是满分回答。

如果还想再加分,可以补一个 XGBoost 的对比,但要注意 xgboost 库需要额外pip install xgboost,而且它的可解释性和树模型一致,效果通常和随机森林接近,课设里不是必需品。

4. 可视化从静态到大屏:用 Matplotlib、Seaborn 和 Pyecharts 讲清预测结果

“气温预测和可视化”这个课设题,可视化部分占的分数比你想的大。老师看代码的时间不超过五分钟,看图的时间反而是最长的。我的经验是准备两层图:第一层是 Matplotlib/Seaborn 的静态图,放进文档和答辩 PPT;第二层是 Pyecharts 的交互式图表,打开就是可视化大屏效果,现场演示用。

4.1 真实值 vs 预测值折线图:横轴密度怎么控制

最核心的一张图是把测试集里真实最高温和预测最高温画在一起。新手最容易翻车的就是 x 轴日期全部堆在一起变成一条黑带,网上搜“python画图横坐标太密集”能搜出一堆同款,解决办法是控制刻度显示密度。

import matplotlib.pyplot as plt import matplotlib.dates as mdates # Windows 常见中文字体是 SimHei,macOS 用 Arial Unicode MS,按自己环境改 plt.rcParams["font.sans-serif"] = ["SimHei"] plt.rcParams["axes.unicode_minus"] = False # 测试集对应的日期范围,df 已经在 2.2 节设成时间索引 test_date = df.index[split:] plt.figure(figsize=(12, 5)) plt.plot(test_date[:50], y_test[:50], label="真实值", marker="o", markersize=3) plt.plot(test_date[:50], rf_pred[:50], label="随机森林预测", marker="x", markersize=3) # 关键参数:每 5 天显示一个刻度,旋转标签防止重叠 plt.gca().xaxis.set_major_locator(mdates.DayLocator(interval=5)) plt.gcf().autofmt_xdate() plt.xlabel("日期") plt.ylabel("最高气温(℃)") plt.title("近 50 天最高气温预测效果") plt.legend() plt.grid(alpha=0.3) plt.savefig("predict_compare.png", dpi=150, bbox_inches="tight")

代码逻辑说明:test_date[:50]只画最近 50 天,而不是全量测试集,原因是全量画出来数据点叠在一起,答辩 PPT 上根本看不清。mdates.DayLocator(interval=5)强制每 5 天显示一个日期标签,这是解决“横坐标太密集”的核心一行。plt.gcf().autofmt_xdate()自动把日期标签旋转 30 度,进一步避免互相遮挡。

参数说明:interval=5是常见值,如果你的图只画 30 天,改成interval=3更合适;dpi=150保证放进 Word 文档后不模糊;bbox_inches="tight"会把保存图片四周多余空白裁掉,不然 x 轴标签经常被截掉一半。marker="o"和marker="x"分别用圆点和叉号区分两条线,不推荐用两条同颜色虚线,打印出来完全分不清。

4.2 用特征重要性和残差图给模型“解释权”

老师最爱问“哪些特征最影响气温”“模型什么时候会失灵”,这两个问题分别由特征重要性图和残差图回答。哪怕你不懂随机森林内部细节,这两张图也能让你在答辩现场言之有物。

import seaborn as sns # 随机森林自带特征重要性接口,直接取出并排序 fi = pd.Series(rf.feature_importances_, index=feature_cols).sort_values() fi.plot.barh(title="特征重要性(随机森林)") plt.tight_layout() plt.savefig("feature_importance.png", dpi=150) # 残差 = 真实值 - 预测值,画分布看模型偏向 residual = y_test - rf_pred plt.figure(figsize=(10, 4)) sns.histplot(residual, kde=True) plt.xlabel("预测误差(℃)") plt.title("残差分布:负值代表预测偏高,正值代表预测偏低") plt.savefig("residual.png", dpi=150)

代码逻辑说明:fi.plot.barh()画的是水平条形图,特征重要性会从下往上从小到大排列,最上面一行就是最重要的特征。气温预测里通常“滞后 1 天”和“近 3 日均值”排最前,这说明温度的最强预测因子是近期温度惯性。sns.histplot(residual, kde=True)画残差直方图,如果分布中心接近 0 且大致对称,说明模型没有系统性偏差;如果中心偏正或拖出长尾,说明模型在极端低温场景下系统性失灵。

参数说明:rf.feature_importances_是训练后自动算好的属性,取值 0 到 1,不需要额外配置。残差图的kde=True会叠加一条平滑密度曲线,目的是让分布形状更直观,如果你的 seaborn 版本没有这个参数,直接去掉即可。

4.3 Pyecharts 版可视化大屏:课设展示的加分项

静态图进文档,交互图做现场演示。Pyecharts 是 ECharts 的 Python 封装,生成的是一个独立 HTML 文件,双击就能打开,完全不需要起 Web 服务。我这边的经验是选 2 到 3 张图拼在一起,一张真实预测对比折线图、一张温度月度分布柱状图、一张特征重要性图,做成像可视化大屏的仪表盘效果,展示时非常有说服力。

from pyecharts import options as opts from pyecharts.charts import Line # 把测试集日期转成字符串列表,pyecharts 才能正确处理时间轴 x_data = [str(d.date()) for d in test_date[:90]] y_real = [round(v, 1) for v in y_test[:90]] y_pred = [round(v, 1) for v in rf_pred[:90]] line = ( Line(init_opts=opts.InitOpts(width="1200px", height="500px")) .add_xaxis(x_data) .add_yaxis("真实气温", y_real, is_smooth=True, label_opts=opts.LabelOpts(is_show=False)) .add_yaxis("预测气温", y_pred, is_smooth=True, label_opts=opts.LabelOpts(is_show=False)) .set_global_opts( title_opts=opts.TitleOpts(title="历史气温与机器学习预测对比"), tooltip_opts=opts.TooltipOpts(trigger="axis"), legend_opts=opts.LegendOpts(pos_top="5%"), ) ) line.render("temperature_dashboard.html") print("已生成 HTML 文件,双击 temperature_dashboard.html 打开")

代码逻辑说明:list(str(d.date()) for d in test_date[:90])这行很容易漏,pyecharts 的 x 轴如果传 pandas Timestamp 对象会渲染成纯数字,必须转成"2023-07-01"格式。label_opts=opts.LabelOpts(is_show=False)是必加项,不关掉的话图上 90 个数据点会把数值标签全部堆在折线上,密密麻麻没法看。trigger="axis"让鼠标悬停时同时显示真实值和预测值两个数据。

参数说明:width="1200px", height="500px"控制输出画布尺寸,放 PPT 里建议 16:9;is_smooth=True把折线画成曲线,视觉上更美观;pos_top="5%"保证图例不压住标题。如果你想让图表更贴近可视化大屏,可以再加一个Grid把折线图和柱状图上下拼接,但课设时间紧张,一张高质量折线图足够撑场。

5. 气温预测课设最容易翻车的 6 个坑:现象、原因、解决

这个课设计从数据到答辩环节的坑,我按出现频率从高到低列了六条。每条都按“现象、原因、解决”展开,前面章节里写的正确做法,在这里对应它的反面和翻车现场。

5.1 打开 Pyecharts 生成的文件一片空白

现象:render()正常输出 HTML,文件名也在,但双击打开后图表区域是空白的,控制台还报一堆 JS 错误。原因:Pyecharts 1.x 和 2.x 的导入路径完全不同,旧教程里常见的from pyecharts import Bar在新版本已经失效;另外file://协议下部分浏览器对本地 JS 资源的加载有限制。解决:确认pip list里 pyecharts 是 2.x 版本,并统一用from pyecharts.charts import Line的新式导入;换用 Chrome 打开而不是某些默认浏览器;实在不行把 HTML 文件和 python 脚本放在同一个目录再打开,多数白屏问题能消失。

5.2 预测 R² 高达 0.98,老师一追问就穿帮

现象:切分数据后随机森林 R² 接近 1.0,看起来完美,但画图发现预测值和真实值几乎完全重合。原因:八成是用了train_test_split(X, y, test_size=0.2, shuffle=True)默认打乱切分,把未来日期的数据放进了训练集,模型学会了“背答案”;还有一种可能是特征里混进了当天的天气现象,相当于把答案提前给了模型。解决:把切分方式改成X[:split]/X[split:]按时间顺序硬切,并写一个自查逻辑:检查所有特征列是否都来自目标日期之前。时间序列建模的铁律是训练集永远只能是测试集之前的数据。

提示:特征矩阵里的“月”“日”这些时间属性不是泄漏,因为它们和目标当天气温不算未来信息;但“当天天气”“当天风力等级”这种只能在当天知道的观测值,放进特征就是泄漏。

5.3 中文乱码和负号变方块

现象:图上标题、坐标轴中文全部变成小方块,温度负号变成一个粗横线。原因:Matplotlib 默认字体里没有中文字符,axes.unicode_minus配置没打开还会把负号渲染成异常符号。解决:在画图代码最前面加两行固定配置:plt.rcParams["font.sans-serif"] = ["SimHei"]和plt.rcParams["axes.unicode_minus"] = False。如果你用的是 macOS,把SimHei换成Arial Unicode MS;Linux 上没有中文字体的话,先fc-list :lang=zh查一下系统里有什么,再填对应的字体名。

5.4 横坐标日期乱序,折线图走迷宫

现象:画出的折线图弯弯曲曲,像一根打结的绳子,日期也没有按时间先后排。原因:原始 CSV 的日期本来就是乱序的,或者你只做了pd.to_datetime但没有sort_values。解决:回到 2.2 节,pd.to_datetime之后立刻执行df = df.sort_values("日期"),后续所有操作都在这之后进行。如果数据是按时间降序排列的,记得加ascending=True重新升序。画图前再执行一次df.sort_index()兜底,成本几乎为零。

5.5 代码能跑,但文档里没有“为什么”

现象:使用文档里写了运行步骤,但老师一看模型部分就问“为什么用随机森林不用线性回归”“这两个模型有什么区别”,学生答不上来。原因:把课设当成了写代码任务,忽略了它本质上是一次“小论文答辩”。解决:文档里必须有三样东西:模型对比表格、特征重要性图、残差分布图,每个图后面配两到三句解释。不要觉得这些话是废话,答辩时你嘴里说出来的就是这些句子的口语化版本。解释不通的时候就用“随机森林能捕捉非线性关系”这句话兜底。

5.6 压缩包里只有代码文件,没有依赖清单

现象:答辩前老师想在自己电脑上复现,结果运行时报ModuleNotFoundError: No module named 'seaborn'。原因:你在自己环境里装过这些包,但没告诉老师项目依赖了什么。解决:随手生成一份requirements.txt,在项目根目录执行pip freeze > requirements.txt,然后把 Python 版本、各库版本、数据集来源写进 README。这份文件的成本大约三分钟,但它决定了老师会不会把你的项目当作“能复现的完整工程”来打分。

6. 从能跑到满分:答辩前把回测升级成真预测

到这里项目能跑、图能看、坑也避得差不多了,但想要冲击“满分”,还差最关键的临门一脚:把对测试集的“回测”升级成对未来的“真预测”。我见过太多课设止步于“模型在历史数据上效果很好”,老师一句“那你预测一下明天几度”就当场卡壳。下面这步升级,是区分 85 分和 95 分的关键,也是这篇笔记最后的干货。

升级的核心是做一个滚动窗口接口:用当前已有数据的最后一天作为起点,构造出“明天”的特征向量,喂给训练好的模型,输出一个真实的气温预测值。因为“最高温度_滞后1天”的取值就是今天的气温,所以你只需把今天的真实值或观测值填进去,其余特征按日历自动生成。

from datetime import timedelta # 取数据最后一行的特征作为基准,造出明天的新特征行 last_row = df.iloc[-1] tomorrow = df.index[-1] + timedelta(days=1) new_features = { "最高温度_滞后1天": last_row["最高温度"], # 今天的气温就是明天模型的滞后1天 "最高温度_滞后7天": last_row["最高温度_滞后1天"], # 七天前对应的是昨天滞后7天的值 "月": tomorrow.month, "日": tomorrow.day, "星期": tomorrow.dayofweek, "最高温度_近3日均值": last_row["最高温度_近3日均值"], "最高温度_近7日均值": last_row["最高温度_近7日均值"], } # 转成和训练时一致的特征顺序,模型.predict 一次输出 tomorrow_pred = rf.predict([list(new_features[col] for col in feature_cols)])[0] print(f"预测 {tomorrow.date()} 最高气温: {tomorrow_pred:.1f}℃")

这段代码说明:last_row是最后一天的真实数据,整套特征构造逻辑和 2.3 节保持一致,只是把“当前行”变成了“未来一天”。预测明天,就用今天的气温当滞后值;预测后天,就要先拿今天预测出的结果当明天的滞后值滚动下去,这个过程在气象预测里叫滚动预测。答辩时把这段代码跑一下,老师会看到你不仅能复现历史,还能做真实预测,项目完整度直接高一个档位。注意,预测结果不保证准,因为气温还受气压、湿度等你没纳入的特征影响,但只要在答辩时说出“当前模型只做短时预测,超过三天误差会快速放大”,这就是一个成熟的工程判断。

最后说一句我自己的习惯:做课设一定留出两个晚上的时间专门“吹毛求疵”自己的代码——检查有没有把未来信息漏给模型、确认所有图的中文正常、在干净环境里重新跑一遍。你替老师把坑都踩平了,老师在打分时自然会给你一个满意的分数。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/12 20:32:40

多智能体协同围捕算法Python实现:从源码到避坑指南

简介:这是一份面向计算机专业课程设计、期末大作业及项目实战的多智能体协同围捕算法Python实现,适合需要完成高分毕设,或想系统学习多智能体规划、强化学习与机器人仿真控制的学习者。项目以Voronoi剖分与MADDPG为核心方案,覆盖单…

作者头像 李华
网站建设 2026/10/12 20:30:58

用 AI 起一卦:基于 opencode 与 SKILL.md 的六爻排盘 Skill 实战

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

作者头像 李华
网站建设 2026/10/12 20:29:24

手写词法与LL(1)/LR(1)分析器:深入编译原理底层逻辑

简介:本资源是面向高校计算机专业本科生的编译原理课程实验配套源码包,完整实现词法分析器、LL(1)语法分析器与LR(1)语法分析器三大核心模块,覆盖编译前端基础能力训练。压缩包共52个文件,含4个C源文件(cpp&#xff09…

作者头像 李华
网站建设 2026/10/12 20:29:13

OpenStack Horizon深度解析:架构设计、部署调优与二次开发实战

1. 从一次控制台卡顿说起:Horizon到底在OpenStack里扮演什么角色如果你正在维护一套私有云环境,大概率遇到过这样的场景:计算节点跑得好好的,虚拟机也正常在线,但用户突然在群里喊“控制台打不开了”“创建实例的页面一…

作者头像 李华
网站建设 2026/10/12 20:28:32

Azure SQL Query Store实战:缺失索引排查与优化

1. 从一个真实场景说起:为什么我盯上了Query Store数据库性能问题最让人头疼的地方,不是问题本身有多复杂,而是你根本不知道问题出在哪。我见过太多团队,数据库跑着跑着突然某条查询从几十毫秒变成几秒,开发说SQL没改过…

作者头像 李华