ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Python时间序列预测代码包实战:环境配置与ARIMA建模全流程

Python时间序列预测代码包实战:环境配置与ARIMA建模全流程 简介一份针对Python时间序列预测学习的配套代码包面向数据分析和机器学习初学者特别是希望掌握自回归积分滑动平均、季节性模型以及开源预测工具的使用方法并在真实数据上动手实践的读者。代码包围绕时间序列分析完整流程展开包含数据读取与清洗、缺失值处理、差分平滑、模型构建与调参、预测效果可视化等环节的示例脚本。资源共214个文件以181个py脚本为主体配有32个csv格式的示例数据如每日气温、太阳黑子、每日出生人数等和1个md说明文档压缩包仅237KB轻量易用。目前已有7257人学习内容由浅入深既覆盖经典统计模型也引入基于机器学习的非线性预测思路。通过研读这些代码读者可以系统理解季节性建模、状态空间方法以及均方误差等评估指标的实际调用方式将代码灵活迁移到金融、气象、销售等实际预测任务中是一份性价比很高的入门参考资料。1. 这个 zip 包到底值不值得打开先说结论很多人在刚接触时序预测时会直接搜「Python 时间序列预测代码」最后多半会落在一个名为Code for Introduction to Time Series Forecasting with Python.zip的压缩包上。这个包不是某个网站的营销资料也不是一个只能跑 demo 的玩具工程它是《Introduction to Time Series Forecasting with Python》这本书的配套代码集内容覆盖从数据读入、平稳性检验、ACF/PACF 定阶到 ARIMA、SARIMA、ETS 拟合和评估的完整链路。你的场景不管是做销量预测、流量监控还是量化策略里的特征工程这套代码的骨架都能直接借。但先说句实话这个 zip 解压后并不会开箱即用它是一本正经的书配代码跑通它需要一点环境功夫。接下来的内容我就按「这个包里有什么 → 环境怎么配 → 代码怎么改成自己的 → 哪些坑我踩过」的顺序给你一条能复现的路。2. 解压和选环境把代码跑起来的第一关是版本不是代码2.1 解压之前先确认目录结构别急着双击拿到压缩包后我的习惯是先看一眼包内的目录树而不是直接解压到桌面。常见做法是在终端里先列压缩包内容unzip -l Code for Introduction to Time Series Forecasting with Python.zip这个命令会列出 zip 内所有文件和路径不需要解压就能看到顶层目录。典型的包内结构一般长这样code/ chapter_01_introduction/ 01_load_data.ipynb 02_plot_series.ipynb chapter_02_arima/ 03_adf_test.ipynb 04_acf_pacf.ipynb 05_arima_grid_search.ipynb data/ airline_passengers.csv shampoo_sales.csv requirements.txt README.md注意看.ipynb后缀这说明核心内容是 Jupyter Notebook。有的版本里还附带.py脚本但主链路仍然是 notebook。先确认有requirements.txt或 README能省掉后面很多猜依赖的功夫。确认结构没问题再解压unzip Code for Introduction to Time Series Forecasting with Python.zip -d ./tsf_code-d指定解压目标目录避免文件散落到当前目录。解压后我一般会用tree或编辑器的文件树再核对一遍路径因为后面很多 notebook 里的数据路径是相对路径你挪动位置就等于把代码弄坏了。2.2 版本搭配是本包最大的隐性门槛这个压缩包是跟书走的书里的代码写于 statsmodels 还比较老的年代直接在一套全新环境里跑最常见的反馈是AttributeError: module statsmodels has no attribute tsa或者ImportError: cannot import name ARIMA from statsmodels.tsa.arima.model。这不是代码错了是包的结构变了。我建议直接用 Anaconda 建一个独立环境Python 版本选 3.9 左右最稳妥不要图新上 3.12。为什么因为 statsmodels 对 Python 3.12 的适配虽然已经跟上但这个包的代码用的是旧 API越新的环境里那些FutureWarning越吵甚至会因为 pandas 的索引行为变化直接影响结果。conda create -n tsf python3.9 conda activate tsf然后按要求装依赖。这个包依赖的核心库不多我的标准组合是pip install pandas1.5.3 numpy1.23.5 matplotlib3.6.3 statsmodels0.13.5 jupyter参数说明pandas 锁 1.5.x 是因为DatetimeIndex的行为在 2.x 里有变化而这个包里的代码大量依赖df[date] pd.to_datetime(df[date])后直接画图、切窗、做滞后特征的老写法statsmodels 锁 0.13.5 是这套代码的最舒适区0.14 之后ARIMA和SARIMAX的默认参数有变动结果会跟书里的输出对不上。如果你已经装了新版也不用推翻重来本书后面我会给一条升级路径。2.3 用 VS Code 还是 Jupyter先跑通再谈习惯这个包的代码是 notebook但你不需要刻意去装一个独立的 Jupyter 桌面应用。VS Code 装上 Python 和 Jupyter 插件后可以直接打开.ipynbPython 解释器选中你刚建的tsf环境就行。我个人的习惯是终端里起一个 jupyter server浏览器里跑调试VS Code 只用来改代码和看 diff。但新手我更推荐直接用命令jupyter notebook启动后浏览器会打开文件列表页进到解压目录里点开任意一个 notebook。点开第一个01_load_data.ipynb确认右上角 Kernel 选的是tsf而不是默认的 base 环境。这一步很多人忽略结果代码报错说缺包其实包里装了kernel 没选中而已。注意不要双击一个.ipynb文件让系统默认程序打开Windows 下容易绑到奇怪的编辑器上功能不全还误导人。3. 把书里的数据换成你自己的读入、改列名、重新切窗3.1 先摸清每个 notebook 的数据来源这个包里的代码分两类一类用内置数据比如statsmodels.datasets另一类读data/目录下的 csv。从你自己的项目出发csv 那类才是你要重点改的。随便打开一个读 csv 的 notebook你大概率会看到类似这样的代码import pandas as pd from pandas import read_csv series read_csv(data/shampoo_sales.csv, header0, parse_dates[0], index_col0) print(series.head()) print(series.shape)逻辑说明parse_dates[0]是把第一列解析成日期index_col0再把日期列设为索引。这两步合起来就是「按时间索引读时序数据」的标准姿势。参数说明header0表示第 0 行是表头。如果你的 csv 没有表头把headerNone并加names[date, value]。这个包的数据文件都是两列格式日期、数值如果你的数据是长表、多列直接套会挂见 3.2。3.2 从「跑通书的代码」改成「跑自己的数据」假设你要预测的是自己业务里的每日订单量csv 长这样order_date,order_count 2024-01-01,120 2024-01-02,86 ...只需把读入部分改成df pd.read_csv(data/your_orders.csv, parse_dates[order_date]) df df.set_index(order_date) series df[order_count].astype(float) print(series.asfreq(D)) # 设定频率后面要用的逻辑说明asfreq(D)很关键因为 ARIMA 类模型要求索引有明确频率。如果你的数据是工作日数据把D改成B如果是小时级改H或h取决于 pandas 版本旧版用H新版用h。这里不用resample是因为 resample 会聚合数据而 asfreq 只重设索引频率不改变数值。我见过不少人直接把书的series变量换掉但忽略了频率设定结果后面plot_acf(series)报ValueError: statsmodels.tsa.acf is not supported for freq。这不是模型的问题是索引频率没声明。另外要注意空值。书的原始数据集没有 NaN你的数据几乎一定有缺失。先做一步series series.fillna(methodffill) # 向前填充注意fillna(methodffill)在新版 pandas 里会标FutureWarning改用series.ffill()或series.fillna(methodffill)加future_stackFalse。这个包配的 pandas 1.5.3 里暂时没这问题但如果你升了 pandas 2.x会开始刷警告。3.3 训练集和测试集是这套代码里最值得改的部分书里的切分方式通常是按固定比例比如split_point int(len(series) * 0.8)。这在教学场景没问题但真实的时序预测里随机切分或者单一切分都会让评估失真。我一般会改写成显式的日期切分train series.loc[:2024-09-30] test series.loc[2024-10-01:]逻辑说明时序数据只能按时间先后切不能打乱。loc[:2024-09-30]这种切法比按行数切更可读也避免了索引偏移导致的错位。改完这一处后面所有用train和test的代码段都不会受影响。但要注意部分 notebook 里后面会重新定义train、test你要全局搜索确认不要只改第一处就以为完事了。4. 这套包的核心代码逻辑ADF、ACF/PACF、ARIMA 网格搜索4.1 ADF 平稳性检验不是跑出 p_value 就完事包里对每个序列做的第一件事是 ADF 检验代码通常长这样from statsmodels.tsa.stattools import adfuller result adfuller(series.dropna()) print(ADF Statistic:, result[0]) print(p-value:, result[1])逻辑说明ADF 的原假设是序列存在单位根非平稳。p-value 小于 0.05 拒绝原假设说明序列平稳可以直接建模大于 0.05 就得先差分。这个判断别交给眼睛要看数字。我的建议是不要在代码里只打印 p-value把它封装成判断逻辑def is_stationary(s, alpha0.05): p adfuller(s.dropna())[1] return p alpha if not is_stationary(series): diff_series series.diff().dropna() else: diff_series series参数说明adfuller里有个autolagAIC的默认参数表示自动选择滞后阶数来消除自相关。这个默认值是好的不要改成None否则滞后量固定后可能得出错误的平稳性结论。另外 ADF 检验对异常值敏感如果你的业务数据在双 11 或者促销日有尖峰先做一次 clip 或对数变换。4.2 ACF/PACF 定阶这个方法能粗定但别迷信包里有大量plot_acf、plot_pacf的调用作用是看截尾和拖尾来定 AR 阶数 p 和 MA 阶数 q。典型的判断口诀是PACF 截尾定 pACF 截尾定 q。代码段通常这样from statsmodels.graphics.tsaplots import plot_acf, plot_pacf fig, axes plt.subplots(2, 1, figsize(12, 8)) plot_acf(diff_series, axaxes[0], lags40) plot_pacf(diff_series, axaxes[1], lags40, methodywm) plt.tight_layout() plt.show()逻辑说明methodywm是偏自相关估计的算法老代码里写的是methodyw或者不写新版本 statsmodels 给了多种选项。这里选ywmYule-Walker with m adjusted是因为它在小样本下比默认的ols更稳但如果你用的是 0.13.5 版本的 statsmodelsmethodywm可能不存在——那就删掉这个参数用默认值。这里必须说破一件事靠看图定阶是有主观性的同一个图有人定 p2 有人定 p3。所以我的工作流里把 ACF/PACF 当作「缩小搜索范围」的手段而不是最后答案。上界的设置方式见 4.3。4.3 网格搜索 ARIMA 参数上界比模型本身更值得调包的最后一个核心部分通常是用 itertools 遍历(p,d,q)组合然后按 AIC 或 RMSE 选最优。这一段是最能直接抄到自己项目里的代码我贴一个改造过的版本import itertools import warnings from statsmodels.tsa.arima.model import ARIMA warnings.filterwarnings(ignore) # 网格搜索会刷一堆收敛警告 p_range range(0, 4) d_range range(0, 2) q_range range(0, 4) results [] for p, d, q in itertools.product(p_range, d_range, q_range): try: model ARIMA(train, order(p, d, q)) fit model.fit() results.append((fit.aic, p, d, q, fit)) except Exception as e: continue results.sort(keylambda x: x[0]) best_aic, best_p, best_d, best_q, best_fit results[0] print(fBest ARIMA({best_p},{best_d},{best_q}) AIC{best_aic:.2f})逻辑说明itertools.product生成所有参数组合try/except跳过不收敛的组合。fit.aic是赤池信息准则越低越好。注意这里训练用的是train序列而不是完整series这是为了后面做 walk-forward 验证时不被未来数据污染。参数调节建议p_range和q_range的合理上界取决于数据长度。100 个观测值p、q 上界给到 3 就够了超过 500 个观测值可以给到 5。d_range给range(0, 2)就足够差分超过一阶的序列通常是过度差分了。如果你的数据有季节性比如按月度销售网格搜索应该用SARIMAX而非ARIMA。包的后续章节有 SARIMA 的代码模板结构一样多一组季节阶数(P,D,Q,s)。再补一个重要参数fit()里可以加methodnm强制用 Nelder-Mead 优化。默认的 BFGS 在某些组合下会收敛失败或报Non-stationary starting autoregressive parameters此时改优化器比改数据有用。5. 避坑跑这份书配代码最常见的 5 个坑5.1 现象ImportError: cannot import name ARIMA from statsmodels.tsa.arima.model原因statsmodels 版本过老。ARIMA类是在 0.11 左右才被挪到statsmodels.tsa.arima.model里的更早的版本在statsmodels.tsa.arima_model。解决把你环境里的 statsmodels 升级到 0.12 以上或者直接按我 2.2 节的环境配置建新环境。如果你因为别的原因不能升级把 import 语句改成from statsmodels.tsa.arima_model import ARIMA但后面所有接口都要跟着改不建议走这条路。5.2 现象ADF 检验结果说序列平稳但模型预测是一条水平线原因这是最常见的「翻车」不是代码问题是数据问题。ADF 检验只检验线性趋势和单位根它判别不出「季节性」和「方差变化」。月度航空旅客数据就是一个经典例子——ADF p-value 可能很低但画图明显有年周期。解决不要只看 ADF配合画出原序列图和按月聚合图。如果看到固定周期直接跳过 ARIMA 改用 SARIMA 或加季节差分。在包代码里找到 SARIMA 对应的 notebook不要死磕在普通 ARIMA 上。5.3 现象ValueError: Pandas data cast to numpy dtype of object. Check input data原因序列里有非数值类型。常见于读 csv 时数值列带了单位、千分位逗号或空字符串被 pandas 读成了 object 类型。解决读入后强制转数值pd.to_numeric(series, errorscoerce)然后用dropna()去掉转换失败的值。转换之后用print(series.dtype)确认是float64或int64再往下走。5.4 现象notebook 里的图正常但换成自己的日期后plot_acf报错原因索引没有频率。plot_acf和plot_pacf在较新版本里要求序列是固定频率的 DatetimeIndex如果只是普通日期索引没有 freq会直接抛ValueError。解决建模前统一加series series.asfreq(D)必要时先补缺失值再定频。如果你用的是工作日数据asfreq(B)会在周末位置插入 NaN所以要先用 5.2 的逻辑处理缺失。5.5 现象网格搜索跑出几百个警告输出被刷屏原因ARIMA 在不同参数组合下收敛失败是常态statsmodels 会为每个失败组合打印一条警告网格搜索时组合数乘以数据类型刷屏很壮观。解决不鼓励全程warnings.filterwarnings(ignore)那会掩盖真要命的 warning。我的习惯是保留一个 cell 专门打印收敛失败次数数据量少的时候肉眼扫一遍数据量大就只记录不打印import warnings with warnings.catch_warnings(recordTrue) as w: warnings.simplefilter(always) fit model.fit() print(f{len(w)} warnings for order {order})这样哪组参数容易出问题一目了然又不会刷屏。6. 模型选完别急着上线验证残差和回测的三个习惯模型在网格搜索里拿到最低 AIC 不代表它能用三件事我每次都做。第一件是看残差图。代码resid best_fit.resid fig, axes plt.subplots(2, 1, figsize(12, 6)) axes[0].plot(resid) axes[0].set_title(Residuals) axes[1].hist(resid, bins30) plt.show()残差要看起来像白噪声——均值在 0 附近没有明显趋势直方图接近正态。如果残差里还有周期性波动说明模型没把信息抽干SARIMA 是下一步。第二件是回测我不用单一切分用 walk-forward 验证。简单版本是滚动预测每步只预测一个点然后带着真实值滚到下一窗history list(train) predictions [] for t in range(len(test)): fit ARIMA(history, order(best_p, best_d, best_q)).fit() yhat fit.forecast()[0] predictions.append(yhat) history.append(test.iloc[t])这个循环慢但它是判断模型真实泛化能力的底线。跑一次你就知道很多在单一切分下漂亮的模型在 walk-forward 下原形毕露。时间宝贵的话至少用rolling_origin思路手动写一个步长为 3 的版本。第三件是永远把预测结果画在原序列上。可视化不能让你调参但它能让你立刻发现预测滞后、尺度偏移、季节性错位这类数字上看不出的问题。这是我的血泪经验有一次我看 RMSE 从 15 降到 7 很兴奋画出来才发现是模型学会了复制上一个值预测曲线整体右移了一天——指标好看模型是个废的。这个 zip 包的价值不在于让你复现书里的例子而在于它的骨架能直接套到你的序列上。你换掉数据、改好频率、把网格搜索跑通就等于把时间序列预测的主干走了一遍后面再做特征工程也好、做深度模型也好都知道基线在哪里。希望这套步骤能帮你在自己的数据上少走几趟弯路。本文还有配套的精品资源点击获取
返回列表