当前位置: 首页 > news >正文

第 4 篇:平稳性 - 时间序列分析的基石

第 4 篇:平稳性 - 时间序列分析的基石

在上一篇中,我们学习了如何将时间序列分解为趋势、季节性和残差。我们看到,很多真实世界的时间序列(比如 CO2 浓度)都包含明显的趋势(长期向上或向下)和/或季节性(固定周期的波动)。

这些成分虽然揭示了数据的内在模式,但也带来了一个“问题”:它们使得序列的统计特性随时间而变化。例如,带有上升趋势的序列,其均值(平均水平)会随着时间推移而增加。这种“不稳定”的特性,在时间序列分析中被称为非平稳性 (Non-stationarity)

为什么我们要关心这个?因为许多经典且强大的时间序列预测模型(如 ARIMA 模型家族)都建立在一个关键假设之上:数据是平稳的 (Stationary)

本篇我们就来深入探讨这个时间序列分析的基石——平稳性。我们将了解:

  1. 什么是平稳性?
  2. 为什么平稳性如此重要?
  3. 如何判断一个序列是否平稳?
  4. 如果序列不平稳,最常用的处理方法是什么?

什么是平稳性 (Stationarity)?

想象一条平静的湖面(Stationary)和一条奔腾的河流(Non-stationary)。

  • 平静的湖面: 在任何位置取一瓢水,它的平均深度、水面的波动程度(方差)看起来都差不多。
  • 奔腾的河流: 在上游和下游取水,平均深度可能截然不同;在急流和缓滩处,水流的湍急程度(方差)也相差甚远。

平稳性 就是时间序列数据拥有类似“平静湖面”的特性。更严谨地说,一个时间序列是**(弱)平稳**的,如果它的:

  1. 均值 (Mean) 不随时间 t 变化。
  2. 方差 (Variance) 不随时间 t 变化。
  3. 自协方差 (Autocovariance) 只依赖于时间的间隔 k,而不依赖于具体的时间点 t。(这保证了序列内部的相关性结构是稳定的,我们暂时不用深究数学细节,理解前两点更重要)。

看图说话:

  • 平稳序列 (Stationary): 数据点围绕一个固定的水平线上下波动,且波动的幅度大致稳定。典型的例子是白噪声 (White Noise),即纯粹的随机波动。
    在这里插入图片描述
  • 非平稳序列 (Non-stationary):
    • 含趋势: 数据明显呈现长期上升或下降。 (例如我们上一篇分解出的 CO2 趋势部分)
    • 含季节性: 数据存在固定的周期性波动。 (例如 CO2 的季节性部分)
    • 方差变化: 数据的波动幅度随时间变化(例如,早期波动小,后期波动剧烈)。
    • 随机游走 (Random Walk): 一个典型的非平稳过程,下一步的位置是当前位置加上一个随机步长。股价有时被建模为类似随机游走。
    • 在这里插入图片描述

为什么平稳性如此重要?

  1. 模型假设: 很多经典时间序列模型(如 ARMA, ARIMA)明确要求输入数据是平稳的。如果用非平稳数据直接建模,可能会导致模型参数估计不准、预测结果不可靠。
  2. 可预测性基础: 平稳序列意味着其统计特性在未来可能保持不变。这为我们基于历史模式进行预测提供了更坚实的基础。如果一个序列的均值和方差都在不断变化,预测其未来将非常困难。
  3. 简化分析: 处理平稳序列通常比处理非平稳序列更简单。我们可以专注于分析其内部的相关性结构(自相关性),而不用同时处理变化的趋势和季节性。

如何判断平稳性?

