尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

天气预测Python课程设计:从数据清洗到ARIMA模型与可视化实现

天气预测Python课程设计:从数据清洗到ARIMA模型与可视化实现 简介这是一份面向高校数据科学课程设计的完整实战项目基于Python实现天气数据的采集、清洗、建模预测与可视化展示适合作为课程设计、期末大作业或多学分的综合实训参考。项目已通过导师指导并获97分整体质量经过验证解压后按说明即可直接运行无需额外改动。压缩包共24个文件大小仅1.43MB结构清晰4个.py脚本分别负责数据获取、处理、建模与主流程4个csv文件提供训练、验证、测试及当日实况数据还包含Model.pkl预训练模型、天气网HTML可视化页面、readme说明文档以及运行截图便于对照效果和快速理解设计思路。目前已有653人学习使用特别适合初学Python数据分析与机器学习的学生参考可从中学习完整的数据处理管线、模型保存与加载、前端可视化衔接等方法也能直接作为自己的课程设计材料提交。1. 天气预测课程设计一张数据表到一条可展示的预测曲线拿天气数据做预测和可视化是Python课程设计里出场率最高的题目之一。它看起来简单——无非是读取数据、跑个模型、画张图——但真正动手时你会发现数据清洗、日期对齐、模型选型和出图样式每一个环节都能卡住人。市面上流传的“完整源码包”大多只给一个能跑的脚本数据一换、Python版本一换就翻车。这篇笔记照着课程设计的真实评分点来拆数据从哪里来、特征怎么做、模型怎么选、图怎么画、坑在哪里最后给一个能让答辩老师点头的验证思路。适合正在做课设的学生也适合想快速搭一个天气数据demo的开发者照着复现。2. 从城市天气数据到训练集清洗与特征工程的三个关键动作2.1 先决定数据来源爬虫接口还是本地CSV课程设计里最常见的数据来源有两种。第一种是用爬虫抓天气网站的历史数据优点是能拿到任意城市、任意时间段的数据缺点是网站改版、反爬策略、字段名不统一都会打断你的节奏而且答辩时现场联网经常出意外。第二种是直接用现成的CSV数据包稳、可复现、离线可跑数据包里一般包含日期、最高气温、最低气温、天气现象、风力风向这几个字段对课程设计完全够用。我的做法是本地CSV为主爬虫脚本作为加分项放在项目里。这样既保证主流程稳定又能向老师展示你“会爬数据”。如果选择爬虫优先找提供JSON接口的天气服务商解析比解析HTML省事得多。下面是一段读取并检查CSV数据的代码import pandas as pd df pd.read_csv(weather_data.csv, encodingutf-8) df[date] pd.to_datetime(df[date]) df df.sort_values(date).reset_index(dropTrue) print(df.shape) print(df.head()) print(df.isnull().sum())逻辑说明先用pd.to_datetime把日期字符串转成时间类型这是一切时间序列分析的前提——如果日期是字符串后面切分训练集和测试集时顺序会错。然后按日期排序并重置索引避免原始数据乱序导致训练集和测试集互相污染。isnull().sum()用来快速定位哪些列有空值这一步看似基础但相当一部分课设翻车就翻在缺失值没处理。参数说明encodingutf-8必须和你数据文件实际编码一致。有些数据包是GBK编码读进来直接乱码需要改成encodinggbk。判断方法很简单读出来打印df.head()看到中文正常就不是编码问题看到一堆乱码或者直接报错换编码再试。2.2 缺失值与异常值处理不要用均值填一切天气数据里的缺失通常集中在极端天气或站点维护时段。处理时先看缺失比例比例低于5%可以直接删除比例在5%到20%之间用插值法补齐超过20%这个字段直接丢弃别硬留。异常值的判断逻辑更有讲究。气温数据里出现40℃或-40℃不一定是错的得结合城市和季节判断。一般做法是用滚动窗口算均值和标准差偏离均值超过3倍标准差的数据点标记为异常再用相邻日期的均值替换。# 缺失值处理 df[temp_high] df[temp_high].interpolate(methodlinear) # 滚动窗口异常值检测 rolling_mean df[temp_high].rolling(window7, centerTrue).mean() rolling_std df[temp_high].rolling(window7, centerTrue).std() upper rolling_mean 3 * rolling_std lower rolling_mean - 3 * rolling_std df[temp_high] df[temp_high].clip(lowerlower, upperupper)逻辑说明interpolate用的是线性插值拿缺失值前后两个有效数据的平均值补位比用整列均值填充要合理得多——气温有季节性趋势前后日期的值才更有参考意义。异常值检测先用7天滚动窗口算出局部均值和标准差然后通过clip把超出3倍标准差的值压回合理范围。参数说明rolling(window7)表示以7天为窗口centerTrue让窗口以当前日期为中心。窗口宽度可以调窗口越小对短期波动的反应越敏感但也越容易把正常天气变化误判为异常窗口越大检测越平滑但可能漏掉真实的剧烈降温。课程设计里7到14天是比较稳的选择。2.3 特征工程让模型看到“昨天和去年的今天”如果直接把日期字符串丢给模型模型学不到任何时间规律。特征工程的核心是把时间维度拆成模型能消化的数值。常用的做法有三个滞后特征、滑动窗口统计、周期性编码。滞后特征是最直接有效的。预测明天的最高气温时把昨天、前天的最高气温作为输入特征模型就有了“气温惯性”这个概念。滑动窗口统计则是取过去7天平均气温、最高最低温差等。周期性编码时把月份转成sin和cos防止12月和1月因为是“相邻月份”却被当作风马牛不相及的类别。# 滞后特征 for lag in [1, 2, 3, 7]: df[ftemp_high_lag{lag}] df[temp_high].shift(lag) # 滑动窗口统计 df[temp_high_avg7] df[temp_high].rolling(window7).mean() # 周期性编码 df[month_sin] np.sin(2 * np.pi * df[date].dt.month / 12) df[month_cos] np.cos(2 * np.pi * df[date].dt.month / 12) # 删除含NaN的行滞后和滚动窗口会产生前几行的空值 df df.dropna().reset_index(dropTrue)逻辑说明shift(lag)把目标列向上移动lag行让模型用前1天、前2天、前3天、前7天的真实气温来预测当天。这里的核心是删除含NaN的行做了滞后和滚动窗口之后数据集前几行必然缺失直接训练会报错或产生无意义的预测。参数说明滞后天数选[1, 2, 3, 7]是有讲究的。1和2捕捉短期惯性3捕捉一般天气过程周期7对应一周前的温度能帮模型感知“和上周同一天比是冷是热”。如果你手头数据跨了好几年可以再加一个365的滞后特征让模型知道“去年今天的气温”。周期性编码里sin和cos配合使用能把月份映射到一个连续的圆环上模型才学得到“冬天和夏天不是线性两端”这种常识。3. 选 ARIMA 还是线性回归课程设计里预测模型的落地选择3.1 两个常用方案的能力边界对比课程设计里预测部分最常看到两个方向线性回归和ARIMA。还有一部分人会硬上LSTM但对课设来说性价比很低。线性回归的优势在于特征透明、训练快、容易解释。你可以清楚地说出“滞后1天的气温对预测贡献最大”答辩时老师问“为什么这个特征重要”你能从容回答。缺点是它对时间序列的自相关结构建模能力有限趋势和季节项需要靠外部特征补齐。ARIMA全称是差分自回归移动平均模型专门为时间序列设计。它能自动捕捉序列自身的自相关结构对平稳序列的预测效果通常比普通线性回归更好。缺点是需要人工判断差分阶数、看自相关图和偏自相关图参数选择有门槛而且不太方便加入外部特征。课程设计的评分逻辑里“代码能跑出合理曲线”和“你能讲清楚为什么这么做”各占一半。我的建议是数据量超过两年、有明显的季节性用ARIMA数据量只有几个月或者你想做多特征融合用线性回归。如果时间充裕两个都做然后对比RMSE反而是最好的答辩素材。3.2 用 statsmodels 跑通 ARIMA 的最小流程ARIMA需要三个参数p自回归阶数、d差分阶数、q移动平均阶数。课程设计里不需要用复杂的ACF/PACF判断法一个自动定阶的循环就够了。import itertools import warnings import statsmodels.api as sm warnings.filterwarnings(ignore) # 也只取最高气温作为预测目标 ts df.set_index(date)[temp_high].astype(float) # 遍历参数组合用AIC选最优模型 best_aic float(inf) best_order None for p in range(0, 4): for d in range(0, 2): for q in range(0, 4): try: model sm.tsa.ARIMA(ts, order(p, d, q)).fit() if model.aic best_aic: best_aic model.aic best_order (p, d, q) except Exception: continue print(f最优ARIMA参数: {best_order}, AIC: {best_aic:.2f})逻辑说明这段代码把所有p在0到3、d在0到1、q在0到3的共32种组合都训练一遍选取AIC信息准则最小的那个作为最终模型。AIC不是预测准确率它衡量的是模型拟合质量和复杂度之间的平衡——AIC越低说明在拟合得好的同时参数尽量少不容易过拟合。参数说明p和q的搜索范围设在0到3是合理的天气数据的气温序列自相关通常不会太复杂超过3的阶数很容易过拟合。d的搜索范围0到1因为气温序列有年周期但整体平稳二阶差分会把序列内部的季节关系破坏掉。如果数据量特别大可以把p和q范围扩大到0到5但训练时间会明显增长课设数据量下没必要。3.3 训练测试切分时间序列不能随机打乱这个错误几乎每个课设都有用train_test_split默认的随机切分来切时间序列。随机打乱意味着模型可能用7月的数据去预测3月的数据测试集里混着训练集的时间段得到的准确率完全是假的。train_size int(len(ts) * 0.8) train, test ts[:train_size], ts[train_size:] # 在训练集上重新拟合最优模型 model sm.tsa.ARIMA(train, orderbest_order).fit() forecast model.forecast(stepslen(test)) # 计算评估指标 from sklearn.metrics import mean_absolute_error, mean_squared_error mae mean_absolute_error(test.values, forecast) rmse mean_squared_error(test.values, forecast, squaredFalse) print(fMAE: {mae:.2f}°C, RMSE: {rmse:.2f}°C)逻辑说明这段代码严格按时间顺序切分前80%做训练、后20%做测试模拟“用过去预测未来”的真实场景。model.forecast(stepslen(test))直接预测未来N个时间点N等于测试集的长度。MAE和RMSE都是温度预测里常用的误差指标RMSE对偏大的误差更敏感。参数说明train_size0.8是时间序列切分的常见比例。数据量偏少时可以调到0.7让测试集有更多样本去评估稳定性数据量充裕时可以0.85。用RMSE时注意sklearn不同版本里mean_squared_error的squared参数新版本默认是True返回MSE要拿到RMSE必须设squaredFalse。4. 可视化实现让预测结果在答辩屏幕上站得住脚4.1 用 Matplotlib 画“实际对比预测”图三个默认设置必须改Matplotlib的默认样式放在论文里尚可放在课程设计答辩上就显得单薄。重点改三个方面中文字体、坐标轴密度、图例样式。尤其是中文字体Windows下默认不显示中文画出来的图全是方块一下就能扣分。import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei] plt.rcParams[axes.unicode_minus] False plt.figure(figsize(12, 5)) plt.plot(train.index, train, label训练集实际值, color#2E86AB) plt.plot(test.index, test, label测试集实际值, color#A23B72) plt.plot(test.index, forecast, label预测值, color#F18F01, linestyle--, linewidth2) plt.xlabel(日期) plt.ylabel(最高气温 (°C)) plt.title(ARIMA 最高气温预测效果对比) plt.legend() plt.grid(alpha0.3) plt.tight_layout() plt.savefig(arima_forecast.png, dpi300) plt.show()逻辑说明训练集实际值用蓝色实线测试集实际值用红色实线预测值用橙色虚线。三条线的关系一眼就能看出模型的预测是滞后还是超前。linestyle--和linewidth2让预测线在视觉上更突出答辩时站在两米外也能看清。参数说明font.sans-serif必须放在绘图代码最前面且要放在plt.figure()之前才生效。SimHei是Windows自带黑体Microsoft YaHei是微软雅黑两个都写上是为了兼容不同环境。axes.unicode_minusFalse解决的是坐标轴负号显示为方块的问题这个不设的话冬天零下温度的图会多一处硬伤。dpi300导出的图片足够清晰放进答辩PPT不会糊。4.2 用 Pyecharts 做交互式大屏从静态图到可缩放页面如果课程设计要求里有“可视化大屏”或“交互式界面”字样Matplotlib画完静态图之后还需要一个交互式页面。Pyecharts是首选它能生成HTML文件双击就能在浏览器打开比Flask搭网站省事得多。贴合天气主题主要用两个图表一个是折线图展示预测曲线另一个是温度计图或仪表盘展示当天实时温度。from pyecharts.charts import Line from pyecharts import options as opts line ( Line() .add_xaxis([d.strftime(%Y-%m-%d) for d in ts.index]) .add_yaxis(实际气温, ts.values.tolist(), is_smoothTrue) .add_yaxis(预测气温, forecast.values.tolist(), is_smoothTrue, linestyle_optsopts.LineStyleOpts(width2, type_dashed)) .set_global_opts( title_optsopts.TitleOpts(title城市最高气温预测趋势), xaxis_optsopts.AxisOpts(axislabel_optsopts.LabelOpts(rotate45)), datazoom_opts[opts.DataZoomOpts(range_start60)], ) ) line.render(weather_forecast.html)逻辑说明Pyecharts的链式调用把数据源、坐标轴、缩放组件依次配置。add_xaxis的日期列表必须和温度值列表一一对应常见错误是两个列表长度不一致页面渲染时报错或曲线错乱。datazoom_opts加了一个缩放条初始显示后40%的数据区间方便直观看到测试集和预测值的对比细节。参数说明is_smoothTrue让折线变得平滑天气数据本身连续折线图带棱角反而显得不自然。range_start60表示缩放条初始位置在60%处也就是一打开页面直接看后半段预测部分。轴标签旋转45度是因为日期字符串较长默认横排会互相重叠。4.3 数据可视化里“产地”字段缺失时怎么办做可视化时一个常见尴尬是数据包里的天气数据没有经纬度或城市字段而做可视化大屏时你想加一个地图组件。遇到这种情况不要硬改数据更不要在代码里写死城市名。数据包里有什么字段就用什么可视化如果没有地理信息就把重点放在时间维度的可视化上比如叠加多条曲线对比不同月份的温差分布。如果确实要地图效果常见做法是在数据预处理阶段把城市名称映射到Google或高德的行政区划码然后用Pyecharts的Map组件和opts.ItemStyleOpts配合颜色区间来呈现。不过对这个课设而言一条清晰的预测曲线远比一张花哨但数据生硬的地图更能说明问题。5. 天气预测项目避坑5 个让人翻车的细节和对应解法5.1 日期索引丢失预测结果整体错位现象预测曲线画出来看起来形状和实际气温一致但对不上日期整体偏移了几天。原因做特征工程时dropna()删除了前几行但索引重置不彻底或者把date列单独拿出来训练模型不知道日期顺序预测结果被随机排序。解决所有涉及时间顺序的操作之后都检查一遍数据顺序。一个稳的做法是在切分训练集和测试集之前显式排序并重置索引df df.sort_values(date).reset_index(dropTrue)然后每次做dropna()之后再加一次reset_index(dropTrue)。如果模型输出后需要重新关联日期用pd.Series的索引对齐而不是按位置对齐。5.2 归一化泄漏用全量数据的均值去缩放训练集现象训练时模型误差很小测试时预测值明显偏低或偏高。原因做标准化或归一化时用了整个数据集的均值和标准差包括测试集的信息。这在机器学习里叫数据泄漏测试集的信息跑到了训练过程里导致评估结果虚高。解决先切分训练集和测试集再分别做标准化。from sklearn.preprocessing import StandardScaler scaler StandardScaler() train_scaled scaler.fit_transform(train.reshape(-1, 1)) test_scaled scaler.transform(test.reshape(-1, 1))fit_transform只在训练集上计算均值和标准差测试集只用transform继承同一套参数。如果模型最后要输出真实温度值需要inverse_transform还原。5.3 Matplotlib 中文是方块负号也是方块现象图标题和图例里的中文全是空心方块温度图上的负号也变成方块。原因Matplotlib默认字体不带中文字形axes.unicode_minus默认True会用Unicode负号但默认字体不支持。解决在任何绘图代码之前加上两行配置plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei, Arial Unicode MS] plt.rcParams[axes.unicode_minus] False如果是在Mac或Linux上跑SimHei不存在换成PingFang SC或WenQuanYi Micro Hei。最省事的方法把自己环境的可用中文字体名打印出来看一遍。5.4 做多步预测时把预测值当成真实值滚进去现象预测未来7天温度前两天准第三天以后越来越偏最后偏差好几度。原因用“滚动预测”方式把上一步的预测值作为下一步的输入特征。在线性回归模型里如果特征包含滞后特征预测第2天用的是第1天的预测值而非真实值误差一步步累积。解决要么只做单步预测预测一天然后重新训练或滑动窗口推进要么在代码里明确区分训练阶段和预测阶段预测时只允许使用已有的历史值。这个问题不是bug是方法论选择。课设答辩时主动说出这一点反而是加分项——说明你理解误差累积的机制。5.5 Pyecharts 图表渲染空白只有标题没有数据现象HTML页面打开标题和坐标轴都在折线区域却是空的。原因常见的是数据类型问题。传入给add_yaxis的数值列表里混入了None值、NaN或者numpy的float64类型Pyecharts的序列化器无法处理。另一个原因是日期索引和数值列表长度不匹配页面渲染时静默地丢弃了这段数据。解决传值之前统一转换类型。x_data [d.strftime(%Y-%m-%d) for d in df[date]] y_data [float(v) if pd.notnull(v) else None for v in df[temp_high]]用float()把numpy类型转成Python原生类型用pd.notnull过滤掉NaNNone值要手动处理或删除对应日期。这行代码能解决大部分Pyecharts渲染空白问题。5.6 文件路径与编码换一台电脑就跑不起来现象项目在你自己电脑上运行正常拷给老师或换台电脑后直接报错FileNotFoundError或UnicodeDecodeError。原因源码里用了绝对路径或者文件编码在不同系统间不一致。Windows默认GBKMac和Linux默认UTF-8CSV文件从Windows拷到Mac上用UTF-8读取就会乱码。解决项目里所有文件路径统一用相对路径并放到同一个目录结构下。读取CSV时先用try尝试UTF-8失败再回退到GBKtry: df pd.read_csv(weather_data.csv, encodingutf-8) except UnicodeDecodeError: df pd.read_csv(weather_data.csv, encodinggbk)这是一个很小的防御性写法但能让你的项目在别人电脑上少一次“跑不起来”的尴尬。6. 让模型更可信残差检验与滚动预测验证课程设计做完预测和可视化能得高分的关键一步是验证模型到底靠不靠谱。除了RMSE和MAE还有两个验证手段值得加进项目里能让答辩时更有底气。第一个是残差检验。残差是真实值减预测值的差值序列。好的预测模型残差应该围绕0随机波动不应该有明显的趋势或周期性。画一张残差图再用statsmodels里的acf函数算一下残差的自相关系数如果前几个滞后的相关系数都落在置信区间内说明模型已经把时间序列里的规律学干净了——剩下的都是随机噪声。import statsmodels.api as sm residual test.values - forecast sm.graphics.tsa.plot_acf(residual, lags20) plt.title(预测残差自相关图) plt.show() norm_residual (residual - residual.mean()) / residual.std()残差自相关图的理想形态是除0之外没有明显超出蓝色置信带的柱状线。如果某个滞后处显著超出置信带说明模型漏掉了对应天数的周期性规律这时返回去检查是否需要提高ARIMA的p或q阶数或者补上更多滞后特征。第二个是滚动预测验证。固定训练集起点每次只预测未来一天然后把真实值加入训练集再预测下一天。这个过程模拟的是实际使用场景——每天更新数据、每天产出新的预测。课程设计里可以用一个循环实现把每天预测的MAE单独打印出来你能直观看到模型在不同天气条件下的表现差异。比如降温天误差普遍偏大就说明模型对突变天气的学习不充分需要增加气温变化率这个特征。这两个验证加进去之后你的课设从“能出图”提升到了“能解释”。老师问误差来源、问你模型改进方向时你可以指着残差图说哪个滞后项还有相关性而不是含糊其辞。我自己做这类项目时固定下来的习惯是预测结果必须配一张残差图才敢拿出去展示否则一条曲线看不出模型内部的问题。这套思路同样适用于数据量更大的项目。希望这份拆解能帮你的天气预测课程设计少走几步弯路把源码跑通、把图做清楚、把原理讲明白。本文还有配套的精品资源点击获取
返回列表