ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Python天气预测与数据可视化课程设计:从数据清洗到随机森林模型实战

Python天气预测与数据可视化课程设计:从数据清洗到随机森林模型实战 简介面向高校期末大作业或课程设计这份Python项目实现了天气预报与数据可视化功能下载后无需修改即可运行适合作为高分参考涵盖天气预测与可视化两大模块利用线性回归、时间序列分析等模型处理气象数据并通过Matplotlib、Seaborn等工具生成折线图、柱状图与热力图。压缩包共包含二十四个文件主要涉及四个Python源码对应数据获取、处理、建模与主程序逻辑、四份CSV数据集、一个已训练模型、一个HTML页面及一份使用说明文档另附十二张效果预览图整体仅一点四二MB结构清晰便于按模块对照学习目前已有六十二人学习下载。借助模型文件与示例图表读者可快速理解预测流程也可依据源码和文档进行二次开发是巩固Python数据分析与可视化技能的实用案例项目还附带了天气网HTML和图片为作业答辩或成果展示提供直观支撑。1. 从天气预测到数据可视化一套能直接跑完的 Python 课程设计源码期末周最怕的不是写代码而是写完发现跑不通。这套基于 Python 的天气预报与数据可视化项目是我拆过最省心的课程设计源码下载解压、装好依赖、直接运行 main.py就能输出未来几天气温走势和可视化图表预测部分由 Model.pkl 支撑无需再碰训练细节。它的定位很清楚给 Python 期末大作业、课程设计提供一份高分参考。源码按 GetData→ProcessData→GetModel→main 拆成四个模块每个文件干一件事附带 readme 和网页版可视化结果既能交作业也能当答辩素材讲清楚整条数据链路。下面把文件分工、执行顺序、依赖环境和我实际运行中踩过的坑全部展开。新手照着步骤能复现熟手可以直接看第五节排查记录和第六节的图表验收技巧。2. 数据获取链路GetData.py 怎么拿数据四份 CSV 各自管什么2.1 先看懂文件分工四份 CSV 的角色差异进入代码之前我建议先把压缩包里这几份 CSV 的用途对清楚。很多同学拿到项目第一反应是直接运行 main.py跑完截图就交差结果答辩被问「date_train.csv 和 china_today.csv 到底谁喂给模型」就卡住了。这个问题不难但现场卡住很伤。文件角色典型内容使用阶段date_train.csv训练集历史日期对应的气温、湿度、气压等特征和真实标签GetModel.py 训练date_valid.csv验证集与训练集同口径的样本调参时只做评估不参与训练GetModel.py 调参date_test.csv测试集最近的待预测样本交给 main.py 生成预报结果main.py 预测china_today.csv城市当日快照城市维度的实时天气给网页地图坐标点展示可视化阶段这三份 date 开头的 CSV实际上对应训练、验证、预测三个时间窗口。date_train 覆盖的历史周期最长date_valid 是中间一段date_test 是最末尾的一段。做过时间序列预测的人都知道这种切法比随机切分更接近真实场景模型学到的是趋势而不是记住某几天的答案。顺序切分带来的泛化性答辩时讲出来是加分项。china_today.csv 则完全是另一个用途。它是城市维度的当日天气快照给网页端地图展示用的跟模型没有直接关系。把这条线分清之后再看 GetData.py 就明白它至少承担两件事拉取实时天气写入 china_today.csv以及整理历史数据生成 train/valid/test。2.2 GetData.py 的采集脚本requests 拉数据的写法源码里的 GetData.py 是数据链路的起点。它的核心逻辑就是向天气接口发请求、解析返回值、落盘成 CSV。我拆的时候顺手写了一个最小可用版本方便你看清每个参数在干嘛import requests import pandas as pd from datetime import datetime # 城市列表按自己的需要增删 CITIES [北京, 上海, 广州, 深圳, 成都] def fetch_city_weather(city: str) - dict: 拉取单个城市当天天气返回结构化字段 url https://xxx/api/weather params { city: city, key: your_api_key, # 换成自己的 API 密钥 unit: metric, # 摄氏度而不是华氏度 } # timeout 设 10 秒避免某个城市拖垮整个采集任务 resp requests.get(url, paramsparams, timeout10) data resp.json() return { city: city, date: datetime.now().strftime(%Y-%m-%d), temp: data[now][temp], # 当前气温单位摄氏度 humidity: data[now][humidity], # 相对湿度单位 % pressure: data[now][pressure], # 气压单位 hPa wind_dir: data[now][wind_dir], # 风向文本字段 } rows [fetch_city_weather(c) for c in CITIES] df pd.DataFrame(rows) df.to_csv(china_today.csv, indexFalse, encodingutf-8-sig) print(df.head())这段代码的要点不在请求本身而在三个容易被忽略的参数。第一个是 timeout网络请求最忌讳不设超时接口假死会卡住整个采集任务第二个是 encoding写 CSV 用 utf-8-sigWindows 上 Excel 打开才不乱码第三个是 unitmetric不同平台默认单位不一样不统一的话后面建模全是错值。如果要补历史数据通常是把同一个接口按日期参数循环请求每天响应追加进同一个 DataFrame最后按日期去重。这类脚本运行时间是分钟级我一般会在循环里加 time.sleep 限速请求太频繁会被服务端封 IP。2.3 数据源选型公开 API 和本地 CSV 怎么取舍如果 GetData.py 内置的是免费天气接口那它通常有几个限制日请求配额、历史数据不完整、返回字段不统一。课程设计阶段我建议分两步走。第一步确认接口能稳定返回当前天气和近期预报用上面的脚本把 china_today.csv 跑通保证可视化部分有真实数据。第二步核对训练用历史数据的覆盖时长。免费接口往往只给最近几十天训练集太小模型和作业展示效果都会打折。备选方案是自己在本地整理历史 CSV从一个可靠平台导出近两年的天气记录整理成 date_train.csv 需要的列这比纠结接口稳不稳定更实际。不少高分大作业的训练数据就是这么来的——评分看的是数据链路是否完整不是数据集有多大。这里还有一个常见误解认为每次运行 main.py 前都必须跑 GetData.py。实际不是这样main.py 读的是已经躺在目录里的 CSV只有你想更新数据时才需要重新采集。源码把数据文件和采集脚本拆开目的就是让你把训练和预测跑在稳定数据上。拿到 CSV 后别急着跑模型先做一次粗检用 pandas 读进来看行数、列数、缺失值比例再按日期 groupby 看有没有重复。我见过历史数据源在节假日或极端天气时出现整段缺失比如某城市少了三十天记录训练阶段就会变成异常的误差尖峰。3. 数据清洗与特征构造ProcessData.py 的预处理链路3.1 清洗环节缺失值、类型转换和异常值ProcessData.py 处理的是模型喂进去之前的最后一公里也是最容易被轻视的一公里。爬下来的天气数据通常带着三个毛病字段类型不对、日期格式不统一、个别异常值像钉子一样扎在序列里。不处理直接训练模型会把噪音当成规律。清洗的第一步是统一类型。date 列要转成 datetime温度、湿度、气压要转成数值型风向这种文本列要决定保留还是编码。下面这个函数展示了最常见的清洗操作import pandas as pd def clean_weather_data(df: pd.DataFrame) - pd.DataFrame: 标准清洗流程类型转换、缺失值、异常值 # 日期统一成 pandas 时间戳之后才能按时间窗口切分 df[date] pd.to_datetime(df[date], errorscoerce) # 关键数值列统一成 float爬下来是字符串的情况很常见 for col in [temp, humidity, pressure]: df[col] pd.to_numeric(df[col], errorscoerce) # 按时间排序后做前向填充比直接填均值合理 df df.sort_values(date).reset_index(dropTrue) df[[temp, humidity, pressure]] ( df[[temp, humidity, pressure]].ffill() ) # 异常值气温低于 -50 或高于 60 直接裁剪 df.loc[df[temp] -50, temp] -50 df.loc[df[temp] 60, temp] 60 return df这段代码有三处值得展开。ffill() 是按时间顺序用前一个有效值填充缺失对气象序列来说前一天的观测值比全局均值更接近当天状态errorscoerce 把无法解析的脏值变成 NaN交给后续步骤处理异常值用硬边界裁剪而不是删除整行因为删除行会在时间序列里挖出空洞破坏连续性。很多教程喜欢用 df[temp].mean() 填缺失那适合独立样本不适合天气这种强自相关的时序数据。这是我在实际项目里改用前向填充后模型误差明显下降的原因。填充方法一改验证集 MAE 可能差出 0.5 度以上这个量级足以影响作业评分。3.2 特征构造从日期里拆出模型真正关心的信息原始数据只有日期、温度、湿度、气压直接丢给回归模型也能跑但特征太单薄。日期本身是有信息的是几月、星期几、一年第几天气温走势和这些强相关。所以特征构造的重头戏是从 date 列拆出一组新特征。def build_features(df: pd.DataFrame) - pd.DataFrame: 从日期列构造时间特征并加入滞后期特征 df df.copy() dt df[date] # 时间基础特征月份、星期几、一年中的第几天 df[month] dt.dt.month df[dayofweek] dt.dt.dayofweek df[dayofyear] dt.dt.dayofyear # 滞后特征昨天的气温对今天有直接参考价值 df[temp_lag1] df[temp].shift(1) df[temp_lag2] df[temp].shift(2) # 滑动平均近三天平均气温平滑短期波动 df[temp_ma3] df[temp].rolling(window3).mean() # 预测目标明天的气温也就是监督学习的标签 df[target] df[temp].shift(-1) # 去掉没有目标值和滞后特征的头部记录 df df.dropna().reset_index(dropTrue) return dfshift(1) 生成滞后特征让模型知道昨天的温度rolling(3).mean() 生成滑动平均相当于给模型一个近期趋势基线target 用 shift(-1) 取明天的气温是监督学习的标签。dropna 会丢掉序列头尾几行这是边缘损耗不用心疼。这里有个容易犯的错误把 target 本身也当特征喂进模型这叫数据泄漏。检查方式很简单训练特征矩阵里不允许出现未来时刻的值否则评估阶段的精度虚高答辩时被追问两句就露馅。泄漏问题在课程设计里是最常见的高级错误主动在 readme 里写一句「特征中不包含任何未来信息」老师会觉得你真正理解了监督学习的边界。3.3 三份数据统一口径train/valid/test 的切分纪律ProcessData.py 除了清洗和构造特征还要让 date_train、date_valid、date_test 三份数据的特征口径完全一致。同样是 month 字段训练集覆盖 1 到 12 月测试集只落在最近两周这没问题但如果训练集做了边缘裁剪、测试集没做模型加载时直接报维度错误。处理多份文件时最稳的做法是让三份数据走同一个函数def process_all(): 三份数据走同一套清洗和特征逻辑并校验特征列一致 paths { date_train: date_train.csv, date_valid: date_valid.csv, date_test: date_test.csv, } result {} for name, path in paths.items(): df pd.read_csv(path) df clean_weather_data(df) df build_features(df) result[name] df print(f{name}: {df.shape}) # 特征列必须完全一致顺序也不能差 cols result[date_train].columns assert result[date_valid].columns.equals(cols) assert result[date_test].columns.equals(cols) print(columns check passed) return result这个设计的核心就一句话特征逻辑只维护一份代码三份数据都调同一个函数。shape 不同是正常的训练集样本多、测试集样本少但列名和列顺序必须一致。加了 assert 之后如果后续训练阶段报维度错误可以先回来查这里。切分还得强调一点必须按时间顺序不能随机切分。随机切分会让验证集里混入训练窗口之前或之后的数据模型等于偷偷看过答案验证分数的参考意义直接归零。date_train 年份靠前、date_valid 居中、date_test 最近这样的安排是站得住脚的。注意assert 检查只能拦住列完全对不上的情况如果某列只是取值区间变了assert 不会报错。跑模型前最好把两边的 describe 打印出来人工过一眼。4. 训练模型与持久化GetModel.py 怎么把随机森林装进 Model.pkl4.1 模型选型为什么是随机森林而不是深度学习课程设计阶段的数据量通常在几百到几千行之间深度学习在这个量级上没有优势反而容易过拟合调参成本也高。随机森林这类树模型是更稳妥的起点对异常值和缺失值容忍度高、不需要特征缩放、还能输出特征重要性答辩时能讲出东西。线性回归也要提一下它可以作为对照基线。如果线性回归和随机森林在验证集上差得不多说明目标变量和特征基本是线性关系这在气温预测里是常见现象。时间序列分析里的回归方法也是可选方向但对多维特征的处理不如树模型灵活所以多数方案会把随机森林作为主力。Model.pkl 就是这个主力模型的持久化产物。训练完序列化到磁盘main.py 运行时直接加载不需要重训。这里用 joblib 而不是 pickle是因为 joblib 对大数组和 sklearn 模型对象的序列化更稳默认支持内存映射加载速度也更快。4.2 训练脚本与模型保存关键参数怎么设GetModel.py 的完整流程是读入已经处理好的 train/valid指定特征列训练评估保存模型。下面这段代码我按通用实现整理了一遍源码里算法可能不同但职责是一样的import pandas as pd import joblib from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_absolute_error def train_and_save(): # 读入已经过 ProcessData 处理的数据 train pd.read_csv(date_train.csv) valid pd.read_csv(date_valid.csv) # 特征列排除 date 和 target按顺序固定下来 feature_cols [c for c in train.columns if c not in [date, target]] X_train train[feature_cols] y_train train[target] X_valid valid[feature_cols] y_valid valid[target] # 随机森林树偏多、深度限制防过拟合 model RandomForestRegressor( n_estimators200, max_depth8, min_samples_leaf3, random_state42, ) model.fit(X_train, y_train) # 训练集和验证集各评估一次看是否过拟合 mae_train mean_absolute_error(y_train, model.predict(X_train)) mae_valid mean_absolute_error(y_valid, model.predict(X_valid)) print(ftrain mae: {mae_train:.2f}, valid mae: {mae_valid:.2f}) # 序列化到 Model.pklmain.py 直接加载 joblib.dump(model, Model.pkl) if __name__ __main__: train_and_save()参数方面n_estimators200 控制树的棵数树越多训练越慢精度不一定线性提升超过 300 之后收益通常很小max_depth8 限制单棵树深度防止过拟合min_samples_leaf3 保证每个叶子至少有 3 个样本减少噪声分支。random_state42 固定随机种子确保每次运行结果可复现这一点在作业说明里写一句会很加分。训练完看两个 MAE。如果训练 MAE 远低于验证 MAE说明过拟合调低 max_depth 或加大 min_samples_leaf如果两个都很高说明特征不够或数据质量有问题回头查 ProcessData.py。气温预测的 MAE 落在 2 到 3 度内是合理的超过 5 度就要怀疑是数据的问题而不是模型的问题了。4.3 验证集的价值调参不能只看训练集很多初学者盯着训练集精度高就觉得大功告成这是危险的错觉。模型在训练集上表现好只能说明它记住了训练样本不能说明它对未来的天气有预测力。评分老师真正关心的是验证集和测试集上的表现调参决策也应该只看验证集。手动试几个档位就足够。比如把 max_depth 从 6 调到 12、n_estimators 从 100 调到 300每次记录验证集 MAE画一张小表就能看出趋势。这个表放进大作业报告里比任何理论叙述都有说服力因为它展示了真实的调参过程。Model.pkl 里保存的是训练好的模型结构和参数不包含训练数据。所以 main.py 加载它做预测时并不需要重新读入 date_train.csv。这解释了为什么压缩包里可以同时放下 CSV 和 pkl也能说明为什么 main.py 的运行速度和训练速度完全不是一个量级——加载一个序列化的模型是秒级训练一次模型可能到分钟级。还要提一个边界如果你换了新数据或改了特征旧 Model.pkl 必须重新训练生成否则模型拿到的特征分布是陌生的预测结果不可信。每个版本的数据对应一个版本的模型这是工程上的建模纪律。5. 运行与排查main.py 启动顺序、依赖环境与常见翻车5.1 main.py 的执行流程设计main.py 是这个项目交付时的门面。它的典型流程是加载 Model.pkl → 读入 date_test.csv → 按同一套特征逻辑构造预测特征 → 调用 model.predict 得到未来几天气温 → 用 matplotlib 出图并以天气网.html 的方式展示结果。跑通之后终端能看到预测值目录里多出图表文件。如果你打开 main.py 发现它比你预期的短不用奇怪。模型训练已经在 GetModel.py 里做完了main.py 只负责推理和展示这是合理的分工。如果运行时报错先按流程一环一环定位报错在加载模型就检查 Model.pkl 是否存在报错在特征构造就回头看测试集有没有经过 ProcessData.py 的处理。大部分报错信息会精确到文件和行号照着拆就行。5.2 依赖环境Python 版本、sklearn 安装、vscode 配置这个项目依赖的第三方库不多核心是 pandas、numpy、scikit-learn、matplotlib。先做一件事检查当前 Python 能不能导入这些库。python -c import pandas, numpy, sklearn, matplotlib; print(ok)如果报 ModuleNotFoundError说明依赖没装齐。常见做法是一次装完python -m pip install pandas numpy scikit-learn matplotlib注意这里刻意用了 python -m pip而不是直接 pip。原因是 Windows 上同时存在多个 Python 版本时pip 可能指向另一个解释器装完还是 import 不到。python -m pip 能保证安装目标就是当前终端里那个 python。vscode 里跑项目还要确认解释器路径。最经典的翻车现场是在系统终端里 pip install 装到了 Python 3.11vscode 右下角却选中了 Python 3.9于是 import pandas 直接报错。我一般在 vscode 终端里先跑一遍上面的 python -c 检查过了再打开 main.py。这一步能过滤掉八成环境问题。提示如果项目文件里有 readme.md里面写了当前环境建议的 Python 版本尽量对齐。sklearn 新版对旧模型的兼容性整体不错但有些老模型文件用新版库加载时会提示版本不一致处理办法是重新运行 GetModel.py 生成新的 Model.pkl。5.3 常见问题排查记录下面是这个项目最容易翻车的几个点每一条都按现象、原因、解决问题的顺序写。现象 1运行 main.py 报 ModuleNotFoundError: No module named sklearn原因库没有安装在当前解释器里或 pip 装到了另一个 Python。 解决先跑 python -m pip install scikit-learn再跑 python -c 验证。如果还报错把终端里的 python 路径打印出来和 vscode 选择的解释器路径对比必须一致。这个坑在 Windows 上出现频率最高因为系统里往往有多个 Python。现象 2提示维度错误说 predict 传进去的特征数量不对原因测试集的特征列和训练模型时的特征列不一致常见于重新生成了 CSV 但没有走 ProcessData 的统一处理。 解决把 date_train.csv 和 date_test.csv 的列名列表打印出来对比先确认 date 列没有被当成特征——我见过最高频的场景就是处理测试集时忘了排除 date导致多了一列。再确认特征列顺序和数量完全一致建议直接用第 3 章的 process_all 函数统一处理。现象 3CSV 里的中文乱码原因文件写入时用了默认编码或读取时没有指定 utf-8-sig。 解决统一用 encodingutf-8-sig 读写。如果乱码已经存在用 pandas 带编码参数重新读一遍再另存。图表里的中文乱码是另一回事那是 matplotlib 缺中文字体需要手动指定字体路径这也是很常见的坑。现象 4Pandas 版本升级后出现 FutureWarning 或运行报错原因老代码用了 fillna(methodffill) 这类在 pandas 2.0 里已被标记废弃的写法新版本仍然会警告甚至报错。 解决把 fillna(methodffill) 改成 df.ffill()然后看输出确认没有其它废弃写法。这里提醒一下拿到老源码不要急着升级 pandas 到最新版先在当前环境跑通再说别给自己加戏。6. 可视化与验收把预测结果做成能拿高分的图表6.1 两条出图路径静态图和网页交互图项目的可视化分两支。main.py 里通常用 matplotlib 出静态图适合贴进作业文档天气网.html 是网页端交互展示打开浏览器就能看到城市地图和温度趋势答辩演示时很加分。网页端的实现常见做法是 ECharts把数据导成 JSON页面脚本读取后绘制折线图和地图散点。这部分的核心不是代码量而是结果让老师能一眼看懂。静态图建议先画两条曲线预测值和真实值叠在一起。对测试集来说如果 target 列保留着直接对比一目了然。6.2 验证模型的一个技巧先看残差再看曲线图表不只是给别人看的也是给你自己看模型的。先把预测残差按日期画出来如果残差围绕 0 上下无规律波动说明模型没有系统性偏差如果从某一天开始误差持续为正或持续为负说明时间窗口切分有问题或者数据在那个区间发生了分布漂移。import pandas as pd import joblib import matplotlib.pyplot as plt # 加载模型并对测试集预测 model joblib.load(Model.pkl) test pd.read_csv(date_test.csv) feature_cols [c for c in test.columns if c not in [date, target]] pred model.predict(test[feature_cols]) # 如果测试集里保留真实值可以直接对比 if target in test.columns: resid test[target] - pred plt.figure(figsize(10, 3)) plt.plot(test[date], resid, markero, linewidth1) plt.axhline(0, colorred, linewidth1, alpha0.6) plt.title(Prediction Residual) plt.tight_layout() plt.savefig(residual.png, dpi150) plt.show()这个检查花的时间不到一分钟但在答辩时能回答「你的模型预测准吗」这个问题直接给出验证集 MAE 和残差图比任何口头描述都硬气。从那以后我每次拿到这类预测项目都会强制自己先画残差再画结果图确认残差稳定在零轴附近才开始调可视化样式。希望帮到你。本文还有配套的精品资源点击获取
返回列表