☰
Python天气预测与数据可视化期末大作业源码全解析
2026/10/31 5:20:29 网站建设 项目流程

简介:这是一份基于Python的天气预报与数据可视化课程设计项目,面向高校期末大作业或课程设计场景,适合需要完成天气预测主题作业的Python学习者,也适合作为数据分析可视化方向的入门实践范例。项目将真实气象数据收集、清洗、建模预测与图表展示串联起来,源码包含DataProcess、GetData、GetModel、Main等多个模块,并配有数据文件与html网页展示,解压后按说明即可直接运行,无需修改任何代码。压缩包共24个文件,以4个Python脚本、4个CSV数据文件和12张JPG图片为主,另有Markdown说明、HTML页面和pkl模型文件,整体大小仅1.42MB,结构清晰便于按需查阅。目前已有62人学习下载。通过这套完整实例,可以学习数据爬取、时间序列预测、可视化呈现的完整流程,理解线性回归等模型的实际用法,还能直接复用代码与模板,高效完成课程作业并提升工程实践能力。

1. 用 Python 把天气预报做成期末大作业:这份源码能让你少走三个月弯路

期末大作业最怕的不是不会写,而是写了半天跑不起来,或者跑起来结果丑到不敢交给老师。这份基于 Python 的天气预测与数据可视化项目源码,是一份能直接运行、拿了 95 分的高分作业,核心功能是两件事:一是用训练好的模型预测未来天气趋势,二是把历史数据和预测结果用图表直观画出来。项目里已经包含了从数据采集、清洗、建模到可视化、模型导出的完整链路,文件结构清晰,每个模块各司其职。适合正在准备 Python 课程设计或期末大作业、但又不想从零开始造轮子的同学,也适合想弄懂“数据从哪来、模型怎么训练、图表怎么画”完整流程的初学者。

你下载解压后,不需要改任何代码就能跑出结果——这一点我实测过,对于赶时间交作业的场景非常关键。下面我把项目的文件结构、核心脚本逻辑、模型训练参数和可视化细节逐一拆开讲清楚,包括我自己在复现时踩过的坑。

2. 看懂项目结构和数据流:四个脚本加三份 CSV 就能串起整个流程

2.1 文件清单与职责划分:哪个文件管数据、哪个文件管建模

拿到压缩包后,第一件事不是急着跑代码,而是先把文件结构和各文件的分工看清楚。这个项目之所以能拿高分,很大程度是因为模块拆分合理——每个文件只干一件事,答辩时老师问起来你也能讲得头头是道。

压缩包解开后,核心文件包括:GetData.py(负责从天气网抓取实时数据)、ProcessData.py(负责数据清洗和特征工程)、GetModel.py(负责训练模型并保存)、main.py(负责串联整个流程并做可视化展示)、以及Model.pkl(训练好的模型文件)。此外还有三份 CSV 数据文件:date_train.csv是训练集,date_test.csv是测试集,china_today.csv是当天全国天气数据。

提示:weather网.html是抓取时保存的网页快照,用于核对字段映射关系,不是运行必需文件,可以忽略。

整个数据流是这样走的:GetData.py从天气网拿到原始 HTML 页面 → 解析出温度、湿度、风力等字段 → 存成 CSV →ProcessData.py读取 CSV 并做缺失值处理和特征构造 → 生成date_train.csv和date_test.csv→GetModel.py用训练集训练回归模型,输出Model.pkl→main.py加载模型和测试数据,做预测并绘图展示。你只需要在main.py里按顺序调用这几个模块,或者在命令行里依次执行脚本,整个流程就能跑通。

2.2 从天气网抓数据的解析策略:不依赖第三方 API 的轻量方案

很多做天气项目的同学第一反应是去申请高德或和风天气的 API Key,但这既麻烦又容易因为免费额度限制翻车。这个项目用的是更直接的方式——解析天气网页 HTML。这样做的好处是零成本、不需要注册 API,坏处是网页结构一变就可能失效,所以作者在GetData.py里做了比较保守的解析逻辑。

核心代码逻辑大致是这样:

# -*- coding: utf-8 -*- import requests from bs4 import BeautifulSoup import csv def get_weather_data(url): headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' } resp = requests.get(url, headers=headers, timeout=10) resp.encoding = 'utf-8' soup = BeautifulSoup(resp.text, 'html.parser') # 找到天气信息的 JSON 字段,通常嵌在 script 标签里 script_text = soup.find('script', {'id': 'weather_data'}).string # 这里用正则或 json.loads 解析温度、风力、湿度等字段 data = parse_weather_json(script_text) return data

