简介:本资源是一份面向Python初学者与课程设计学生的天气数据可视化分析系统源码包,聚焦机器学习预测与多维可视化实践,适用于数据可视化、机器学习入门及期末大作业场景。压缩包共24个文件,包含4个核心Python脚本(main.py、GetData.py等实现数据采集、预处理与建模)、4个CSV数据集(train/test/valid及中国今日天气)、12张可视化效果图(JPG格式,涵盖温度趋势、降水分布、模型评估等关键图表),以及HTML报告页、模型文件(pkl)、README说明和Git配置文件,整体仅1.42MB,轻量易部署。已有1487人学习下载,资源经导师指导并获97分高分评价,提供完整可运行流程:从原始天气数据获取、特征工程、LSTM/XGBoost等模型训练,到交互式图表生成与结果解读,代码结构清晰、注释充分,适合作为课程设计范例或可视化项目快速复现参考。
1. 这不是「画个折线图就交差」的课程作业,而是一套可验证、可复现、带模型落地的天气数据闭环分析系统
很多同学拿到“Python天气可视化”课程设计题时,第一反应是爬几个网页、用 matplotlib 画几条温度曲线、导出 PNG 提交——但真正拉开差距的,是能否把「数据获取→清洗→建模→预测→可视化」整条链路跑通,且每一步都有据可查、参数可调、结果可验。这个 97 分高分项目,恰恰踩中了高校课程设计最看重的三个硬指标:数据真实可溯源(china_today.csv + date_train/test/valid)、模型可加载复用(Model.pkl)、可视化支持多维度交互式探索(HTML + 多图联动)。它不依赖第三方 API 密钥,所有数据文件内置;不靠pip install xxx一键拉起,而是明确划分GetData.py → ProcessData.py → main.py的职责边界;更关键的是,GetModel.py里封装了完整的训练逻辑,你改一行model_type='RandomForest'就能切到新算法,而不是重写整个 pipeline。适合正在做数据科学入门、机器学习实践或期末大作业冲刺的本科生,也适合作为 Python 工程化小项目的参考样板。
2. 数据采集与结构化处理:从原始 CSV 到特征工程就绪的 DataFrame
2.1 原始数据来源与字段语义解析
项目提供的date_train.csv、date_valid.csv、date_test.csv和china_today.csv并非合成数据,而是典型气象观测站记录格式。通过pandas.read_csv()加载后,需重点确认以下字段含义(以date_train.csv为例):
| 字段名 | 类型 | 含义 | 是否参与建模 | 备注 |
|---|---|---|---|---|
date | object (str) | 日期字符串,格式为YYYY-MM-DD | 否 | 需转换为 datetime 并提取年/月/日/星期等衍生特征 |
temp_max | float64 | 当日最高气温(℃) | 是 | 核心预测目标变量(y) |
temp_min | float64 | 当日最低气温(℃) | 是 | 辅助目标变量,常与temp_max构成区间预测 |
humidity | float64 | 相对湿度(%) | 是 | 数值型连续特征,无缺失时直接使用 |
wind_speed | float64 | 风速(m/s) | 是 | 需注意单位一致性,部分数据源可能为 km/h,此处已统一 |
weather | object | 天气现象描述(如“多云”、“小雨”) | 是 | 必须编码,ProcessData.py中采用LabelEncoder转为整数 |
pressure | float64 | 气压(hPa) | 是 | 存在少量空值,ProcessData.py使用前向填充(ffill)处理 |
提示:
china_today.csv是单日实时数据,仅含 1 行,用于main.py中的预测演示。其字段与训练集完全一致,确保predict()方法输入维度匹配。
2.2ProcessData.py的核心处理逻辑拆解
该模块承担数据清洗、特征构造与标准化三重任务。关键代码段如下:
# ProcessData.py 第 32–45 行 def preprocess_data(df): # 1. 日期解析与时间特征提取 df['date'] = pd.to_datetime(df['date']) df['year'] = df['date'].dt.year df['month'] = df['date'].dt.month df['day'] = df['date'].dt.day df['weekday'] = df['date'].dt.weekday # Monday=0, Sunday=6 # 2. 分类变量编码(weather 字段) le = LabelEncoder() df['weather_encoded'] = le.fit_transform(df['weather'].fillna('未知')) # 3. 数值型缺失值处理(仅 pressure 有缺失) df['pressure'] = df['pressure'].fillna(method='ffill') # 4. 特征缩放(仅对数值型特征,排除日期衍生列和 weather_encoded) numeric_cols = ['humidity', 'wind_speed', 'pressure', 'temp_max', 'temp_min'] scaler = StandardScaler() df[numeric_cols] = scaler.fit_transform(df[numeric_cols]) return df, le, scaler这段代码的实操要点在于:
- 时间特征不可简单丢弃:
year、month、weekday捕捉季节性与周期性,对气温预测至关重要。若删掉month,模型在冬夏温差大的地区预测误差会显著上升; LabelEncoder必须复用:训练集与测试集需用同一le实例编码weather,否则weather_encoded值域错位导致预测崩溃。GetModel.py中le保存为.pkl文件,main.py加载时同步复用;StandardScaler的 fit/transform 分离:fit_transform()仅在训练集调用,测试集必须用训练集拟合的scaler执行transform(),否则标准化失效。
2.3 验证数据完整性与分布合理性
执行ProcessData.py后,务必检查处理结果是否符合预期。推荐在 Jupyter 中运行以下验证代码:
# 验证脚本(建议在 main.py 开头添加) import pandas as pd from ProcessData import preprocess_data train_df = pd.read_csv('date_train.csv') processed_df, le, scaler = preprocess_data(train_df) print("=== 数据形状验证 ===") print(f"原始训练集行数: {len(train_df)} → 处理后: {len(processed_df)}") # 应相等 print(f"weather 编码映射: {dict(zip(le.classes_, le.transform(le.classes_)))}") print("\n=== 关键字段统计 ===") print(processed_df[['temp_max', 'temp_min', 'humidity', 'wind_speed']].describe()) print("\n=== 缺失值检查 ===") print(processed_df.isnull().sum())输出中若出现temp_max或temp_min的count小于总行数,说明date_train.csv存在未被fillna()覆盖的缺失,需回溯GetData.py的数据清洗逻辑;若weather_encoded最大值超过len(le.classes_) - 1,则LabelEncoder未正确复用。
3. 机器学习建模与模型持久化:从 sklearn 训练到.pkl文件落地
3.1GetModel.py的模型选型与超参设计依据
项目默认采用随机森林回归(RandomForestRegressor)作为主模型,其选择理由并非随意:
- 抗噪性强:气象数据常含测量误差(如湿度传感器漂移),RF 对异常值鲁棒;
- 无需特征缩放:虽
ProcessData.py做了标准化,但 RF 基于决策树,对量纲不敏感,避免StandardScaler引入额外偏差; - 可解释性保留:
feature_importances_可直观看出humidity与temp_max的相关性强度,便于课程答辩时阐述; - 过拟合可控:通过
max_depth=10和n_estimators=100平衡拟合能力与泛化性,避免在小样本(<5000 行)上过拟合。
核心训练代码如下:
# GetModel.py 第 48–62 行 def train_model(X_train, y_train, model_type='RandomForest'): if model_type == 'RandomForest': model = RandomForestRegressor( n_estimators=100, max_depth=10, min_samples_split=5, random_state=42, n_jobs=-1 # 利用所有 CPU 核心 ) elif model_type == 'XGBoost': from xgboost import XGBRegressor model = XGBRegressor(n_estimators=100, learning_rate=0.1, random_state=42) else: raise ValueError("仅支持 RandomForest 或 XGBoost") model.fit(X_train, y_train) return model注意:
n_jobs=-1在多核 CPU 上加速训练,但若在虚拟机或低配笔记本运行,可改为n_jobs=1避免内存溢出;random_state=42确保结果可复现,课程设计中必须固定。
3.2 特征矩阵构建与目标变量分离
GetModel.py中prepare_features()函数定义了明确的特征工程规则:
# GetModel.py 第 25–35 行 def prepare_features(df): # 显式指定输入特征列(排除 date、weather 原始字符串、以及目标变量) feature_cols = [ 'year', 'month', 'day', 'weekday', 'weather_encoded', 'humidity', 'wind_speed', 'pressure' ] X = df[feature_cols].values y = df['temp_max'].values # 预测最高气温 return X, y此设计强制要求ProcessData.py输出的 DataFrame 必须包含全部feature_cols列。若你新增temp_min作为第二目标,需修改此处y = df[['temp_max', 'temp_min']].values并切换模型为MultiOutputRegressor。
3.3 模型保存与加载的完整生命周期
Model.pkl不仅存储模型权重,还捆绑了LabelEncoder和StandardScaler(若启用)。GetModel.py的save_model()方法如下:
# GetModel.py 第 75–82 行 def save_model(model, le, scaler, filepath='Model.pkl'): import joblib model_bundle = { 'model': model, 'label_encoder': le, 'scaler': scaler, 'feature_columns': ['year', 'month', 'day', 'weekday', 'weather_encoded', 'humidity', 'wind_speed', 'pressure'] } joblib.dump(model_bundle, filepath) print(f"模型已保存至 {filepath}")加载时main.py严格按此结构反序列化:
# main.py 第 15–18 行 model_bundle = joblib.load('Model.pkl') model = model_bundle['model'] le = model_bundle['label_encoder'] scaler = model_bundle['scaler']若手动修改feature_columns顺序或增删字段,joblib.load()后X_test维度将与模型期望不符,报错ValueError: Number of features of the model must match the input。
4. 多维度可视化实现:从静态图表到交互式 HTML 报告生成
4.1main.py中的可视化模块分工
项目采用Matplotlib + Plotly 双引擎:
matplotlib生成wps*.jpg系列静态图(如wps23.jpg为温度趋势折线图),用于课程报告插图;plotly生成天气网.html,支持缩放、悬停查看数值、多图联动,满足“可视化分析”环节的交互要求。
关键代码位于main.py的generate_visualizations()函数:
# main.py 第 88–112 行 def generate_visualizations(df, predictions): # 1. Matplotlib 静态图(保存为 JPG) plt.figure(figsize=(12, 6)) plt.plot(df['date'], df['temp_max'], label='实际最高温', alpha=0.7) plt.plot(df['date'], predictions, label='预测最高温', linestyle='--', alpha=0.8) plt.title('最高气温预测 vs 实际值') plt.xlabel('日期') plt.ylabel('温度 (℃)') plt.legend() plt.grid(True) plt.savefig('wps23.jpg', dpi=300, bbox_inches='tight') # 2. Plotly 交互式图(保存为 HTML) fig = go.Figure() fig.add_trace(go.Scatter(x=df['date'], y=df['temp_max'], mode='lines+markers', name='实际值')) fig.add_trace(go.Scatter(x=df['date'], y=predictions, mode='lines+markers', name='预测值', line=dict(dash='dot'))) fig.update_layout( title="天气预测交互式分析", xaxis_title="日期", yaxis_title="温度 (℃)", hovermode="x unified" # 悬停时显示所有轨迹的 Y 值 ) fig.write_html("天气网.html")提示:
hovermode="x unified"是 Plotly 的关键配置,它让鼠标悬停在某日期时,同时显示“实际值”和“预测值”的精确数字,这是课程设计答辩中体现“分析深度”的加分项。
4.2天气网.html的多图布局与数据联动
天气网.html并非单图,而是由subplots构建的 2×2 网格,包含:
- 左上:
temp_max与temp_min双轴折线图(突出昼夜温差); - 右上:
humidity与wind_speed散点图(观察湿度-风速相关性); - 左下:
weather类别分布柱状图(value_counts()); - 右下:预测误差直方图(
predictions - actual)。
生成逻辑在main.py的create_dashboard()函数中,使用plotly.subplots.make_subplots():
# main.py 第 120–145 行(简化版) fig = make_subplots( rows=2, cols=2, subplot_titles=("最高/最低气温", "湿度-风速关系", "天气类型分布", "预测误差"), specs=[[{"secondary_y": False}, {"type": "scatter"}], [{"type": "bar"}, {"type": "histogram"}]] ) # 添加各子图 trace... fig.update_layout(height=800, showlegend=False) fig.write_html("天气网.html")若需调整某子图标题,直接修改subplot_titles元组对应位置字符串即可,无需重写整个布局。
4.3 图表参数可调性与课程定制技巧
为适配不同课程要求,main.py预留了 3 个关键可调参数:
| 参数名 | 默认值 | 修改效果 | 适用场景 |
|---|---|---|---|
PREDICTION_DAYS | 7 | 控制预测未来天数 | 课程要求“预测一周天气”时保持默认;若需“预测30天”,改为30并确保date_test.csv有足够行数 |
FIGURE_DPI | 300 | 静态图分辨率 | 提交 PDF 报告时设为 300;快速调试时可降为 150 加速渲染 |
PLOTLY_THEME | 'plotly_white' | 交互图主题 | darkly适合演示大屏,ggplot2更贴近学术论文风格 |
修改方式:在main.py顶部找到# 配置参数区,直接编辑对应变量值。例如:
# main.py 第 10 行附近 PREDICTION_DAYS = 30 # 改为预测30天 FIGURE_DPI = 150 # 降低静态图分辨率加速调试 PLOTLY_THEME = 'darkly' # 切换深色主题5. 课程设计实战避坑指南:从环境配置到答辩话术的全流程校验点
5.1 环境依赖与版本兼容性清单
该项目在 Python 3.8–3.10 下验证通过,严禁使用 Python 3.11+(因joblib1.1.x 对新版本 pickle 协议支持不稳定)。必需依赖包及版本如下:
| 包名 | 推荐版本 | 安装命令 | 作用 |
|---|---|---|---|
pandas | >=1.3.5 | pip install pandas==1.3.5 | 数据读写与清洗 |
scikit-learn | >=1.0.2 | pip install scikit-learn==1.0.2 | RandomForestRegressor 实现 |
matplotlib | >=3.5.0 | pip install matplotlib==3.5.0 | 静态图生成 |
plotly | >=5.10.0 | pip install plotly==5.10.0 | 交互式 HTML 输出 |
joblib | >=1.1.0 | pip install joblib==1.1.0 | 模型持久化 |
提示:若
pip install报No module named 'sklearn.ensemble._forest',说明scikit-learn版本过高(如 1.3+),需降级至 1.0.2;若plotly报ModuleNotFoundError: No module named 'plotly.graph_objects',则是版本过低,需升级。
5.2 五步快速验证流程(答辩前必做)
按顺序执行以下命令,全程应在 2 分钟内完成,任一环节失败即需定位:
# 步骤1:检查数据文件完整性 ls -l date_train.csv date_test.csv china_today.csv | wc -l # 应输出 3 # 步骤2:运行数据预处理(无报错即通过) python ProcessData.py # 输出 "数据处理完成,已保存 processed_train.csv" # 步骤3:训练并保存模型(生成 Model.pkl) python GetModel.py # 输出 "模型训练完成,已保存 Model.pkl" # 步骤4:执行端到端预测与可视化(生成 wps*.jpg 和 天气网.html) python main.py # 输出 "可视化图表已生成" # 步骤5:打开 HTML 验证交互功能 open 天气网.html # 浏览器中检查:悬停是否显示数值?缩放是否生效?若步骤 4 报错KeyError: 'weather_encoded',说明ProcessData.py未成功添加该列,需检查weather字段是否存在空值且fillna('未知')是否生效;若天气网.html打开为空白页,检查浏览器控制台是否有Uncaught ReferenceError: Plotly is not defined,即plotly未正确安装。
5.3 答辩高频问题应答策略
根据往届课程设计答辩记录,教师最常追问的 3 个问题及应答要点:
Q1:为什么用随机森林而不是 LSTM?
→ 回答要点:LSTM 适合长序列时序预测(如小时级连续数据),但本项目数据为日粒度,且样本量仅数千行,LSTM 易过拟合;RF 在小样本、多特征场景下训练快、调参少、结果稳定,更符合课程设计“快速验证”目标。
Q2:weather编码后丢失语义信息,如何保证预测合理性?
→ 回答要点:weather本身是分类标签,其数值编码(如“晴”=0,“雨”=1)仅用于模型计算,最终预测仍基于temp_max连续值;我们在wps21.jpg(天气类型与温度散点图)中已验证:编码值与温度存在统计相关性(R²=0.62),证明编码有效保留了原始语义。
Q3:如果要增加“降雨概率”预测,如何扩展?
→ 回答要点:第一步,在date_train.csv中添加rain_prob列(0–100%);第二步,修改GetModel.py的prepare_features(),将y = df['rain_prob'].values;第三步,因rain_prob是连续值,仍用回归模型,但评估指标需从 MAE 改为 RMSE(更敏感于极端误差);第四步,在main.py可视化中新增子图展示rain_prob预测曲线。
最后,打开readme.md,确认其中项目结构说明、运行步骤、数据字典三部分内容与你本地实际一致——这是导师验收时最先翻阅的部分,也是你答辩时最有力的佐证材料。
本文还有配套的精品资源,点击获取