用Python实现天气预测:机器学习期末大作业全流程指南
简介:这是一份面向计算机相关专业学生与机器学习初学者的Python天气预测项目,源自导师指导并通过的高分期末大作业,适合用作期末大作业、课程设计或毕业设计参考。项目覆盖数据采集、清洗、特征工程、模型训练与评估、结果可视化完整流程,包含数据处理、模型训练与预测、可视化展示等模块,并配有详细文档说明,代码结构清晰,便于学习与二次开发。压缩包共24个文件,主要有4个Python脚本、4个CSV数据集、1个Markdown说明文档、1个HTML可视化页面及12张效果截图,整体仅1.42MB,轻量但功能完整。目前已有737人学习下载,说明其实用性获得了认可。下载后可直接运行,也可按文档说明修改数据或模型参数,对想快速完成机器学习大作业的同学是省时省力的选择。
1. 为什么期末大作业选"天气预测":这个选题到底值不值得做
先说结论:天气预测是我见过最适合当机器学习期末大作业的题目之一,尤其对Python课程来说。它不像图像识别那样需要显卡和数据量,也不像自然语言处理那样要碰词向量和Transformer,它的核心算法朴素、数据集容易获取、可视化结果直观,评委一眼就能看出你做了什么东西。
我当年选这个题的时候,主要是看中三点:第一,天气数据是典型的时间序列数据,可以讲清楚回归、分类、特征工程这些核心概念;第二,公开数据集非常多,不需要自己爬虫采集,省掉大量时间;第三,预测结果可以用图表直观呈现,"温度预测曲线"这种图放在答辩PPT里,比一堆准确率数字有说服力得多。
但这里有个很容易踩的坑:很多人把"天气预测"理解成"预测明天会不会下雨",然后直接套分类模型。其实天气预测可以拆成好几个方向——预测具体温度(回归问题)、预测天气类别(分类问题)、预测未来多天的变化趋势(时间序列问题)。不同方向对应的模型、评估指标、代码结构完全不同。我建议期末大作业选"温度预测"作为主任务,因为回归任务评估起来直观,MSE和R²讲起来不费劲,而且还能顺带演示特征相关性分析,内容非常充实。
一句话总结这个选题的定位:它是一个"数据预处理占大头、模型不必太复杂、结果容易可视化"的典型入门级机器学习项目,特别适合一个人在一到两周内从零完成。
2. 数据从哪来:三步搞定数据集,不用爬虫也不用手敲
数据集是整个作业的地基,但大部分同学的误区是一上来就想着爬天气网站,结果爬虫反爬、字段解析、数据清洗折腾了三天,机器学习本身反而没时间写了。其实有两条更靠谱的路,我分别说一下。
2.1 最省事方案:直接用现成的CSV数据集
Kaggle和GitHub上有很多现成的天气历史数据集,最经典的是"Daily Weather Observations"这类,字段通常包括日期、最低温度、最高温度、平均温度、湿度、气压、风速、天气状况等。这类数据集的优势是已经做过基本清洗,缺失值不多,拿来就能用。
如果你用的是国内网络环境,Kaggle有时候访问不太稳定,还有一个替代办法:直接用Python的第三方库 sklearn 自带的波士顿房价数据集练手?不行,那个和天气没关系。我建议你搜索"weather dataset csv"或者直接去GitHub找"weather prediction dataset",很多仓库直接提供了 weather.csv ,下载下来就能用。实在不行, seaborn 库自带了一个叫 flights 的数据集,虽然不是天气,但结构可以作为模拟数据来练代码流程。
我的经验是:直接把数据集文件放进项目文件夹,用 pd.read_csv() 读进来,先别管数据质量,跑通整个流程之后,再回头处理异常值。
2.2 兜底方案:自己构造一份带时间趋势的模拟数据
如果你实在找不到合适的数据集,或者想展示自己"造数据"的能力(这个在答辩时反而可能是加分项),可以用Python手动生成一份带季节周期和随机噪声的温度数据:
import numpy as np
import pandas as pd
# 生成365天的日期序列
dates = pd.date_range(start='2023-01-01', periods=365, freq='D')
# 温度:以年为周期,平均15度,振幅12度
day_of_year = dates.dayofyear.values
temperature = 15 + 12 * np.sin(2 * np.pi * day_of_year / 365) + np.random.normal(0, 2, 365)
df = pd.DataFrame({'date': dates, 'temperature': temperature})
df.to_csv('weather_simulated.csv', index=False)
这样生成的模拟数据自带明显的季节性规律,线性回归、决策树都能拟合出不错的趋势,用来交作业完全够用。但注意,如果导师对数据真实性有要求,你必须在文档里写清楚"这是模拟数据,用于演示建模流程",别误导人。
2.3 拿到数据后的第一件事:先画图,别急着建模
这是很多新手最容易忽略的一步。数据读进来第一件事应该是做探索性数据可视化(EDA),把温度随时间的折线图、湿度和温度的关系散点图画出来,一方面你能直观判断数据是否合理,另一方面这些图可以直接放进报告里,作为"数据探索"章节的内容。
我常用的代码很简单:
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 解决中文乱码
plt.rcParams['axes.unicode_minus'] = False
df['temperature'].plot(figsize=(12, 4), title='温度时序图')
plt.xlabel('日期')
plt.ylabel('温度(°C)')
plt.show()
注意:中文乱码是Python可视化的老问题,如果运行环境是Linux服务器,SimHei字体经常不存在,建议改成设置中文字体路径,或者干脆把图例和标题写成英文,省心不少。
3. 特征工程怎么做:从"日期字符串"里挖出四个有效特征
数据拿到之后,真正的机器学习工作才开始。天气数据里最有价值的信息往往藏在"日期"这一个字段里,很多新手直接把这个字段删掉,等于把最重要的特征丢了。
3.1 把日期拆解成可用的数值特征
日期本身是字符串,模型不认识,但我们可以从日期中提取出多个数值特征:
df['year'] = df['date'].dt.year
df['month'] = df['date'].dt.month
df['day'] = df['date'].dt.day
df['dayofyear'] = df['date'].dt.dayofyear
其中 dayofyear (一年中的第几天)是最有价值的特征,因为温度随季节变化本质上就是随 dayofyear 变化的。有了这个特征,线性回归就能学到一个近似正弦的曲线。另外, month 和 day 可以作为辅助特征,让模型学到月内的小波动。
如果你想让模型更强大,还可以构造"滞后特征",也就是前一天的天气值。比如用"昨天的温度"来预测"今天的温度",这在时间序列预测里非常常用:
df['temp_yesterday'] = df['temperature'].shift(1)
df = df.dropna() # 删除第一行(因为没有前一天数据)
3.2 相关性分析:让你的报告有说服力
做特征工程之后,强烈建议做一次相关性分析,输出一张热力图。这不仅是建模前的必要步骤,更是报告中"分析特征与目标变量关系"这一章节的天然素材。
import seaborn as sns
corr = df[['temperature', 'month', 'day', 'dayofyear', 'temp_yesterday']].corr()
sns.heatmap(corr, annot=True, cmap='coolwarm')
plt.title('特征相关性热力图')
plt.show()
正常情况下你会发现 dayofyear 和 temp_yesterday 与目标温度的相关性都很高,而 day 几乎不相关。这个结果就能支撑你后面的建模策略:核心特征用 dayofyear 和 temp_yesterday ,次要特征可以尝试加 month 。
3.3 特征工程的三个坑
- 坑一:
shift(1)之后不删空值,模型会报错(NaN没法训练),而且很多人会忘记这件事。 - 坑二:训练集和测试集切分时,时间序列数据不能随机打乱!必须按时间顺序切分,比如前80%作训练,后20%作测试。随机切分会导致"用未来的数据预测过去",结果虚高,答辩时一问就露馅。
- 坑三:标准化和归一化不能在整个数据集上做,要先fit训练集再transform测试集,否则会有数据泄漏。虽然树模型不在乎这个,但如果用了线性回归或SVR,这个错误会导致评估结果偏乐观。
4. 模型选型和对比:线性回归、决策树、随机森林谁更适合
天气温度预测本质是回归任务,可选的模型很多,但大作业不需要上深度学习,经典机器学习模型完全足够。我建议至少对比三个模型,这样报告里可以画对比表格,显得考虑全面。
4.1 三个模型的基本定位
线性回归是最简单的基准模型,它假设特征和目标之间是线性关系。由于 dayofyear 和温度之间本质是正弦关系,线性回归只能学到一个整体趋势,精度不会太高,但它的可解释性最强,答辩时你可以指着回归系数说"dayofyear每增加一天,温度平均变化多少",这种东西很加分。
决策树可以捕捉非线性关系,拟合能力比线性回归强,但单棵树的泛化能力一般,容易过拟合。随机森林是决策树的集成版本,通过多棵树投票降低方差,通常在结构化数据上是默认首选。对天气温度预测这种数据量不大的任务,随机森林效果往往最好。
4.2 完整训练和评估代码
我给出一个可以直接复制的训练脚本,包含数据切分、模型训练、评估指标计算:
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, r2_score
features = ['month', 'day', 'dayofyear', 'temp_yesterday']
X = df[features]
y = df['temperature']
# 时间序列切分:按顺序切,不shuffle
split_idx = int(len(df) * 0.8)
X_train, X_test = X.iloc[:split_idx], X.iloc[split_idx:]
y_train, y_test = y.iloc[:split_idx], y.iloc[split_idx:]
models = {
'LinearRegression': LinearRegression(),
'DecisionTree': DecisionTreeRegressor(max_depth=6, random_state=42),
'RandomForest': RandomForestRegressor(n_estimators=100, max_depth=10, random_state=42)
}
for name, model in models.items():
model.fit(X_train, y_train)
pred = model.predict(X_test)
mse = mean_squared_error(y_test, pred)
r2 = r2_score(y_test, pred)
print(f"{name}: MSE={mse:.4f}, R²={r2:.4f}")
4.3 结果解读与模型调参
运行之后,你大概率会看到线性回归R²在0.7到0.8之间,决策树和随机森林能到0.9以上。这个结果非常理想:既有差距可以对比,又不会差距大到让人觉得数据有问题。
调参方面,新手别一上来就GridSearchCV网格搜索,那是耗时大户。先把 max_depth 控制在5到15之间, n_estimators 设为100左右就够了。如果发现训练集R²远高于测试集R²,说明过拟合了,减小 max_depth ;如果两者都低,说明特征不够,回去检查特征工程。
有一个提升效果的简单技巧:加入"月份"作为类别特征并做独热编码,同时把 dayofyear 做周期变换(比如 sin(2π * dayofyear / 365) ),线性回归也能拟合出很好的季节性曲线:
df['sin_dayofyear'] = np.sin(2 * np.pi * df['dayofyear'] / 365)
df['cos_dayofyear'] = np.cos(2 * np.pi * df['dayofyear'] / 365)
4.4 可视化:画一张预测值对比真实值的散点图
模型跑完,一定要有可视化结果。我推荐画出测试集上的"真实值vs预测值"散点图,或者时间序列对比折线图。后者更直观,一眼就能看出预测曲线跟着真实曲线走,这张图就是你报告的核心成果图。
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 5))
plt.plot(y_test.values[:100], label='真实温度', marker='o', markersize=3, linestyle='-')
plt.plot(pred[:100], label='预测温度', marker='x', markersize=3, linestyle='--')
plt.xlabel('样本序号')
plt.ylabel('温度(°C)')
plt.title('随机森林模型:真实温度 vs 预测温度')
plt.legend()
plt.show()
5. 源码结构和文档撰写:大作业能不能拿高分,看的是这层"包装"
很多同学代码写得不错,但最后成绩不理想,问题出在交付物组织太乱。期末大作业的评分通常看三样东西:源码能否直接运行、文档是否完整、答辩能否讲清楚。下面一个个说。
5.1 推荐的项目目录结构
一个清晰的项目目录能让老师对你的印象分直接上一个档次:
weather_prediction/
├── data/
│ ├── weather.csv # 原始数据集
│ └── weather_processed.csv # 清洗后的数据
├── src/
│ ├── data_preprocessing.py # 数据预处理和特征工程
│ ├── train_model.py # 模型训练和评估
│ └── visualize.py # 可视化
├── output/
│ ├── correlation_heatmap.png # 相关性热力图
│ ├── prediction_curve.png # 预测结果曲线图
│ └── model_comparison.csv # 模型对比结果
├── requirements.txt # 依赖库列表
├── README.md # 项目说明
└── 实验报告.docx
如果导师允许用Jupyter Notebook,也可以改成单个 .ipynb 文件,分块展示数据探索、特征工程、建模、评估全流程。用Notebook的好处是代码和图示混排,文档都不用单独写图表解释了,但坏处是代码容易变成"面条式",我建议还是用py脚本+报告的经典结构。
5.2 requirements.txt 怎么写
这个文件一定要有,它保证老师在别的电脑上能直接复现你的环境。内容不需要写死版本号,但最好指定大版本:
numpy>=1.21
pandas>=1.3
matplotlib>=3.5
seaborn>=0.11
scikit-learn>=1.0
5.3 文档说明怎么写:不要写"这是一个天气预测项目"这种废话
实验报告或项目文档,最忌讳大段空话。我见过很多同学写"本项目使用了机器学习技术,通过Python实现天气预测,达到良好效果",这种话一点信息量都没有。我建议报告按以下逻辑组织,每章都要有实际数据和结论支撑:
- 项目背景:为什么选这个题,目标是什么(预测明天的最高温度?还是预测未来7天温度?)
- 数据来源与探索:数据多少条、哪些字段、有没有缺失值、数据的分布图
- 特征工程:构造了哪些特征,相关性分析结果
- 建模与评估:用了哪些模型,评估指标(MSE、R²)对比表格
- 结论与展望:哪个模型最好,为什么,后续可以怎么改进
其中"评估指标对比表格"是报告的杀手锏,建议直接用Markdown语法放进文档:
| 模型 | MSE | R² |
|---|---|---|
| 线性回归 | 5.23 | 0.76 |
| 决策树 | 2.41 | 0.89 |
| 随机森林 | 1.87 | 0.91 |
5.4 README.md 是给老师的第一印象
README不要写太长,但要让人三分钟能跑起来。我建议写五块内容:项目简介(3句话)、环境依赖、运行方法(先执行哪个脚本再执行哪个)、数据集说明、结果展示。运行方法部分要精确到命令行:
pip install -r requirements.txt
python src/data_preprocessing.py
python src/train_model.py
python src/visualize.py
5.5 答辩时会被问到的三个高频问题
提前准备这三个问题的答案,答辩就成功了一半:
- 为什么不用LSTM等深度学习模型?——回答:大作业数据量较小,经典机器学习模型在精度和计算资源上性价比更高,并且可解释性更强。如果一定要提LSTM,可以说"后续可以扩展的方向"。
- 为什么用R²而不是只用准确率?——回答:这是回归任务,准确率没有意义,R²表示模型解释了目标变量方差的百分比。
- 数据量这么少,会不会过拟合?——回答:用了交叉验证和限制树的深度来控制过拟合,测试集上的表现证明泛化能力较好。
6. 踩坑实录:我在写这个项目时遇到的5个真实问题
6.1 日期解析报错
读CSV时如果日期列是字符串格式,直接 pd.to_datetime() 有时候会报 Unknown string format 。解决方法是加上 format 参数:
df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d')
这个问题通常在数据来自不同地区、日期格式混合(比如有的是 2023/1/1 ,有的是 2023-01-01 )时出现。一个更省心的办法是用 pd.to_datetime(df['date'], errors='coerce') ,解析失败会变成NaT,然后再删掉这些行。
6.2 中文乱码改了字体还是报错
Windows下SimHei字体一般没问题,但如果你用的是Mac或Linux,SimHei不存在,图表中的中文会变成方块。解决方案是改用系统自带中文字体,Mac下用 Arial Unicode MS ,Linux下可以先查一下 fc-list :lang=zh 列出可用字体。另外 axes.unicode_minus=False 一定要加,否则负号会显示成方框。
6.3 模型评估结果"好得离谱"
如果你发现R²接近0.99,先别高兴。大概率触发了数据泄漏。常见原因有两个:一是随机切分测试集导致未来数据混入训练集;二是在整个数据集上做了标准化再切分。检查办法很简单:把预测值和真实值画散点图,如果点完美落在对角线上,基本可以确定泄漏了。
6.4 shift(1) 导致最后一行预测不了
这是时间序列预测特有的问题:你用了 temp_yesterday 做特征,意味着预测时需要知道前一天的温度,这在实际应用场景中有局限。如果答辩老师问到"那我想预测未来7天怎么办",你可以回答:第一天的预测可以用真实值,后续天数的预测值可以作为输入递推下去。这个回答不仅化解了问题,还展示了你的思考深度。
6.5 随机森林训练超慢
如果数据集有几十万行,随机森林在单机上可能跑几分钟。大作业一般不需要那么多数据,你可以用 df.sample(n=20000, random_state=42) 抽样,或者减少 n_estimators 到50。如果还是慢,检查一下是不是特征里混进了字符串类型,模型会把字符串当成类别,导致树的分裂计算量暴增。
7. 最终交付:这份代码还能怎么扩展
如果你时间充裕,想让这份大作业更有亮点,我推荐三个低成本扩展方向,每个都不需要太多额外代码,但能明显提升项目的完整度。
第一个方向是引入更多的气象字段。如果原始数据里有湿度、风速、气压,可以把它们都作为特征加入模型,然后做一个"仅用日期特征"和"日期+气象特征"的对比实验,证明气象数据对预测精度有提升。这个对比本身就是一段很漂亮的实验分析。
第二个方向是做一个简单的可视化交互界面。用Streamlit或Flask写一个20行代码的网页,用户输入日期,返回预测温度。这种"能跑起来的Demo"在答辩现场演示效果远胜于PPT里的截图。Streamlit的代码非常简洁:
import streamlit as st
st.title('天气温度预测')
day = st.date_input('选择日期')
pred = model.predict(...)
st.write(f'预测温度: {pred[0]:.1f} °C')
第三个方向是预测多个气象变量,比如同时预测温度和湿度,用多输出回归模型 MultiOutputRegressor 包装一下即可。这能体现你对机器学习更深入的理解。
不过提醒一句:扩展可以做,但不要喧宾夺主。大作业的核心始终是主线流程——数据、特征、模型、评估、结论,把这五步的每一步做扎实,拿到一个好的成绩完全不成问题。
我自己的实际体会是,天气预测这个选题最大的价值不是算法有多深,而是它帮助你完整走了一遍"从原始数据到模型落地"的机器学习全流程。这个过程走完,你再去学深度学习或者其他算法,会发现很多东西都通了。这也是为什么我愿意花这么多篇幅把它讲透——它真的值得每个选它的人认真做一次。
更多推荐


所有评论(0)