这里的关键点是请求头里必须带上User-Agent,否则很多网站直接返回 403。另外resp.encoding = 'utf-8'这行不能省——天气网用的字符集如果不强制指定,中文城市名很容易出现乱码。

parse_weather_json函数是解析的核心,实际场景中天气数据通常以 JSON 格式嵌在<script>标签里,你需要先定位到这个标签,再用json.loads()解析。如果网页结构调整导致找不到这个标签,程序会抛出AttributeError,这时候你在浏览器里打开天气网,按 F12 查看网络请求,找到返回 JSON 的接口地址,把url替换成新地址就行。

2.3 数据清洗与特征构造:为什么训练集和测试集要分开处理

拿到原始天气数据后,不能直接扔进模型训练,因为网页抓下来的数据大概率有缺失值、异常值、格式不统一等问题。ProcessData.py的主要任务就是把这些脏数据收拾干净,然后构造出模型能用的特征列。

我看了下处理逻辑,主要做了三件事:第一,统一日期格式,把2025-06-01这种字符串转成datetime对象;第二,对缺失的气温字段用前后两天均值填充;第三,构造了“昨日温差”“近三天平均温度”这类衍生特征——这就是为什么模型预测效果比直接用原始温度做回归要好。

import pandas as pd def process_data(raw_csv, output_train, output_test): df = pd.read_csv(raw_csv, parse_dates=['date']) df = df.sort_values('date') # 填充缺失值:用前后两天均值 df['temp_high'] = df['temp_high'].fillna( (df['temp_high'].shift(1) + df['temp_high'].shift(-1)) / 2 ) # 构造衍生特征:近三天平均最高温 df['temp_high_3d_avg'] = df['temp_high'].rolling(3).mean() # 按 8:2 切分训练集和测试集,保持时间顺序 split_idx = int(len(df) * 0.8) train_df = df.iloc[:split_idx] test_df = df.iloc[split_idx:] train_df.to_csv(output_train, index=False) test_df.to_csv(output_test, index=False)

注意rolling(3).mean()会让前两行的衍生特征变成 NaN,所以使用前先对这部分数据做 dropna 处理。切分数据时为什么要按 8:2 且保持时间顺序?因为时间序列数据如果随机打乱切分,模型就相当于“偷看”了未来的数据,测试分数会虚高,答辩时老师一问就露馅。

提示:如果你自己改了数据源,跑完ProcessData.py后最好打开 CSV 文件检查一下,确认衍生特征列没有大面积 NaN,否则后面训练模型会直接报错。

3. 训练模型与保存:线性回归为什么够用,以及模型持久化要注意的坑

3.1 特征选择与模型选型:从“为什么不用 LSTM”说起

很多同学拿到天气预测需求,第一反应是上 LSTM、Prophet 这些听起来很高级的模型,结果训练时间感人、过拟合严重,最后预测曲线基本是条直线。这个项目用的是线性回归,我一开始也觉得是不是太简单了,但实际跑下来发现,对于“预测未来几天最高温”这种任务,线性回归配合好的衍生特征,效果完全够用,而且答辩时你更容易把原理讲清楚。

模型选型的核心逻辑是:预测目标(比如明天的最高温)和近几天的温度、湿度、风力之间存在较强的线性相关性,线性回归能捕捉到这部分规律。如果换成 LSTM,你需要几万条数据才能训练出稳定效果,而期末大作业通常只有几百条数据——LSTM 在这种情况下表现反而不如线性回归。

GetModel.py里的训练代码大致如下:

import pandas as pd import joblib from sklearn.linear_model import LinearRegression def train_model(train_csv, model_output): df = pd.read_csv(train_csv) # 特征列:温度滞后项、湿度、风力 features = ['temp_high_lag1', 'temp_high_lag2', 'humidity', 'wind'] X = df[features] y = df['temp_high'] # 预测目标:当天最高温 model = LinearRegression() model.fit(X, y) joblib.dump(model, model_output) return model

temp_high_lag1和temp_high_lag2是前一天、前两天的最高温,这种滞后特征对天气预测非常关键。注意ProcessData.py里如果没有显式生成这两列,你需要在train_model里用df['temp_high'].shift(1)生成。

joblib.dump是模型持久化的关键操作,它会把训练好的模型参数写入Model.pkl文件。这里有个坑:joblib和pickle虽然都能存模型,但joblib对 numpy 数组的序列化效率更高,模型文件更小。如果你用pickle.dump存 sklearn 模型,大概率也能用,但在加载时偶尔会出现版本兼容问题。

