什么是序列相关?
针对时间序列的趋势和季节性,我们可以很容易地利用“时间相关”的属性进行建模,即直接从时间索引中得出特征。但是有些情况下,一些时间序列只能利用“序列相关”属性,即使用序列的历史值作为特征。如下图所示,随着时间的推移,这些时间序列的结构可能并不明显,但如果与历史进行对比的话,结构就会很清晰。
周期性
周期性是时间序列中序列相关最常见的一种表现方式,表示时间序列中增长和衰减的模式,某个时间序列中的取值依赖于之前的历史取值,但不一定依赖于时间步长。周期性是可以影响自身反应持续一段时间的系统特征,经济、流行病、火山爆发和类似的自然现象经常表现出周期性。
周期性与季节性的区别在于,周期性不一定像季节性那样依赖于时间,在一个周期中发生的事情与发生的特定日期关系不大,更多的是与最近发生的事情有关,这种相对于时间的独立性意味着周期性可能比季节性更不规律。
滞后序列和滞后图
为了研究时间序列中可能存在的序列相关,通常的做法是创建滞后的序列,滞后时间序列是指将序列取值向前移动一个或多个时间步,相当于将其索引中的时间向前移动一个或多个时间步。
这里给出一个示例:美国月度失业率(y
)以及它的一阶和二阶滞后序列(y_lag_1
、y_lag_2
),我们可以使用滞后序列作为特征进行建模来预测美国失业率,即利用 y_lag_1
和 y_lag_2
来预测 y
。
import pandas as pd
reserve = pd.read_csv(
"data/ts-course-data/reserve.csv",
parse_dates={
'Date':['Year', 'Month', 'Day']},
index_col='Date',
)
y = reserve.loc[:, 'Unemployment Rate'].dropna().to_period('M')
df = pd.DataFrame({
'y': y,
'y_lag_1': y.shift(1),
'y_lag_2': y.shift(2),
})
df.head()
y | y_lag_1 | y_lag_2 | |
---|---|---|---|
Date | |||
1954-07 | 5.8 | NaN | NaN |
1954-08 | 6.0 | 5.8 | NaN |
1954-09 | 6.1 | 6.0 | 5.8 |
1954-10 | 5.7 | 6.1 | 6.0 |
1954-11 | 5.3 | 5.7 | 6.1 |
滞后图
时间序列的滞后图显示了其取值与滞后取值的关系,通过观察滞后图,时间序列中的序列相关性通常会很明显,我们可以从美国失业率的滞后图中看到,当前失业率和历史失业率之间存在明显的线性关系。
序列相关性最常用的度量方法是自相关,指一个时间点上时间序列的值与另一个时间点上时间序列的值之间的相关性,例如美国失业率与一阶滞后的相关性为 0.99,二阶为 0.98。
选择滞后阶数
当选择滞后阶数时,将全部强自相关的阶数纳入特征通常是无用的。例如,在美国失业率中,二阶滞后的自相关性很高,但很可能是来自于一阶滞后的衰减信息,如果二阶滞后不包含任何新的信息,在模型纳入一阶特征后,就没有理由再包含新的特征。
偏相关指一个滞后与之前所有滞后之间的相关性,即该滞后带来的新的信息,绘制相关图可以帮助我们选择要使用的滞后阶数。下图中 1 阶到 6 阶滞后超出了“不相关”的区域(蓝色),因此我们选择1 阶到 6 阶滞后特征进行建模(11 阶可能是误报)。
滞后特征的相关图本质上就像傅里叶特征的周期图一样。值得注意的是,自相关和偏相关的度量方式是线性依赖的,由于很多现实的时间序列存在非线性依赖关系,因此在选择滞后特征时,最好查看一下滞后图,例如太阳黑子序列是存在非线性依赖的,我们就可以通过自相关来忽略,像这样的非线性关系可以转换成线性关系,或者通过适当的算法学习。
示例——流感趋势
流感趋势数据集是 2009-2016 年的周统计流感就诊记录,我们的目标是预测未来几周的流感病例的数量。这里采用两种方法,一种是使用滞后特征来预测就诊情况;另一种是使用“另一组”时间序列的滞后特征来预测就诊情况:由谷歌捕获的与流感相关的搜索词。
from pathlib import Path
from warnings import simplefilter
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
from scipy.signal import periodogram
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from statsmodels.graphics.tsaplots import plot_pacf
# Configuration
simplefilter('ignore')
sns.set(style='whitegrid')
plt.rc('figure', autolayout=True, figsize=(11, 4))
plt.rc(
'axes',
labelweight='bold',
labelsize='large',
titleweight='bold',
titlesize=16,
titlepad=10,