如何检测时间序列中的异方差性
检测和处理时间序列中的非恒定方差
如果时间序列的方差随时间变化,则该时间序列是异方差的。否则,数据集是同方差的。
异方差性影响时间序列的建模。因此,检测和处理这种情况很重要。
介绍
下面的图显示了热门航空公司乘客的时间序列。你可以看到整个系列的变化是不同的。该系列的后半部分方差较高。这也是数据水平也更高的地方。
该 数据集 [1] 在 pmdarima Python 库中公开可用。
方差的变化对预测来说是有问题的。它会影响适当模型的拟合,从而影响预测性能。
但是,仅目视检查是不切实际的。你如何以更系统的方式检测和处理异方差性?
检测异方差
你可以使用统计检验检查时间序列是否异方差。其中包括:
-
White 测试 [2] ; -
Breusch-Pagan 测试 [3] ; -
Goldfeld–Quandt 检验 [4]
statsmodels Python 库实现了上述三个测试。这是将这些包装在一个类中的片段:
import pandas as pd
import statsmodels.stats.api as sms
from statsmodels.formula.api import ols
TEST_NAMES = [ 'White' , ' Breusch -Pagan' , ' Goldfeld -Quandt' ]
FORMULA = 'value ~ time'
class Heteroskedasticity:
@staticmethod
def het_tests ( series: pd.Series, test: str ) -> float :
"""
异方差测试
:param series: 单变量时间序列作为 pd.Series
:param test: 表示测试的字符串。'white','goldfeldquandt', 或者 'breuschpagan'之一
:return: p 值作为浮点数。
如果 p 值很高,我们接受零假设,即数据是同方差的
"""
assert test in TEST_NAMES, 'Unknown test'
series = series.reset_index(drop= True ).reset_index()
series.columns = [ ' time' , 'value' ]
series[ 'time' ] += 1
olsr = ols(FORMULA, series).fit()
if test == 'White':
_, p_value, _, _ = sms.het_white(olsr.resid, olsr.model.exog)
elif test == 'Goldfeld-Quandt' :
_, p_value, _ = sms.het_goldfeldquandt(olsr.resid, olsr.model. exog, alternative= 'two-sided' )
else :
_, p_value, _, _ = sms.het_breuschpagan(olsr.resid, olsr.model.exog)
return p_value
@classmethod
def run_all_tests ( cls, series: pd.Series ):
test_results = {k: cls.het_tests(series, k) for k in TEST_NAMES}
return test_results
@staticmethod
def get_residuals(series: pd.Series):
series = series.reset_index(drop=True).reset_index()
series.columns = ['time', 'value']
series['time'] += 1
olsr = ols(FORMULA, series).fit()
return olsr.resid
Heteroskedasticity类包含两个函数。函数
het_tests
应用特定测试(White、Breusch-Pagan 或 Goldfeld-Quandt)。函数
run_all_tests
一次应用所有三个测试。这些函数的输出是相应检验的 p 值。
下面介绍如何将此代码应用于图 1 中的时间序列。
from pmdarima.datasets import load_airpassengers
from src.heteroskedasticity import Heteroskedasticity
series = load_airpassengers( True )
test_results = Heteroskedasticity.run_all_tests(series)
# {'Breusch-Pagan': 4.55e-07,
# 'Goldfeld-Quandt': 8.81e-13,
# 'White': 4.34e-07}
所有测试的 p 值都接近于零。因此,你可以拒绝原假设。这些检验很好地证明了异方差性的存在。
这是时间序列前半部分和后半部分的残差分布:
这两个部分的残差分布不同。Goldfeld-Quandt 检验使用这种类型的拆分来检验异方差性。它检查两个数据子样本中残差的方差是否不同。
转换数据
时间序列中异方差性的常见补救措施是转换数据。对时间序列取对数有助于稳定其变异性。
这是与之前相同的时间序列,但采用对数标度:
这一次,该系列的可变性看起来很稳定。我们使用对数标度时间序列重新运行测试:
import numpy as np
test_results = Heteroskedasticity.run_all_tests(np.log(series))
# {'Breusch-Pagan': 0.033,
# 'Goldfeld-Quandt': 0.18,
# 'White': 0.10}
这次的 p 值更大。只有一个测试(Breusch-Pagan)拒绝了恒定方差的假设。这是假设显着性水平为
0.05
。
还原log转换
假设你正在使用对数log转换数据进行预测。此时,你需要将预测恢复到原始比例。这是通过逆向转换完成的——在对数的情况下,你应该使用指数。
因此,预测过程的步骤如下:
-
变换数据以稳定方差; -
拟合预测模型; -
获取预测,并将它们恢复到原始比例。
下面是一个例子。
import numpy as np
from pmdarima.datasets import load_airpassengers
from pmdarima.arima import auto_arima
from sklearn.model_selection import train_test_split
series = load_airpassengers( True )
# 保留最后 12 个点用于测试
train, test = train_test_split(series, test_size= 12 , shuffle= False )
# 稳定训练中的方差
log_train = np.log(train)
# 构建 arima 模型,m 是季节周期(每月)
mod = auto_arima(log_train, seasonal= True, m= 12 )
# 获取日志预测
log_forecasts = mod.predict( 12 )
# 恢复预测
forecasts = np.exp(log_forecasts)
总结
-
如果方差不是常数,则时间序列是异方差的; -
你可以使用统计检验来检验时间序列是否异方差。其中包括 White Breusch-Pagan 或 Goldfeld–Quandt 检验; -
使用对数变换来稳定方差; -
不要忘记将预测恢复到原始比例。
参考资料
作者|Vitor Cerqueira
🏴☠️宝藏级🏴☠️ 原创公众号『 数据STUDIO 』内容超级硬核。公众号以Python为核心语言,垂直于数据科学领域,包括 可戳 👉 Python | MySQL | 数据分析 | 数据可视化 | 机器学习与数据挖掘 | 爬虫 等,从入门到进阶!
长按👇关注- 数据STUDIO -设为星标,干货速递