金融相关时间序列分析全指南

来源:yv.l1.pnn - kesci.com
原文链接:时间序列分析入门,看这一篇就够了
点击以上链接👆 不用配置环境,直接在线运行
数据集下载:DJIA 30股票时间序列

本文包含时间序列的数据结构、可视化、统计学理论及模型介绍,主要侧重金融相关数据实践。翻译自:kaggle - everything you can do with a time series

# 导入必要的包
import os
import warnings
warnings.filterwarnings('ignore')
import numpy as np 
import pandas as pd
import matplotlib.pyplot as plt
plt.style.use('fivethirtyeight') 
# Above is a special style template for matplotlib, highly useful for visualizing time series data
%matplotlib inline
from pylab import rcParams
from plotly import tools
import plotly.plotly as py
from plotly.offline import init_notebook_mode, iplot
init_notebook_mode(connected=True)
import plotly.graph_objs as go
import plotly.figure_factory as ff
import statsmodels.api as sm
from numpy.random import normal, seed
from scipy.stats import norm
from statsmodels.tsa.arima_model import ARMA
from statsmodels.tsa.stattools import adfuller
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
from statsmodels.tsa.arima_process import ArmaProcess
from statsmodels.tsa.arima_model import ARIMA
import math
from sklearn.metrics import mean_squared_error
print(os.listdir("../input"))
Matplotlib is building the font cache using fc-list. This may take a moment.

['DJIA3716', 'djia307822']

1.介绍日期与时间

1.1 导入时间序列数据

使用的数据

  1. Google Stocks Data
  2. Humidity in different world cities
  3. Microsoft Stocks Data
  4. Pressure in different world cities

这里使用parse_dates参数将所需的时间序列列导入为datetime列,并使用index_col参数将其选择为数据框的索引。

google = pd.read_csv('/home/kesci/input/DJIA3716/GOOGL_2006-01-01_to_2018-01-01.csv', 
index_col='Date', parse_dates=['Date'])

google.head()

1.2 清洗以及准备时间序列数据

如何准备数据?

Google 数据没有缺失值,所以我们这里不用处理缺失值。如果有缺失值的话,我们可以使用 fillna() 方法并设置参数 ffill 来填充缺失值。

该参数 ffill 意味着用空白处前面的的最后一个的有效观察值来填补缺失值。

google.isnull().any()
Open      False
High      False
Low       False
Close     False
Volume    False
Name      False
dtype: bool
google.isnull().sum()
Open      0
High      0
Low       0
Close     0
Volume    0
Name      0
dtype: int64

以上代码表示这几列都没有缺失值

1.3 可视化数据集

plt.figure()
google['2008':'2010'].plot(subplots=True, figsize=(10,12))
plt.title('2008年至2010年Google股票各个属性的表现')
plt.show()

1.4 Timestamps和Periods

什么是timestamps 与 periods? 为什么说他们很有用?

Timestamps 用于表示时间点. Periods 代表时间间隔.

Periods 可用于检查给定期间内是否有特定事件.

它们也可以转换为彼此的形式。

# 创建一个Timestamp
timestamp = pd.Timestamp(2017, 1, 1, 12)
timestamp
Timestamp('2017-01-01 12:00:00')
# 创建一个period
period = pd.Period('2017-01-01')
period
Period('2017-01-01', 'D')
# 检查给定timestamp是否在给定period内
period.start_time < timestamp < period.end_time
True
# timestamp 转换为 period
new_period = timestamp.to_period(freq='H')
new_period
Period('2017-01-01 12:00', 'H')
# period 转换为 timestamp
new_timestamp = period.to_timestamp(freq='H', how='start')
new_timestamp
Timestamp('2017-01-01 00:00:00')

1.5 使用 date_range

什么是 date_range ?

date_range 是一种返回固定频率datetimeindex的方法。

当创建自己的时间序列属性——以用于预先存在的数据,或围绕您创建的时间序列属性排列整个数据时,此函数非常有用。

# 创建一个 datetimeindex ,使用日频率(freq 默认是 daily)
dr1 = pd.date_range(start='1/1/18', end='1/9/18')
dr1
DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04',
               '2018-01-05', '2018-01-06', '2018-01-07', '2018-01-08',
               '2018-01-09'],
              dtype='datetime64[ns]', freq='D')
# 创建一个 datetimeindex ,使用月(month)频率
dr2 = pd.date_range(start='1/1/18', end='1/1/19', freq='M')
dr2
DatetimeIndex(['2018-01-31', '2018-02-28', '2018-03-31', '2018-04-30',
               '2018-05-31', '2018-06-30', '2018-07-31', '2018-08-31',
               '2018-09-30', '2018-10-31', '2018-11-30', '2018-12-31'],
              dtype='datetime64[ns]', freq='M')
# 创建一个 datetimeindex ,并且不指定起始日期,只使用 periods
dr3 = pd.date_range(end='1/4/2014', periods=8)
dr3
DatetimeIndex(['2013-12-28', '2013-12-29', '2013-12-30', '2013-12-31',
               '2014-01-01', '2014-01-02', '2014-01-03', '2014-01-04'],
              dtype='datetime64[ns]', freq='D')
# 创建一个 datetimeindex ,并且指定起始日期,终止日期与 periods
dr4 = pd.date_range(start='2013-04-24', end='2014-11-27', periods=3)
dr4
DatetimeIndex(['2013-04-24', '2014-02-09', '2014-11-27'], dtype='datetime64[ns]', freq=None)

1.6 使用 to_datetime

pandas.to_datetime() 用于将参数转换为日期时间。