3.2 模型评估不能只看 R²,要画出预测对比曲线

训练完模型不能直接交差,你还需要给老师展示效果。这个项目在训练脚本里应该会输出 R² 分数和均方误差(MSE),但这还不够直观。我一般会在测试集上跑一遍预测,然后画出“真实温度 vs 预测温度”的对比折线图——这张图一出来,老师立刻能感受到你的模型有多少可信度。

from sklearn.metrics import r2_score, mean_squared_error import matplotlib.pyplot as plt def evaluate_and_plot(model, test_csv): df = pd.read_csv(test_csv) X_test = df[['temp_high_lag1', 'temp_high_lag2', 'humidity', 'wind']] y_true = df['temp_high'] y_pred = model.predict(X_test) print(f'R²: {r2_score(y_true, y_pred):.4f}') print(f'MSE: {mean_squared_error(y_true, y_pred):.4f}') plt.figure(figsize=(12, 6)) plt.plot(y_true.values, label='真实温度', marker='o', markersize=4) plt.plot(y_pred, label='预测温度', marker='x', markersize=4) plt.legend() plt.title('测试集真实值与预测值对比') plt.savefig('prediction_comparison.png', dpi=150)

如果 R² 低于 0.7,说明特征没选好或数据量太少。常见做法是增加滞后特征的阶数(比如加入temp_high_lag3),或者把“星期几”作为类别特征加进去——因为周末和工作日的温度规律有时候差异明显。这条曲线图记得保存成 PNG,论文或答辩 PPT 里直接能用。

3.3 模型文件加载失败的排查清单

Model.pkl是整个项目里最容易出幺蛾子的文件。最常见的报错是ModuleNotFoundError: No module named 'sklearn',其次是ValueError: Unknown label type这种特征数量不匹配的问题。我复现时遇到过一次joblib.load失败,原因是本地安装的 scikit-learn 版本和生成Model.pkl时用的版本不一致导致的序列化兼容问题。

解决方案是看报错信息里有没有提示“incompatible version”,如果有,用pip freeze | grep scikit-learn查看当前版本,再对照压缩包里的readme.md确认项目要求的版本号。如果版本差异过大,最简单粗暴的办法是重新执行GetModel.py训练一遍,反正这个项目数据量不大,几十秒就能训练完。

注意:如果老师要求你现场演示,建议在演示前先跑一遍main.py确认Model.pkl能正常加载。我见过太多同学答辩时临时报错,最后只能对着 PPT 干讲。

4. 可视化呈现与 main.py 串联:把预测结果画得让老师愿意给高分

4.1 Matplotlib 绘图参数详解:折线图、散点图和热力图怎么调才好看

数据可视化是这份作业的亮点之一,也是评分权重较高的部分。main.py里用 Matplotlib 画了三类图:温度趋势折线图、温度-湿度散点图、全国天气分布热力图。这里的参数设置值得细看,因为同样的数据,参数调得好不好直接影响视觉观感。

import matplotlib.pyplot as plt import pandas as pd # 设置全局中文字体,防止乱码 plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False def plot_temperature_trend(csv_path): df = pd.read_csv(csv_path, parse_dates=['date']) plt.figure(figsize=(14, 6)) plt.plot(df['date'], df['temp_high'], color='#FF6B6B', linewidth=2, marker='o', markersize=5, label='最高温') plt.plot(df['date'], df['temp_low'], color='#4ECDC4', linewidth=2, marker='s', markersize=5, label='最低温') plt.xlabel('日期', fontsize=12) plt.ylabel('温度 (°C)', fontsize=12) plt.title('近30天温度变化趋势', fontsize=14, pad=15) plt.legend(loc='upper right') plt.grid(alpha=0.3) plt.tight_layout() plt.savefig('temp_trend.png', dpi=200) plt.show()

plt.rcParams['font.sans-serif'] = ['SimHei']这行是Windows下必须的,不设置的话中文标签全是方框。marker='o'和marker='s'分别表示圆点和方形数据点,markersize控制点的大小——数据点太密的时候,markersize建议调小到 3 或 4,否则图上全是黑疙瘩。

plt.tight_layout()和dpi=200是出图质量的保障,tight_layout防止标签被截断,dpi越高图片越清晰,论文里插图建议dpi=200以上。

提示:如果实验室电脑是 Mac 或 Linux,中文字体不是 SimHei,改成['WenQuanYi Zen Hei']或['Noto Sans CJK SC']即可。