主要有两种方法:

  1. 视觉检查 (Visual Inspection):

    • 直接绘制时间序列图: 观察是否存在明显的趋势或季节性模式?数据的均值线是否大致水平?数据的波动幅度是否大致恒定?
    • 查看分解图 (来自上一篇): seasonal_decompose 的结果可以帮助我们。如果趋势 (Trend) 成分不是水平的,或者季节性 (Seasonal) 成分很明显,那么原始序列很可能不是平稳的。
  2. 统计检验 (Statistical Tests):

    • 肉眼观察有时会骗人,我们需要更客观的统计方法。最常用的检验之一是 ADF 检验 (Augmented Dickey-Fuller Test)

    • ADF 检验的目的: 它的“原假设 (Null Hypothesis)”是序列存在单位根 (Unit Root),即序列是非平稳的。它的“备择假设 (Alternative Hypothesis)”是序列没有单位根,即序列是平稳的。

    • 如何解读结果? 我们主要关心检验输出的 p-value

      • 如果 p-value > 0.05 (常用的显著性水平): 我们没有足够证据拒绝原假设。也就是说,我们倾向于认为序列是非平稳的。
      • 如果 p-value <= 0.05: 我们拒绝原假设。也就是说,我们倾向于认为序列是平稳的。
    • Python 实现 (使用 statsmodels):

    from statsmodels.tsa.stattools import adfuller
    import statsmodels.api as sm
    import pandas as pd# 仍然使用上一篇的月度 CO2 数据
    data = sm.datasets.co2.load_pandas().data
    data['co2'].interpolate(inplace=True)
    monthly_data = data.resample('M').mean()print("对原始月度 CO2 数据进行 ADF 检验:")
    result = adfuller(monthly_data['co2'])print('ADF Statistic: %f' % result[0])
    print('p-value: %f' % result[1])
    print('Critical Values:')
    for key, value in result[4].items():print('\t%s: %.3f' % (key, value))# 解释 p-value
    if result[1] > 0.05:print("\n结论:p-value > 0.05,未能拒绝原假设,数据很可能非平稳。")
    else:print("\n结论:p-value <= 0.05,拒绝原假设,数据很可能平稳。")
    

    运行上述代码,你会发现 CO2 数据的 p-value 远大于 0.05,印证了我们视觉观察到的非平稳性。

如何让序列平稳?—— 差分 (Differencing)

如果我们的序列被判断为非平稳,怎么办?最常用、最简单的处理方法就是差分 (Differencing)

差分的思想很简单:计算相邻时间点数据之间的差值

  • 一阶差分 (First Difference): Y'(t) = Y(t) - Y(t-1)

    • 目的: 主要用于消除序列中的线性趋势
    • 效果: 如果原序列有稳定增长或下降的趋势,差分后的序列通常会围绕 0 值上下波动。
  • 季节性差分 (Seasonal Difference): Y'(t) = Y(t) - Y(t-s),其中 s 是季节性周期长度(例如,对于月度数据年度季节性,s=12)。

    • 目的: 主要用于消除序列中的季节性
  • 高阶差分: 有时需要进行多次差分(例如,对一阶差分后的序列再做一次差分,称为二阶差分),或者结合使用普通差分和季节性差分,来达到平稳。但通常一阶或二阶差分就足够了。过度差分可能会引入不必要的模式。

Python 实现一阶差分 (.diff()):

import matplotlib.pyplot as plt
import seaborn as sns# 对 CO2 数据进行一阶差分
monthly_data['co2_diff'] = monthly_data['co2'].diff()# 差分后第一个值是 NaN,需要去掉或填充
monthly_data_diff = monthly_data.dropna() # 去掉 NaN 值print("\n差分后的数据 (前几行):")
print(monthly_data_diff.head())# 绘制差分后的序列图
plt.figure(figsize=(12, 6))
sns.lineplot(data=monthly_data_diff, x=monthly_data_diff.index, y='co2_diff')
plt.title('First Difference of Monthly CO2 Data')
plt.xlabel('Date')
plt.ylabel('First Difference')
plt.axhline(0, color='red', linestyle='--') # 添加 0 值参考线
plt.show()# 对差分后的序列再次进行 ADF 检验
print("\n对一阶差分后的 CO2 数据进行 ADF 检验:")
result_diff = adfuller(monthly_data_diff['co2_diff'])
print('ADF Statistic: %f' % result_diff[0])
print('p-value: %f' % result_diff[1])
print('Critical Values:')
for key, value in result_diff[4].items():print('\t%s: %.3f' % (key, value))if result_diff[1] > 0.05:print("\n结论:p-value > 0.05,差分后数据仍可能非平稳 (可能需要进一步处理,如季节性差分)。")
else:print("\n结论:p-value <= 0.05,拒绝原假设,差分后数据很可能平稳。")# 注意:CO2 数据同时有强趋势和强季节性,仅一阶差分可能不足以完全平稳,
# ADF检验的 p-value 可能会显著降低,但仍可能大于 0.05 或略小于 0.05。
# 完全平稳化可能需要再做季节性差分: .diff(12)
# monthly_data['co2_diff_seasonal'] = monthly_data['co2'].diff().diff(12).dropna()
# 但我们这里主要演示一阶差分的效果。