在这里,DataFrame转换为日期时间Series

df = pd.DataFrame({'year': [2015, 2016], 'month': [2, 3], 'day': [4, 5]})
df
# 转化为时间Series
df = pd.to_datetime(df)
df
0   2015-02-04
1   2016-03-05
dtype: datetime64[ns]
# 转化为Timestamp
df = pd.to_datetime(df)
df
Timestamp('2017-01-01 00:00:00')

1.7 移动(Shift)和滞后(Lags)

我们可以使用可选的时间频率将索引按所需的周期数移动

可让我们将时间序列与其自身的过去进行比较时,这很有用

google.loc['2008':'2009'].High.plot(legend=True)
google.loc['2008':'2009'].High.shift(10).plot(legend=True,label='移动后High')
plt.show()

1.8 重新采样(Resampling)

Upsampling - 向上采样,时间序列从低频到高频(每月到每天)重新采样。 它涉及填充内插丢失的数据

Downsampling - 向下采样,时间序列从高频重新采样到低频(每周一次到每月一次)。 它涉及现有数据的汇总

这里要用一个极其不完整的数据集来展示

pressure = pd.read_csv('/home/kesci/input/djia307822/pressure.csv', 
index_col='datetime', parse_dates=['datetime'])
pressure.tail()

可以看到有非常多的缺失值需要我们去填充

pressure = pressure.iloc[1:]
pressure = pressure.fillna(method='ffill')
pressure.tail()
pressure.head(3)
# 向上填充
pressure = pressure.fillna(method='bfill')
pressure.head(3)

解释一下

首先,我们使用 ffill 参数向下填充缺失值。

然后,我们使用 bfill 向上填充缺失值。

# downsampling前查看数据形状
pressure.shape
(45252, 36)
# 使用3日频率进行downsample,这里使用了mean (减少数据量——高频到低频)
pressure = pressure.resample('3D').mean()
pressure.head()
# downsampling后数据形状
pressure.shape
(629, 36)

可以看见,downsample后剩下的行要少得多。

现在,我们将从3天的频率 upsample 到每日频率,即低频到高频

pressure = pressure.resample('D').pad()
pressure.head()
pressure.shape
(1885, 36)

行数再次增加。

如果使用正确,Resample的操作是很酷炫的。

2. 金融与统计

2.1 百分比变化量

# div为除法,shift()表示向后移动一期,这里是一天,因为是日数据
google['Change'] = google.High.div(google.High.shift())
google['Change'].plot(figsize=(20,8))

2.2 股票收益

plt.figure()
google['Return'] = google.Change.sub(1).mul(100)
google['Return'].plot(figsize=(20,8))
plt.axhline(y=0, color='r', linestyle='-')
plt.show()
# 另一个计算收益的方法
plt.figure()
google.High.pct_change().mul(100).plot(figsize=(20,6),color='b') 
google['Return'].plot(figsize=(20,8))
plt.axhline(y=0, color='r', linestyle='-')
plt.show()

2.3 连续的行中的绝对数值变化

# 用差分
google.High.diff().plot(figsize=(20,6))
plt.axhline(y=0, color='r', linestyle='-')
plt.show()

2.4 比较两个或多个时间序列

我们将通过归一化两个时间序列再进行比较。

这是通过将所有时间序列的每个时间序列元素除以第一个元素来实现的。

这样,两个系列都从同一点开始,可以轻松进行比较。

# 我们将比较微软和Google的股价
microsoft = pd.read_csv('/home/kesci/input/djia307822/MSFT_2006-01-01_to_2018-01-01.csv', index_col='Date', parse_dates=['Date'])
# 可视化
plt.figure()
google.High.plot()
microsoft.High.plot()
plt.legend(['Google','Microsoft'])
plt.show()
# 标准化并进行比较
# 全部都除以第一行的数据
# 两支股票都从100开始
normalized_google = google.High.div(google.High.iloc[0]).mul(100)
normalized_microsoft = microsoft.High.div(microsoft.High.iloc[0]).mul(100)

# 可视化
plt.figure()
normalized_google.plot()
normalized_microsoft.plot()
plt.legend(['Google','Microsoft'])
plt.show()

您可以清楚地看到Google在一段时间内的表现胜过微软。

2.5 Window函数

Window 函数用于标识子periods,计算子periods的子度量metrics。

Rolling - 大小相同,且滑动步数相同

Expanding - 包含所有先前值

# Rolling window 函数
# Rolling 90天
rolling_google = google.High.rolling('90D').mean()

# 与Rolling前数据进行比较
google.High.plot()
rolling_google.plot()
plt.legend(['High','Rolling Mean'])
plt.show()

可看出,Rolling均值图是原始图的平滑版本

# Expanding window 函数
microsoft_mean = microsoft.High.expanding().mean()
microsoft_std = microsoft.High.expanding().std()
microsoft.High.plot()
microsoft_mean.plot()
microsoft_std.plot()
plt.legend(['High','Expanding Mean','Expanding Standard Deviation'])
plt.show()

2.6 OHLC图

O:代表开盘价
Open H:代表最高价
High L: 代表最低价
Low C: 代表收盘价

OHLC图是显示特定时间段的开盘价,最高价,最低价和收盘价的任何类型的价格图。开盘-高-低-收盘图表(或OHLC图)用作交易工具来可视化和分析证券,货币,股票,债券,商品等随时间的价格变化。

OHLC图可解释当日价格-当今市场的情绪,并通过产生的模式预测未来的价格变化。