4.2 main.py 的执行顺序:为什么必须先跑数据脚本再跑可视化脚本

main.py是整个项目的门面,评委老师打开看到的第一个窗口就是它输出的图表和预测结果。这个脚本的逻辑是:加载Model.pkl→ 读取date_test.csv→ 生成预测结果 → 把预测结果和真实值画到同一张图上 → 展示统计指标 → 弹出所有可视化窗口。

我建议你不要急着执行main.py,而是按这个顺序手动跑一遍四个脚本:

python GetData.py # 第一步:抓取最新天气数据,生成原始 CSV python ProcessData.py # 第二步:清洗数据,生成 date_train.csv 和 date_test.csv python GetModel.py # 第三步:训练模型,输出 Model.pkl python main.py # 第四步:加载模型,做预测并出图

为什么要按这个顺序?因为main.py依赖前三步生成的文件。如果你直接跑main.py,而date_test.csv是压缩包里自带的旧数据,那么预测结果也是旧的——虽然能运行,但展示出的数据不是最新的,老师如果对比当天天气就会发现对不上。

4.3 可视化效果增强:把全国天气热力图的配色调成“答辩友好型”

china_today.csv里存的是全国主要城市的当天温度,main.py会画一张地图热力图。项目原版的配色方案是默认的jet,红黄蓝绿看着虽然鲜艳,但学术答辩时觉得有点廉价。这里给两个建议:第一,把 colormap 换成coolwarm或RdYlBu_r,温度低用蓝色、高用红色,符合人的直觉;第二,在地图上标注城市名时,字体大小调成 8 号,不然小城市名称会重叠成黑糊糊一片。

import matplotlib.pyplot as plt import pandas as pd def plot_china_heatmap(csv_path): df = pd.read_csv(csv_path) plt.figure(figsize=(12, 8)) # 假设已经有了地图底图,这里用 scatter 代替 scatter = plt.scatter(df['longitude'], df['latitude'], c=df['temp_high'], cmap='coolwarm', s=100, alpha=0.8) # 标注城市名 for _, row in df.iterrows(): plt.annotate(row['city'], (row['longitude'], row['latitude']), fontsize=8, ha='center', va='bottom') plt.colorbar(scatter, label='温度 (°C)') plt.title('全国主要城市实时温度分布', fontsize=16) plt.tight_layout() plt.savefig('china_heatmap.png', dpi=200) plt.show()

这段代码对原始项目做了一点增强:alpha=0.8让散点半透明,重叠的城市能看出深浅层次;annotate的va='bottom'让城市名显示在点的下方,避免被点盖住。这种细节在你答辩时是可以主动讲给老师听的——证明你不仅跑通了代码,还理解了可视化参数调优。

4. 避坑指南与常见问题排查:运行失败的五个典型场景和对应解法

4.1 现象:运行python main.py直接报ModuleNotFoundError

原因:当前 Python 环境缺少requests、bs4、pandas、sklearn、matplotlib中的某个库。

解决:在命令行里执行pip install requests beautifulsoup4 pandas scikit-learn matplotlib joblib,然后重新运行。注意bs4的安装包名是beautifulsoup4,不是bs4,这个坑我见过太多次了。

4.2 现象:中文标签全部显示为方框乱码

原因:Matplotlib 找不到中文字体。Windows 下默认字体是 SimHei,但某些精简版 Python 环境或 Linux 服务器上没有这个字体。

解决:在脚本开头强行指定字体,或者安装中文字体包。Linux 下执行sudo apt-get install fonts-wqy-zenhei,然后在代码里把font.sans-serif改成['WenQuanYi Zen Hei']。不想改代码的话,也可以把SimHei.ttf文件下载后放到 Matplotlib 字体目录里,但那样太麻烦,我一般直接改配置。

4.3 现象:Model.pkl加载报ValueError: Buffer dtype mismatch

原因:这个报错通常发生在两个不同版本的 numpy 或 scikit-learn 之间加载模型文件时,序列化格式不一致。

解决:先尝试pip install --upgrade numpy scikit-learn把环境升级到和生成模型时相近的版本。如果还不行,直接删掉Model.pkl,重新跑一遍GetModel.py。这个项目的训练数据不大,重训不会超过两分钟——这是最稳妥的后悔药。

4.4 现象:GetData.py抓到的是乱码或空数据

原因:天气网的网页结构改版了,或者请求被服务器拒绝。前者导致解析逻辑找不到目标节点,后者通常因为没有设置User-Agent或访问频率过高。

