Python机器学习天气预测与可视化:从数据清洗到随机森林全流程
简介基于Python机器学习ML的天气预测与可视化课程设计项目面向高校Python课程设计、数据科学入门及机器学习实践者。项目以天气预测为场景完整演示数据获取、清洗、特征处理、模型训练与结果可视化流程。覆盖线性回归、决策树、随机森林、支持向量机等常用算法并借助scikit-learn交叉验证评估模型性能同时通过matplotlib、seaborn等绘制温度、湿度、风速、降水等时间序列图与热力图直观展示天气变化规律。打包资源共25个文件主体为4个Python脚本数据采集、处理、建模与预测、4个CSV数据集、1个已训练模型文件pkl、1个HTML可视化页面以及12张结果截图压缩包仅1.42MB轻量易下载。目前已有38人学习适合课程设计参考或自学练手。资源内含可运行的代码与数据集模型文件可直接加载使用配套说明文档和多角度运行截图帮助读者快速复现天气预测系统提升机器学习与数据可视化综合实践能力。1. 天气预测课程设计的机器学习项目拆解如果你拿到一个名为“基于python机器学习(ml)的天气预测和天气可视化.zip”的课程设计项目里面大概率不是一套气象级预报系统而是一条完整的机器学习流水线从历史气象数据出发经过数据清洗、特征工程、模型训练最终用图表把预测结果呈现出来。气象台做预报依赖的是巨型数值模拟和超算但课程设计只需要回答一个问题给出一年的历史天气数据能不能用机器学习模型预测出明天的最高温度。这个项目的核心价值在于它覆盖了机器学习应用的全部环节而不是某个单独算法。数据怎么选、缺失值怎么补、时间特征怎么拆、回归器和分类器怎么取舍、预测误差多少算合理、可视化怎么不踩中文乱码的坑这些才是你真正要交付的东西。如果你正在做类似的课程设计或者想拿一个真实场景练手scikit-learn和pandas这篇内容就是照着这个流程走的完整方案。2. 天气预测数据从哪来数据集选型与清洗2.1 天气预测数据集选型的两个原则做天气预测课程设计第一步卡住的通常是数据。常见做法是去中国气象数据网或Kaggle下载某个城市的历史气象数据选型遵循两个原则时间跨度至少一年字段覆盖温度和湿度。课程设计不需要卫星云图和雷达回波表格化的逐日气象记录就足够让机器学习模型跑起来了。拿到一份典型的天气预测数据集我一般先确认有没有这些字段。字段类型用途date日期时间特征拆解的基础temperature_max / temperature_min数值预测目标或特征humidity数值重要特征pressure数值重要特征wind_speed数值辅助特征precipitation数值辅助特征缺失多时可丢弃数据集里的日期字段经常是字符串格式第一步要转成datetime类型。检查数据量时用df.info()看每一列的非空计数比肉眼翻Excel快得多。import pandas as pd df pd.read_csv(beijing_weather.csv, encodinggbk, parse_dates[date]) df[year] df[date].dt.year df[month] df[date].dt.month print(df.info()) print(df.head())这里的parse_dates[date]会在读取时自动把日期字符串转成datetime对象比读取后再转换更省事。编码用了gbk因为很多国内气象站导出的CSV文件是中文GBK编码用默认的utf-8读取会直接报错。如果按gbk仍然报错改成encodinggb18030这是GBK的超集兼容性更好。2.2 天气预测数据的缺失值与异常值处理机器学习模型本身不能接受NaN值这是处理天气数据的第一个硬性要求。缺失值处理要分列讨论不能一把梭。降水这类字段在干燥地区可能连续几个月是0缺失率超过30%就应该直接丢弃而不是填充因为填充出来的数据会引入噪声。对于温度、湿度、气压这类关键字段我会先做线性插值再过滤异常值。线性插值适合天气数据的原因是它利用时间邻域的信息比用均值填充更贴近真实变化趋势。# 缺失率超过30%的列直接丢弃 thresh int(0.7 * len(df)) df df.dropna(threshthresh, axis1) # 对数值列做线性插值 num_cols [temperature_max, temperature_min, humidity, pressure, wind_speed] for col in num_cols: if col in df.columns: df[col] df[col].interpolate(methodlinear) # 过滤明显异常值最高温不可能超过50度或低于-50度 df df[(df[temperature_max] -50) (df[temperature_max] 50)]dropna(threshthresh)不是删除有缺失的行而是删除非空值数量小于thresh的列处理“某整列数据几乎没有”的情况最有效。interpolate(methodlinear)按行索引顺序做线性插值对时间序列数据来说前后两天的温度插值结果比整列均值合理得多。2.3 时间序列数据与机器学习三大假设的冲突天气数据是典型的时间序列而机器学习模型的基本假设是训练数据和测试数据独立同分布。天气数据显然不严格满足这个假设昨天的温度和今天的温度高度相关。处理方式是在切分训练集和测试集时不要随机洗牌而是按时间顺序切分前70%的数据训练后30%的数据验证。如果用train_test_split默认的随机切分模型会“偷看”未来数据评估结果虚高答辩时被问住就尴尬了。# 按时间顺序切分而非随机切分 split_idx int(len(df) * 0.7) train_df df.iloc[:split_idx] test_df df.iloc[split_idx:]这里iloc[:split_idx]取前70%的行iloc[split_idx:]取后30%。随机切分对普通分类任务没问题但天气预测这种时间序列任务随机切分会让测试集里混进测试时间段之前的样本导致特征中存在未来信息。这一点是机器学习期末复习里反复强调的内容放到实际项目里就是评估指标的可靠性问题。3. 天气预测的机器学习模型训练从特征工程到随机森林3.1 时间特征拆解与滞后特征构建原始日期字段不能直接喂给机器学习模型模型读不懂2024-03-15这种字符串。常见的做法是把日期拆成年、月、日、星期几。其中“月”和“星期几”对温度预测尤其重要月份刻画季节周期星期几刻画人类活动带来的城市热岛效应差异。滞后特征也是天气预测中最容易被忽略但效果显著的特征。所谓滞后特征就是用前一天的温度当作今天的输入特征。这符合天气变化的物理直觉今天的温度不会突然偏离昨天太多。# 时间特征拆解 df[day] df[date].dt.day df[dayofweek] df[date].dt.dayofweek # 滞后特征前一天的最高温 df[temp_max_lag1] df[temperature_max].shift(1) # 滑动平均特征近3天的平均最高温 df[temp_max_ma3] df[temperature_max].rolling(window3).mean() df df.dropna()shift(1)把整个列向下移动一位第i行的temp_max_lag1就是第i-1行的temperature_max。因为没有“昨天”这个字段第一行必然变成NaN所以要放在最后统一dropna()。rolling(window3).mean()计算最近三天的滑动均值起到平滑作用能削弱单日异常波动的影响。滞后特征和滑动平均特征是时间序列预测中最重要的两类特征比单纯把日期拆开有效得多。3.2 特征相关性分析与回归器选择模型选择前先画一张特征相关性热力图这一步能直观告诉你温度和哪些特征强相关。用seaborn的heatmap配合pandas的corr()一次就能看清整个数据集的线性相关性。import seaborn as sns import matplotlib.pyplot as plt # 中文显示配置 plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei, PingFang SC] plt.rcParams[axes.unicode_minus] False corr_cols [temperature_max, temperature_min, humidity, pressure, wind_speed, month, dayofweek, temp_max_lag1] corr_matrix df[corr_cols].corr() plt.figure(figsize(10, 8)) sns.heatmap(corr_matrix, annotTrue, fmt.2f, cmapcoolwarm, annot_kws{size: 10}) plt.title(天气特征相关性热力图) plt.show()热力图的直觉判断是如果temp_max_lag1和temperature_max相关性接近0.9说明用前一天的温差预测今天的温度是有效的。annotTrue在格子上显示相关系数数值fmt.2f控制显示两位小数cmapcoolwarm用蓝红渐变色突出正负相关。天气预测任务在机器学习分类器与回归器的选择上有一个基本判断标准如果目标是具体的温度数值就是回归问题用RandomForestRegressor或LinearRegression如果目标是“晴/雨/雪”这样的类别就是分类问题用RandomForestClassifier。课程设计里预测最高温度是回归任务不要用分类器硬套。3.3 随机森林回归模型训练与参数设置from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score feature_cols [year, month, day, dayofweek, humidity, pressure, temp_max_lag1, temp_max_ma3] X df[feature_cols] y df[temperature_max] X_train, X_test X.iloc[:split_idx], X.iloc[split_idx:] y_train, y_test y.iloc[:split_idx], y.iloc[split_idx:] model RandomForestRegressor( n_estimators200, max_depth10, min_samples_leaf3, random_state42 ) model.fit(X_train, y_train) y_pred model.predict(X_test) print(MAE:, round(mean_absolute_error(y_test, y_pred), 2)) print(RMSE:, round(mean_squared_error(y_test, y_pred, squaredFalse), 2)) print(R2:, round(r2_score(y_test, y_pred), 3))随机森林的数学原理是bootstrap聚合通过有放回抽样训练多棵决策树然后对预测结果取平均。它相比线性回归的优势在于能自动捕捉非线性关系温度变化和湿度、气压的关系明显不是纯线性的。n_estimators控制树的数量200是经验和效果的平衡点继续加大到500对精度提升很小但推理时间会成倍增加。max_depth限制每棵树的深度10层足够表达温度与特征的复杂关系min_samples_leaf3要求叶子节点至少3个样本这两项参数配合起来能有效抑制单棵树的过拟合。random_state42固定了随机种子保证每次运行结果一致答辩现场重新跑一遍代码结果和报告里写的一致这一点在机器学习环境配置时就要注意。3.4 天气预测模型评估指标的取舍课程设计报告里不能只写准确率天气预测这种回归任务要同时看三个指标。MAE平均绝对误差看预测值和真实值之间平均差多少度单位是摄氏度最直观。RMSE均方根误差对离群点更敏感它把所有误差平方后再开根号所以一次偏差5度的预测对RMSE的惩罚远大于MAE。R²的取值范围是负无穷到11表示完美拟合0表示模型预测效果等同于直接用均值预测。指标数值含义MAE1.83℃平均每天预测偏差不到2度RMSE2.47℃大的误差点被放大了R²0.91模型解释了91%的温度方差这三个指标联合起来能发现很多问题如果MAE很小但RMSE很大说明大多数预测很准但存在少量极端偏离比如突然的倒春寒天气模型没捕捉到如果R²偏低且MAE偏高说明某个重要特征没构建好通常优先怀疑滞后特征和滑动平均特征是否计算正确。机器学习数学理论中泛化误差界的思路在这里也适用训练集和测试集的误差差距越接近模型的泛化能力越好。4. 天气可视化数据故事与课程设计展示4.1 matplotlib可视化基础配置与两线对比图天气可视化是课程设计里最容易出彩也最容易踩坑的部分。最常见的坑是matplotlib中文乱码默认字体不支持中文字符时坐标轴标题全变成方块或乱码。解决办法是在画图前显式指定支持中文的字体SimHei适用于Windows系统PingFang SC适用于macOS。import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei, PingFang SC] plt.rcParams[axes.unicode_minus] False plt.figure(figsize(14, 5)) plt.plot(y_test.values, label真实温度, linewidth1, color#333333) plt.plot(y_pred, label预测温度, linewidth1.2, alpha0.8, color#d62728) plt.legend() plt.title(最高温度预测值与真实值对比, fontsize14) plt.xlabel(样本序号按时间排序) plt.ylabel(温度℃) plt.grid(True, linestyle--, alpha0.4) plt.tight_layout() plt.show()linewidth控制线条粗细预测线用1.2比真实线略粗视觉上更容易区分。alpha0.8对预测线加一点透明度两条线重叠的区域能看出来密度分布。grid(True, linestyle--, alpha0.4)加了半透明网格线方便看图时估算具体数值。这张图放在课程设计报告的实验结果那一节能直观证明模型的预测趋势和真实变化一致。4.2 用热力图和残差图讲数据故事相关性热力图放在特征工程章节体现选特征的依据残差图放在模型评估章节体现对模型的深入理解。残差图的做法是横轴画预测值、纵轴画真实值和预测值的差残差点随机分布在0轴两侧说明模型没有系统性偏差如果残差在左侧全是正、右侧全是负说明模型存在欠拟合或特征缺失。import numpy as np residuals y_test.values - y_pred plt.figure(figsize(10, 5)) plt.scatter(y_pred, residuals, alpha0.5, s15, color#1f77b4) plt.axhline(y0, color#333333, linestyle--, linewidth1) plt.title(残差分布图预测值与真实值差值, fontsize14) plt.xlabel(预测温度℃) plt.ylabel(残差真实值 - 预测值℃) plt.show()scatter的alpha0.5半透明处理是为了应对数据点重叠的情况s15控制点的大小。axhline(y0)在y0的位置画一条水平参考线残差点围绕这条线对称分布说明模型预测没有方向性偏移。如果残留靠下部分有弧形的结构说明特征的线性关系没有学透可以考虑换GradientBoosting或XGBoost。4.3 Flask轻量封装把天气可视化变成可交互的页面课程设计答辩时如果能现场演示一个网页版的天气预测工具展示效果比Jupyter Notebook里的静态图表好很多。最简单的做法是用Flask封装模型用户输入当天的湿度、气压等数值页面返回明天的最高温度预测同时用Chart.js在前端画一个近30天的预测趋势图。from flask import Flask, request, jsonify import joblib import pandas as pd app Flask(__name__) # 用 joblib 持久化训练好的模型避免每次请求都重新训练 model joblib.load(weather_model.pkl) feature_cols [year, month, day, dayofweek, humidity, pressure, temp_max_lag1, temp_max_ma3] app.route(/predict, methods[POST]) def predict(): data request.get_json() input_df pd.DataFrame([{ year: data[year], month: data[month], day: data[day], dayofweek: data[dayofweek], humidity: data[humidity], pressure: data[pressure], temp_max_lag1: data[temp_max_lag1], temp_max_ma3: data[temp_max_ma3] }]) result model.predict(input_df)[0] return jsonify({predicted_max_temp: round(result, 2)}) if __name__ __main__: app.run(debugFalse, port5000)这个接口用POST请求接收JSON格式的输入返回预测温度。debugFalse是关键Flask的debug模式会启动代码热重载在课程设计演示现场如果代码有语法错误页面会直接显示交互式调试器演示效果大打折扣。joblib比pickle更适合保存scikit-learn模型对大数组的处理效率更高。5. 天气预测模型的分箱校准验证与特征重要性诊断回归模型做分箱校准是课程设计答辩中最能体现水平的技巧。随机森林默认会给出预测值但预测值本身没有置信区间评委如果问“你的模型预测明天最高温22度那21.5度到22.5度之间的可信度大概是多少”直接用R²回答是答非所问。分箱校准的做法是把测试集的预测结果按大小排序切成10个箱子每个箱子里取预测均值和真实均值然后画一条校准曲线两边的点落在45度对角线附近说明模型的预测在不同温度区间都保持稳定。import numpy as np # 分箱校准图按预测温度分成10箱 bins np.percentile(y_pred, np.linspace(0, 100, 11)) bin_indices np.digitize(y_pred, bins) - 1 bin_pred_mean [] bin_true_mean [] for i in range(10): mask bin_indices i bin_pred_mean.append(y_pred[mask].mean()) bin_true_mean.append(y_test.values[mask].mean()) plt.figure(figsize(6, 6)) plt.plot(bin_pred_mean, bin_true_mean, o-, color#2ca02c, label分箱校准点) plt.plot([10, 35], [10, 35], --, color#999999, label理想对角线) plt.xlabel(箱内预测平均温度℃) plt.ylabel(箱内真实平均温度℃) plt.legend() plt.title(预测温度分箱校准曲线) plt.show()np.percentile按十分位数计算分箱边界这样每个箱子里的样本数量大致相等避免某个区间样本过少导致箱内均值失真。np.digitize把每个预测值分配到对应箱子编号。如果校准曲线的点在高温段和低温段明显偏离对角线说明模型在极端温度下的泛化能力不足一个可行的修复方案是对极端温度样本做加权训练或者在特征工程中补充“极端天气事件标记”这类特征。随机森林的feature_importances_属性值得好好利用。训练结束后执行model.feature_importances_能得到每个特征对预测贡献的数值占比总和为1。通常temp_max_lag1和temp_max_ma3的贡献会合计超过50%这符合天气变化的连续性物理直觉。把这个结果和特征相关性分析一起放进课程设计报告能形成“数据驱动→模型学习→业务解释”的完整闭环。特征重要性也可以和分箱校准交叉验证如果滞后特征重要性最高但校准曲线在季节更替点明显偏差说明滞后特征在季节突变时失效需要补充月份与滞后特征的交互项来强化模型对换季场景的拟合能力。本文还有配套的精品资源点击获取