OHLC图上的y轴用于价格标度,而x轴是时间标度。在每个单个时间段上,OHLC图都会绘制一个代表两个范围的符号:最高和最低交易价格,以及该单个时间段(例如一天)中的开盘价和收盘价。

在范围符号上,高和低价格范围由主垂直线的长度表示。开盘价和收盘价由刻度线的垂直位置表示,这些刻度线出现在高低垂直线的左侧(代表开盘价)和右侧(代表收盘价)。

可以为每个OHLC图符号分配颜色,以区分市场是“看涨”(收盘价高于开盘价)还是“看涨”(收盘价低于开盘价)。

# 2008六月的OHLC图
trace = go.Ohlc(x=google['06-2008'].index,
                open=google['06-2008'].Open,
                high=google['06-2008'].High,
                low=google['06-2008'].Low,
                close=google['06-2008'].Close)
data = [trace]
iplot(data, filename='simple_ohlc')
# 2008年OHLC图
trace = go.Ohlc(x=google['2008'].index,
                open=google['2008'].Open,
                high=google['2008'].High,
                low=google['2008'].Low,
                close=google['2008'].Close)
data = [trace]
iplot(data, filename='simple_ohlc')
# 2006-2018年OLHC图
trace = go.Ohlc(x=google.index,
                open=google.Open,
                high=google.High,
                low=google.Low,
                close=google.Close)
data = [trace]
iplot(data, filename='simple_ohlc')

2.7 蜡烛图

这种图表用作交易工具,以可视化和分析证券,衍生工具,货币,股票,债券,商品等随时间的价格变动。尽管烛台图中使用的符号类似于箱形图,但它们的功能不同,不要彼此混淆。

蜡烛图通过使用类似烛台的符号来显示价格信息的多个维度,例如开盘价收盘价最高价最低价。每个符号代表单个时间段(分钟,小时,天,月等)的交易活动。每个烛台符号均沿时间轴绘制在x轴上,以显示一段时间内的交易活动。

蜡烛符号中的主要矩形称为real body,用于显示该时间段的开盘价和收盘价之间的范围。从实体的底部和顶部延伸的线被称为上下阴影(或灯芯)。每个阴影代表所表示的时间段内交易的最高或最低价格。当市场看涨(收盘价高于开盘价)时,机构的颜色通常为白色或绿色。但是,当市场看跌(收盘价低于开盘价)时,机构通常会被涂成黑色或红色。


蜡烛图非常适合检测和预测一段时间内的市场趋势,并且通过每个蜡烛符号的颜色和形状来解释市场的日常情绪很有用。例如,身体越长,销售或购买压力就越大。虽然这是一个非常短的主体,但这表明该时间段内价格变动很小。

蜡烛图通过各种指标(例如形状和颜色)以及烛台图表中可以找到的许多可识别模式,帮助揭示市场心理(买卖双方所经历的恐惧和贪婪)。总共有42种公认的模式,分为简单模式和复杂模式。烛台图表中的这些模式对于显示价格关系很有用,并可用于预测市场的未来走势。您可以在此处找到每个模式的列表和说明。

请记住,蜡烛图不表示开盘价和收盘价之间发生的事件,仅表示两种价格之间的关系。 因此,您无法确定在那个时间段内交易的波动性。

Source: Datavizcatalogue

# 2008三月蜡烛图
trace = go.Candlestick(x=google['03-2008'].index,
                open=google['03-2008'].Open,
                high=google['03-2008'].High,
                low=google['03-2008'].Low,
                close=google['03-2008'].Close)
data = [trace]
iplot(data, filename='simple_candlestick')
# 2008蜡烛图
trace = go.Candlestick(x=google['2008'].index,
                open=google['2008'].Open,
                high=google['2008'].High,
                low=google['2008'].Low,
                close=google['2008'].Close)
data = [trace]
iplot(data, filename='simple_candlestick')
# 2006-2018蜡烛图
trace = go.Candlestick(x=google.index,
                open=google.Open,
                high=google.High,
                low=google.Low,
                close=google.Close)
data = [trace]
iplot(data, filename='simple_candlestick')

2.8 自回归系数Autocorrelation与偏自回归系数Partial Autocorrelation

  • 自回归系数Autocorrelation - 自相关函数(ACF)可测量序列在不同滞后情况下,与其自身的相关关系。
  • 偏自回归系数Partial Autocorrelation - 偏自相关函数在另一角度上可以解释为该序列相对于其过去滞后值的做回归后的回归系数。可以用与标准线性回归相同的方式解释这些术语,即:在使其他滞后(lags)保持不变的同时,特定滞后变化的贡献。

Source: Quora

自回归系数Autocorrelation

# Google股票自回归系数
plot_acf(google.High,lags=365,title="Lag=365的自回归系数")
plt.show()

偏自回归系数Partial Autocorrelation

# google票价偏自回归系数
plot_pacf(google.High,lags=365)
plt.show()
# 微软收盘价的PACF
plot_pacf(microsoft["Close"],lags=25)
plt.show()

在此,只有第0,第1和第20个滞后在统计上是有显著的。

3. 时间序列分解与随机游走

3.1. 趋势、季节性与噪声

这些是时间序列的组成部分

  • 趋势 - 时间序列的向上或向下一致的斜率
  • 季节性 - 时间序列的清晰周期性模式(例如正弦函数)
  • 噪声 - 离群值或缺失值
google["High"].plot(figsize=(16,8))
# 现在我们分解它
rcParams['figure.figsize'] = 11, 9
decomposed_google_volume = sm.tsa.seasonal_decompose(google["High"],freq=360) 
figure = decomposed_google_volume.plot()
plt.show()