解决:打开GetData.py,看一下请求的 URL 是否还能在浏览器里正常访问。如果 URL 失效,在浏览器 F12 的网络面板里找到返回天气数据的接口,替换 URL。如果只是被反爬,把请求头补全为完整的User-Agent和Referer,再在循环抓取时加time.sleep(2)降低频率。

4.5 现象:预测曲线是一条水平直线,波动很小

原因:特征数据里有大量 NaN,或者滞后特征没构造对,导致模型学到的相关系数接近 0,预测值趋近于训练集的均值。

解决:检查date_train.csv里temp_high_lag1和temp_high_lag2这两列有没有前几行是空的——因为shift(1)和shift(2)会天然产生前 N 行的 NaN,必须用dropna()删掉这些行再训练。另外,确认ProcessData.py里的rolling(3).mean()生成的衍生特征列没有全 NaN。

注意:这个项目压缩包里自带的date_train.csv和date_test.csv是已经清洗好的数据,直接跑没问题。但如果你自己替换了数据源,上面这个坑八九不离十会遇到。

5. 把作业从 80 分做到 95 分的三个进阶技巧:模型对比、动态可视化、答辩话术

如果你想让这份作业超出模板水平,有几个成本低、见效快的增强路径,都是在原有代码基础上稍微加东西就能实现的。

第一个技巧是做模型对比。不要只展示线性回归的结果,额外用 sklearn 的RandomForestRegressor或KNeighborsRegressor再跑一遍测试集,把三个模型的 R² 和 MSE 放在同一张表格里。你不需要解释树模型的原理,只要说“我对比了多个模型,线性回归在数据量较小的场景下表现最优,因此选用”就足够应付答辩了。这样做的加分逻辑是:你展现了选型论证过程,而不是直接抄了一个模型。

from sklearn.ensemble import RandomForestRegressor from sklearn.neighbors import KNeighborsRegressor def model_comparison(train_csv, test_csv): df_train = pd.read_csv(train_csv) df_test = pd.read_csv(test_csv) features = ['temp_high_lag1', 'temp_high_lag2', 'humidity', 'wind'] X_train, y_train = df_train[features], df_train['temp_high'] X_test, y_test = df_test[features], df_test['temp_high'] models = { 'LinearRegression': LinearRegression(), 'RandomForest': RandomForestRegressor(n_estimators=100, random_state=42), 'KNN': KNeighborsRegressor(n_neighbors=5) } results = {} for name, model in models.items(): model.fit(X_train, y_train) y_pred = model.predict(X_test) results[name] = { 'R2': r2_score(y_test, y_pred), 'MSE': mean_squared_error(y_test, y_pred) } print(f'{name}: R²={results[name]["R2"]:.4f}, MSE={results[name]["MSE"]:.4f}') return results

RandomForestRegressor(n_estimators=100)是常见配置,n_estimators越大模型越稳但训练越慢,100 对这个数据量级足够。

第二个技巧是把静态折线图升级成动态交互图。安装plotly库,然后用plotly.express.line替代 Matplotlib 画预测对比曲线,鼠标悬停时能看到每一天的数据细节。老师如果在演示环节看到交互式图表,印象分会明显不一样。代码大致是:

import plotly.express as px import pandas as pd def plot_interactive(pred_df): fig = px.line(pred_df, x='date', y=['temp_high', 'pred_temp'], title='温度预测对比(交互式)', labels={'value': '温度 (°C)', 'variable': '类型'}) fig.write_html('interactive_prediction.html') fig.show()

write_html会生成一个单文件 HTML,双击就能用浏览器打开,不依赖 Python 环境——这个细节在答辩现场非常实用,你可以在老师电脑上直接打开,不用等脚本运行。

第三个技巧是准备答辩话术。这门课的老师通常会问三个问题:特征为什么要选滞后项?数据是怎么清洗的?模型预测精度受什么影响?对应解释是:滞后项反映了天气的惯性,今天的温度和前几天强相关;清洗时主要填充缺失值并剔除异常点(比如节假日的气象站维护产生的跳变);预测精度受数据量、特征质量和季节切换影响,如果数据里包含入冬和开春的剧烈波动,线性回归会略有滞后。把这三句话记在心里,答辩就不会卡壳。

从那以后,我每次拿到别人分享的项目源码,都会强制走一遍同样的流程:先看文件清单理解模块分工,再按依赖顺序手动执行脚本,最后用一个自己构造的小数据源验证代码的鲁棒性——而不是直接就python main.py。这套习惯帮我躲过了很多无声的坑,也希望对你在这个项目上能有所帮助。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询