资讯动态

气温预测课程设计:数据处理与特征工程是关键

发布时间:2026/10/12 19:48:41 来源:尧图企业网站定制
简介一套面向Python课程设计与期末大作业的机器学习气温预测与可视化项目覆盖数据爬取、模型训练、对比分析到GUI展示的完整流程。项目中构建了MLP、LSTM、随机森林、决策树与线性回归五种回归模型通过训练结果对比选出表现最佳的LSTM并配套图形化界面直观展示预测效果。资源共38个文件除py脚本与ipynb实验笔记外还包含csv历史天气数据集、训练好的pkl/h5/joblib模型、全国天气信息爬取脚本以及docx使用文档压缩包约12.17MB部署即可复现完整实验。代码注释详细新手也能快速理解建模思路可直接作为课程设计或期末大作业的高分范本目前已吸引426人学习下载。1. 气温预测课程设计分数差距不在模型而在数据处理这两步带了这么多届课程设计气温预测是出现频率最高的 Python 机器学习题目之一。很多学生把随机森林换到 XGBoost再试 LSTM调参调到头秃最后分数还是卡在 85 上下。反直觉的结论是气温预测拿满分的关键不在模型的深度而在你数据特征怎么构造、验证集怎么切。这篇文章把基于 Python 机器学习的气温预测和可视化从项目结构、数据处理、特征工程、模型训练一直讲到报告和源码交付适合正在做课程设计、或者想拿气温预测练手入门机器学习的同学直接照做。2. 把气温预测拆成可交付的项目数据预处理、特征构造与ML建模课程设计翻车大多不是模型不行而是交上去的东西不像一个项目。评分老师拿到手的是一堆散落的 .py 文件和一个 gym 里的 notebook跑一遍报错印象分直接打骨折。所以先别急着写模型把项目骨架立起来。2.1 项目骨架与目录组织源码、文档、数据各归其位我一般会先搭这样一个目录几十行代码的事但后面省下的时间不止几个小时temperature-prediction/ ├── data/ │ ├── raw/ # 原始气象数据只读不改 │ └── processed/ # 清洗和特征工程后的中间产物 ├── src/ │ ├── data_process.py # 数据清洗与特征构造 │ ├── train_model.py # 模型训练与评估 │ └── visualize.py # 全部可视化脚本 ├── output/ │ ├── figures/ # 图片输出集中地 │ └── model/ # 训练好的模型存档 ├── docs/ │ └── 使用文档.md └── requirements.txt这个结构最大的价值是数据是数据代码是代码产物是产物文档单独放。很多同学把模型文件、图片、数据集全堆在根目录最后写文档的时候自己都找不到哪个是哪个。源文件里我只放三个脚本每个脚本只干一件事这样文档里先跑哪个、再看哪个一句话就能说清楚。2.2 用 pandas 读取气象数据缺失值、时间索引与特征列气温预测最常见的数据来源是气象站导出的 CSV长这样date、temp、humidity、pressure、wind_speed。读进来的时候先把日期列转成时间索引这一步决定了后面所有时间特征能不能做import pandas as pd df pd.read_csv( data/raw/temperature.csv, parse_dates[date], # 把date列解析成datetime类型 index_coldate # 直接用date做索引后面聚合、偏移都方便 ) print(df.info()) print(df.isna().sum())parse_dates 和 index_col 这两个参数是这套代码的灵魂。如果不指定 parse_datesdate 会被读成字符串对象后面的 .hour、.dayofyear 全都取不出来如果不设 index_col滞后特征和滑动窗口的 shift/rolling 就得额外指定列名代码丑一倍。缺失值处理这里有个新手最爱踩的坑直接用 df.mean() 填。气温是连续变化的气象变量用全序列均值去填一个缺口等于在一条平滑曲线上砸了个台阶。我一般用线性插值# 单点缺失用线性插值保持气温变化的连续性 df[temp] df[temp].interpolate(methodlinear, limit_directionboth) # 连续缺失太多直接丢掉这一段 df df[df[temp].notna()] print(f处理后剩余 {len(df)} 条记录)interpolate 的 method 选 linear 对气温这种短时平稳序列够用换成 quadratic 也行但对异常值更敏感。limit_directionboth 表示序列开头和结尾的缺失也尽量补不补的话前几条数据就浪费了。如果某一段连续缺失超过窗口长度插值就没意义了直接裁掉这一整段别硬补。2.3 特征工程的三个必做步骤时间特征、滞后特征与滑动平均机器学习模型不认昨天凌晨这些概念只认数字。气温预测的本质是把时间语义转成模型能吃的特征这一步做好了线性回归都能打出不错的成绩# 1. 时间特征把周期性信息拆解成数值 df[hour] df.index.hour # 24小时周期内的小时 df[dayofyear] df.index.dayofyear # 一年中的第几天能抓季节趋势 df[month] df.index.month # 2. 滞后特征昨天的气温是今天最强的信号 for lag in [1, 3, 24, 48]: df[ftemp_lag_{lag}] df[temp].shift(lag) # 3. 滑动平均用过去24小时均值消掉短时波动 df[temp_ma_24] df[temp].shift(1).rolling(window24).mean() # 滞后和滑动窗口会引入NaN统一丢弃 df df.dropna()滞后阶数怎么定看数据采样频率。如果数据是小时级的lag1 是1小时前lag24 是24小时前lag48 是两天前的同一时刻。这几个滞后项分别抓住短期惯性、昨日同期和天气过程的持续性物理意义比随机堆几十列强得多。注意这里的滑动平均是 shift(1) 之后再 rolling意思是只用当前时刻之前的 24 小时计算。如果直接 df[temp].rolling(24).mean()当前时刻的观测值自己被算进了均值里模型在训练时见过答案测试时就没有这个答案这是典型的数据泄漏做气温预测翻车的头号原因。2.4 模型选型与参数说明线性回归、随机森林与 XGBoost气温预测课程设计用不着上深度学习。LSTM 听起来高级但小时级气象数据往往只有几千到几万条神经网络在这种规模下训练不稳定还容易被说黑匣子。我一般这样配from sklearn.linear_model import LinearRegression from sklearn.ensemble import RandomForestRegressor models { 线性回归: LinearRegression(), 随机森林: RandomForestRegressor( n_estimators200, # 树越多越稳但超过200收益递减 max_depth12, # 限制深度防过拟合 random_state42, # 固定随机种子保证结果可复现 n_jobs-1 # 用满所有CPU核心 ), }线性回归是必须有的 baseline它告诉你最简单模型能做到什么程度。随机森林是课程设计的主力n_estimators 取 200 足够max_depth 取 12 是因为特征维度不大太深了纯属记忆训练集。random_state 一定固定不然两次运行结果不一样评分老师会怀疑你的结果。训练之前还要注意量纲。线性回归对特征尺度敏感随机森林完全不受影响。所以用管道把标准化绑进去避免测试阶段漏掉某一步from sklearn.pipeline import make_pipeline from sklearn.preprocessing import StandardScaler X df.drop(temp, axis1) # 特征时间特征 滞后 滑动平均 y df[temp] # 标签当前时刻气温 # 管道保证预测时自动做同样的标准化 linear_pipe make_pipeline(StandardScaler(), LinearRegression())3. 训练与验证气温预测模型的参数调优和结果评估模型能跑只是第一步验证方式决定你的分数是 看起来不错 还是 真的不错。气温预测里最大的坑就是数据划分很多人的模型分高纯粹是划分方式做错了。3.1 训练集与测试集划分时间序列不能随机打乱做分类、回归时 sklearn 的 train_test_split 默认随机打乱这个习惯搬到气温预测上就是灾难。气温有强烈的年周期和日周期随机打乱相当于让模型偷看了未来同一季节的数据测试分数虚高到没有参考价值。气温预测必须按时间顺序硬切split_idx int(len(df) * 0.8) # 前80%训练 train df.iloc[:split_idx] test df.iloc[split_idx:] # 后20%测试模拟未来 X_train, X_val train.drop(temp, axis1), test.drop(temp, axis1) y_train, y_val train[temp], test[temp]这里没有任何随机操作纯粹按时间切。为什么是 80/20对于小时级数据20% 测试集一般能覆盖到完整的昼夜周期和至少一周的气象过程。如果你的数据只有一个月的量测试比例可以降到 15%但不要低于 10%否则评估结果波动太大。3.2 评估指标怎么选MAE、RMSE、R² 的分工气温预测报告里只写 R² 是不完整的评分老师看一眼就想扣分。三个指标各说一件事import numpy as np from sklearn.metrics import mean_absolute_error, r2_score y_pred linear_pipe.predict(X_val) mae mean_absolute_error(y_val, y_pred) rmse np.sqrt(mean_squared_error(y_val, y_pred)) r2 r2_score(y_val, y_pred) print(fMAE{mae:.2f}°C, RMSE{rmse:.2f}°C, R²{r2:.4f})MAE 的单位是摄氏度直接告诉你平均错多少度这是气温预测最直观的指标。RMSE 对大的误差更敏感如果 RMSE 明显大于 MAE说明存在个别预测得很离谱的点。R² 是相对指标容易被整体方差抬高——夏天冬天温差大R² 自然高但这不是模型厉害。所以报告里三个指标一起给并解释每一个的意义。3.3 用 TimeSeriesSplit 做交叉验证避免气温预测的未来泄漏单次划分有运气成分交叉验证更稳。但气温预测不能用 KFold要用 sklearn 专门为时间序列设计的 TimeSeriesSplitfrom sklearn.model_selection import TimeSeriesSplit tscv TimeSeriesSplit(n_splits5) # 切5折每次训练集都在验证集前面 scores [] for fold, (train_idx, val_idx) in enumerate(tscv.split(X)): X_tr, X_va X.iloc[train_idx], X.iloc[val_idx] y_tr, y_va y.iloc[train_idx], y.iloc[val_idx] linear_pipe.fit(X_tr, y_tr) pred linear_pipe.predict(X_va) scores.append(np.sqrt(mean_squared_error(y_va, pred))) print(f5折RMSE均值: {np.mean(scores):.2f}°C, 标准差: {np.std(scores):.2f}°C)TimeSeriesSplit 和 KFold 的区别在于KFold 随机打乱后切分TimeSeriesSplit 永远保持训练集在时间上早于验证集。标准差重要如果 5 折 RMSE 忽高忽低说明模型在某些季节段不稳比如冬天冷空气过程预测崩了但夏天表现很好。这种问题只看单次划分根本发现不了。3.4 预测结果的保存与输出规范为可视化做准备模型训练完要把预测结果落盘。很多人只把图存了csv 不存后面想换一个指标重新算就得重跑一遍训练浪费时间import joblib # 保存整个pipeline里面包含标准化器和模型别人拿到就能直接预测 joblib.dump(linear_pipe, output/model/linear_pipeline.pkl) # 预测结果落盘可视化、报告、答辩时候直接读这个csv result pd.DataFrame({ true: y_val, pred: y_pred }, indexX_val.index) result.to_csv(output/predictions.csv, index_labeldate)保存整个 pipeline 而不是裸模型这是个很重要的习惯。裸模型保存后预测时还得记得自己做 StandardScaler 变换漏一步结果就是错的。pipeline 把这些步骤全包进去加载之后直接 .predict() 完事。4. 可视化呈现从 matplotlib 对比图到可视化大屏可视化是评分老师最先看的东西。气温预测的可视化不需要花哨需要的是一张主图讲清结果两张辅助图证明稳定一张特征图解释原理。4.1 真实值与预测值对比曲线课程设计的主图这是报告和答辩 PPT 里必须有的核心图其他所有图都是它的配角import matplotlib.pyplot as plt plt.figure(figsize(14, 5)) plt.plot(result.index, result[true], label真实气温, linewidth1) plt.plot(result.index, result[pred], label预测气温, linewidth1, alpha0.85) plt.legend() plt.ylabel(气温 (°C)) plt.title(测试集气温预测效果对比) plt.tight_layout() plt.savefig(output/figures/compare.png, dpi150)dpi 至少 150不然放进文档里打印出来边缘发虚。linewidth 取 1 就行两条线叠一起时太粗反而看不出细节。这张图评分老师第一眼看的是两条线是否贴着走贴得越紧模型的说服力越强。4.2 残差与误差分布证明模型稳定的两张辅助图对比曲线只能看整体残差图能暴露局部问题。残差是真实值减预测值如果残差随机分布在 0 轴两侧说明模型没有系统性偏差result[error] result[true] - result[pred] # 残差散点图看预测误差是否随气温高低变化 plt.figure(figsize(10, 4)) plt.scatter(result[pred], result[error], s8, alpha0.5) plt.axhline(0, colorred, linewidth0.8) plt.xlabel(预测气温 (°C)) plt.ylabel(残差 (°C)) plt.title(预测残差分布) plt.savefig(output/figures/residual.png, dpi150) # 误差直方图看误差是否符合正态分布 plt.figure(figsize(8, 4)) plt.hist(result[error], bins50, edgecolorwhite) plt.xlabel(残差 (°C)) plt.ylabel(频数) plt.title(预测误差直方图) plt.savefig(output/figures/error_hist.png, dpi150)如果残差图呈现漏斗形左边窄右边宽说明模型在高温段误差大、低温段误差小这种信息写在报告里非常加分。误差直方图近似正态分布是最理想的情况说明模型没有欠拟合也没有过拟合。4.3 特征重要性排序让报告有解释力随机森林自带特征重要性这是课程设计最省力的一张图而且最能体现你理解模型在干什么# 单独对随机森林模型fit一次拿到特征重要性 rf models[随机森林] rf.fit(X_train, y_train) importance pd.Series(rf.feature_importances_, indexX.columns) importance.sort_values(ascendingFalse).head(10).plot.barh() plt.title(随机森林特征重要性 Top10) plt.tight_layout() plt.savefig(output/figures/importance.png, dpi150)典型结果里temp_lag_1 和 temp_lag_24 一定排在最前面这是符合气象常识的——最近的观测值对当前气温影响最大。如果特征重要性排名里时间特征反而靠前、滞后特征靠后你要警觉是不是数据有问题。报告里写一句模型认为前一时刻气温是最强信号符合气象连续性特征这比调参过程值钱多了。4.4 用 echarts 做交互式可视化大屏加分还是减分可视化大屏这个词在课程设计里很流行用 echarts 把气温预测结果做成网页交互大屏确实炫。但我要给个实在建议如果时间只剩两三天别碰大屏。echarts 要做得好需要前端基础而且交互数据要从 Python 侧导出 json中间调试时间不可控。我见过的稳妥做法是以 matplotlib 出图为核心大屏作为加分项放到答辩演示环节。用 echarts 做一个折线图支持 hover 显示数值、拖拽缩放时间范围数据从 output/predictions.csv 转成 json几十行代码的事。时间充裕再做时间紧张就干脆不做matplotlib 四张图足够撑起一个高分报告。5. 气温预测避坑指南数据泄漏、日期乱序与评分陷阱这部分是血泪经验每条都来自实际跑偏过的案例。气温预测的坑很集中大部分都是数据处理阶段埋下的。5.1 现象测试集 R² 很高但 RMSE 却很难看有一年我帮人看一个气温预测项目R² 报了 0.95表面光鲜电脑前的同学也很高兴但 RMSE 算出来 6.3°C平均偏差超过 6 度这在气象上完全不可用。原因是有几天寒潮气温突然从 15°C 掉到 -2°C模型没抓住突变单点误差十几度把 RMSE 拉爆了。解决训练前先画箱线图看气温分布把极端离群点找出来。处理方式看情况——如果是传感器故障产生的脏数据直接剔除如果是真实的寒潮记录保留但要在报告里说明模型对极端天气的捕获能力有限。千万别为了指标好看偷偷删真实数据那是造假。5.2 现象预测曲线比真实曲线慢半拍这是气温预测最典型的翻车现场。滞后特征太强时模型学到的是预测值约等于上一时刻的真实值画出来两条曲线几乎平行但预测线整体向右平移了 1 到 2 个小时。评分老师一眼就能看出来。解决限制滞后阶数别把 lag_1 和 lag_3 同时放太多权重。可以加差分特征把变化趋势显式喂给模型比如 temp_diff_1 表示上一小时气温变化了多少。另外要在报告里承认这是单步预测的固有限制并展示多步滚动预测的误差累积曲线这反而是加分操作。5.3 现象按年份随机打乱数据模型得到虚高分数我见过最夸张的一次学生用 train_test_split 默认参数没关 shuffle随机森林 R² 跑到 0.98答辩时被老师追问了几句就崩了。原因就是随机打乱后模型在训练阶段已经见过未来同季节的气温特征。解决时间序列必须按时间顺序划分。划分完之后再确认一下 train 数据集的日期区间确实全部早于 test 数据集。用 TimeSeriesSplit 做交叉验证更保险它从机制上杜绝打乱。5.4 现象matplotlib 画出来的中文全是方框这个小问题每年都有一批人遇到。系统或 matplotlib 默认字体里没有中文字库plt.title(真实气温) 画出来全是豆腐块。图放到报告里非常掉价。解决画图脚本最前面统一设置字体别一张图一个设置plt.rcParams[font.sans-serif] [SimHei] # Windows普遍可用 plt.rcParams[axes.unicode_minus] False # 负号显示正常Linux 服务器上 SimHei 可能没有改成文泉驿正黑或思源黑体。设置完一定要重启 Python 进程再画rcParams 是全局的改晚了前面的图已经废了。5.5 现象滚动预测时误差越滚越大把预测值当作滞后特征输入继续预测下一天误差会快速累积。这不是模型坏了是递归预测的数学本质——每一次的小误差都在下一次成为输入的一部分。很多同学第一次做多步预测画出一条发散曲线以为代码写错了。解决明确区分两种预测模式。测试集上的单步预测用真实历史值做滞后特征评估的是模型本身的能力滚动预测用预测值递归输入评估的是长期外推能力。报告里两种都做分别说明用途并画出误差随预测步长增长的曲线——这么做的人非常少做了就是亮点。6. 从跑通到满分三个让报告脱胎换骨的验证动作课程设计打分最看重的是过程完整结果可信文档能复现。这里分享三个我总结的加分动作都是低成本但效果明显的。第一个动作做一张模型对比表。把线性回归、随机森林、XGBoost 三个模型的 MAE、RMSE、R² 列成表格三行三列再加一列训练时间。这张表是报告的门面评分老师扫一眼就知道你做了对比实验而不是只跑通了一个模型。第二个动作做一次滚动预测 7 天的实验。用前面说的递归预测方式从测试集开头起步连续预测未来 168 个小时把误差累积曲线画出来。气温预测的短期可预报性是有极限的你能定量说明3 天内 MAE 在 1.5°C 以内7 天退化到 4°C这个深度远超课程设计平均水平。第三个动作使用文档里写清楚运行三步骤。环境要求python 版本、每个库的最低版本这个判断以你自己 pip install 能顺利跑通为准、数据文件放置位置、三个 src 脚本的执行顺序。保证一个从没看过你代码的人按文档能从零复现你的整套结果。Python 安装建议用 Anaconda 或官方安装包别用系统自带的旧版本这一步能挡掉一半的环境问题。我第一次做类似课程设计时贪快跳过验证直接上 LSTM数据量撑不起来最后几天才慌忙换回随机森林。回头看评分老师真正看重的不是模型多新而是你有没有把每个环节做扎实。希望你这次能一次成型少走我当年的弯路希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