从上面的分解图我们可以看到:

  • 上图中明显有上升趋势。
  • 还可以看到统一的季节性变化。
  • 代表异常值和缺失值的非均匀噪声

3.2. 白噪声

白噪声具有如下性质:

  • 恒定均值
  • 恒定方差
  • 所有滞后之间的相关关系均为0
# 画出白噪声
rcParams['figure.figsize'] = 16, 6
white_noise = np.random.normal(loc=0, scale=1, size=1000)
# 以上:loc表示期望,scale表示方差
plt.plot(white_noise)
# 白噪声之间的自相关系数图
plot_acf(white_noise,lags=20)
plt.show()

所有滞后在置信区间(阴影部分)内,在统计上不显著

3.3. 随机游走

随机游走是一种数学对象,它描述由某些数学空间(例如整数)上的一系列随机步长构成的路径。

总的来说我们在谈论股票的时候:

今日股价 = 前一天的股价 + 噪声

P_t = P_{t-1}+\epsilon_t

随机游走是不能很好地被预测的,因为噪声具有随机性。

有漂移的随机游走

(漂移 \mu 具有0均值的特性)

P_t - P_{t-1} = \mu + \epsilon_t

相关的统计检验

P_t = \alpha + \beta P_{t-1} + \epsilon_t

上面的式子等价于 P_t - P_{t-1} = \alpha + \beta P_{t-1} + \epsilon_t

Test:

  • H_0: \beta = 1 (这是随机游走)
  • H_1: \beta < 1 (这不是随机游走)

Dickey-Fuller Test:

  • H_0: \beta = 0 (这是随机游走)
  • H_1: \beta < 0 (这不是随机游走)

Augmented Dickey-Fuller test

Augmented Dickey-Fuller Test 是一种统计学的检测方法,用于检测一个有某种趋势的时间序列的平稳性。是一种重要的单根检测方法。
其初始假设null hypothesis是该序列不稳定(存在单位根),检测可以有两种途径:

  • 一是统计量小于特定拒绝域值;
  • 二是p-value大于相应域值。如果是,则拒绝假设,认为序列是稳定的。
# 对谷歌和微软股票交易量进行Augmented Dickey-Fuller检验
adf = adfuller(microsoft["Volume"])
print("p-value of microsoft: {}".format(float(adf[1])))
adf = adfuller(google["Volume"])
print("p-value of google: {}".format(float(adf[1])))
p-value of microsoft: 0.00032015252776520505
p-value of google: 6.510719605768349e-07

因为微软的 p-value 为 0.0003201525 小于 0.05, 所以拒绝H_0,我们有充足理由认为它不是随机游走.

因为谷歌的 p-value 0.0000006510 小于 0.05, 所以拒绝H_0,我们有充足理由认为它不是随机游走.

生成随机游走

seed(42)
rcParams['figure.figsize'] = 16, 6

# 从高斯分布生成随机数
random_walk = normal(loc=0, scale=0.01, size=1000)
plt.plot(random_walk)
plt.show()
fig = ff.create_distplot([random_walk],['Random Walk'],bin_size=0.001)
iplot(fig, filename='Basic Distplot')

3.4 平稳性

平稳时间序列是一种统计特性,例如均值,方差,自相关等不论时间怎么变化,他们都是恒定的。

  • 强平稳性:是一个随着时间的推移,其无条件联合概率分布不会改变的随机过程。 因此,诸如均值和方差之类的参数也不会随时间变化而变化。其条件性非常强,一般很难满足。

  • 弱平稳性:在整个过程中,均值,方差,自相关都是“恒定”的过程

平稳性很重要,因为依赖时间的非平稳序列具有太多的参数,无法在对时间序列建模时考虑到。

diff()(差分)方法可以轻松地将非平稳序列转换为平稳序列。

我们将尝试解析出上述分解后的时间序列中的季节成分。

# 绘制原始的非平稳时间序列
decomposed_google_volume.trend.plot()
# 新的平稳的时间序列(使用diff()做了一阶差分)
decomposed_google_volume.trend.diff().plot()

4. 用统计工具建模

建议记住统计模型的英文名称即可,不必纠结其中文译名

4.1 AR 模型

自回归模型(AR)模型是一种随机过程的表示; 因此,自回归模型指定输出变量线性地依赖于其自身的先前值随机项(一个不完全可预测的项)。 因此该模型采用随机差分方程的形式来表示。

AR(1)

R_t = \mu + \phi R_{t-1} + \epsilon_t

由于公式右边只有一阶滞后项(R_{t-1}),这也成为在时间 t 的一阶 AR模型,其中 \mu 是常数而 \epsilon 是随机游走

如果 \phi = 1, 那么它是随机游走.

如果 \phi = 0, 它是白噪声.

如果 -1 < \phi < 1, 它是平稳的.

如果 \phi 是 -ve, 存在均值回归.

如果 \phi 是 +ve, 存在动量.

AR(2)

R_t = \mu + \phi_1 R_{t-1} + \phi_2 R_{t-2} + \epsilon_t

AR(3)

R_t = \mu + \phi_1 R_{t-1} + \phi_2 R_{t-2} + \cdots + \phi_p R_{t-p} + \epsilon_t

模拟 AR(1) 过程

