导入包
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
import seaborn as sns
import statsmodels.api as sm
plt.rcParams['font.sans-serif'] = ['Times New Roman']
plt.rcParams['axes.unicode_minus'] = False
问题分析
No module named 'seaborn'
: 安装依赖包!pip install seaborn
No module named 'statsmodels'
: 安装依赖包!pip install statsmodels
from pandas.plotting import register_matplotlib_converters
register_matplotlib_converters()
from matplotlib.font_manager import FontProperties
kaiti = FontProperties("KaiTi", size=16) # 楷体字体
1. 时间序列
1.1 读取数据
df = pd.read_csv('data/stock/600036.xls')
df.head()
outputs:
date\topen\thigh\tlow\tclose\tvol | |
---|---|
0 | 2014/01/20\t6.01\t6.1\t5.92\t5.97\t27537862 |
1 | 2014/01/21\t6.04\t6.18\t5.98\t6.03\t25159216 |
2 | 2014/01/22\t6.06\t6.28\t5.98\t6.2\t50123656 |
3 | 2014/01/23\t6.17\t6.21\t5.99\t6.02\t38634112 |
4 | 2014/01/24\t5.98\t6.06\t5.89\t5.93\t52264196 |
csv文件中以\t作为分隔符,需要重新读入
df = pd.read_csv('data/stock/600036.xls',sep='\t')
df.head()
outputs:
date | open | high | low | close | vol | |
---|---|---|---|---|---|---|
0 | 2014/01/20 | 6.01 | 6.10 | 5.92 | 5.97 | 27537862 |
1 | 2014/01/21 | 6.04 | 6.18 | 5.98 | 6.03 | 25159216 |
2 | 2014/01/22 | 6.06 | 6.28 | 5.98 | 6.20 | 50123656 |
3 | 2014/01/23 | 6.17 | 6.21 | 5.99 | 6.02 | 38634112 |
4 | 2014/01/24 | 5.98 | 6.06 | 5.89 | 5.93 | 52264196 |
df.dtypes
outputs:
date object
open float64
high float64
low float64
close float64
vol int64
dtype: object
由以上结果可以看出,读取的日期为object类型,不是datetime64[ns]
1.2 绘图
# 绘图函数
def plot_df(df, x, y, title="", xlabel='日期', ylabel='股价', dpi=100):
plt.figure(figsize=(16,5), dpi=dpi)
plt.plot(x, y, color='red')
plt.title(title, fontproperties=kaiti)
plt.xlabel(xlabel, fontproperties=kaiti)
plt.ylabel(ylabel, fontproperties=kaiti)
plt.show()
plot_df(df, x=df.index, y=df.close, title='招商银行收盘价')
1.3 绘制日期
df_drug = pd.read_csv('data/a10.csv', parse_dates=['date'], index_col='date')
plot_df(df_drug, x=df_drug.index, y=df_drug.value, title='澳大利亚1992-2008糖尿病药品月销售额',ylabel='销售额')
df_drug.index, df_drug.dtypes
outputs:
(DatetimeIndex(['1991-07-01', '1991-08-01', '1991-09-01', '1991-10-01',
'1991-11-01', '1991-12-01', '1992-01-01', '1992-02-01',
'1992-03-01', '1992-04-01',
...
'2007-09-01', '2007-10-01', '2007-11-01', '2007-12-01',
'2008-01-01', '2008-02-01', '2008-03-01', '2008-04-01',
'2008-05-01', '2008-06-01'],
dtype='datetime64[ns]', name='date', length=204, freq=None),
value float64
dtype: object)
由上述结果可知,此时index为日期
2. 平稳性检验
from statsmodels.tsa.stattools import adfuller, kpss
# 读取数据
df = pd.read_csv('data/a10.csv', parse_dates=['date'])
plot_df(df, x=df.date, y=df.value, title='澳大利亚1992-2008糖尿病药品月销售额',ylabel='销售额')
2.1 ADF检验
ADF检验,也称为单位跟检验
ADF检验原理
要检验的对象是单位根。
对于一阶AR模型,即AR(1)的情况,其模型如下:
$r_t = \alpha_1r_{t-1} + w_t$
- 如果$\alpha_1=1$,那么前一时刻的收益率对当下时刻的影响是100%的,不会减弱;那么就算是很远的某个时刻,当下对它的影响还是不会消除,所以方差受前面所有时刻的影响,是和t相关的,因此不平稳;
- 如果$\alpha_1>1$,那么当前时刻的波动不仅受前面时刻的影响,还被放大了,所以肯定不平稳;
- 只有当$\alpha_1<1$的时候,前面时刻的波动对当前时刻的影响会逐渐减小。此时的自协方差以及自相关系数是一个固定值。这种情况下,序列是平稳的。
对于高阶AR模型也是如此。对于AR(P)阶模型:
$r_t = \sum_{i=1}^{p}(\alpha_ir_{t-i} + w_t)$
如果$\alpha_1~\alpha_P$都小于1,那么这个序列是平稳的;如果存在某一个$\alpha_i>=1$,这个序列就不是平稳的。
要判断$\alpha_1~\alpha_P$是否都小于1,一般利用AR模型的特征方程,如下:
$1-\alpha_1x - \alpha_2x^2 - \alpha_3x^3 - … - \alpha_Px^P = 0$
这个方程有p个根。
检验AR序列是否平稳,就是检验是否存在某个根大于等于1。这个过程叫单位根检验
。
(如果序列平稳,就不存在单位根;否则,就会存在单位根。
)
所以,ADF检验的原假设就是存在单位根,如果得到的显著性检验统计量小于三个置信度(10%,5%,1%),则对应有(90%,95,99%)的把握来拒绝原假设。
result = adfuller(df.value.values, autolag='AIC')
print('ADF Statistic:', result[0])
print('p-value:',result[1])
for key, value in result[4].items():
print('Critial Values:',key, value)
ADF Statistic: 3.14518568930675
p-value: 1.0
Critial Values: 1% -3.465620397124192
Critial Values: 5% -2.8770397560752436
Critial Values: 10% -2.5750324547306476
分析以上结果:
t统计量为3.14518568930675
p值为1.0
t统计量同时大于1%、5%、10%,说明保留原假设,有单位根,序列不平稳。
2.2 KPSS检验
# KPSS Test
result = kpss(df.value.values, regression='c')
print('\nKPSS Statistic: %f' % result[0])
print('p-value: %f' % result[1])
for key, value in result[3].items():
print('Critial Values:',key, value)
KPSS Statistic: 2.013126
p-value: 0.010000
Critial Values: 10% 0.347
Critial Values: 5% 0.463
Critial Values: 2.5% 0.574
Critial Values: 1% 0.739
分析以上结果:
统计量为2.013126
p值为0.01
统计量同时大于1%、2.5%、5%、10%,说明保留原假设,序列不平稳。
2.3 一阶差分
plot_df(df, x=df.date, y=df.value.diff(1), title='澳大利亚1992-2008糖尿病药品月销售额的一阶差分',ylabel='销售额')
# ADF Test
diff_value = df.value.diff(1)
result = adfuller(diff_value[1:].values, autolag='AIC')
print('ADF Statistic:', result[0])
print('p-value:',result[1])
for key, value in result[4].items():
print('Critial Values:',key, value)
# KPSS Test
result = kpss(diff_value[1:].values, regression='c')
print('\nKPSS Statistic: %f' % result[0])
print('p-value: %f' % result[1])
for key, value in result[3].items():
print('Critial Values:',key, value)
ADF Statistic: -2.495172147449788
p-value: 0.11665341686467584
Critial Values: 1% -3.465811691080702
Critial Values: 5% -2.877123351472649
Critial Values: 10% -2.5750770662586864
KPSS Statistic: 0.134106
p-value: 0.100000
Critial Values: 10% 0.347
Critial Values: 5% 0.463
Critial Values: 2.5% 0.574
Critial Values: 1% 0.739
此时ADF检验不平稳,KPSS检验平稳,则趋势平稳,即去除趋势后平稳
2.4 二阶差分
# ADF Test
diff_value = df.value.diff(1).diff(1)
result = adfuller(diff_value[2:].values, autolag='AIC')
print('ADF Statistic:', result[0])
print('p-value:',result[1])
for key, value in result[4].items():
print('Critial Values:',key, value)
# KPSS Test
result = kpss(diff_value[2:].values, regression='c')
print('\nKPSS Statistic: %f' % result[0])
print('p-value: %f' % result[1])
for key, value in result[3].items():
print('Critial Values:',key, value)
ADF Statistic: -10.292304706517312
p-value: 3.5439163585295715e-18
Critial Values: 1% -3.465811691080702
Critial Values: 5% -2.877123351472649
Critial Values: 10% -2.5750770662586864
KPSS Statistic: 0.162690
p-value: 0.100000
Critial Values: 10% 0.347
Critial Values: 5% 0.463
Critial Values: 2.5% 0.574
Critial Values: 1% 0.739
此时ADF检验和KPSS检验均为平稳
2.5 自相关图检验
平稳序列通常具有短期相关性。该性质用自相关系数来描述就是随着延迟期数的增加,平稳序列的自相关系数会很快地衰减向零
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
# 读取数据
df = pd.read_csv('data/a10.csv', parse_dates=['date'], index_col="date")
plt.figure()
ax1 = plt.subplot2grid((2,2), (0,0))
ax2 = plt.subplot2grid((2,2), (0,1))
plot_acf(df.value, ax1)
plot_pacf(df.value, ax2)
- 对于自相关图蓝色区域为误差范围(Error Band),区域内的数据被认为是不显著的。上图中,1-15是显著的。
- PACF只考虑特定周期的相关性,它给了我们很好的确定自相关周期的起点,上图中,比如1,2,3,12,13可作为自相关时间周期的备选。
plt.figure()
ax1 = plt.subplot2grid((2,2), (0,0))
ax2 = plt.subplot2grid((2,2), (0,1))
plot_acf(df.value.diff(1), ax1)
plot_pacf(df.value.diff(1), ax2)
自相关系数衰减到了0
3. 纯随机性检验(白噪声检验)
from statsmodels.stats.diagnostic import acorr_ljungbox
# 读取数据
df = pd.read_csv('data/a10.csv', parse_dates=['date'])
3.1 标准正态分布白噪声
varepsilon_values_1 = np.random.randn(df.shape[0])
plt.figure(figsize=(10, 6))
plt.plot(varepsilon_values_1)
plt.show()
白噪声序列的性质
1.纯随机性
各序列值之间没有任何相关关系,即为 “没有记忆”的序列。
2.方差齐性
根据马尔可夫定理,只有方差齐性假定成立时,用最小二乘法得到的未知参数估计值才是准确的、有效的。
3.2 白噪声检验
result = acorr_ljungbox(varepsilon_values_1, lags=20) # 返回统计量和p值,lags为检验的延迟数
result
outputs:
lb_stat | lb_pvalue | |
---|---|---|
1 | 0.153627 | 0.695093 |
2 | 0.331413 | 0.847295 |
3 | 3.132339 | 0.371668 |
4 | 3.408137 | 0.491983 |
5 | 3.486530 | 0.625427 |
6 | 5.388970 | 0.494976 |
7 | 6.007531 | 0.538870 |
8 | 6.309364 | 0.612622 |
9 | 6.749453 | 0.663186 |
10 | 7.257745 | 0.700909 |
11 | 7.961411 | 0.716756 |
12 | 10.103270 | 0.606901 |
13 | 10.445171 | 0.657189 |
14 | 10.986957 | 0.687060 |
15 | 10.989072 | 0.753369 |
16 | 12.687205 | 0.695476 |
17 | 14.131766 | 0.657754 |
18 | 14.244514 | 0.713018 |
19 | 14.296445 | 0.766144 |
20 | 14.977978 | 0.777666 |
上述中第二列为p值,当p值中最小值大于等于0.05时,说明序列是随机的。
上述中第二列最小值为0.37,说明序列是随机的。
result = acorr_ljungbox(df.value, lags=20) # 返回统计量和p值,lags为检验的延迟数
result
outputs:
lb_stat | lb_pvalue | |
---|---|---|
1 | 175.433787 | 4.813705e-40 |
2 | 339.417587 | 1.978826e-74 |
3 | 491.848576 | 2.787243e-106 |
4 | 640.295836 | 2.939213e-137 |
5 | 784.110251 | 3.167141e-167 |
6 | 918.690676 | 3.419747e-195 |
7 | 1048.308626 | 4.383473e-222 |
8 | 1171.998472 | 1.075302e-247 |
9 | 1291.089683 | 2.599520e-272 |
10 | 1411.387306 | 3.450320e-297 |
11 | 1531.057189 | 0.000000e+00 |
12 | 1664.327467 | 0.000000e+00 |
13 | 1776.570839 | 0.000000e+00 |
14 | 1878.886391 | 0.000000e+00 |
15 | 1973.993523 | 0.000000e+00 |
16 | 2064.957725 | 0.000000e+00 |
17 | 2152.320626 | 0.000000e+00 |
18 | 2234.123711 | 0.000000e+00 |
19 | 2311.147387 | 0.000000e+00 |
20 | 2383.748884 | 0.000000e+00 |
上述结果最小值为0,小于0.5,所以不是随机的。