导读:
本文介绍了数据平稳的重要性,平稳的数据对模型有什么影响。
描述了如何从直观的数据图中,和数据分布图(钟形曲线),以及数据统计值(Dickey-Fuller)上判断数据是否是平稳的。
正文:
时间序列不同于更传统的分类和回归预测建模问题。
时间结构为观察增加了一个顺序。这种强加的顺序意味着需要专门处理关于这些观察的一致性的重要假设。
例如,在建模时,假设观测的汇总统计数据是一致的。在时间序列术语中,我们将此期望称为时间序列是静止的。
通过增加趋势,季节性和其他依赖于时间的结构,可以在时间序列中容易地违反这些假设。
在本教程中,您将了解如何使用Python检查时间序列是否稳定。
完成本教程后,您将了解:
- 如何使用线图识别明显的静止和非平稳时间序列。
- 如何查看随时间变化的均值和方差等汇总统计信息。
- 如何使用具有统计显着性的统计检验来检查时间序列是否静止。
固定时间序列
静止时间序列中的观察结果不依赖于时间。
如果没有趋势或季节性影响,时间序列是固定的。按时间序列计算的汇总统计数据随时间变化是一致的,如观测值的均值或方差。
当时间序列静止时,可以更容易建模。统计建模方法假定或要求时间序列是静止的以使其有效。
以下是固定的每日女性出生数据集的示例。
from pandas import Series
from matplotlib import pyplot
series = Series.from_csv('daily-total-female-births.csv', header=0)
series.plot()
pyplot.show()
运行该示例将创建以下图表。
每日女性出生数据集图
非定时时间序列
非平稳时间序列的观测显示了季节性影响,趋势和其他依赖于时间指数的结构。
像平均值和方差这样的汇总统计数据会随着时间的推移而发生变化,从而使模型可能尝试捕获的概念发生偏差。
经典时间序列分析和预测方法涉及通过识别和消除趋势以及消除季节性影响来使非平稳时间序列数据静止。
以下是非固定航空公司乘客数据集的示例,显示趋势和季节性组件。
from pandas import Series
from matplotlib import pyplot
series = Series.from_csv('international-airline-passengers.csv', header=0)
series.plot()
pyplot.show()
运行该示例将创建以下图表。
非固定航空公司乘客数据集
固定时间序列的类型
平稳性的概念来自时间序列的理论研究,在预测时它是一个有用的抽象。
如果你深入研究这个话题,你可能会遇到一些更细微的平稳性概念。他们是:
他们是:
- 固定过程:产生一系列固定观测的过程。
- 固定模型:描述固定观测系列的模型。
- Trend Stationary:不显示趋势的时间序列。
- 季节性文具:没有季节性的时间序列。
- 严格固定:静止过程的数学定义,特别是观测的联合分布对时移是不变的。
固定时间序列与预测
你应该把你的时间序列固定吗?
一般来说,是的。
如果您的时间序列中有明确的趋势和季节性,那么对这些组件进行建模,将其从观察中移除,然后在残差上训练模型。
统计时间序列方法甚至现代机器学习方法将受益于数据中更清晰的信号。
当经典方法失败时,我们转向机器学习方法。当我们想要更多或更好的结果时。我们不知道如何最好地模拟时间序列数据中的未知非线性关系,并且一些方法在使用非平稳观测或某些固定和非静止视图的混合时可以产生更好的性能。
这里的建议是将时间序列的属性视为静止或不作为另一个信息源,可以在使用机器学习方法时在时间序列问题中使用特征工程和特征选择。
检查平稳性
有许多方法可以检查时间序列(直接观察,残差)是静止的还是非静止的。
- 看看Plots:您可以查看数据的时间序列图,并目视检查是否有任何明显的趋势或季节性。
- 摘要统计:您可以查看季节或随机分区数据的摘要统计信息,并检查明显或显着的差异。
- 统计测试:您可以使用统计测试来检查是否满足或已经违反了平稳性的期望。
在上文中,我们已经将每日女性出生和航空旅客数据集分别定为静止和非静止,并且图表显示趋势和季节性成分明显缺乏和存在。
接下来,我们将看一个快速的方法来计算和查看我们的时间序列数据集的摘要统计数据,以检查它是否是静止的。
摘要统计
如何快速的检查以确定您的时间序列是非静止的是查看摘要统计信息。
您可以将时间序列拆分为两个(或更多)分区,并比较每个组的均值和方差。如果它们不同并且差异具有统计显着性,则时间序列可能是非平稳的。
接下来,让我们在Daily Births数据集上尝试这种方法。
每日出生数据集
因为我们正在研究均值和方差,所以我们假设数据符合高斯(也称为钟形曲线或正态)分布。
我们还可以通过观察我们观察的直方图来快速检查这一点。
from pandas import Series
from matplotlib import pyplot
series = Series.from_csv('daily-total-female-births.csv', header=0)
series.hist()
pyplot.show()
运行该示例绘制时间序列中的值的直方图。我们清楚地看到高斯分布的钟形曲线形状,也许右尾更长。
每日女性出生的直方图
接下来,我们可以将时间序列分成两个连续的序列。然后我们可以计算每组数字的均值和方差并比较这些数值。
from pandas import Series
series = Series.from_csv('daily-total-female-births.csv', header=0)
X = series.values
split = len(X) / 2
X1, X2 = X[0:split], X[split:]
mean1, mean2 = X1.mean(), X2.mean()
var1, var2 = X1.var(), X2.var()
print('mean1=%f, mean2=%f' % (mean1, mean2))
print('variance1=%f, variance2=%f' % (var1, var2))
运行此示例显示均值和方差值不同,但大致在同一水平线上。
mean1=39.763736, mean2=44.185792
variance1=49.213410, variance2=48.708651
接下来,让我们在Airline Passengers数据集上尝试相同的方法。
航空公司乘客数据集
直接切入追踪,我们可以分割我们的数据集并计算每个组的均值和方差。
from pandas import Series
series = Series.from_csv('international-airline-passengers.csv', header=0)
X = series.values
split = len(X) / 2
X1, X2 = X[0:split], X[split:]
mean1, mean2 = X1.mean(), X2.mean()
var1, var2 = X1.var(), X2.var()
print('mean1=%f, mean2=%f' % (mean1, mean2))
print('variance1=%f, variance2=%f' % (var1, var2))
运行该示例,我们可以看到均值和方差看起来非常不同。因此这是一个非平稳的时间序列。
mean1=182.902778, mean2=377.694444
variance1=2244.087770, variance2=7367.962191
让我们退一步,检查在这种情况下假设高斯分布是否有意义,将时间序列的值绘制为直方图。
from pandas import Series
from matplotlib import pyplot
series = Series.from_csv('international-airline-passengers.csv', header=0)
series.hist()
pyplot.show()
运行该示例表明,值的分布确实看起来不像高斯,因此均值和方差值的意义不大。
这种观察的压扁分布可能是非平稳时间序列的另一个指标。
航空公司乘客的直方图
再次回顾时间序列的章节,我们可以看到有一个明显的季节性成分,看起来季节性成分正在增长。
这可能表明每个季节都呈指数级增长。可以使用对数变换将指数变化平坦回到线性关系。
下面是具有时间序列的对数变换的相同直方图。
from pandas import Series
from matplotlib import pyplot
from numpy import log
series = Series.from_csv('international-airline-passengers.csv', header=0)
X = series.values
X = log(X)
pyplot.hist(X)
pyplot.show()
pyplot.plot(X)
pyplot.show()
运行这个例子,我们可以看到更熟悉的高斯分布或类似统一的值分布。
航空公司乘客的直方图记录
我们还创建了对数转换数据的线图,可以看到指数增长似乎减少了,但我们仍然有趋势和季节性元素。
航空公司乘客的线路图
我们现在可以计算对数变换数据集的值的均值和标准差。
from pandas import Series
from matplotlib import pyplot
from numpy import log
series = Series.from_csv('international-airline-passengers.csv', header=0)
X = series.values
X = log(X)
split = len(X) / 2
X1, X2 = X[0:split], X[split:]
mean1, mean2 = X1.mean(), X2.mean()
var1, var2 = X1.var(), X2.var()
print('mean1=%f, mean2=%f' % (mean1, mean2))
print('variance1=%f, variance2=%f' % (var1, var2))
运行示例显示了每组的平均值和标准偏差值,这些值相似但不相同。
或许,仅从这些数字来看,我们就会说时间序列是静止的,但我们坚信在审查线图时不会出现这种情况。
mean1=5.175146, mean2=5.909206
variance1=0.068375, variance2=0.049264
这是一种快速的方法,但很容易被误导。
我们可以使用统计检验来检查两个高斯随机变量样本之间的差异是真实的还是统计的侥幸。我们可以探索统计显着性检验,例如Student t检验,但由于值之间的序列相关性,事情变得棘手。
在下一节中,我们将使用统计测试来明确评论单变量时间序列是否是静止的。
增强Dickey-Fuller测试
统计测试对您的数据做出了强有力的假设。它们只能用于通知零假设可被拒绝或未被拒绝的程度。必须解释结果才能使给定问题有意义。
然而,他们可以提供快速检查和确认,证明您的时间序列是静止的或非静止的。
该扩张的Dickey-Fuller检定是一类被称为统计测试的单位根检验。
单位根检验背后的直觉是它确定趋势定义时间序列的强度。
有许多单位根测试,Augmented Dickey-Fuller可能是更广泛使用的之一。它使用自回归模型并优化跨多个不同滞后值的信息标准。
测试的零假设是时间序列可以用单位根表示,它不是静止的(具有一些时间依赖的结构)。替代假设(拒绝零假设)是时间序列是静止的。
- 空假设(H0):如果未被拒绝,则表明时间序列具有单位根,这意味着它是非平稳的。它有一些时间依赖的结构。
- 替代假设(H1):零假设被拒绝; 它表明时间序列没有单位根,这意味着它是静止的。它没有时间依赖的结构。
我们使用测试中的p值来解释这个结果。低于阈值的p值(例如5%或1%)表明我们拒绝零假设(静止),否则高于阈值的p值表明我们未能拒绝零假设(非静止)。
- p值> 0.05:无法拒绝原假设(H0),数据具有单位根并且是非平稳的。
- p值<= 0.05:拒绝原假设(H0),数据没有单位根并且是静止的。
下面是在Daily Female Births数据集上计算Augmented Dickey-Fuller测试的示例。statsmodels库提供了实现测试的adfuller()函数。
from pandas import Series
from statsmodels.tsa.stattools import adfuller
series = Series.from_csv('daily-total-female-births.csv', header=0)
X = series.values
result = adfuller(X)
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))
运行该示例将打印测试统计值-4。这个统计数据越负,我们就越有可能拒绝零假设(我们有一个固定的数据集)。
作为输出的一部分,我们得到一个查找表来帮助确定ADF统计数据。我们可以看到,我们的统计值-4小于-3.449的值,1%。
这表明我们可以拒绝具有小于1%的显着性水平的零假设(即结果是统计学侥幸的低概率)。
拒绝原假设意味着该过程没有单位根,反过来,时间序列是静止的或没有时间依赖的结构。
ADF Statistic: -4.808291
p-value: 0.000052
Critical Values:
5%: -2.870
1%: -3.449
10%: -2.571
我们可以在Airline Passenger数据集上执行相同的测试。
from pandas import Series
from statsmodels.tsa.stattools import adfuller
series = Series.from_csv('international-airline-passengers.csv', header=0)
X = series.values
result = adfuller(X)
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))
运行该示例给出了与上面不同的图片。检验统计量是正的,这意味着我们不太可能拒绝零假设(它看起来是非平稳的)。
将测试统计量与临界值进行比较,看起来我们不得不拒绝零假设,即时间序列是非平稳的并且具有时间依赖性结构。
ADF Statistic: 0.815369
p-value: 0.991880
Critical Values:
5%: -2.884
1%: -3.482
10%: -2.579
让我们再次对数据集进行log转换,使值的分布更加线性,更好地满足此统计检验的预期。
from pandas import Series
from statsmodels.tsa.stattools import adfuller
from numpy import log
series = Series.from_csv('international-airline-passengers.csv', header=0)
X = series.values
X = log(X)
result = adfuller(X)
print('ADF Statistic: %f' % result[0])
print('p-value: %f' % result[1])
for key, value in result[4].items():
print('\t%s: %.3f' % (key, value))
运行该示例显示测试统计信息的负值。
我们可以看到该值大于临界值,这意味着我们不能拒绝零假设,反过来说时间序列是非平稳的。
ADF Statistic: -1.717017
p-value: 0.422367
5%: -2.884
1%: -3.482
10%: -2.579