# AR(1) model:AR parameter = +0.9
rcParams['figure.figsize'] = 16, 12
plt.subplot(4,1,1)
ar1 = np.array([1, -0.9]) # We choose -0.9 as AR parameter is +0.9
ma1 = np.array([1])
AR1 = ArmaProcess(ar1, ma1)
sim1 = AR1.generate_sample(nsample=1000)
plt.title('AR(1) model: AR parameter = +0.9')
plt.plot(sim1)
# 后面会介绍MA(q)模型
# AR(1) MA(1) AR parameter = -0.9
plt.subplot(4,1,2)
ar2 = np.array([1, 0.9]) # We choose +0.9 as AR parameter is -0.9
ma2 = np.array([1])
AR2 = ArmaProcess(ar2, ma2)
sim2 = AR2.generate_sample(nsample=1000)
plt.title('AR(1) model: AR parameter = -0.9')
plt.plot(sim2)
# AR(2) MA(1) AR parameter = 0.9
plt.subplot(4,1,3)
ar3 = np.array([2, -0.9]) # 我们选择 -0.9 作为 AR 参数: +0.9
ma3 = np.array([1])
AR3 = ArmaProcess(ar3, ma3)
sim3 = AR3.generate_sample(nsample=1000)
plt.title('AR(2) model: AR parameter = +0.9')
plt.plot(sim3)
# AR(2) MA(1) AR parameter = -0.9
plt.subplot(4,1,4)
ar4 = np.array([2, 0.9]) # 我们选择 +0.9 作为 AR 参数: -0.9
ma4 = np.array([1])
AR4 = ArmaProcess(ar4, ma4)
sim4 = AR4.generate_sample(nsample=1000)
plt.title('AR(2) model: AR parameter = -0.9')
plt.plot(sim4)
plt.show()

预测

model = ARMA(sim1, order=(1,0))
result = model.fit()
print(result.summary())
print("μ={} ,ϕ={}".format(result.params[0],result.params[1]))

                              ARMA Model Results                              
==============================================================================
Dep. Variable:                      y   No. Observations:                 1000
Model:                     ARMA(1, 0)   Log Likelihood               -1415.701
Method:                       css-mle   S.D. of innovations              0.996
Date:                Wed, 16 Oct 2019   AIC                           2837.403
Time:                        05:23:12   BIC                           2852.126
Sample:                             0   HQIC                          2842.998
                                                                              
==============================================================================
                 coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------
const          0.7072      0.288      2.454      0.014       0.142       1.272
ar.L1.y        0.8916      0.014     62.742      0.000       0.864       0.919
                                    Roots                                    
=============================================================================
                  Real          Imaginary           Modulus         Frequency
-----------------------------------------------------------------------------
AR.1            1.1216           +0.0000j            1.1216            0.0000
-----------------------------------------------------------------------------
μ=0.707201867170821 ,ϕ=0.8915815672242373

\phi 在 0.9 附近,我们可以选其作为我们AR模型的参数。

预测模型

# Predicting simulated AR(1) model 
result.plot_predict(start=900, end=1010)
plt.show()
rmse = math.sqrt(mean_squared_error(sim1[900:1011], result.predict(start=900,end=999)))
print("The root mean squared error is {}.".format(rmse))
The root mean squared error is 1.0408054564799076.

y 是预测结果的可视化

# 预测Minneapolis的气压水平
humid = ARMA(pressure['Minneapolis'].diff().iloc[2:].values, order=(1,0))
res = humid.fit()
res.plot_predict(start=1000, end=1100)
plt.show()

再试试谷歌股票

# Predicting closing prices of google
humid = ARMA(google["Close"].diff().iloc[1:].values, order=(1,0))
res = humid.fit()
res.plot_predict(start=900, end=1010)
plt.show()

也许会有更好的模型

4.2 MA 模型

即移动平均模型 (MA) model专门针对单变量时间序列建模。

移动平均模型指定输出变量线性地取决于随机(不完全可预测)项的当前值和各种过去值。

MA(1)

R_t = \mu + \epsilon_t + \theta \epsilon_{t-1}

可理解为 今日回报 = 均值 + 今日噪声 + 前一天的噪声

因为等式右边只有一阶滞后项, 所以此为一阶MA过程。

模拟 MA(1)

rcParams['figure.figsize'] = 16, 6
ar1 = np.array([1])
ma1 = np.array([1, -0.5])
MA1 = ArmaProcess(ar1, ma1)
sim1 = MA1.generate_sample(nsample=1000)
plt.plot(sim1)

预测模拟的 MA 模型

model = ARMA(sim1, order=(0,1))
result = model.fit()
print(result.summary())
print("μ={} ,θ={}".format(result.params[0],result.params[1]))
                              ARMA Model Results                              
==============================================================================
Dep. Variable:                      y   No. Observations:                 1000
Model:                     ARMA(0, 1)   Log Likelihood               -1423.276
Method:                       css-mle   S.D. of innovations              1.004
Date:                Wed, 16 Oct 2019   AIC                           2852.553
Time:                        05:30:51   BIC                           2867.276
Sample:                             0   HQIC                          2858.148
                                                                              
==============================================================================
                 coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------
const         -0.0228      0.014     -1.652      0.099      -0.050       0.004
ma.L1.y       -0.5650      0.027    -20.797      0.000      -0.618      -0.512
                                    Roots                                    
=============================================================================
                  Real          Imaginary           Modulus         Frequency
-----------------------------------------------------------------------------
MA.1            1.7699           +0.0000j            1.7699            0.0000
-----------------------------------------------------------------------------
μ=-0.022847164219747917 ,θ=-0.5650012133945569

用 MA 模型做预测

model = ARMA(pressure['Minneapolis'].diff().iloc[2:].values, order=(0,3))
result = model.fit()
print(result.summary())
print("μ={} ,θ={}".format(result.params[0],result.params[1]))
result.plot_predict(start=1000, end=1100)
plt.show()
                              ARMA Model Results                              
