ARTICLE DETAIL

资讯详情

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

用Python绘制ACF/PACF图:时间序列ARIMA定阶实战

用Python绘制ACF/PACF图:时间序列ARIMA定阶实战 简介面向数据分析与时间序列建模学习者的一份Python实操教程PDF内容聚焦自相关图(ACF)与偏自相关图(PACF)的绘制方法及应用场景适合正在学习时间序列预测、需要判断序列随机性与依赖结构的读者。文档完整讲解了statsmodels库中plot_acf()、plot_pacf()两个核心函数的具体用法提供可直接运行的代码片段并通过图表结果帮助读者辨别序列的截尾、拖尾特征进而为ARIMA等模型参数选择提供依据同时补充了利用seaborn热力图对DataFrame变量间相关性进行可视化的方法方便从整体上发现数据集中存在的主要模式与异常结构。资源包共含1个PDF文件大小约77KB已有11436人浏览学习。对于正在学习时间序列分析并希望快速上手Python绘图实践的初、中级读者是一份便于随时查阅的轻量参考资料。1. 先把 ACF/PACF 画出来是时间序列建模中回报最高的一步做单变量时间序列预测时我见过太多人一上来就调库、跑 LSTM、上 AutoARIMA最后却解释不了模型为什么选这个阶数。真正的第一步其实是把自相关图ACF和偏自相关图PACF画出来。这个 python 实现时间序列自相关图(acf)、偏自相关图(pacf)教程要解决的就是这件事用最直接的图形判断数据背后是 AR、MA 还是 ARMA 结构从而确定 p、q 阶数把后面 ARIMA 建模从“盲猜”变成“有依据地确认”。为什么值得学因为 ACF/PACF 是时间序列分析里少有的“图形即答案”的工具不涉及复杂的数学推导一个下午就能掌握。适合刚接触时间序列预测的 Python 数据分析师也适合被 AutoARIMA 黑匣子搞烦的量化、运维场景从业者。它的核心价值不是画两张图而是给你一个快速定位模型结构的标准动作避免在阶数选择上反复试错。2. 理解 ACF 与 PACF为什么这两张图能暴露数据规律2.1 自相关函数衡量“自己和自己过去”的相关性自相关函数描述的是同一序列在不同滞后阶数之间的线性相关程度。假设你有过去 90 天的每日订单量ACF 就是一个序列其中第一个点代表“今天”和“昨天”的相关性滞后 1第二个点代表“今天”和“前天”的相关性滞后 2以此类推。其数学表达为[ \rho_k \frac{\text{Cov}(y_t, y_{t-k})}{\text{Var}(y_t)} ]它的取值范围在 -1 到 1 之间 | 值越大说明当前时刻受 k 期之前的影响越强。在实践中我们看 ACF 图时会重点关注两个东西一是条形是否超过蓝色置信区间二是整体衰减速度。若 ACF 在前几个滞后处突然掉进置信区间内并保持稳定称为“截尾”若呈现出缓慢衰减或周期性波动则称为“拖尾”。你可能会问为什么要关心这个因为 ACF 拖尾是 MA(q) 模型的信号——意味着单靠滞后几期的白噪声组合就能解释数据。而 ACF 截尾则更倾向表明数据本身有自回归结构需要进一步看 PACF 才能确定阶数。这就像先拍 X 光片知道哪个部位有问题再去做 CT 精确定位。2.2 偏自相关函数剔除中间变量的“净相关”判断PACF 解决的是 ACF 的一个盲区相关性可能被中间变量传导。举个例子今天的销量同时受昨天和前天影响那么今天与前三天的相关系数有一部分其实是经由昨天和前天“间接传过来”的。如果我们只看着 ACF 的数值可能错误推断出一个很高的滞后阶数。偏自相关函数的做法是在计算 y_t 与 y_{t-k} 的相关性之前先把 y_{t-1} 到 y_{t-k1} 对 y_t 的影响剔除掉仅保留“纯直接”的那一段关系。这在数学上通常用尤尔-沃克方程求解不必深究关键是理解图形含义PACF 在 p 阶后陡然截尾说明数据符合 AR(p) 结构若是拖尾则配合 ACF 一起判断是否为 MA 或 ARMA 模型。2.3 配合平稳性原理为什么非平稳数据画了也白画严格来说ACF 与 PACF 的统计推断依赖数据满足弱平稳性——均值、方差在时间轴上保持稳定。一个带上升趋势的序列ACF 图往往是第一根柱子接近 1后面衰减极慢看起来像“永远拖尾”但这并不是真实模型结构而只是趋势造成的假象。因此标准流程是先做单位根检验如 ADF不平稳就做一阶差分再用差分后的序列画 ACF/PACF。这一条务必记住否则你画出来的图会误导你大半天。3. 在 Python 中画出 ACF/PACF完整实现步骤与参数调优3.1 环境需求statsmodels 与绘图依赖我假设你已经有一个能跑 Python 的本地环境方法是先完整安装 Python 并配置好路径接着用 pip 安装以下依赖pip install numpy pandas matplotlib statsmodels如果你用的是 Anaconda 或 Miniconda也可以改成 conda install 这些包。这里 statsmodels 是核心画图依赖它内部的 tsaplots 模块。需要提醒的是statsmodels 0.13 之后的 API 变化不大plot_acf 和 plot_pacf 函数签名基本稳定但如果你用了很老的版本建议先升级再跑否则可能出现参数名不兼容的情况。安装完成后可以用一个简单的 import 检查环境是否就绪import statsmodels.api as sm from statsmodels.graphics.tsaplots import plot_acf, plot_pacf print(sm.__version__)如果能正常输出版本号说明环境没问题。这一步虽然基础但值得养成惯性凡是画不出来的怪问题八成是版本冲突而不是代码错。3.2 生成一份 200 点的模拟数据让画图有东西可画很多初学者第一步就卡在“我没有合适的数据”。其实要验证自己对 ACF/PACF 的理解完全可以按已知模型生成数据。我这里用 AR(2) MA(1) 的混合过程来演示因为它的 ACF/PACF 形态比较典型能覆盖大部分读图规则。import numpy as np import pandas as pd np.random.seed(42) n 300 # 生成误差项白噪声 error np.random.normal(0, 1, n) # 预生成数组按 ARMA(2, 1) 过程填充 # y_t 0.6 * y_{t-1} - 0.3 * y_{t-2} e_t - 0.4 * e_{t-1} y np.zeros(n) for t in range(2, n): y[t] 0.6 * y[t-1] - 0.3 * y[t-2] error[t] - 0.4 * error[t-1] # 转成 DataFrame方便后续可视化 df pd.DataFrame({value: y}) df.index pd.date_range(2023-01-01, periodsn, freqD) print(df.head())代码逻辑不复杂先生成 300 个独立标准正态随机数作为噪声再用一个循环按固定的线性组合关系构造时间序列。其中 0.6 和 -0.3 是 AR 部分的系数它决定了 PACF 会在第 2 阶后截尾-0.4 是 MA 部分的系数它会让 ACF 呈现“第 1 阶显著、后续快速衰减”的形态。参数说明np.random.seed(42) 保证每次运行结果一致方便复现n300 对画 ACF/PACF 足够因为 Lags 一般只用到 20 到 40样本太少会让置信区间宽到失去判断力。3.3 用 plot_acf 和 plot_pacf 画图核心参数字段逐项拆解下面是画图的核心代码我把它写成一个相对完整的脚本import matplotlib.pyplot as plt from statsmodels.graphics.tsaplots import plot_acf, plot_pacf # 设置画布1 行 2 列 fig, axes plt.subplots(1, 2, figsize(14, 4)) # 左侧ACF plot_acf( df[value], axaxes[0], lags24, alpha0.05, zeroFalse, titleACF of Simulated ARMA(2,1) ) # 右侧PACF plot_pacf( df[value], axaxes[1], lags24, alpha0.05, methodywm, zeroFalse, titlePACF of Simulated ARMA(2,1) ) plt.tight_layout() plt.savefig(acf_pacf_demo.png, dpi150) plt.show()这段代码有几个地方要重点说明。plot_acf 传的第一个参数是原始序列接收 Series 或一维数组都行lags24 表示显示 0 到 24 阶但因为我们设置了 zeroFalse所以实际绘图从滞后 1 开始最左侧那一根“自己和自己”的相关性柱就被跳过了避免数值总是 1.0 而压缩其他柱子的尺度。alpha0.05 是显著性水平它决定了蓝色置信区间的边界宽度默认就是 0.05表示 95% 置信区间如果你希望判断更严格可以调成 0.01但工程实践中 0.05 是主流选择。PACF 这边的 methodywm 是 Yule-Walker 方程的修正算法也是 statsmodels 比较推荐的默认项。旧版本里默认方法可能是 ywunbiased画出来的结果有时会出现超出 [-1, 1] 区间的柱子纯属算法层面的数值现象不必惊慌。如果你在旧代码里看到的是 plot_pacf(x, lags20) 这样不写 method 的写法在新版本中会遇到提示要显式声明 method我建议直接填 ywm。这里需要注意plot_pacf 在滞后阶数太大而样本量不足时会直接抛异常报错信息一般是与你传入的最大滞后数相关的规模问题。解决办法是通过数据长度动态控制 lags 上限我一般用经验公式min(int(10 * np.log10(n)), n // 3)例如 n300 时10*log10(300)≈24.8n//3100取较小值 24与上面代码里的 lags24 刚好吻合。设置 lags 的完整代码可以写成import numpy as np n len(df) lags_limit min(int(10 * np.log10(n)), n // 3) print(f建议 lags 最大值: {lags_limit})为什么要限制因为滞后阶数与样本量之比过大会导致自相关估计方差剧增图上会出现很多“看起来显著”的孤立柱子误导定阶。这也是我踩过坑的地方下面避坑章节里还会展开讲。3.4 画完图后怎么读拖尾截尾规则与 AR/MA 定阶对照有了图下一步是把它翻译成模型阶数。我先把规则写成一个更接近实战的表格后面再解释怎么灵活运用图形表现模型判断阶数如何确定ACF 截尾k 阶后落回置信区间内PACF 拖尾MA(k)q 截尾阶数PACF 截尾p 阶后落回置信区间内ACF 拖尾AR(p)p 截尾阶数ACF 拖尾且 PACF 拖尾ARMA(p, q)需结合信息准则或网格搜索判断截尾有一个关键细节不要把“某根柱子掉回区间”当成截尾。真正的截尾是从某个滞后开始柱子掉回置信区间内并且后续几乎所有柱子都留在区间内。偶尔一根越界是正常随机波动毕竟显著水平 0.05 本身就允许 5% 的假警报。对于上面的 ARMA(2,1) 模拟数据你会看到 ACF 在第 1 阶处比较高随后很快衰减PACF 在第 2 阶后整体猝落。这是一个理想实验实际数据不会这么干净但只要抓住“多数点落在区间内”这个原则就不会被噪音牵着走。4. 用 ACF/PACF 指导 ARIMA 定阶从观图到模型参数的完整链条4.1 先处理非平稳差分、对数变换与 ADF 检验的顺序习惯拿到真实业务数据时第一件事不是画 ACF/PACF而是先观察原始序列有没有明显趋势或季节性。你可以先看折线图再做 ADF 检验。我用 statsmodels 里的 adfuller 已经形成了个人的固定流程from statsmodels.tsa.stattools import adfuller result adfuller(df[value].values) print(fADF Statistic: {result[0]:.4f}) print(fp-value: {result[1]:.4f}) if result[1] 0.05: print(拒绝原假设序列平稳可直接画 ACF/PACF) else: print(存在单位根先做一阶差分后再判断)判断逻辑是ADF 检验的原假设是“存在单位根序列非平稳”所以 p 值小于 0.05 就拒绝原假设认为序列平稳。反之如果 p 值较大就得先差分一次。常见做法是直接对原始序列做一阶差分生成新的列# 一阶差分 df[diff_1] df[value].diff().dropna()差分之后原序列里的趋势会被消除。有时候一阶差分还不够需要做二阶差分但这是少数。在实际业务场景里我更偏爱先做对数变换再差分尤其是处理销量、价格、流量这类方差随均值变化的序列。对数变换能把乘法关系转为加法关系让方差稳定下来你再画 ACF/PACF 时柱子会更“听话”。4.2 在真实数据集上画图以电商日订单量为例子假设你有 200 天的日订单量文件 orders_daily.csv 只有 date 和 orders 两列。先读取数据并快速画出 ACF/PACFimport pandas as pd import matplotlib.pyplot as plt from statsmodels.graphics.tsaplots import plot_acf, plot_pacf df pd.read_csv(orders_daily.csv, parse_dates[date], index_coldate) fig, axes plt.subplots(1, 2, figsize(14, 4)) plot_acf(df[orders], axaxes[0], lagsmin(int(10 * np.log10(len(df))), len(df)//3), zeroFalse) plot_pacf(df[orders], axaxes[1], lagsmin(int(10 * np.log10(len(df))), len(df)//3), methodywm, zeroFalse) plt.show()这段代码与你平时在教程里看到的有些不同我没有把 lags 硬编码成 20 或 24而是动态计算。好处是换一份不同长度的数据脚本仍然适用不用回头手动调整。如果你发现画出来的图太密可以手动把 lags 设小一点比如 30反过来如果样本量巨大、lags 太小图会显得太“稀疏”丢失长周期自相关信息。至于怎么判断这个平衡看横轴刻度的密度是否适合人眼就行。4.3 读图定阶后用信息准则做二次校验读图有一定主观性尤其是两个人都说 PACF 在 1 阶截尾但一个人看 2 阶也差不多。为避免这种模棱两可我习惯在观图之后跑一个简单的 ARIMA 阶数选择脚本用 AIC 或 BIC 确认候选 p、q 组合。别全文依赖因为信息准则也会有倾向性但至少可以和图示互相印证。import itertools import warnings from statsmodels.tsa.arima.model import ARIMA warnings.filterwarnings(ignore) df[diff_1] df[orders].diff().dropna() best_aic np.inf best_order (0, 0, 0) # 在 p4, q4 范围内搜索 for p, q in itertools.product(range(5), range(5)): try: model ARIMA(df[orders].dropna(), order(p, 1, q)) fitted model.fit() if fitted.aic best_aic: best_aic fitted.aic best_order (p, 1, q) except Exception: continue print(f最低 AIC 对应的阶数: ARIMA{best_order})这里的参数说明ARIMA 的 order 参数是一个三元组 (p, d, q)d1 表示一阶差分因为我们在外部已经做了差分这里使用原始 orders 序列并指定 d1 是等价写法。搜索范围限定在 p/q 都在 0 到 4 之间这是业务序列的常见范围再高很容易过拟合。如果你的业务有周期性比如 7 天一个周期网格搜索范围还得加大但那是另一个话题。4.4 确定阶数后建模ARIMA 的 fit 与残差验证定好阶数后建模本身很快from statsmodels.tsa.arima.model import ARIMA best_model ARIMA(df[orders], orderbest_order) fitted_model best_model.fit() print(fitted_model.summary()) # 残差检验看残差是否还是白噪声 resid fitted_model.resid plot_acf(resid, lags20, zeroFalse) plt.show()残差检验是很容易被跳过的环节。如果模型真正捕捉到了时间依赖结构残差应当近似白噪声也就是 ACF 图上几乎所有柱子都在置信区间内。如果你画出残差的 ACF 后发现前几阶仍然显著说明模型没捕捉干净建议回到第 2 章去重新审视模型结构而不是急着用这个模型做预测。5. 避坑ACF/PACF 画图与定阶的 6 个常见翻车点5.1 非平稳数据直接画图看到的全是假拖尾现象原始序列明明有明显上升趋势ACF 图从滞后 1 开始就是一根接近 1 的柱子后面几十阶缓慢下降PACF 则第一根接近 1、第二根也超限看起来像 AR(1)。如果直接照这个图定阶会误判为 AR(1) 甚至 AR(2)但模型预测效果很差。原因趋势属于非平稳成分ACF 中所有相关值都会被趋势拉高这不是数据真实的短期依赖结构而是长期趋势造成的伪相关。解决画图之前先做 ADF 检验。若 p 值大于 0.05做一阶差分后再画。记住一句话观察 ACF/PACF 的永远是“已经平稳的序列”不是原始序列。很多时候差分一次后原来显著的很多柱子一下就掉回置信区间内那才是真正的模型结构。5.2 lags 设置过大导致置信区间失真现象样本量为 100lags 却设成 50图又宽又密置信区间看起来特别窄很多柱子越界读图时恨不得把阶数定到 10 阶以上。原因lags 相对样本量太大滞后阶数接近样本量的一半时自相关估计方差大幅膨胀置信区间公式开始失效显著性错误率飙升。解决用 n 动态控制 lags我常用的经验公式是 min(int(10*log10(n)), n//3)。如果样本量是 200那 lags 最多 23 左右。宁愿 lags 小一点也不要为了“看到更多阶数”而用不合理的参数。大样本时代反而要克制这是所有画 ACF 的工程师都该记住的教训。5.3 plot_pacf 方法参数不兼容导致报错现象代码在更新 statsmodels 之后突然报错错误信息大致是“method parameter is required”或 ValueError提示需要显式传入 method。原因statsmodels 新版本要求 plot_pacf 指定 partical 自相关估计方法而旧代码省略了这个参数。解决在 plot_pacf 中显式添加 methodywm。如果你的数据有明显的季节性或者样本比较小可以考虑 methodldb但多数单变量场景用 ywm 就够了。这个报错非常典型搜一搜“plot_pacf error method”就能看到大量同类问题提前写上参数是最好的后悔药。5.4 用 1.96/sqrt(n) 的近似阈值代替置信区间现象画图时自己手动画蓝色虚线用 ±1.96/sqrt(n) 来判读显著性结果和 plot_acf 内置区间不一致导致误判。原因ACF 的置信区间在很多实现里使用了 Bartlett 公式即考虑高阶自相关对估计方差的影响近似公式只适用于纯 MA(0) 场景。当数据存在明显自相关时近似区间过窄或过宽都可能发生。解决在统计学上一律以 statsmodels 内置绘制的置信区间为准。如果你确实需要手动画区间先阅读源码或文档确认它内部使用的公式不要凭经验手画。对于工程场景来说内置区间已经足够可靠。5.5 过度解读孤立显著点现象某张 ACF 图 20 阶里只有第 7 阶一根柱子越界其余都在区间内但为了“保险起见”把 MA 项设到 7 阶。原因alpha0.05 意味着理论上 20 根柱子里有一根越界也是正常随机波动把它当作真实自相关会引入多余参数导致过拟合。解决判断截尾时看的是“截断后大部分后续点是否都在区间内”而不是单点是否越界。只有连续多个或至少集中在低阶的部分才值得关注。如果还是拿不准用 4.3 节的信息准则搜索做交叉验证比盯着孤点纠结可靠得多。5.6 ARMA 混合结构的误判ACF、PACF 都拖尾不等于没有价值现象ACF 和 PACF 都缓慢衰减看起来没有任何截尾初学者认为这两张图没用直接全部交给 AutoARIMA。原因ARMA 过程确实会让 ACF 和 PACF 都拖尾但拖尾的“起点”和衰减速度仍会告诉你一个范围。例如 ARMA(2,1) 的 PACF 在前两阶明显高于后续本质上是一种“伪拖尾”。解决当两图都拖尾时把注意力放在前几阶谁更长、更突出。同时用信息准则从小阶数开始搜索不要因为图不直观就放弃定阶。一般把 p、q 的搜索上限限制在 4 以内多数业务数据都够用过高的阶数只会让模型解释性变差。6. 进阶把 ACF/PACF 融入单变量预测模型的日常工作流如果你已经在做时间序列预测希望能有一个可复用的工作流我建议你这样组织先看点线图与 ADF 检验再画 ACF/PACF 定阶随后用信息准则确认最后建模并做残差白噪声检验。这个顺序每换一个数据集都跑一遍很快就能积累出对不同数据形态的判断力。一种值得养成的技巧是在画 ACF/PACF 时把季节性因素也考虑进去。如果一个时间序列带有 7 天或 12 个月的周期ACF 图在对应滞后处会再次出现高峰比如日订单量通常在滞后 7、14、21 处出现额外的高显著柱。这种情况说明需要引入季节性 ARIMASARIMA而不是普通 ARIMA。判断方法很直接观察间隔固定的多个滞后点是否反复越界。实际工作中我并不迷信任何单个画图参数。我曾遇到一份数据lags 设 20 时看 PACF 是 1 阶截尾设 40 时觉得是 2 阶截尾最后通过 AIC 对比确认 2 阶更好。这说明图像定阶天然存在误差边界与数据长度、噪声水平都有关靠一张图定终身不现实。把 ACF/PACF 当成“缩小候选范围”的工具而不是“唯一答案”的机器心态会稳很多。另一个容易被忽视的做法是保存每次画图的副本。对同一份时间序列我都会把差分前后的 ACF/PACF 图存成 PNG并附上 ADF 检验的 p 值。一个月后再回看能很清楚地看到当时决策的依据。这个小习惯帮助我避免了很多次“改了下数据又忘了当时模型为什么这么定”的尴尬。最后给你一个我自己常用的收尾动作建模后把拟合值和真实值的前 20 个点画在一起如果预测曲线明显偏移回去再看残差 ACF 图。如果残差 ACF 前几阶还有越界柱子不要急着加阶数先检查是否漏掉了差分或季节性。这两张图配合的力量远远大于任何自动定阶搜索因为自动搜索只告诉你“数字上最优”而 ACF/PACF 能告诉你“结构上合理”。希望这些实践经验能帮你少走几步弯路在 Python 里把 ACF/PACF 这个基本功扎扎实实练好。本文还有配套的精品资源点击获取
返回列表