Python 用于金融数据分析第9课-----时间序列分析模型
大纲
一、时间序列基础知识
时间序列有一些基本的性质。
1. 趋势
从上图可以看出有个一开始向上,中间静止或者叫水平,后半段向下的趋势,这个趋势需要通过对数据求平均值才会看得更加明显。
虽然有围绕着均值上下波动的偏差,但是从较大的时间尺度上面来看,它仍然是可以看作有明显的趋势的。
2. 季节性
季节性季节性比较好理解,就是值随着月份有着明显的涨落,比如谷歌搜索snowboarding的明显到了冬天就有个明显的飞涨,到了夏天就有明显的回落,重复出现。当然,从图上总体趋势还可以看出搜索snowboarding的量总体上也有个下降。
3. 周期性
周期性周期性跟季节性的区别在于它带有明显的趋势,但没有重复,在上图当中不是季节性,因为并不是一到某个季节值就会有明显的涨落,而是每隔几年就有一次涨落。(这里还有些不理解)
二、statsmodels模块介绍
statsmodels是能够对数据进行建模,预测的工具包,它还能对数据进行假设性检验。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import statsmodels.api as sm
nt=sm.datasets.macrodata.NOTE#datasets模块包含了很多数据集,我们在这里调用macrodata这个数据集,然后查看这个数据集的相关信息
print nt
接下来载入数据集
df=sm.datasets.macrodata.load_pandas().data
df.head()
在这里的意思是说以pandas的形式加载这个macrodata的数据,然后我取加载后的数据(可能是load_pandas之后不只有data这个属性,还有其他的属性)
我们看一下官方文档,可以发现,它的作用是传入开始start和end的日期文本,然后会转换成一系列的datetime序列(可以认为是range函数的日期版),关键是这里的日期缩写是怎么规律?
在这里我们大致可以看到缩写前面一部分是年份,后面字母代表频率,如果是Q则代表季度qurter,字母后面的数字代表开始的节点,如果是1996Q2,代表1996年的第二个季度开始,往后推length个长度的单位。
index=pd.Index(sm.tsa.datetools.dates_from_range('1959Q1', '2009Q3'))
df.index=index
我们发现原始数据的步长都是按照季度来的,因此我们生成按照季度来的时间序列,并将这个序列作为索引,给原始数据对应上
#画出重新设置序列以后的图
df['realgdp'].plot(color='darkgreen', linestyle='dashed')
plt.ylabel('gdp')
使用statsmodel模块得到趋势
Hodrick-Prescott filter能够把趋势和周期性区分开来。趋势用tao_{t}表示,而周期项用zeta_{t}
表示。所以某个时间的值可以用两者的加和表示。
而预测模型的组成由是最小化以下这个二次方损失函数所决定:
gdp_cyclical, gdp_trend=sm.tsa.filters.hpfilter(df['realgdp'])
gdp_trend.head()
打印出的结果是这个。
接下来我们把趋势和原数据都一起作图。
df['gdp_trend']=gdp_trend
df['gdp_cyclical']=gdp_cyclical
df[['realgdp', 'gdp_trend']].plot(figsize=(16, 6), color=['darkgreen', 'red'], linestyle='dashed')
可以看得到趋势和原始数据符合得不错。
还可以通过设置线的颜色和实虚线来突出表示。
df[['realgdp', 'gdp_trend']].plot(figsize=(16, 6), color=['darkgreen', 'red'], style=['-','--'])
三、指数平均化移动平均值EWMA
#导入航班数据
df=pd.read_csv('airline_passengers.csv', index_col='Month', parse_dates=True)
#指定index column,并且尽可能按照日期格式来解析index
df.dropna(inplace=True)#丢掉缺失的行
df.index=pd.to_datetime(df.index)
plt.plot_date(data=df, x=df.index, y='Thousands of Passengers', xdate=True, marker=None, linestyle='solid', color='darkgreen')
小提示,在这里可以通过指定marker为None来消除标记。
SMA
接下来使用简单的移动平均,也就是不引入权重和指数。
df['6_rolling_mean']=df['Thousands of Passengers'].rolling(6).mean()#仍旧是在移动完rolling之后要用聚合函数
df['12_rolling_mean']=df['Thousands of Passengers'].rolling(12).mean()
df.plot(kind='line', color=['darkred', 'darkgreen', 'darkblue'])
以上分别代表原数据,6个月为一个窗口的移动平均值以及12个月为移动窗口的平均值绘图。
EWMA
简单移动平均值具有一些缺点:
- 过小的窗口会受到噪声的影响,而不是反映出真实的信号。
- 移动平均值一直与窗口的大小有关。
- 移动平均值不会达到数据的极值。
- 移动平均值并不会告诉你的未来的发展,它只是告诉你过去的趋势。
-
极端的历史值会影响到现在的移动平均值。
针对以上问题,引入expotentionial weighted moving average,也就是引入为指数项表达的权重,权重的大小除了与窗口有关,也跟当前时间上的远近程度有关,与当前时间相距更远的,权重会更小,可以理解为影响效果会更弱。
表达式如下:
这里的x_{t-i}代表输入(其实我这里也不太懂是什么输入),代表着距离当前时间点t前i个单位的输入的影响,wi就是这个距离为i的权值。
这样以上的公式可以写成:
如果adjust=False,那么就是另外一种计算方式:
相当于使用权重:
在这里其实是类似于之前的ARIMA模型,认为当前值是跟前面的一项有关,并且加上当前的误差项。
具体有进一步的推导,参考这篇文章。
接下来要注意
,alpha可以从以下这些值当中取。
在这里s代表移动平均值所涉及的跨度,c代表移动跨度s的一半,
,h是指权重项衰减到原有的一半的时候所需的时间大小。
代码部分。
df['12_span_ewm']=df['Thousands of Passengers'].ewm(span=12).mean()
df[['12_span_ewm', 'Thousands of Passengers']].plot(style=['--', '-'], color=['darkgreen','darkred'])
可以看得出相对于简单的移动平均值,指数权值化后的移动平均值具有更加明显的季节性,与原有的数据更加贴合。
关于这部分还有很多需要学习的,目前只是入门。
三、ETS模型
我们还可以通过对原始数据按照Error、Trend和Seasonality三部分来分解,具体原理可以参考这篇文章。
ETS模型分为加法和乘法模型,如果趋势Trend是线性增长的关系,那么就用加法模型additive,否则非线性则用multiplicative乘法模型。具体用法是用seasonal_decompose,传入数据,以及对应的模型参数model。
from statsmodels.tsa.seasonal import seasonal_decompose
result=seasonal_decompose(df['Thousands of Passengers'], model='multiplicative')
result.plot()
plt.show()
result包括四部分内容,一个是观察值,趋势,季节性的值还有残差。残差可以认为是trend和观察值之间的差距。