==============================================================================
Dep. Variable:                      y   No. Observations:                 1883
Model:                     ARMA(0, 3)   Log Likelihood               -5242.754
Method:                       css-mle   S.D. of innovations              3.915
Date:                Wed, 16 Oct 2019   AIC                          10495.508
Time:                        05:31:42   BIC                          10523.212
Sample:                             0   HQIC                         10505.712
                                                                              
==============================================================================
                 coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------
const          0.0003      0.026      0.010      0.992      -0.050       0.050
ma.L1.y    -1.101e-06      0.018  -6.06e-05      1.000      -0.036       0.036
ma.L2.y    -1.162e-06      0.018  -6.39e-05      1.000      -0.036       0.036
ma.L3.y       -0.7176      0.027    -26.450      0.000      -0.771      -0.664
                                    Roots                                    
=============================================================================
                  Real          Imaginary           Modulus         Frequency
-----------------------------------------------------------------------------
MA.1           -0.5585           -0.9673j            1.1170           -0.3333
MA.2           -0.5585           +0.9673j            1.1170            0.3333
MA.3            1.1170           -0.0000j            1.1170           -0.0000
-----------------------------------------------------------------------------
μ=0.0002522391526654763 ,θ=-1.1005662984144147e-06
image
rmse = math.sqrt(mean_squared_error(pressure['Minneapolis'].diff().iloc[1000:1101].values, result.predict(start=1000,end=1100)))
print("The root mean squared error is {}.".format(rmse))
The root mean squared error is 3.0713710764189415.

4.3 ARMA 模型

自回归移动平均模型 (ARMA) 用两个多项式来简要描述(弱)平稳随机过程,一个多项式用于自回归,第二个多项式用于移动平均值。 它是AR和MA模型的融合。

ARMA(1,1)

R_t = \mu + \phi R_{t-1} + \epsilon_t + \theta \epsilon_{t-1}

基本上

今日回报 = 均值 + 前一天的回报 + 噪声 + 昨天的噪声

使用 ARMA 作预测

# 预测Microsoft库存量
model = ARMA(microsoft["Volume"].diff().iloc[1:].values, order=(3,3))
result = model.fit()
print(result.summary())
print("μ={}, ϕ={}, θ={}".format(result.params[0],result.params[1],result.params[2]))
result.plot_predict(start=1000, end=1100)
plt.show()
                              ARMA Model Results                              
==============================================================================
Dep. Variable:                      y   No. Observations:                 3018
Model:                     ARMA(3, 3)   Log Likelihood              -55408.974
Method:                       css-mle   S.D. of innovations       22751608.082
Date:                Wed, 16 Oct 2019   AIC                         110833.948
Time:                        05:32:58   BIC                         110882.047
Sample:                             0   HQIC                        110851.244
                                                                              
==============================================================================
                 coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------
const       -2.03e+04   9915.585     -2.047      0.041   -3.97e+04    -863.030
ar.L1.y        0.2053      0.160      1.287      0.198      -0.107       0.518
ar.L2.y        0.7297      0.179      4.081      0.000       0.379       1.080
ar.L3.y       -0.1413      0.057     -2.467      0.014      -0.254      -0.029
ma.L1.y       -0.8117      0.157     -5.166      0.000      -1.120      -0.504
ma.L2.y       -0.7692      0.258     -2.979      0.003      -1.275      -0.263
ma.L3.y        0.5853      0.130      4.494      0.000       0.330       0.841
                                    Roots                                    
=============================================================================
                  Real          Imaginary           Modulus         Frequency
-----------------------------------------------------------------------------
AR.1           -1.1772           +0.0000j            1.1772            0.5000
AR.2            1.1604           +0.0000j            1.1604            0.0000
AR.3            5.1820           +0.0000j            5.1820            0.0000
MA.1           -1.1579           +0.0000j            1.1579            0.5000
MA.2            1.0075           +0.0000j            1.0075            0.0000
MA.3            1.4647           +0.0000j            1.4647            0.0000
-----------------------------------------------------------------------------
μ=-20297.220675944438, ϕ=0.20526115960300076, θ=0.7297015548306405
image
rmse = math.sqrt(mean_squared_error(microsoft["Volume"].diff().iloc[1000:1101].values, result.predict(start=1000,end=1100)))
print("The root mean squared error is {}.".format(rmse))
The root mean squared error is 38038294.04431978.

ARMA 模型展现出了比 AR 与 MA 更好的结果.

4.4 ARIMA 模型

自回归综合移动平均(ARIMA)模型是自回归移动平均(ARMA)模型的概括。

这两个模型都适合于时间序列数据,以更好地理解数据或预测序列中的未来点(预测)。

ARIMA模型适用于数据显示出非平稳特性的某些情况,其可以执行一次或多次差分以消除非平稳性。

ARIMA 模型的形式: ARIMA(p,d,q): p 是 AR 参数, d 是差分参数, q 是 MA 参数。

ARIMA(1,0,0)

等价于一阶自回归模型AR(1)

ARIMA(1,0,1)

等价与ARMA(1,1)

ARIMA(1,1,1)

\Delta y_t = a_1 \Delta y_{t-1} + \epsilon_t + b_1 \epsilon_{t-1}

其中 \Delta y_t = y_t - y_{t-1}

使用 ARIMA 做预测

