文章目录
1 引言
本篇主要帮助大家理解移动平均,指数平滑,平稳性,自相关,SARIMA,通过案例和Python编程实现时间序列的预测技术。
无论我们是预测金融市场或股票趋势,或是电能耗费的趋势,时间都是我们模型中必须考虑的一个重要因素。例如,预测一天中什么时间会出现的电能消耗高峰,并以此来调整价格或发电量。
时间序列简单来说就是按时间顺序排列的数据点。在时间序列中,时间通常是独立变量,目标则是对未来进行预测。
当然,在处理时间序列时,其他许多因素同样会有影响。
- 时间序列是平稳的吗?
- 时间序列具有季节性吗?
- 目标变量是自相关的吗?
在本文中,我们将介绍时间序列的不同特征,以及如何进行建模以获得尽可能准确的预测。当然,预测未来是十分困难的。
2 时间序列的特性
2.1 自相关
简单来说,自相关是观察值之间的相似性,并作为它们之间是时间延迟的函数。
上图就是一个自相关的图例。仔细观察,我们发现第1个值和第24个值具有很高的自相关性。同样,第12 个观测和第36个观测也是高度相关的。这意味着,每24个单位时间,我们就可以找到一个相似的值。
注意,这个图与正弦函数很相似,这就是对序列季节性的暗示,在上图中,我们可以按照24个单位时间一个周期,找到相似的值。
2.2 季节性
季节性指的是周期性的波动。例如,白天用电量高,晚上低,或是网购量在圣诞节期间增加,然后再次放缓。
正如上图所示,每一天都有明显的季节性趋势。每一天,傍晚时都会出现一个高峰,而最低点则是每天的开始和结束。
如果自相关图像是正弦的,那么也可以认为其具有季节性。只要简单的看一下它的周期,就可以得到季节的长度。
2.3 平稳性
平稳性是时间序列的一个重要特征。如果一个时间序列的统计特征不随时间而改变,那么他就是平稳的。换句话说,它的均值和方差是常数,并且协方差与时间无关。
同一张图,可以看到上面的过程是平稳的。均值和方差不随时间变化。
通常情况下,股票价格不是一个平稳过程,因为我们可能会看到增长的趋势,或者它的波动性会随着时间而增加(方差的变化)。
理想情况下,我们希望对一个平稳的时间序列建模。当然,并不是所有的时间序列都是平稳的,但我们可以通过不同的变换使它们变为平稳序列。
如何检验一个过程是否平稳
你可能已经注意到,上图标题中的迪基-福勒Dickey-Fuller。迪基-福勒检验就是用来在统计学领域检验时间序列是否平稳的。
不讨论迪基-福勒检验的技术细节,简单来说,它检验了原假设:单位根存在。
- 如果为真,则p>0,这个过程是不平稳的。
- 否则,p=0, 拒绝原假设,过程被认为是平稳的。
以下图为例,该过程是不平稳的,平均值随时间变化,不为常数。
3 时间序列建模
有许多方法可以对时间序列进行建模,并作出预测。本文,我们将介绍:
- 移动平均法
- 指数平滑法
- ARIMA
3.1 移动平均法
移动平均模型可能是所有时间序列模型中最初级的方法:下一个观测值是之前所有观测值的平均值。尽管十分简单,但这个模型却出人意料的有效,也是一个很好的起点。
移动平均模型可以用于识别数据中有趣的趋势。我们可以定义一个窗口,应用移动平均模型对时间序列进行平滑处理,以突出不同的趋势。
在上图中,我们将移动平均应用在一个窗口为24小时的模型。图中绿线是时间序列的平滑,我们可以看到在24小时内存在两个峰值。
当然,时间窗口越长,趋势就越平稳。下图是一个小窗口的移动平均模型的案例。
3.2 指数平滑法
指数平滑法使用与移动平均法相似的逻辑,但在此方法中,将赋予每个观测值不同的递减权重。换句话说,随着观察值离现在的时间点越来越远,观察值的重要性就越来越小。
在数学上,指数平滑表示为:
α是一个平滑因子,值在0到1之间。它决定了观测值权重下降的速度。
从上图可以看出:
- 深蓝线表示使用0.3平滑因子对时间序列进行指数平滑的结果;
- 橙线则是使用0.05的指数平滑结果。
- 正如我们看到的,平滑因子越小,结果就越平滑。这很容易理解,因为当平滑因子接近0时,模型就越接近移动平均模型。
3.3 双指数平滑法
当时间序列中存在趋势时,我们可以采用双指数平滑法。这种方法简单来说,是指数平滑法的递归使用。
数学上:
上式中,β是趋势平滑因子,值在0-1之间。
预测公式为:
下图中,我们可以看到不同值如何影响处理后时间序列的形状。
3.4 三重指数平滑法
此方法通过增加季节平滑因子,扩展了双指数平滑法。因此,当你发现时间序列具有季节性时,此方法就十分有效。
数学上:
其中 γ 是季节平滑因子,L是季节的长度。
3.5 周期性差分自动平滑回归模型(SARIMA)
SARIMA模型实际上是一些简单模型的组合,并组成复杂的模型,此模型可以对非平稳的和具有季节性的时间序列进行建模。
我们先来看自回归模型AR§,它可以说是对时间序列自身的回归。我们假设当前值依赖于有些许滞后的先前值,并使用参数p表示最大滞后值。为了找到它,我们可以观察偏自相关图像,找到滞后值开始不显著的点,即最大滞后值。
下图的例子中,该p值为4。
接下来,我们加入移动平均模型MA(q)。参数q代表最大滞后值,在此后的其他滞后在相关性图中不显著。下图中,q值为4。
之后,我们再加入单整阶数I(d)。参数d表示是序列平稳所需进行的差分次数(阶数)。
现在,让我们添加最后一个组成部分:季节性s(P, D, Q, s),其中s为季节的长度,参数P和Q是与p和q相似的季节性部分。最后,D是季节性单整阶数,代表从序列中去除季节性所需的差分次数。
综合这些,我们得到了SARIMA(p, d, q)(P,D, Q, s)模型。
主要结论:在使用SARIMA建模前,我们必须对时间序列进行变换,以消除季节性,并使序列平稳。
这一大堆理论可能让我们难以理解,下面我们将在项目中应用上面所讨论的技术,
我们将预测某一公司的股票价格。当然,预测股票价格在现在是几乎不可能的,但是这仍然是个有趣的联系,也是一个很好实践所学的方式。
4 实例——股票价格的预测
我们利用新德国基金(GF)的历史股价来预测未来五个交易日的收盘价。
我们可以在https://github.com/marcopeix/stock-prediction找到数据集和笔记本。
启动您的编辑器,让我们开始吧。
(1)导入数据
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set()
from sklearn.metrics import r2_score, median_absolute_error, mean_absolute_error
from sklearn.metrics import median_absolute_error, mean_squared_error, mean_squared_log_error
from scipy.optimize import minimize
import statsmodels.tsa.api as smt
import statsmodels.api as sm
from tqdm import tqdm_notebook
from itertools import product
def mean_absolute_percentage_error(y_true, y_pred):
return np.mean(np.abs((y_true - y_pred) / y_true)) * 100
import warnings
warnings.filterwarnings('ignore')
%matplotlib inline
DATAPATH = 'data/stock_prices_sample.csv'
data = pd.read_csv(DATAPATH, index_col=['DATE'], parse_dates=['DATE'])
data.head(10)
首先,我们导入一些在分析过程中可能会用到的Python包。此外,定义了平均百分比误差(MAPE),这将是误差的评判标准。之后,我们导入数据集并预览了前十条数据:
我们可以发现,有一些条目并不属于新德国基金,并且有些条目为交易日内信息,并非我们所需的收盘信息。因此我们需要对数据进行一定的清理。
(2)数据清理
我们首先删除不符合要求的条目,然后删除不需要的列,只留下我们关注的股票收盘价。
data = data[data.TICKER != 'GEF']
data = data[data.TYPE != 'Intraday']
drop_cols = ['SPLIT_RATIO', 'EX_DIVIDEND', 'ADJ_FACTOR', 'ADJ_VOLUME', 'ADJ_CLOSE', 'ADJ_LOW', 'ADJ_HIGH', 'ADJ_OPEN', 'VOLUME', 'FREQUENCY', 'TYPE'