气温预测课程设计:时间序列数据处理与机器学习建模全流程解析

发布时间:2026/10/19 0:22:16
气温预测课程设计:时间序列数据处理与机器学习建模全流程解析
简介面向Python课程设计与期末大作业场景机器学习气温预测与可视化项目提供完整源码及使用文档代码注释全面新手也能顺利部署运行。项目围绕气温预测任务构建了MLP三层感知机、LSTM长短期记忆网络、随机森林、决策树和线性回归五种模型经系统训练与对比LSTM综合表现最优同时搭配图形化用户界面可将预测结果直观可视化界面美观、操作简单。资源包共38个文件涵盖10个Python脚本、4个Jupyter Notebook、3个训练好的模型文件pkl/joblib/h5、2个CSV数据集、2个JSON配置、1份docx使用手册以及10张结果图片等整体大小约12.17MB目录结构清晰便于按模块学习。从天气数据爬取、数据探索、模型构建到GUI展示项目链条完整且已训练好的模型可直接调用适合需要完成高分课设或系统学习机器学习建模流程的开发者。目前已有429人学习/下载。1. 气温预测课程设计到底在考什么先看清题目再动手这个标题拆开看其实是四个评分点数据预处理、模型训练、可视化呈现、文档完整性。很多同学一上来就把重心压在“用哪个模型更高级”上结果数据划分出了泄漏、日期被读成字符串、测试集被随机洗牌模型指标再漂亮也经不起答辩时一句追问。这类项目适合两类读者正在为课程设计选题发愁、想找一个链路完整且好讲清原理的人以及代码已经写完但分数不理想、想定位扣分点的人。课程设计评分看重的从来不是模型多前沿而是你能否用机器学习把“预测气温”这件事按工程流程做完整并把每个决策讲出理由。2. 数据从哪来、怎么洗干净气温预测的第一个分水岭气象数据通常是公开站点历史记录导出的CSV字段一般包含日期、最高气温、最低气温、平均气温、湿度、气压、风向、天气状况等。拿到数据不要急着训练先回答三个问题预测目标是什么、候选特征有哪些、数据质量能不能支撑建模。这个判断直接决定后续特征工程和模型效果的上限。2.1 数据源与字段设计先决定你要预测什么我一般会先确定预测目标是最高气温还是平均气温两者建模难度略有差异。以预测次日最高气温为例标签字段就是temp_max其余字段作为候选特征。日期字段必须解析成时间索引这不只是为了画图好看更是为了后续按时间顺序划分训练集和测试集以及构造滞后特征。import pandas as pd df pd.read_csv( weather_data.csv, parse_dates[date], index_coldate ) df df.sort_index() # 时间序列必须先按时间排序 print(df.head()) print(df.dtypes)逻辑说明parse_dates[date]让Pandas把日期列解析成datetime64类型后续做滞后、按月聚合等时间操作才有基础。sort_index()这一步很多课程设计会漏掉数据一旦乱序后续时间序列划分和可视化全部失去意义。参数说明如果数据是Excel文件把pd.read_csv换成pd.read_excel即可日期列名不是date时换成实际列名。排序后顺手看一眼df.dtypes确认日期列是datetime64而不是object这是后续一切操作的前提。数据缺失方面有些站点记录会在某些日期缺测先统计缺失比例单列缺失超过30%优先考虑删除而不是填补否则填补出来的字段会对模型产生误导。2.2 缺失值与异常值处理时间序列数据不能按表格数据那样洗常见的错误做法是df.fillna(df.mean())把均值填进所有缺失日期。这在普通表格数据里问题不大但气温序列有季节性和连续性7月的缺失值不该用全年均值去填而应该用相邻日期的趋势去推。气温变化是连续过程前向填充和插值才是符合物理直觉的处理方式。# 对连续缺失先用前向填充承接前一天的值 df[temp_max] df[temp_max].ffill() # 再用线性插值处理中间残余的空洞 df[temp_max] df[temp_max].interpolate(methodlinear) df[temp_min] df[temp_min].ffill().interpolate(methodlinear) # 异常值检查用 3σ 法则标记偏离过大的点 for col in [temp_max, temp_min, humidity]: mean df[col].mean() std df[col].std() outliers df[col][(df[col] - mean).abs() 3 * std] print(f{col} 异常点数量: {len(outliers)})逻辑说明ffill()用前一时刻的值填补短时缺失适合传感器夜间断档这类场景interpolate(methodlinear)再对中间残余空位做线性插值让温度曲线平滑过渡。异常值这里只打印标记不直接删除因为3σ规则在气温序列上会把某些极端天气误判为异常。参数说明3σ是统计学常用阈值不是硬规定。如果打印出的异常点集中在每年最冷的几天那很可能是真实寒潮而不是坏数据需要人工复核后再决定去留。温度列也可以改用物理边界比如temp_max 45或temp_min -30这类气候学常识阈值。2.3 特征构建与数据集划分预测明天气温该用什么特征原始字段不能直接全塞进模型。日期本身不是数值特征必须拆成月份、星期几、季节等周期性特征。最关键的增量特征是滞后特征——昨天的最高气温、昨天的温差这些字段携带了天气的惯性信息对预测提升非常明显。# 基础特征 df[month] df.index.month df[dayofweek] df.index.dayofweek df[season] df[month] % 12 // 3 # 春0 夏1 秋2 冬3 # 滞后特征昨天和前天的信息 df[temp_max_lag1] df[temp_max].shift(1) df[temp_max_lag2] df[temp_max].shift(2) df[temp_diff] df[temp_max] - df[temp_min] # 删除含 NaN 的行构建滞后特征必然产生前几行的空值 df df.dropna()逻辑说明shift(1)让整个序列向下移动一行保证预测第t天时只使用第t-1天及之前的信息。season的计算是month % 12 // 3把12个月压缩成4个季节值。注意temp_diff是当天的温差它只能用于预测下一天不能用于预测当天这个边界要在划分数据前想清楚。参数说明滞后步数不是越多越好。对气温来说滞后1天和滞后2天物理意义最明显滞后7天可以捕捉周周期性但更多步长会引入噪声。特征构建完后定义features列表把标签单独取出然后进入数据集划分环节。这里的dropna()会把头部几行删掉因为shift必然产生NaN这是正常现象。数据集划分是气温预测项目里最容易被扣分的地方。分类项目习惯了train_test_split默认随机切分但时间序列一旦随机洗牌等于让模型在训练时偷看了未来数据测试集分数虚高到失去参考价值。from sklearn.model_selection import train_test_split features [month, dayofweek, season, humidity, pressure, temp_max_lag1, temp_max_lag2, temp_diff] X df[features] y df[temp_max] X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, shuffleFalse )逻辑说明shuffleFalse是时间序列划分的生死线。代码保持数据原始顺序前80%作为训练集、后20%作为测试集模拟“用过去预测未来”的真实场景。参数说明test_size0.2适合几百条以上的数据。如果总样本只有100条左右建议改为test_size0.3保证测试集有足够样本做评估。如果数据跨越多年更稳妥的做法是按年份切分比如前3年训练、第4年测试这样顺便考察模型对未见年份的泛化能力。3. 模型选型与训练线性回归、树模型与时序模型的三选一气温预测本质上是回归任务不是分类。课程设计在模型选择上常见两个极端只用一个线性回归显得技术含量不够硬上LSTM训练时间长、可解释性差答辩时还说不清原理。中间地带是树模型随机森林或梯度提升在几千条气象数据上表现稳定又容易解释特征重要性是课程设计的性价比之选。我一般建议先跑通线性回归当基线再用随机森林对比提升幅度报告里既有参照又有亮点。3.1 基线模型多元线性回归为什么是课程设计的及格线线性回归的价值不在精度而在提供一个可对照的基准。气温预测中温度与滞后温度、季节之间确实存在近似线性关系所以线性回归不会差得离谱后续树模型的效果对比也就更有说服力。答辩时老师通常先问你“有没有对比实验”线性回归就是那个锚点。from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score model_lr LinearRegression() model_lr.fit(X_train, y_train) y_pred_lr model_lr.predict(X_test) mae_lr mean_absolute_error(y_test, y_pred_lr) rmse_lr mean_squared_error(y_test, y_pred_lr, squaredFalse) r2_lr r2_score(y_test, y_pred_lr) print(f线性回归 MAE{mae_lr:.2f} RMSE{rmse_lr:.2f} R²{r2_lr:.3f})逻辑说明mean_squared_error(..., squaredFalse)直接返回RMSE避免手动开方。这三个指标足够支撑报告里的效果分析MAE代表平均绝对误差RMSE对大误差更敏感R²代表模型解释了多少方差。参数说明如果你用的sklearn版本较新squared参数已被标记弃用可以改用root_mean_squared_error函数。线性回归没有需要特别调的超参数它的作用就是快速验证特征工程是否合理。如果线性回归的R²都不足0.8优先回头检查特征而不是直接换复杂模型。3.2 进阶模型随机森林与梯度提升的取舍随机森林的优势是训练快、超参数少、不容易过拟合。梯度提升如GradientBoostingRegressor或XGBRegressor精度通常会高一点但需要调的参数更多课程设计答辩时被问到“你怎么调参的”如果答不上来反而扣分。样本量只有几千条时两者差距很小我一般推荐随机森林。from sklearn.ensemble import RandomForestRegressor model_rf RandomForestRegressor( n_estimators200, max_depth12, min_samples_leaf4, random_state42 ) model_rf.fit(X_train, y_train) y_pred_rf model_rf.predict(X_test) mae_rf mean_absolute_error(y_test, y_pred_rf) rmse_rf mean_squared_error(y_test, y_pred_rf, squaredFalse) r2_rf r2_score(y_test, y_pred_rf) print(f随机森林 MAE{mae_rf:.2f} RMSE{rmse_rf:.2f} R²{r2_rf:.3f})逻辑说明n_estimators200表示训练200棵决策树这个量级已经能稳定收敛max_depth12限制单棵树深度防止单棵树过深导致整体过拟合min_samples_leaf4要求每个叶节点至少4个样本同样起正则化作用。random_state42固定随机种子保证答辩演示和文档里的结果可复现。参数说明这几组参数不是唯一正确组合而是适合几千条气象数据的起点。如果是梯度提升模型重点调n_estimators和学习率learning_rate学习率建议从0.05开始。无论选哪个模型训练后一定要固定random_state否则每次运行结果不同文档实验数据对不上是课程设计的大忌。3.3 训练与评估气温预测不能用分类准确率那一套回归任务没有“准确率”这个概念但很多报告里出现“预测准确率90%”这种说法实际是用分类指标硬套回归把±1度以内的预测当正确、±2度当错误然后算百分比。这种做法在答辩时很难自圆其说因为温度预测是连续值不存在明确的“对/错”边界。更严谨的做法是同时报MAE、RMSE和R²用三个角度交叉说明模型效果。# 统一比较两个模型 results pd.DataFrame({ 模型: [线性回归, 随机森林], MAE: [mae_lr, mae_rf], RMSE: [rmse_lr, rmse_rf], R²: [r2_lr, r2_rf] }) print(results) # 误差的区间分布用来检查偏差是否集中在极端天气 errors y_test - y_pred_rf print(f误差绝对值≤1度的占比: {(errors.abs() 1).mean():.1%}) print(f误差绝对值≤2度的占比: {(errors.abs() 2).mean():.1%})逻辑说明用DataFrame把两个模型的指标排在一起报告里直接截图使用。误差区间分布比单一指标更有业务意义——如果±1度以内比例能到80%左右说明模型对绝大多数天气状况都预测得不错。参数说明这两个占比是辅助性指标写了显得分析细致但不能替代MAE、RMSE、R²三个主要指标。如果误差在高温日或寒潮日明显偏大说明模型对极端天气拟合不足可以在文档里专门分析这一点这反而是加分项。4. 可视化把预测结果画成老师一眼能看懂的样子课程设计的可视化不需要炫技但要覆盖三个层次整体趋势对比、误差分布分析、特征贡献解释。老师看图的顺序通常是先看整体拟合效果再看误差是否合理最后看模型可解释性。一套逻辑完整的图比一个花哨的交互页面更能拿分。4.1 预测曲线对比图真实值 vs 预测值的时间序列图最核心的一张图是测试集上的真实值与预测值折线图。画的时候提取测试集时间索引作为横轴真实温度序列和预测温度序列各画一条线就能直观看到模型是跟随真实趋势还是整体偏移。import matplotlib.pyplot as plt plt.figure(figsize(14, 5)) plt.plot(y_test.index, y_test.values, label真实气温, linewidth1.5) plt.plot(y_test.index, y_pred_rf, label预测气温, linewidth1.5, alpha0.8) plt.xlabel(日期) plt.ylabel(最高气温 (°C)) plt.title(RandomForest 气温预测效果对比) plt.legend() plt.grid(alpha0.3) plt.tight_layout() plt.savefig(prediction_curve.png, dpi150) plt.show()逻辑说明y_test.index是测试集对应时间索引因为划分时用了shuffleFalse索引顺序和真实时间线完全一致。alpha0.8让预测线半透明与真实线重叠时仍能看清走势差异。savefig把图保存到本地方便插进课程设计文档。参数说明figsize(14, 5)避免折线挤在一起dpi150保证截图插入Word或PDF时清晰。如果测试集跨越好几年图会很长可以只截取最近90天或180天展示更能看清单日预测误差。4.2 误差分布与特征重要性图让报告有“分析味”很多课程设计的可视化只停留在第一张对比图缺少误差分析和特征分析。其实这两张图成本很低但能让评分老师一眼看出你理解了模型而不是单纯调包。散点图考察真实值与预测值是否集中在对角线附近特征重要性图则能回答“哪些因素最能影响气温”这个业务问题。# 真实值-预测值散点图 plt.figure(figsize(5.5, 5)) plt.scatter(y_test, y_pred_rf, s12, alpha0.6) plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], r--, linewidth1.5, label理想对角线) plt.xlabel(真实气温 (°C)) plt.ylabel(预测气温 (°C)) plt.legend() plt.tight_layout() plt.savefig(scatter_pred.png, dpi150) plt.show() # 特征重要性 importances model_rf.feature_importances_ feat_imp pd.DataFrame({特征: features, 重要性: importances}) feat_imp feat_imp.sort_values(重要性, ascendingTrue) plt.figure(figsize(8, 5)) plt.barh(feat_imp[特征], feat_imp[重要性]) plt.xlabel(特征重要性) plt.tight_layout() plt.savefig(feature_importance.png, dpi150) plt.show()逻辑说明散点图里红色虚线代表“真实值等于预测值”的理想位置点越靠近这条线说明预测越准。sort_values按重要性升序排列画水平条形图时最重要的特征显示在最上方。参数说明s12是散点大小参数点太大会互相遮挡太小则看不清分布alpha0.6处理点重叠区域的暗色堆积。特征重要性用的是随机森林自带feature_importances_基于节点不纯度下降计算解释为“该特征对做决策的贡献程度”即可。4.3 用 Matplotlib 或 Pyecharts 做交互图表的取舍交互图表比如Pyecharts的动态折线图确实比静态Matplotlib图好看但课程设计的核心是逻辑完整性和可复现性。Pyecharts生成的HTML页面在答辩演示时很加分但不能直接插入Word文档需要截图。我一般建议主报告用Matplotlib静态图答辩演示时额外放一个Pyecharts的HTML版对比图两头兼顾。from pyecharts import options as opts from pyecharts.charts import Line line_chart Line() line_chart.add_xaxis(y_test.index.strftime(%Y-%m-%d).tolist()) line_chart.add_yaxis(真实气温, y_test.round(1).tolist(), is_smoothTrue) line_chart.add_yaxis(预测气温, y_pred_rf.round(1).tolist(), is_smoothTrue) line_chart.set_global_opts( title_optsopts.TitleOpts(title气温预测对比), xaxis_optsopts.AxisOpts(type_category) ) line_chart.render(prediction_interactive.html)逻辑说明y_test.index.strftime(%Y-%m-%d)把时间索引转成字符串列表这是Pyecharts接收横轴的常见格式。round(1).tolist()把Numpy数组转成Python列表并保留一位小数Pyecharts才能正确序列化。参数说明交互图的价值在于演示时可以放大某个时间段、悬停查看具体数值但精度不是重点。如果数据量超过几百个日期建议下采样或只看最近90天否则HTML文件会变得很大、拖动卡顿。如果出现离群点导致曲线被压扁可以手动调整yaxis_opts的min_和max_。5. 气温预测项目的五个高发坑现象、原因与解法气温预测这个题目得分温差特别大有些项目模型指标很好看但一查数据划分和特征构建就露馅。下面五条是最高发的坑按“现象→原因→解决”逐一拆解照着排查一遍基本能保住关键分。这些坑我基本都见过有的甚至出现在所谓“满分模板”里。5.1 数据泄漏把未来数据混进特征里分数直接打七折现象训练集上R²高达0.98测试集也高达0.95但换一段新数据后效果崩到0.6。原因是特征构建时用了“当天”的信息来预测“当天”。比如把第t天的温差temp_diff、第t天湿度同时当作特征构建训练输入又用第t天的最高气温作为标签等于让模型直接看到了答案。解决建立特征时只保留shift(k)得到的滞后特征凡是来自预测目标当天的字段都要排除。写一个自检函数遍历所有特征列检查数据框的索引是否等于标签索引一旦发现非滞后特征参与当天预测立即修正。最稳妥的做法是特征列表里只放_lag1、_lag2这类显式滞后列不污染原始列。5.2 时间序列乱序划分shuffle 一开测试集全是“偷看答案”现象train_test_split(X, y, test_size0.2)之后打印测试集日期发现日期是乱序的训练集里混着测试期间的气温数据。原因是默认的shuffleTrue对时间序列危害极大模型在训练时已经见过“未来”的样本测试集分数没有实际说服力。解决划分必须显式传shuffleFalse这在前文已经强调过。如果数据来自多年按年份切分更合理例如df[df.index.year 2023]作为训练集、df[df.index.year 2023]作为测试集。这是答辩时最常被追问的一个点答清楚就是加分项。5.3 评估指标选错用 R² 还是 RMSE评分标准不一样现象报告只写了一个“准确率”或者只写R²没有误差绝对量级。其实“准确率”在回归任务里没有官方定义而R²接近0.99也不代表预测精确因为温度数据的方差有限基线高时R²容易被顶高。只报R²会让老师误以为模型调得很好实际上可能是数据本身波动小。解决MAE、RMSE、R²三个指标一起报并补充“误差绝对值≤1度占比”这个业务化指标。写文档时用一行注释说明每个指标代表什么——比如MAE 1.8度意味着平均每天偏差不到2度这在气温预测场景是可接受范围。5.4 日期字段没解析Pandas 把日期读成字符串可视化全乱现象画折线图时横轴挤成一团或者时间顺序颠倒因为CSV里的日期被Pandas读成了object类型。直接plot()时横轴按字典序排序而不是时间先后导致1月、10月、11月排在一起曲线完全不可读。解决读取时就用parse_dates[date]或者读完之后用pd.to_datetime(df[date])转换。转换之后注意时区问题统一用pd.to_datetime(..., utcTrue)或确保本地化时间一致。做滞后特征前先确认索引已按时间排序df.sort_index()不能省。5.5 模型保存与复现random_state 没固定答辩时结果对不上现象答辩前一天运行脚本得到一个R²当天演示变成另一个值老师追问“为什么和文档对不上”现场非常被动。原因是训练时没固定随机种子随机森林每次生成的树有差异测试集评估结果也会细微变化。解决在数据划分、模型初始化两处都固定random_state并在文档开头写明随机种子值。更保险的方式是用joblib.dump(model_rf, model_rf.pkl)保存训练好的模型答辩前joblib.load再预测结果完全可复现。还有一个细节如果用了交叉验证也要给KFold或ShuffleSplit固定随机种子。6. 从 80 分到满分的三个进阶技巧基础链路跑通后课程设计通常在80分上下。想拿满分档需要在业务建模和文档表达上再做深一步。以下三个技巧是我反复验证过最有效的提升手段。6.1 用滞后特征把“昨天的气温”变成最强特征特征重要性图里往往能看到temp_max_lag1排在第一位说明昨天最高气温对今天有极强影响。除了滞后1天和2天可以再加一个滞后7天特征对应周期性冷空气活动模型对这组特征可以单独分析。df[temp_max_lag7] df[temp_max].shift(7) df[temp_mean_lag7] df[temp_mean].shift(7) df df.dropna()逻辑说明滞后7天特征捕捉的是“一周前同一天”的温度趋势能帮模型识别周期性天气过程。滞后特征增多后样本前7行必然变成空值必须dropna()否则模型会因NaN报错。参数说明特征不是滞后步长越多越好。写文档时可以说“本文实验了lag1、lag2、lag7三种滞后步长lag7在测试集上带来约0.1度MAE提升”这比“我加了滞后特征”要具体很多。要严谨对比可以分三组实验各跑一遍随机森林取MAE最低一组作为最终模型。6.2 滚动预测验证像真实业务一样逐日预测前面是单步预测每个测试样本的特征都来自真实历史数据。但真实业务里预测后天时明天的数据还没发生。要做多日预测只能用滚动预测先用第t天真实特征预测第t1天把预测值当作第t2天的滞后特征再继续。def rolling_forecast(model, df, features, start, steps): df df.copy() preds [] for i in range(steps): current df.iloc[start i] X_input current[features].values.reshape(1, -1) pred model.predict(X_input)[0] preds.append(pred) # 构造下一天的滞后特征 if temp_max_lag1 in features: df.iloc[start i 1, df.columns.get_loc(temp_max_lag1)] pred return preds逻辑说明滚动预测的核心是把新预测出来的气温写回temp_max_lag1特征列替代原来缺失的“真实值”。每走一步就用上一步预测更新滞后信息误差会小幅度累积这正反映真实场景的难度边界。参数说明steps不宜过长气温预测滚动超过7天误差会明显扩大。滚动预测的RMSE通常比单步预测高这很正常报告里可以单列一节讨论说明“单步预测代表模型上限滚动预测代表业务可行性”老师会认为你对模型局限性有清醒认识。6.3 报告与技术文档的写法让评分老师 10 分钟内看懂标题里带“使用文档”说明文档本身占相当比例分数。很多同学把文档写成代码注释摘录这是最大误区。按四段来写需求与数据说明、特征工程与模型选择、实验结果对比、运行方式说明。实验对比部分放模型指标对比表并加两三句对差异原因的解释比如“随机森林优于线性回归说明气温预测中存在明显的非线性交互关系”。运行方式部分写清从原始CSV到最终图表的完整命令流程附环境依赖清单让拿到源码的人能直接复现。答辩演示时只展示三样东西预测对比图、误差分析图、特征重要性图再多就会冲淡重点。我自己的习惯是演示完主动指出模型局限比如夏季强对流天气预测误差偏大这反而比一味吹嘘效果更有说服力。课程设计的方向虽然常见但能把数据、模型、解释串成完整闭环就足以在评分老师这里拿到该拿的分数希望帮到你。本文还有配套的精品资源点击获取