# 预测microsoft股票交易量
rcParams['figure.figsize'] = 16, 6
model = ARIMA(microsoft["Volume"].diff().iloc[1:].values, order=(2,1,0))
result = model.fit()
print(result.summary())
result.plot_predict(start=700, end=1000)
plt.show()
                             ARIMA Model Results                              
==============================================================================
Dep. Variable:                    D.y   No. Observations:                 3017
Model:                 ARIMA(2, 1, 0)   Log Likelihood              -56385.467
Method:                       css-mle   S.D. of innovations       31647215.008
Date:                Wed, 16 Oct 2019   AIC                         112778.933
Time:                        05:33:01   BIC                         112802.981
Sample:                             1   HQIC                        112787.581
                                                                              
==============================================================================
                 coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------
const       9984.0302   2.48e+05      0.040      0.968   -4.75e+05    4.95e+05
ar.L1.D.y     -0.8716      0.016    -53.758      0.000      -0.903      -0.840
ar.L2.D.y     -0.4551      0.016    -28.071      0.000      -0.487      -0.423
                                    Roots                                    
=============================================================================
                  Real          Imaginary           Modulus         Frequency
-----------------------------------------------------------------------------
AR.1           -0.9575           -1.1315j            1.4823           -0.3618
AR.2           -0.9575           +1.1315j            1.4823            0.3618
-----------------------------------------------------------------------------
rmse = math.sqrt(mean_squared_error(microsoft["Volume"].diff().iloc[700:1001].values, result.predict(start=700,end=1000)))
print("The root mean squared error is {}.".format(rmse))
The root mean squared error is 61937614.65140498.

考虑到轻微的滞后,这是一个很好的模型。

4.5 VAR 模型

向量自回归(VAR)是一种随机过程模型,用于捕获多个时间序列之间的线性相互依赖性。

VAR模型通过允许多个evolving variable来概括单变量AR模型。

VAR中的所有变量都以相同的方式进入模型:每个变量都有一个方程式,该方程式根据其自身的滞后值,其他模型变量的滞后值和误差项来解释其演化。

VAR建模不需要像具有联立方程的结构模型那样,需要了解背后有什么“推力”在影响变量:唯一要求的先验知识是一个假设会在跨时间相互影响的变量列表。

# 预测谷歌和微软的收盘价格
train_sample = pd.concat([google["Close"].diff().iloc[1:],microsoft["Close"].diff().iloc[1:]],axis=1)
model = sm.tsa.VARMAX(train_sample,order=(2,1),trend='c')
result = model.fit(maxiter=1000,disp=False)
print(result.summary())
predicted_result = result.predict(start=0, end=1000)
result.plot_diagnostics()
# 计算误差
rmse = math.sqrt(mean_squared_error(train_sample.iloc[1:1002].values, predicted_result.values))
print("The root mean squared error is {}.".format(rmse))

                           Statespace Model Results                           
==============================================================================
Dep. Variable:     ['Close', 'Close']   No. Observations:                 3018
Model:                     VARMA(2,1)   Log Likelihood              -12184.882
                          + intercept   AIC                          24403.764
Date:                Wed, 16 Oct 2019   BIC                          24505.974
Time:                        05:33:18   HQIC                         24440.517
Sample:                             0                                         
                               - 3018                                         
Covariance Type:                  opg                                         
===================================================================================
Ljung-Box (Q):                77.46, 79.29   Jarque-Bera (JB):   48076.50, 14930.54
Prob(Q):                        0.00, 0.00   Prob(JB):                   0.00, 0.00
Heteroskedasticity (H):         3.31, 1.62   Skew:                      1.15, -0.03
Prob(H) (two-sided):            0.00, 0.00   Kurtosis:                 22.42, 13.90
                           Results for equation Close                          
===============================================================================
                  coef    std err          z      P>|z|      [0.025      0.975]
-------------------------------------------------------------------------------
const           0.3663      0.290      1.265      0.206      -0.201       0.934
L1.Close       -0.3546      0.534     -0.664      0.507      -1.402       0.693
L1.Close       -0.0416      5.614     -0.007      0.994     -11.044      10.961
L2.Close        0.0126      0.034      0.375      0.707      -0.053       0.079
L2.Close        0.3345      0.443      0.755      0.450      -0.533       1.203
L1.e(Close)     0.3946      0.534      0.739      0.460      -0.652       1.441
L1.e(Close)    -0.2233      5.642     -0.040      0.968     -11.281      10.835
                           Results for equation Close                          
===============================================================================
                  coef    std err          z      P>|z|      [0.025      0.975]
-------------------------------------------------------------------------------
const           0.0185      0.028      0.656      0.512      -0.037       0.074
L1.Close        0.0316      0.053      0.591      0.554      -0.073       0.136
L1.Close       -0.3797      0.613     -0.619      0.536      -1.582       0.822
L2.Close        0.0016      0.004      0.450      0.653      -0.005       0.009
L2.Close       -0.0433      0.044     -0.986      0.324      -0.129       0.043
L1.e(Close)    -0.0293      0.053     -0.549      0.583      -0.134       0.075
L1.e(Close)     0.3336      0.614      0.544      0.587      -0.869       1.536
                                Error covariance matrix                                 
========================================================================================
                           coef    std err          z      P>|z|      [0.025      0.975]
----------------------------------------------------------------------------------------
sqrt.var.Close           6.9016      0.041    167.252      0.000       6.821       6.982
sqrt.cov.Close.Close     0.2924      0.005     57.757      0.000       0.282       0.302
sqrt.var.Close           0.4809      0.003    163.163      0.000       0.475       0.487
========================================================================================


The root mean squared error is 3.6743099933249246.
image