在这里插入图片描述

解读结果:

  1. 差分后的图形: 你会看到,原始 CO2 数据那个明显的上升趋势消失了!差分后的序列现在看起来更像是在 0 附近波动,尽管可能还保留着一些季节性模式。
  2. 差分后的 ADF 检验: 运行 ADF 检验,你会发现差分后序列的 p-value 显著降低了(可能已经小于 0.05,或者非常接近)。这表明一阶差分有效地移除了大部分非平稳性(主要是趋势)。如果 p-value 仍然偏高,可能意味着还需要处理季节性(进行季节性差分)。

重要提醒: 我们的目标是使用尽可能少的差分次数来使序列平稳。过度差分会丢失信息。

小结

今天我们学习了时间序列分析中一个至关重要的概念——平稳性

  • 定义: 平稳序列的均值、方差和自协方差结构不随时间改变。
  • 重要性: 是许多经典时间序列模型的基础假设。
  • 判断方法:
    • 视觉检查: 观察时间序列图和分解图中的趋势、季节性及波动幅度。
    • 统计检验: 使用 ADF 检验,通过 P-value 判断是否存在单位根(非平稳)。
  • 处理方法: 最常用的使序列平稳的方法是差分(一阶差分消除趋势,季节性差分消除季节性)。

理解并能够处理数据的平稳性,是进行有效时间序列建模的关键一步。

下一篇预告

到目前为止,我们已经掌握了如何加载、可视化、分解时间序列,以及如何处理非平稳性。现在,我们终于可以开始尝试做一些简单的预测 (Forecasting) 了!

下一篇,我们将学习几种最基础、最直观的预测方法,比如朴素预测、平均法、移动平均法等。它们虽然简单,但有时效果惊人,并且是理解更复杂模型的重要起点。

准备好迎接你的第一个时间序列预测模型了吗?敬请期待!


(对你的数据进行 ADF 检验和差分,结果如何?差分后的序列看起来平稳了吗?欢迎在评论区分享你的实践!)

相关文章:

  • Github 热点项目 Jumpserver开源堡垒机让服务器管理效率翻倍
  • 前端笔记-Axios
  • 云原生与AI的关系是怎么样的?
  • Unreal Engine中FRotator与FQuat在赛车游戏方向盘控制中的协同应用解析
  • Android Kotlin+Compose首个应用
  • SpringBoot整合JWT Token:构建安全无状态认证体系的最佳实践
  • 把dll模块注入到游戏进程的方法_远线程注入
  • 目标检测篇---R-CNN梳理
  • linux驱动框架——i2c驱动模块的probe过程
  • 重构便携钢琴专业边界丨特伦斯便携钢琴V30Pro定义新一代便携电钢琴
  • 120.在 Vue3 中使用 OpenLayers 实现清空删除所有图层功能
  • AI驱动下的企业学习:人力资源视角下的范式重构与价值觉醒
  • 【数据结构和算法】3. 排序算法
  • java多线程的内存可见性问题,volatile是干什么的?
  • 基于Python(Django)+SQLite实现(Web)校园助手
  • Time to event :Kaplan-Meier曲线、Log Rank检验与Shiny R
  • 线上地图导航小程序源码介绍
  • django入门
  • 介绍XML
  • 蓝桥杯 18.分考场
  • 人民热评:大尺度色情语聊、撮合卖淫,社交APP岂止跑偏
  • 湖南平江发生一起意外翻船事件,6人不幸溺亡
  • 史蒂夫·麦奎因透露罹患前列腺癌,呼吁同胞莫受困于男性气概
  • 商务部24日下午将举行发布会,介绍近期商务领域重点工作情况
  • 4月LPR保持不变:1年期3.1%,5年期以上3.6%
  • 人民日报:对科研不端行为加大惩处力度,让造假成本远高于收益