时间序列分析降雨量预测Python项目复现:从ARIMA到平稳性检验
发布时间:2026/10/1 23:10:59来源:尧图网络
简介这是一份基于时间序列分析的降雨量预测 Python 项目源码定位为课程设计与气象数据挖掘实战资源适合计算机、数据分析或大气科学相关专业的初学者和进阶者学习。项目围绕历史降雨数据处理展开重点包含数据清洗与标准化、ARIMA与LSTM模型构建及训练、温度湿度气压等多变量融合、日/月等多个时间尺度预测、模型评估对比等完整流程还可扩展简易可视化界面与极端天气报警功能能够为气象预报、农业规划和水资源管理提供数据支撑。压缩包为zip格式约11.12MB目前平台暂无文件数量和类型明细下载后可直接解压获取项目源码、说明文档与运行所需材料。目前已有161人学习可帮助读者快速理解时间序列建模从数据预处理到模型落地的全过程也能在课程设计、毕业设计或科研实践中直接复用或二次开发。1. 拿到的降雨量预测 cs.zip先分清它是作业包还是能跑的项目网上搜“python项目基于时间序列分析的降雨量预测cs.zip”下载下来多半是一个课程设计或毕设打包工程里面塞着几个 py 脚本、一份说明文档、一个 csv 数据文件运气好还有 requirements.txt。时间序列分析的思路很直白把降雨量当成一串按日、按月排列的数字从历史里找规律去推未来而不是像普通回归那样把日期当无关特征扔给模型。问题是这类 zip 包十个里有六七个解压后跑不起来不是缺库就是数据路径写死要么模型文件没打进去。这篇笔记按我复现这类项目的顺序来先拆包看结构再把环境补齐跑通最小命令然后把平稳性检验、自相关分析和模型选型这套方法论落进代码最后讲数据清洗和四个最容易翻车的坑。新手能照着把项目从黑匣子变成自己能改的程序熟手可以跳过前两章直接看参数边界和验证方法。2. 解包之后先看这四件事跑通最小 python 程序的顺序2.1 解压后第一件事认清项目结构与入口文件这类 zip 包没有统一规范我拿到手习惯先建一个干净目录再解压并打印文件树。因为常见做法是作者把模型训练和预测脚本分开入口文件不一定是名字最像的那个得靠文件清单判断。mkdir rain_project cd rain_project unzip ../基于时间序列分析的降雨量预测cs.zip find . -maxdepth 2 -type f | sort逻辑说明mkdir建独立目录避免解压出来的文件散落到其他地方unzip解压后马上用find列出两层以内的文件目的是在还没打开任何脚本前先形成一份项目地图。参数说明-maxdepth 2表示只向下找两层防止把 python 虚拟环境里几千个文件也列出来-type f只显示文件不显示目录配合sort让同类脚本排在一起。拿到文件清单后我一般先找三个东西数据文件csv/xlsx、模型脚本含 train 或 model 字样、预测脚本含 predict 或 forecast 字样。数据文件的日期列格式、模型脚本里读数据的相对路径是后面百分之八十报错的源头先记下来比什么都强。2.2 用 requirements.txt 还原环境两个命令的连带效应项目能解压不等于能运行。多数课程设计包是在作者本机跑的依赖版本写没写全完全看良心。我的习惯是先看有没有 requirements.txt没有就直接看 import 语句把 pandas、numpy、statsmodels、sklearn 这些常见的先装齐。注意 python 版本和库版本有连带关系python 3.12 上装旧版 statsmodels 会遇到编译报错装新版又可能遇到 API 变更。python -m venv .venv source .venv/bin/activate pip install -r requirements.txt逻辑说明python -m venv .venv建独立虚拟环境避免把项目依赖装进系统 python 里污染其他工程source .venv/bin/activate激活环境之后pip install都落在当前项目里。我一般会在这一步把pip install pandas numpy statsmodels matplotlib一起列进去因为很多旧项目包的 requirements.txt 是手写的漏了绘图库也不知道。参数说明如果解压后没有 requirements.txt就把上面的安装命令换成pip install pandas numpy statsmodels matplotlib scikit-learn。装 statsmodels 时看到需要编译优先换用pip install --only-binary :all: statsmodels直接拉官方预编译包省去本机缺编译器的麻烦。这个环节最容易踩的坑是版本冲突后面第五章专门展开。2.3 跑通最小预测脚本从加载数据到输出一个数字环境就绪后别一上来就跑完整训练先找一个入口文件执行一遍。我这几年复现项目的顺序是先运行、看报错、修路径、再运行直到出结果。很多 zip 包的问题不是逻辑错而是数据路径写死成了C:/Users/xxx/Desktop/在别人机器上必挂。import pandas as pd from statsmodels.tsa.arima.model import ARIMA df pd.read_csv(rainfall.csv, parse_dates[date], index_coldate) df df.asfreq(D).ffill() # 转为日频并前向填充缺失 train df[rain][:-30] # 留最后 30 天做验证 model ARIMA(train, order(1, 0, 1)).fit() forecast model.forecast(steps30) print(forecast.head())逻辑说明parse_dates在读取时把日期列转成 datetime 类型这是时间序列分析的起点后面做索引、重采样、滞后特征全依赖它是时间类型asfreq(D)把数据补齐为连续日序列再用ffill填充空值旧项目的数据经常缺几天不补的话模型会因为索引断裂直接报错。order(1, 0, 1)是最简单的 ARMA 结构forecast输出未来 30 天的预测值。参数说明[:-30]是 python 数组切片的典型写法表示取除最后 30 行以外的全部数据。跑通这一小段说明数据读取、模型训练、预测输出这条链路没断接下来才值得花时间调参数。如果这条链路断了优先去读数据文件的真实列名很多时候不是date和rain而是日期和降水量改列名比改逻辑省事得多。3. 时间序列分析的核心假设与三件套平稳性、自相关和模型选型3.1 降雨量为什么不是普通回归问题时间顺序是信息的载体很多新手会问都是特征预测标签为什么降雨量预测不能用 sklearn 的线性回归原因是降雨量数据里真正有用的信息不在特征的取值而在特征出现的先后顺序。今天的降雨量往往和昨天、前天的降雨量相关这种相关性叫自相关它只能通过保留时间顺序来捕捉。普通回归要求样本独立把日期随机打乱后模型照样能训练但预测的是“在某种特征条件下平均降雨量”不是“下一天降雨量”。所以我复现这类项目时第一件事不是调模型而是确认数据的时间跨度。降雨量预测的建模粒度决定了模型复杂度按天预测用 ARIMA 或 SARIMA 就够按小时预测数据量大了可以上 LSTM按年预测样本量太小什么模型都难做出亮点。zip 包里如果只给了几十条数据超出了模型能力范围的期望得先调低预期。3.2 平稳性检验adfuller 的三个返回值怎么读时间序列模型大多数要求序列平稳意思是均值和方差在时间上没有系统性变化。降雨量明显不满足这个条件旱季雨季交替让均值周期波动所以建模前必须做平稳性检验。statsmodels 里最常用的就是 ADF 检验代码如下from statsmodels.tsa.stattools import adfuller import pandas as pd df pd.read_csv(rainfall.csv, parse_dates[date], index_coldate)[rain] result adfuller(df.dropna()) print(ADF 统计量:, result[0]) print(p 值:, result[1]) print(临界值:, result[4])逻辑说明adfuller的原假设是序列存在单位根即非平稳。返回的第二个值 p 值小于 0.05 时拒绝原假设认为序列平稳。实际操作中只看 p 值就够小于 0.05 认为过关大于 0.05 就需要差分。降雨量序列绝大多数情况下 p 值远大于 0.05所以要进入下一步处理。参数说明dropna()在检验前删掉空值因为 ADF 不接受 NaNresult[4]是三个置信水平下的临界值用来和result[0]对比统计量小于临界值也表示平稳。如果 p 值不达标常见做法是做一阶差分再检验一次也就是把今天的值和昨天的值的差变成新序列。这里有个容易误用的点差分可能会消除趋势但降雨量的季节性差分往往需要按周期来比如月度数据做 12 阶差分而不是只做一阶。3.3 从 ACF/PACF 到 ARIMA 选型p 和 q 的经验取舍平稳性解决后选型靠自相关图。ARIMA 模型有三个参数p是自回归阶数q是移动平均阶数d是差分阶数。求 p 和 q 的常见做法是画出 ACF 和 PACF 图观察截尾和拖尾但实际项目里图形判断对新手并不友好我一般是先用 ACF/PACF 粗定范围再用 AIC 精调。from statsmodels.graphics.tsaplots import plot_acf, plot_pacf import matplotlib.pyplot as plt fig, axes plt.subplots(1, 2, figsize(12, 4)) plot_acf(df.diff().dropna(), axaxes[0], lags20) plot_pacf(df.diff().dropna(), axaxes[1], lags20) plt.tight_layout() plt.show()逻辑说明df.diff()对原序列做一阶差分plot_acf和plot_pacf分别画出自相关函数和偏自相关函数图。ACF 图在滞后阶数之后突然截尾说明 q 取那个阶数PACF 图截尾的阶数对应 p。降雨量数据通常 ACF 衰减缓慢、呈现周期性光靠看图很难下结论所以这里只是给一个候选范围。参数说明lags20表示展示前 20 个滞后的相关系数对日数据来说 20 天足够figsize(12, 4)控制画布宽高横轴太长会把周期信息压扁。真正的参数选择我会用循环遍历几个候选组合比较 AIC 值取最小的那个。注意 AIC 只能在同一数据集上比较差分阶数改了之后数据集长度会变不能拿来直接比。4. 把降雨量数据喂给模型清洗、重采样和训练集划分的落地写法4.1 降雨量数据的清洗逻辑缺测、异常极值和零值堆积气象数据是所有数据里最不干净的之一缺测是常态。常见的处理有删除、均值填充和前向填充但降雨量不能无脑套用因为它的分布是零值堆积加偶发极端值。一个地方一年里大半时间不下雨用均值填充会把“无雨”填成“小雨”直接把分布毁了。我处理这类数据的顺序是先看缺失比例再决定策略。df pd.read_csv(rainfall.csv, parse_dates[date], index_coldate) rain df[rain].copy() missing_ratio rain.isna().mean() print(缺失比例:, round(missing_ratio, 4)) rain rain.mask(rain 0) # 负值视为异常置空 rain rain.fillna(methodffill).fillna(0) rain rain.clip(upperrain.quantile(0.999))逻辑说明isna().mean()算出缺失比例10% 以内可以填充30% 以上就要谨慎填出来的序列可能掩盖真实状态。mask(rain 0)把负值置空传感器故障常见的表现就是出现负的降水量。fillna(methodffill)前向填充对降雨这种短时缺测最稳妥fillna(0)处理序列开头没有历史值的位置。clip(upper...)用分位数截断极端值防止某次特大暴雨把模型参数带偏。参数说明quantile(0.999)表示把超过 99.9% 分位的降雨量压到该分位值相当于手动去掉最极端的天灾级样本。这个参数可以按业务调做防洪预报警报可以放宽做常规预测建议收紧。实际项目里我倾向于不删异常样本而是截断因为降雨量本身的物理上限并不存在删掉会导致模型永远没见过极端情况。4.2 按日重采样和滚动窗口特征把日期列变成可用的监督学习样本时间序列模型可以直接吃原始序列但要上机器学习模型就得把时间序列转成监督学习样本。核心操作是用shift构造滞后特征昨天、前天、上周同期的降雨量作为特征今天的降雨量作为标签。这一步做不好后面所有模型都是白搭。feature_df pd.DataFrame({rain: rain}) feature_df[lag_1] feature_df[rain].shift(1) feature_df[lag_2] feature_df[rain].shift(2) feature_df[lag_7] feature_df[rain].shift(7) feature_df[target] feature_df[rain].shift(-1) feature_df feature_df.dropna()逻辑说明shift(1)把序列整体下移一行第 t 行的lag_1值就是第 t-1 天的降雨量shift(-1)向上移一行第 t 行的target值是第 t1 天的降雨量这正是模型要预测的对象。dropna()删除没有完整历史特征的头部行因为前面几行没有足够的滞后数据。参数说明三个滞后阶数分别对应昨天、前天和一周前周滞后是为了捕捉星期效应虽然降雨不像电商销量有那么强的星期规律但很多地区的天气系统有 7 天左右的周期留着没坏处。这里也可以用resample(W).mean()做周重采样当原始数据是小时级时先聚合到日避免单日数据波动太大。4.3 训练集与测试集的切分时序数据不能用 train_test_split这是时间序列分析和普通机器学习最本质的区别也是我在代码审查里最先看的地方。train_test_split默认随机切分会打乱时间顺序让模型看到未来数据去预测过去测试集指标虚高得离谱。时序切分必须保证训练集时间在前测试集时间在后。split_idx int(len(feature_df) * 0.8) train feature_df.iloc[:split_idx] test feature_df.iloc[split_idx:] X_train, y_train train[[lag_1, lag_2, lag_7]], train[target] X_test, y_test test[[lag_1, lag_2, lag_7]], test[target]逻辑说明int(len(feature_df) * 0.8)算出 80% 位置的行号iloc[:split_idx]取前 80% 行作为训练集iloc[split_idx:]取后 20% 作为测试集。iloc是位置切片不受索引值影响如果数据索引不是整数用loc容易踩坑。切完后单独取出特征列和标签列特征列是滞后值标签列是未来值。参数说明0.8 是常见比例但时序项目里我建议根据数据长度定。样本量少于 500 时用 0.7 比 0.8 更稳因为测试集太薄看不到完整季节周期。另一个要点是切分前先把数据按时间排序zip 包里的数据偶尔会乱序用sort_index()排一下再做切分。5. 时间序列降雨量预测的四个常见坑现象、原因和止损办法5.1 日期解析失败object 类型不是 datetime索引一塌糊涂现象代码跑起来没报错但画的图横坐标挤成一团或者模型报“ValueError: Given date string not a date”。我见过不少从 Excel 导出的数据日期列看起来是2023/1/5实际上 pandas 读进来是字符串。原因read_csv默认把所有列当字符串读虽然2023/1/5能被 pandas 一眼认出但2023-01-05和2023/1/5 0:00混在一起时解析结果不稳定尤其是 Excel 里部分行被存成自定义格式。解决读入后做一次强制转换确认 dtype 是 datetime64。df[date] pd.to_datetime(df[date], errorscoerce) df df.dropna(subset[date]) print(df[date].dtype)pd.to_datetime的errorscoerce把无法解析的值变成NaT再通过dropna把它们连同行一起删掉而不是让脚本在中间环节莫名报错。输出dtype检查是不是datetime64[ns]是才能继续做重采样和滞后特征。5.2 把非平稳序列直接喂给 ARIMAACF 图拖着长尾巴现象seasonal_decompose画出的趋势图一路向下ACF 图衰减极慢模型训练完的残差仍然有明显模式预测结果最后变成一条水平线。原因降雨量受季节驱动序列本身非平稳ARIMA 的d没设够。很多人以为d1差分一次就万事大吉实际上月降雨量可能有年度季节性需要 12 阶差分才能消除周期性。解决先用adfuller检验非平稳再差分差分后重新检验。from statsmodels.tsa.stattools import adfuller diff_1 df[rain].diff().dropna() print(一阶差分 p 值:, adfuller(diff_1)[1]) seasonal_diff diff_1.diff(12).dropna() print(去季节差分 p 值:, adfuller(seasonal_diff)[1])diff(12)对月度数据做 12 阶差分相当于把今年 1 月与去年 1 月的差作为新序列的值周期性被剥掉一层。两个 p 值都小于 0.05 才说明序列已经平稳。很多 zip 包里的脚本只写了一次差分遇到降雨量这种季节性数据必翻车。5.3 零值太多的降雨量序列预测结果全是负值现象模型没有报错但预测的降雨量出现大量负值比如 -3.2mm。业务上完全不可用气象观测里降水量不可能为负。原因ARIMA 这类模型假设误差服从正态分布预测区间是围绕均值对称的。降雨量数据大量堆积在 0 附近分布严重右偏模型学到的均值附近区域就是负数区域。解决先看零值占比超过一半就别硬用 ARIMA 直接拟合原始值考虑两步建模先用分类模型预测是否下雨再用回归模型预测雨量。或者在数据变换层面做处理比如用np.log1p压缩右偏预测完再做逆变换。import numpy as np zero_ratio (df[rain] 0).mean() print(零值占比:, round(zero_ratio, 4)) rain_transformed np.log1p(df[rain]) # 压缩右偏分布log1p对 0 值友好log(10) 等于 0不会产生负无穷。注意预测结果要用np.expm1做逆变换才能得到真实刻度。零值占比超过 30% 就要承认单模型不够用直接分两阶段建模反而更省时间。5.4 requirements.txt 的版本号不干净复现时库冲突现象按pip install -r requirements.txt安装时报一堆“Cannot install XXX”或者装完之后 import 直接报AttributeError: module pandas has no attribute Panel。原因旧项目用的是 pandas 0.x 或非常老的 statsmodels新版本把很多旧 API 删了。最典型的是pandas.Panel在 1.0 版本后被移除到处是pd.Panel的脚本在新环境必崩。解决看 requirements.txt 里是否写死了pandas0.23.4这种版本号如果写了建议先按旧版本建独立环境而不是升级库去迁就代码。操作上就是换 python 3.7 或 3.8 装 pandas 0.25成本比改源码低很多。conda create -n rain37 python3.7 conda activate rain37 pip install pandas0.25.3 statsmodels0.11.1不过与其跟老库搏斗我更推荐花半小时把旧脚本里的pd.Panel、df.append这些过期 API 改成新写法一劳永逸。时间序列项目的代码量通常不大迁移成本远低于维护一个古老环境。6. 用滚动验证检验模型提前一步的预测与评估技巧训练测试集一次性切分只是初步验证它对模型在真实场景下的表现估计过分乐观。真实使用场景是模型站在今天预测未来 30 天明天到来后再用真实值校准。这就要求验证方式也按这个节奏走滚动预测比单次切分更能暴露模型在长期预测时的误差累积。history list(train[rain]) predictions [] for t in range(len(test)): model ARIMA(history, order(1, 0, 1)).fit() yhat model.forecast(steps1)[0] predictions.append(yhat) history.append(test[rain].iloc[t]) # 把真实值滚进历史 mae sum(abs(p - a) for p, a in zip(predictions, test[rain])) / len(test) print(滚动验证 MAE:, round(mae, 2))逻辑说明训练集作为初始历史窗口循环中每预测一步就重新训练一次模型然后把真实观测值加入历史再预测下一步。这个过程模拟了线上每天更新数据、每天出预测的节奏。abs(p - a)计算绝对误差累加后求平均得到 MAE。参数说明order(1, 0, 1)是 ARIMA 的基准配置滚动验证主要测的是流程而不是参数参数调整放到验证之前做。steps1表示只预测一步因为多步预测误差会叠加滚动验证的结果更真实。评估时除了 MAE我还会看一眼 R² 和雨量分级命中率比如把降雨分成无雨、小雨、中雨三个等级看模型命中哪个等级的比例这比单个数值指标更有业务参考价值。如果滚动验证的 MAE 明显高于单次切分说明模型对新数据适应能力差。这时候可以考虑换 SARIMA 显式加季节项或者用 Prophet 试基线。LSTM 的门控循环结构对这类长周期序列也有效但需要更长历史数据少于 1000 天不建议上。我自己的习惯是先把 ARIMA 调到 AIC 最低再用它做滚动验证确认误差规模后才考虑更复杂的模型。这个方向值不值得投入判断标准很简单如果你的数据是按小时或按天记录的、跨度超过三年、零值占比可控低于 50%时间序列分析就能交出可用结果如果只有几十条月度均值任何模型都救不了。我复现过不少课程设计包最后能真正跑出稳定预测的几乎都满足这两个条件。希望这些步骤和踩坑记录帮你在自己的数据上少走一段弯路。本文还有配套的精品资源点击获取
网站建设高端定制企业官网