4.6.1 SARIMA models

SARIMA模型对于季节性时间序列的建模非常有用,在季节性时间序列中,给定季节的平均值和其他统计数据在各年中都不是平稳的。定义的SARIMA模型是非季节自回归综合移动平均(ARMA)和自回归移动平均(ARIMA)模型的直接扩展

# Predicting closing price of Google'
train_sample = google["Close"].diff().iloc[1:].values
model = sm.tsa.SARIMAX(train_sample,order=(4,0,4),trend='c')
result = model.fit(maxiter=1000,disp=False)
print(result.summary())
predicted_result = result.predict(start=0, end=500)
result.plot_diagnostics()
# calculating error
rmse = math.sqrt(mean_squared_error(train_sample[1:502], predicted_result))
print("The root mean squared error is {}.".format(rmse))
                           Statespace Model Results                           
==============================================================================
Dep. Variable:                      y   No. Observations:                 3018
Model:               SARIMAX(4, 0, 4)   Log Likelihood              -10098.505
Date:                Wed, 16 Oct 2019   AIC                          20217.009
Time:                        05:33:31   BIC                          20277.133
Sample:                             0   HQIC                         20238.629
                               - 3018                                         
Covariance Type:                  opg                                         
==============================================================================
                 coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------
intercept      0.1014      0.047      2.137      0.033       0.008       0.194
ar.L1          0.1878      0.008     24.882      0.000       0.173       0.203
ar.L2          1.1923      0.006    190.557      0.000       1.180       1.205
ar.L3          0.2170      0.007     32.332      0.000       0.204       0.230
ar.L4         -0.9787      0.008   -127.674      0.000      -0.994      -0.964
ma.L1         -0.1934      0.008    -23.486      0.000      -0.210      -0.177
ma.L2         -1.1942      0.007   -166.466      0.000      -1.208      -1.180
ma.L3         -0.2249      0.008    -28.546      0.000      -0.240      -0.209
ma.L4          0.9738      0.008    116.740      0.000       0.957       0.990
sigma2        47.1073      0.408    115.374      0.000      46.307      47.908
===================================================================================
Ljung-Box (Q):                       67.27   Jarque-Bera (JB):             52919.32
Prob(Q):                              0.00   Prob(JB):                         0.00
Heteroskedasticity (H):               3.30   Skew:                             1.21
Prob(H) (two-sided):                  0.00   Kurtosis:                        23.37
===================================================================================

Warnings:
[1] Covariance matrix calculated using the outer product of gradients (complex-step).
The root mean squared error is 4.398362762846205.
plt.plot(train_sample[1:502],color='red')
plt.plot(predicted_result,color='blue')
plt.legend(['Actual','Predicted'])
plt.title('Google Closing prices')
plt.show()

4.6.3 动态因子模型

动态因子模型是用于多元时间序列的灵活模型,其中观察到的内生变量是外生协变量和未观察因子的线性函数,具有向量自回归结构。

未观察到的因素也可能是外部协变量的函数。

因变量方程中的扰动可能是自相关的。

# 预测微软和谷歌的收盘价
train_sample = pd.concat([google["Close"].diff().iloc[1:],microsoft["Close"].diff().iloc[1:]],axis=1)
model = sm.tsa.DynamicFactor(train_sample, k_factors=1, factor_order=2)
result = model.fit(maxiter=1000,disp=False)
print(result.summary())
predicted_result = result.predict(start=0, end=1000)
result.plot_diagnostics()
# 计算误差
rmse = math.sqrt(mean_squared_error(train_sample.iloc[1:1002].values, predicted_result.values))
print("The root mean squared error is {}.".format(rmse))

                                   Statespace Model Results                                  
=============================================================================================
Dep. Variable:                    ['Close', 'Close']   No. Observations:                 3018
Model:             DynamicFactor(factors=1, order=2)   Log Likelihood              -12198.578
Date:                               Wed, 16 Oct 2019   AIC                          24409.156
Time:                                       05:33:39   BIC                          24445.230
Sample:                                            0   HQIC                         24422.128
                                              - 3018                                         
Covariance Type:                                 opg                                         
===================================================================================
Ljung-Box (Q):                77.67, 95.04   Jarque-Bera (JB):   48193.46, 15038.05
Prob(Q):                        0.00, 0.00   Prob(JB):                   0.00, 0.00
Heteroskedasticity (H):         3.36, 1.62   Skew:                      1.14, -0.04
Prob(H) (two-sided):            0.00, 0.00   Kurtosis:                 22.44, 13.94
                          Results for equation Close                          
==============================================================================
                 coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------
loading.f1    -6.9110      1.822     -3.794      0.000     -10.481      -3.341
                          Results for equation Close                          
==============================================================================
                 coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------
loading.f1    -0.2922      0.077     -3.784      0.000      -0.444      -0.141
                        Results for factor equation f1                        
==============================================================================
                 coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------
L1.f1          0.0292      0.021      1.382      0.167      -0.012       0.071
L2.f1          0.0137      0.016      0.865      0.387      -0.017       0.045
                            Error covariance matrix                             
================================================================================
                   coef    std err          z      P>|z|      [0.025      0.975]
--------------------------------------------------------------------------------
sigma2.Close  6.184e-05     25.182   2.46e-06      1.000     -49.355      49.355
sigma2.Close     0.2327      0.045      5.119      0.000       0.144       0.322
================================================================================

Warnings:
[1] Covariance matrix calculated using the outer product of gradients (complex-step).
The root mean squared error is 3.682205152159832.

可供参考文献:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341

推荐阅读更多精彩内容