作者:东哥起飞,来源:Python数据科学
当我们拿到时序数据后,首先要进行平稳性和纯随机性的检验,这两个重要的检验是时间序列的预处理。根据检验的结果可以判断出序列属于什么类型,然后对症下药使用相应的分析方法。
本篇讲解平稳性的检验方法。平稳性检验方法可分为两个类,一种是比较直观的画图,根据 ACF 和 PACF 的可视化图判断时序平稳性;另一种是量化的方法,通过假设检验计算结果来准确判断。
该方法主要通过 ACF 和 PACF 自相关可视化图来辅助判断,较为常用。
关于自相关的概念可以参考这篇 时间序列 ACF 和 PACF 理解、代码、可视化
先抛出判断标准:平稳序列通常具有短期相关性,即随着滞后期数
增加,平稳序列的自相关系数会很快地向零衰减,而非平稳时序的自相关系数向零衰减的速度比较慢。
下面我直接通过Python
代码可视化的案例说明如何通过自相关辅助判断,分别模拟出了白噪声、非白噪声平稳时序、非平稳时序、随机游走四种时序。
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
import warnings
warnings.filterwarnings("ignore")
# 白噪声
white_noise = np.random.standard_normal(size=500)
# 随机游走
np.random.seed(6)
def random_walk():
steps = np.random.standard_normal(size=500)
steps[0] = 0
walk = np.cumsum(steps)
return walk
# 模拟时序
def simulate_process(is_stationary:bool)->np.array:
np.random.seed(42)
process=np.empty(100)
if is_stationary:
alpha=0.5
process[0]=0
else:
alpha=1
process[0]=10
for i in range(100):
if i+1<100:
process[i+1]=alpha*process[i]+np.random.standard_normal()
else:
break
return process
# 非平稳时序
non_stationary=simulate_process(False)
# 非白噪声的平稳时序
yes_stationary=simulate_process(True)
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(15, 8))
# fig.subplots_adjust(hspace=0.5)
ax1.plot(white_noise)
ax1.set_title('white_noise')
ax2.plot(random_walk())
ax2.set_title('random_walk')
ax3.plot(yes_stationary)
ax3.set_title('yes_stationary')
ax4.plot(non_stationary)
ax4.set_title('non_stationary')
plt.show()
通过 statsmodels
分别绘制4个时序的 ACF 和 PACF 图。
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
fig, ax = plt.subplots(4, 2, figsize=(15, 12))
fig.subplots_adjust(hspace=0.5)
plot_acf(white_noise, lags=40, ax=ax[0][0])
ax[0][0].set_title('ACF(white_noise)')
plot_pacf(white_noise, lags=40, ax=ax[0][1])
ax[0][1].set_title('PACF(white_noise)')
plot_acf(random_walk(), lags=40, ax=ax[1][0])
ax[1][0].set_title('ACF(random_walk)')
plot_pacf(random_walk(), lags=40, ax=ax[1][1])
ax[1][1].set_title('PACF(random_walk)')
plot_acf(yes_stationary, lags=40, ax=ax[2][0])
ax[2][0].set_title('ACF(yes_stationary)')
plot_pacf(yes_stationary, lags=40, ax=ax[2][1])
ax[2][1].set_title('PACF(yes_stationary)')
plot_acf(non_stationary, lags=40, ax=ax[3][0])
ax[3][0].set_title('ACF(non_stationary)')
plot_pacf(non_stationary, lags=40, ax=ax[3][1])
ax[3][1].set_title('PACF(non_stationary)')
plt.figure(figsize=(20, 6))
plt.show()
白噪声:0时刻ACF为1,相当于自己和自己本身的相关性,这个不难理解,而非0时刻的滞后期ACF迅速退化到0附近,PACF 也是同样的形态,是典型的平稳序列,可见白噪声0时刻与滞后期时序几乎没有相关性,即无法根据历史数据预测未来。
随机游走:0时刻ACF为1,滞后期的ACF整体成下降趋势,但退化非常缓慢,0时刻与滞后40期的相关性仍有0.8左右。由于随机游走每一次的变化都是在上一次基础上累加的,所以相关性很强,滞后k期的ACF退化的非常慢。而PACF图中,滞后1期与0时刻相关性均为1,剩余滞后期迅速退化为0附近。这是因为滞后1期时序是在0时刻基础上随机的,相关性极高,而剩余滞后期时序考虑PACF概念(排除了其他滞后期时序的干扰,仅考虑自身与0时刻的相关性),那就变成随机的白噪声了。
非白噪声平稳时序: 正常平稳时序具体短期相关性的特点,ACF图中相关性在滞后1期以后降到0附近并保持在2倍标准差内窄幅震荡,这是随机性很强的平稳时序特征。与白噪声的区别是,白噪声虽也是平稳时序但从0时刻后就迅速降到0,是毫无相关性的。
非平稳时序: ACF相关性下降非常缓慢,很很长的滞后期里,自相关系数一直为正,随后又一直为负,显示出明显的三角对称性,这是具有单调趋势的非平稳序列的典型特征。
以上是根据自相关图特征进行的判断,关于这几种时序的概念和介绍可以参考:时间序列平稳性、白噪声、随机游走
自相关图的判断方法可以总结为以下几个特点。
自相关图判断时序是否平稳的缺点是会带有主观色彩,所以一般还会通过假设检验的量化方法进行验证,假设检验的方法更为准确。
目前假设检验的主流方法是单位根检验,检验序列中是否存在单位根,如存在,则为平稳时序,如存在则为平稳时序。
什么是单位根检验?
我们看下面这个模型,如果将
去掉,就等于随机游走序列。
,其中
为白噪声。
现在
的不同取值会直接影响到该序列是否平稳,有以下几种情况:
:随着
增大
最终会收敛,长期来看
是平稳的
:
是非平稳的随机游走序列
:
是爆炸式增长的更非平稳序列
以上第二种情况
就是所谓的单位根,是差分方程正好落在单位圆上的特征根
。
单位根检验就是检验差分方程的特征方程的各个特征根
是均小于1,还是存在等于1的情况。由于日常数据中基本不存在单位根均大于1的情况,所以只需检验单位根小于1还是等于1。
ADF检验是目前最常用的单位根假设检验方法,它对DF检验进行了修正,由仅考虑一阶自回归的DF检验拓展到了适用于高阶自回归的平稳性检验。其定义如下:
对任一
过程:
它的特征方程为:
如果该方程所有特征根都在单位圆内,即
,则序列
平稳。
如果有一个特征根存在,即
,则:
设
因此假设条件为:
,即存在单位根,假设时序是非平稳的(因为生活中大多数的时序都是非平稳的,所以原假设为非平稳)
,即不存在单位根
下面使用arch
包实现一个ADF检验过程。首先构造一个非平稳时序。
# 构建一个非平稳时序
import numpy as np
from matplotlib import pyplot as plt
np.random.seed(1)
y = np.random.standard_normal(size=100)
for i in range(1, len(y)):
y[i] = 1 + 0.2*i + y[i]
plt.figure(figsize=(12, 6))
plt.plot(y)
plt.show()
from arch.unitroot import ADF
# 非趋势项非截距项平稳性检验
adf = ADF(y)
print(adf.summary().as_text())
# 趋势平稳检验
adf = ADF(y,trend = 'ct')
print(adf.summary().as_text())
arch
包可以设置参数trend
参数,根据要检验的平稳类型可以选择不包含趋势项n
、包含截距项c
、包含截距项和趋势项ct
、包含截距项和趋势项和二次趋势项ctt
,默认值为c
。
第一次ADF检验trend为默认值c
包含截距项,即检验含截距项是否平稳,
,不能拒绝原假设,故序列非平稳。
第一次ADF检验trend为ct
包含截距项和趋势项,即验证含截距项和趋势项是否平稳,
,拒绝原假设,序列为趋势项平稳。
ADF检验主要适用于方差齐性场合,对于异方差序列的平稳性检验效果不佳。Phillips和Perron(1988) 提出了一种非参数检验方法,对ADF检验进行了非参数修正,既可适用于异方差场合,又服从ADF检验统计量极限分布。假设条件一样,与ADF用法相似,可作为ADF检验的补充。
代码实现如下,仍用前面构造的非平稳时序为例。
import numpy as np
from arch.unitroot import PhillipsPerron
# 非趋势项非截距项平稳性检验
pp = PhillipsPerron(y)
print(pp.summary().as_text())
# 趋势平稳检验
pp = PhillipsPerron(y,trend = 'ct')
print(pp.summary().as_text())
第一次PP检验trend为默认值c
包含截距项,即检验含截距项时序是否平稳,
,不能拒绝原假设,故序列非平稳。
第一次PP检验trend为ct
包含截距项和趋势项,即验证含截距项和趋势项是否平稳,
,拒绝原假设,序列为趋势项平稳。
综合ADF检验和PP检验两种方法,以上构造的时序可以判定为趋势平稳的。
除了以上两种检验方法,还有DF-GLS检验、KPSS检验、Zivot-Andrews检验、Variance Ratio检验等方法,不做详细介绍,代码实现同样可以通过arch
包调用。
参考链接 [1].《应用时间序列分析》王燕 [2].https://mp.weixin.qq.com/s/4M8ayYaghstPFURKybvARA [3].https://mp.weixin.qq.com/s/vgzAbeLWDdRv2YbRXydg8g [4].https://github.com/bashtage/arch [5].https://mp.weixin.qq.com/s/QVziYRaNAqiHDqNTR60Fsw