
简介这是一份面向Python课程设计与期末大作业的机器学习实战项目聚焦气温预测与可视化。项目系统对比了五种回归模型——三层感知机MLP、长短时记忆网络LSTM、随机森林、决策树和线性回归通过严格的训练与评估得出LSTM在预测准确率上表现最佳并配套开发了图形化界面方便用户直观查看预测结果。资源共38个文件压缩包约12.17MB涵盖10个py源码、4个ipynb笔记、多个已训练的pkl/h5/joblib模型文件、csv数据集、json字典及docx使用文档源码包含全国天气信息爬取、历史天气数据处理、模型训练、预测与可视化等完整模块注释详细部署简单新手也能快速上手。除核心算法外还提供了使用文档与模型调用示例便于二次开发和功能扩展。目前已有426人学习下载是期末大作业、课程设计高分参考的优质选择也可作为机器学习回归与GUI应用开发的入门实践。1. 气温预测课设把明天几度做成一份能答辩的机器学习作业每到课设季气温预测就会出现在一大批 Python 课程设计的题目清单里。这个项目的本质并不复杂拿到一段带日期的气温序列通过特征工程把它变成机器学习能直接吃的表格数据用回归模型预测未来一天或几天的气温再用可视化把预测结果讲清楚。它是机器学习入门阶段最有性价比的练手选题——数据免费可得、任务直观、模型从线性回归到集成学习都能跑。但想在这类课设里拿高分功夫全在数据预处理、特征构造和答辩呈现上。这篇笔记按一条完整落地路径来讲数据怎么收拾、特征怎么造、模型怎么选、坑在哪最后给出一套答辩现场最好用的可视化组合。2. 数据准备是第一道坎先让气温数据变得可训练2.1 数据从哪来真实气象数据比模拟数据经得起追问气温预测课设的数据来源常见就三种老师直接给定 CSV、从公开气象数据集下载、自己写爬虫抓天气网站的历史数据。我的建议很简单——优先找带日期 气温两列的现成 CSV因为课设重点在机器学习和可视化不在爬虫。数据量至少要有两年以上最好覆盖完整的四季循环否则模型学不到季节性规律答辩时被问为什么冬季预测偏差大会很被动。拿到数据后第一步不是建模是先看清数据长什么样。用 pandas 读进来看列名、数据类型、有没有空值import pandas as pd df pd.read_csv(temperature.csv) print(df.head()) print(df.info()) print(df[temp].describe())df.info()会告诉你每列的非空数量和数据类型temp列如果出现 object 类型说明里面有脏数据比如气温字段混入了None或空字符串。describe()输出的均值、标准差、min/max 能帮你快速判断有没有离谱的异常值——比如最高温 70 度这种明显错误记录。这个阶段宁可多花十分钟看清楚也不要直接进特征工程后面返工的成本高得多。如果拿到的文件是 Excel用pd.read_excel(temperature.xlsx)即可注意先确认 sheet 名和表头在第几行常见参数sheet_name0, header0默认读第一个 sheet 的第一行当列名如果你的文件结构不是这样指定一下就好。数据源的选取原则是答辩时老师问数据哪来的你能清楚说出时间范围、地点、采样频率这就够了。2.2 日期解析和缺失值前向填充为什么适合气温序列气温 CSV 里最常见的两个坑是日期列没被解析成时间类型以及中间有几天数据缺失。先处理日期列这一步不做好后面所有按时间排序、画趋势图的操作都会出问题df[date] pd.to_datetime(df[date], format%Y-%m-%d, errorscoerce) df df.dropna(subset[date]) df df.set_index(date).sort_index() print(df.index)pd.to_datetime的format参数要写清楚%Y-%m-%d对应2021-03-15这种格式。errorscoerce的意思是解析不了的日期直接置成NaT之后统一删掉而不是让程序报错中断——这样能一次性定位脏数据。set_index(date)把日期变成索引后面做滞后特征和滑动窗口都依赖这个时间索引。sort_index()保证数据按时间从旧到新排列这是时间序列任务的前提。缺失值处理是气温预测里最容易翻车的地方。我的做法是优先用ffill()前向填充df[temp] df[temp].ffill() print(df[temp].isna().sum())为什么用前向填充而不是均值填充因为气温是连续变化的物理量今天缺了昨天的温度是比全年均值靠谱得多的估计。均值填充会把夏天和冬天的缺失值都拉到同一个水平等于给数据人为加了噪声。如果缺失的是连续几天可以考虑interpolate(methodlinear)做线性插值但课设级别用ffill()就足够。填充完再确认一次没有剩余空值然后处理极端异常值mean_temp df[temp].mean() std_temp df[temp].std() df df[(df[temp] mean_temp - 3 * std_temp) (df[temp] mean_temp 3 * std_temp)]这里用的是 3 倍标准差截断把超出正常范围的气温记录当成传感器故障剔除。注意这一步要在填充之后做否则缺失值会被误判成异常值。数据收拾完可以用一句df.plot(figsize(12, 4))画个全量温度曲线确认曲线有季节波动、没有断崖式跳变再继续往下走。2.3 按时间切分训练集时间序列里随机划分是大忌很多入门者在这里会不自觉用train_test_split(X, y, test_size0.2)这是气温预测里最典型的数据泄漏来源之一。train_test_split默认会随机打乱数据随机打乱后训练集里可能混进了未来的样本测试集里也出现了过去的样本模型等于提前偷看了答案。时间序列任务必须按时间顺序切分cutoff int(len(df) * 0.8) train_df df.iloc[:cutoff] test_df df.iloc[cutoff:] print(f训练集{train_df.index[0]} 到 {train_df.index[-1]}) print(f测试集{test_df.index[0]} 到 {test_df.index[-1]})iloc[:cutoff]取前 80% 作为训练集后 20% 作为测试集。这里的 80/20 是课设常用的切分比例气温数据量不大前 80% 足够覆盖至少一个完整年循环。切分后打印两段的时间范围确认训练集的最后日期早于测试集的第一天。这一步做对了后面再谈模型才有意义。切分完先别急着建模。把特征列和目标列拆出来时有一个很容易忽略的细节如果后面做了滞后特征或滚动窗口前几行会出现 NaN必须在切分前统一dropna()否则测试集的第一天会因为没有 lag 特征而被直接丢掉。习惯的顺序是先造特征再删含 NaN 的行最后按时间切分。3. 特征工程让机器学习模型看懂气温的惯性3.1 滞后特征昨天的温度是今天最强的预测因子气温预测和一般的回归任务最大的不同是它是有强自相关的时间序列。昨天的气温和今天的气温相关性极高这比任何复杂模型都更重要。把它变成机器学习能用的特征就是滞后特征——把过去几天的温度值平移到当前行上df[lag_1] df[temp].shift(1) df[lag_2] df[temp].shift(2) df[lag_7] df[temp].shift(7) print(df[[temp, lag_1, lag_2, lag_7]].head(10))shift(1)把整列温度往下移一行所以第 2 行的lag_1等于第 1 行的temp含义就是昨天的实际温度。lag_7是七天前的温度用来捕捉一周为周期的变化——很多地区的气温有稳定的周内规律。观察打印出来的前几行你会发现开头 7 行全是 NaN因为 7 天前没有数据这是正常的之后统一dropna()处理。滞后特征该设几阶我的经验是lag_1、lag_2、lag_7三列足够课设使用。再往前加lag_14、lag_30边际收益很小反而增加了特征维度。答辩时如果老师问为什么选这几个滞后阶数可以说lag_1和lag_2利用气温的短期惯性lag_7捕捉每周周期这是对气温序列做自相关分析后最常见的显著滞后点。回答得有理有据比我试了很多感觉这个好强很多。3.2 滑动窗口统计窗口设 7 天还是 30 天关键在防泄漏滞后特征告诉模型前一天多冷滑动窗口统计告诉模型最近一段时间整体是冷是热。这个特征在寒潮来临、气温连续走低时特别有用。常见的写法是df[rolling_mean_7] df[temp].shift(1).rolling(window7).mean() df[rolling_max_7] df[temp].shift(1).rolling(window7).max() df[rolling_std_7] df[temp].shift(1).rolling(window7).std()注意这里有一个隐藏很深的坑rolling(window7).mean()计算的是当前行及前 6 行的均值如果直接用df[temp].rolling(7).mean()那当前行的特征里已经包含了当天温度——而当天温度恰恰是我们要预测的 y。这就造成了特征泄漏模型在训练集上表现完美测试集上立刻现原形。解决办法就是在rolling之前先.shift(1)让窗口只包含过去 7 天的数据不含当天。窗口值为什么选 7因为日气温的周期是 7 天一周内的冷暖波动规律明显。30 天的窗口会过度平滑把短期寒潮的细节抹掉。rolling_std_7表示最近 7 天的温差波动标准差大说明天气剧烈变化模型可以据此调整预测的置信度。这三列特征组合起来等于给每个样本配了一段最近一周的天气简报。3.3 日期周期编码把季节转成 sin/cos别拿月份当普通数值气温预测里季节因素必须进模型但直接用月份当数值特征是有问题的。12 月的month12和 1 月的month1数值相差 11可实际只隔了一个月气候上非常接近。模型会把 11 的差值当作差距很大从而在冬春交替时产生偏差。正确处理是把日期转换成周期变量用 sin/cos 编码import numpy as np day_of_year df.index.dayofyear df[sin_doy] np.sin(2 * np.pi * day_of_year / 365) df[cos_doy] np.cos(2 * np.pi * day_of_year / 365)dayofyear返回 1 到 365 的整数表示当天在一年中的第几天。sin_doy和cos_doy把季节转成一个平滑循环的二维坐标夏天对应一组值冬天对应另一组值12 月和 1 月在坐标空间里非常接近。这就是为什么说日期特征也能做成特征工程而不是把日期当成一个普通整数丢进去。除了季节还可以加一周内周期的编码df[dayofweek] df.index.dayofweek表示星期几。人的活动规律会影响城市热岛效应工作日和周末的气温模式会有一点差异。如果数据是某个大城市的观测值这个特征值得加。加上之后特征集合大概是这样的features [ lag_1, lag_2, lag_7, rolling_mean_7, rolling_max_7, rolling_std_7, sin_doy, cos_doy, dayofweek ] df df.dropna() X df[features] y df[temp]dropna()这一步会把数据最开始那几行滞后特征和滑动窗口还没形成和缺失日期删掉删完后看一眼X.shape确认行数没有骤减。到这里数据已经从一个日期 温度的两列原始表变成了一张真正的机器学习特征表。接下来才能安心谈模型。4. 模型选型与调参先有基线再谈提升4.1 线性回归当基线跑通流程比追求精度重要气温预测的模型选型我强烈建议按线性回归 → 随机森林/梯度提升的顺序来做而不是一上来就上 LSTM 这类深度学习模型。课设的核心是完整跑通数据-特征-模型-评估-可视化闭环不是展示多复杂的网络。线性回归就是最合适的基线它训练快、可解释性强还能帮你验证特征工程是否有效。from sklearn.linear_model import LinearRegression X_train, y_train train_df[features], train_df[temp] X_test, y_test test_df[features], test_df[temp] model_lr LinearRegression() model_lr.fit(X_train, y_train) pred_lr model_lr.predict(X_test)注意这里train_df和test_df是第 2 章切分好的两个 DataFrame特征列features用的是第 3 章定义的列表。线性回归没有需要调试的超参数fit和predict跑通即可。训练完可以看一眼model_lr.coef_把特征名和系数对应起来你会发现lag_1的系数通常是最大的——这能验证特征构造方向是对的答辩时也是很好的解释材料。线性回归的最大局限是它学不到非线性关系比如最近 7 天温差很大可能意味着强冷空气过境温度会跳变这类模式。所以线性回归的结果只能当基线真正的预测主力还得看集成模型。4.2 随机森林和梯度提升三个关键参数怎么设随机森林是课设模型里性价比最高的选择默认表现稳定、对异常值不敏感、能输出特征重要性。用随机森林回归器训练关键参数就三个——树的数量、树的最大深度、叶子节点的最小样本数from sklearn.ensemble import RandomForestRegressor model_rf RandomForestRegressor( n_estimators200, max_depth10, min_samples_leaf5, random_state42 ) model_rf.fit(X_train, y_train) pred_rf model_rf.predict(X_test)n_estimators200表示 200 棵决策树气温预测的特征数和数据量都不大这个数量足够稳定再多数值提升很小训练时间却线性增长。max_depth10限制每棵树的深度这是防过拟合的关键——树太深会把训练集里的噪声都背下来。min_samples_leaf5要求每个叶子节点至少 5 个样本进一步强制模型学普遍规律而不是个别样本。random_state42固定随机种子保证每次运行结果可复现课设评分演示时不会因为重跑一遍数字变了而尴尬。如果你的环境装好了 XGBoost也可以试试梯度提升路线sklearn 自带的GradientBoostingRegressor同样可用from sklearn.ensemble import GradientBoostingRegressor model_gb GradientBoostingRegressor( n_estimators100, learning_rate0.1, max_depth3, random_state42 ) model_gb.fit(X_train, y_train) pred_gb model_gb.predict(X_test)梯度提升和随机森林的参数逻辑不太一样learning_rate0.1控制每棵树对结果的贡献越小越稳但需要更多树max_depth3是故意限制深度因为梯度提升是串行拟合残差树太深非常容易过拟合。新学期如果 sklearn 版本较新注意GradientBoostingRegressor没有n_jobs参数多核并行在随机森林里才有意义。调参这件事最容易变成玄学我的建议是不要盲目网格搜索先固定random_state依次调max_depth和min_samples_leaf看测试集 MAE 的变化趋势每次只改一个参数记录变化答辩时这就是你的实验分析。4.3 评估指标MAE/RMSE/R² 在气温预测里的合理范围模型训完必须用统一的指标对比。气温预测属于回归任务常用三个指标from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score import numpy as np print(线性回归 MAE:, round(mean_absolute_error(y_test, pred_lr), 3)) print(线性回归 RMSE:, round(np.sqrt(mean_squared_error(y_test, pred_lr)), 3)) print(线性回归 R²:, round(r2_score(y_test, pred_lr), 4)) print(随机森林 MAE:, round(mean_absolute_error(y_test, pred_rf), 3)) print(随机森林 RMSE:, round(np.sqrt(mean_squared_error(y_test, pred_rf)), 3)) print(随机森林 R²:, round(r2_score(y_test, pred_rf), 4))注意新版 sklearn 里mean_squared_error的squared参数已经被移除推荐用np.sqrt(mean_squared_error(...))求 RMSE别踩废弃 API 的坑。三个指标怎么看MAE 是平均绝对误差气温预测误差在 2 度以内算不错1 度以内属于优秀RMSE 比 MAE 大多少反映模型有没有在某些天严重跑偏R² 在 0.8 以上说明模型抓住了主要规律0.9 以上就非常好了。三个模型跑完顺手做一张对比表模型MAERMSER²线性回归2.313.050.81随机森林1.852.440.88梯度提升1.722.300.90这张表放进使用文档的实验分析一节比任何文字描述都有说服力。周志华《机器学习》第 2 章讲过模型评估要看你关心的误差类型——气温预测最常报的是平均偏差所以 MAE 是第一优先指标。5. 气温预测的五个典型坑数据泄漏、中文乱码和过拟合5.1 数据泄漏洗数据时把未来混进了训练集现象训练集 R² 高达 0.97测试集一跑直接崩到 0.4 以下两者差距大得离谱。原因最常见的两个来源一是用了train_test_split默认的随机打乱未来样本混进训练集二是滑动窗口特征里包含了当天的温度即忘记了先shift(1)。两者都会让模型在训练时偷看答案。解决训练集和测试集严格按时间顺序用iloc切分所有滚动窗口统计先shift(1)再做rolling滞后特征本身就是平移过去的不会包含未来信息但要确认没有对整列做任何排序操作。养成一个习惯特征造完后用X_train.index.max()和X_test.index.min()比较一下训练集最晚日期必须早于测试集最早日期。5.2 matplotlib 中文变方块字体设置必须在画图之前现象图例和坐标轴标题的中文全部变成方框预测效果图根本没法放进报告。原因matplotlib 默认字体不支持中文Windows 上常见的中文字体 SimHei 没有被启用。解决在 pyplot 导入后、画任何图之前先执行两行设置import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False第一行把默认无衬线字体换成黑体第二行解决负号显示为方块的问题——气温预测图里冬季数据全是负值这一行不写坐标轴上的-5℃会显示成一个小方块。如果用的是 macOS把SimHei换成Arial Unicode MS或PingFang SC。这个坑不解决后面的可视化做得再细都白费。5.3 过拟合随机森林的深度是祸根现象随机森林训练集 R² 高达 0.99测试集 R² 只有 0.6模型把训练集里的噪声背下来了。原因max_depth不设或设得太大min_samples_leaf默认值为 1树可以无限制分裂直到每个叶子只剩一个样本。解决按第 4 章的参数先跑max_depth10、min_samples_leaf5。如果还过拟合就往下调max_depth到 6~8同时观察训练集和测试集 MAE 的差距差距缩小说明在朝正确方向走。还有一种隐蔽情况特征里同时存在强相关的lag_1和lag_2树会反复用同一组特征分裂这时手动删掉lag_2再试试。调参不是越猛越好指标上训练集和测试集差距控制在 0.1 以内才算健康。5.4 月份编码的坑12 月和 1 月的距离不应该是 11现象模型整体误差不错但在 12 月到次年 2 月的过渡期误差明显放大其他月份正常。原因直接把month当数值特征12 月的值是 121 月的值是 1模型认为这两个月份相距甚远导致冬春交替时预测曲线出现不自然的阶跃。解决用第 3 章的 sin/cos 周期编码替代原始月份或者把月份转成dayofyear再做 sin/cos 变换。这两种做法都能让模型正确理解12 月和 1 月是相邻的季节。这也是气温预测课设里最容易在答辩时被老师点破的细节一旦说出来我把月份做了周期编码印象分会明显不同。5.5 极端温度预测值偏保守回归模型的均值回归倾向现象高温天和寒潮天的预测值总是差一点——夏天的极端高温被预测低了冬天的强寒潮被预测高了整体 MAE 看起来还行但逐日看总是温和。原因回归模型在训练时被优化为最小化平均误差而极端气温在样本里出现频率低模型倾向于输出一个安全的中间值这就是均值回归现象不是 bug是回归任务的天性。解决不要试图用调参硬掰模型就算调得再好极端天也会偏保守。正确做法是在使用文档的误差分析一节里说明这一点模型在平均天气下 MAE 约 1.5 度在极端天气下 MAE 约 3 度并附一张按月份分组的误差表。老师看到你能主动指出模型的系统性偏差比看到一张完美的预测图更说明你理解了这个任务。6. 可视化与报告呈现把预测结果画成老师能一眼看懂的图6.1 三张核心图历史分布、预测对比、残差直方图气温预测的可视化不需要花哨三张图足够支撑整个课设的展示。先画数据概览展示原始气温序列的季节波动这张图放在文档开头让读者理解数据背景。再画测试集的预测对比曲线plt.figure(figsize(12, 5)) plt.plot(test_df.index, y_test, label实际气温, linewidth1.5) plt.plot(test_df.index, pred_rf, label随机森林预测, linewidth1.5, alpha0.8) plt.xlabel(日期) plt.ylabel(气温℃) plt.legend() plt.title(测试集气温预测效果对比) plt.show()图里要能直观看到两条曲线的贴合程度冬季和夏季的波峰波谷是否对齐。第三张是残差直方图即预测值与实际值的差值分布residual y_test - pred_rf plt.hist(residual, bins30, edgecolorwhite) plt.xlabel(预测误差℃) plt.ylabel(频数) plt.title(预测误差分布直方图) plt.show()残差分布接近以 0 为中心的正态分布说明模型没有系统性偏差如果中心在 0.5 以上说明模型整体偏低需要回去检查特征。6.2 特征重要性图用可视化告诉评委模型靠什么工作随机森林自带feature_importances_一张图就能把模型靠什么做预测讲清楚。横向柱状图按重要性从高到低排列import matplotlib.pyplot as plt importance model_rf.feature_importances_ idx_sorted np.argsort(importance) plt.figure(figsize(8, 6)) plt.barh( [features[i] for i in idx_sorted], importance[idx_sorted] ) plt.xlabel(特征重要性) plt.title(随机森林特征重要性排序) plt.show()这张图的价值在于它把模型的决策依据可视化出来了。你可以在答辩时说特征重要性最高的三个是滞后 1 天、滞后 7 天和最近 7 天滑动均值说明气温预测主要由短期惯性和周周期驱动。这样讲比任何指标数字都有说服力。如果特征重要性里 sin/cos 的季节编码排进了前五说明季节性也贡献明显和气温常识完全吻合。如果 lag 特征一枝独秀反而该反思是不是滑动窗口和周期特征构造得不够好。6.3 可视化在报告中的呈现顺序课设使用文档里图表呈现顺序建议固定为数据概览图 → 特征相关性或分布图 → 模型对比表 → 预测效果图 → 残差图 → 特征重要性图。这个顺序对应评审的阅读逻辑先看数据是否合理再看方法是否严谨最后关注结果和解释。所有图必须有坐标轴标签、标题、图例图注里写明数据时间范围这是很多人忽略的评分细节。如果想把课设做得更有诚意可以在预测对比图里加一段放大窗口截取测试集最后 30 天让线条细节看得更清楚或者把预测区间画成阴影带展示模型的不确定性。可视化这块的核心是让别人 30 秒内看懂你做了什么、做得怎么样。我自己的习惯是最后跑一遍完整流程确认所有图片都能在干净环境下重新生成再提交源码和文档。代码能一次跑通、图能完整复现、文档能解释每一处设计选择这才是课程设计拿高分的底层逻辑。希望帮到你。本文还有配套的精品资源点击获取