SARIMA季节项时间序列分析流程+python代码

数据

数据网站:National Aeronautics and Space Administration Goddard Institute for Space Studies
主要分析的是北美陆地表面温度。
训练数据:1990.1-2019.12.
测试数据:2020.1-2020.11
开始只选取了120即10的数据来进行分析,但是到最后发现模型有很多的波动之后,去问老师,老师说这是数据太少导致波动太大造成的,所以建议我们再多训练一些数据。就之后进行模型的定阶而言,至少需要三四百的数据。最后我们选取了360个数据,即30年的数据。
关于模型定阶所需要的阶数,最后展现的lags的选取,老师建议选择
l a g s = n lags=\sqrt{n} lags=n 因为只有这样才会才合理。具体为什么合理,我弄明白之后,回来补充!后来又猜测,应该是大数定律

流程

大致流程:
1、首先画出原始数据的时序图,

2、接着,查看原始时间序列是否稳定,不稳定的话,需要转化成稳定的时间序列;
如果不稳定,可采用一阶12步差分指数平滑法小趋势项法等来消除趋势项和季节项。一般,需要先消除趋势项,再消除季节项。因为趋势项如果不消除,会对后来季节项的去除有影响。
如果时序图呈指数形式增长,则还需要取对数,之后再尝试以上方法来消除趋势项和季节项。
如果方差和自协方差不平稳,使用Box-Cox变换,来使得数据变得平稳。
具体参考第2章 时间序列的预处理

3、尝试使用上面的几种去除趋势项和季节项的方法之后,需要检测你去除的效果。一般需要使用平稳性检验。经常使用的是单位根检验,即ADF检验,之后直接掉包即可。还有DF检验、PP检验。具体参考:单位根检验

4、白噪声检验。在进行平稳性的检验之后,还需要继续对消除趋势项和季节项之后的序列进行白噪声检验。因为一旦在进行两步处理之后,你的时间序列就没有了任何的信息,那就不需要分析了,因为我们已经将里面的信息提取完全了(也就是榨干净了)。即,原来的时间序列中只包含趋势项、季节项和随即向(白噪声)。分析终止。

5、若没有通过白噪声检验,则需要进行ARIMA的建模。可能还有其他的时间序列模型,但是我们在这里只分析ARIMA模型,即差分后的ARMA模型。

6、建模首先需要进行模型的定阶。定阶一般使用的是自相关图和偏自相关图。根据AR、MA、ARMA模型分别的自相关系数和偏自相关系数的拖尾性和截尾性来进行判断。
简单写一下

模型自相关系数偏自相关系数
AR拖尾(p阶)截尾
MA(q阶)截尾拖尾
ARMA拖尾拖尾

这里的判断,人工一般是找不到最优的。比如说,在进行MA模型定阶的时候,截尾最大的阶数是12,即查过95%置信区间的是12阶的,但是这里的12阶并不是最优的。所以我们需要使用借助 AIC和BIC准则来进行判断。

一般,当样本容量n比较时,使用AIC;当样本容量n比较时,使用BIC。这里,我们360个数据使用的时BIC 准则。

7、 进行模型定阶之后就可以将原始数据传入到SARIMAX模型中去训练,得到一个模型啦。得到模型之后,主要利用模型来进行预测。在python包中,这个模型(类)中有很多很有用的方法,残差和预测等等 。

流程分割

1 画图

首先读取数据,将原始数据的图画出来,肉眼观察是否是平稳时间序列。
如果是,则直接平稳性检验和白噪声检验步骤;没有则进行下一步。
在这里插入图片描述

2 季节项和周期项的去除

季节项和周期项的去除。
这里面有讲时间序列的预处理。主要介绍了三种办法:1差分,常见的一阶12步消除趋势项和季节项。2、Box-Cox变换。3、结合1和2来去除。
此外,我们课本上还提及到两种办法:1、小趋势项法,2、滑动平均法。
至于具体怎么实现,可以一个个关键字搜索学习。
我使用的方法1,一阶12步差分得到的图形如下:
在这里插入图片描述

3 平稳性检验

主要使用的是ADF,即单位根检验。
原假设 H 0 H_0 H0:存在单位根,即数据是不平稳的。
备择假设 H 1 H_1 H1:不存在单位根,数据平稳。
这里使用的检验方法一般是P-值检验,所以当p小于上面给出的在10%, 5%, 2.5%, 1%时,则拒绝原假设,平稳;否则,不拒绝原假设,数据不平稳。假设检验中的P值

关于原假设和备择假设
平稳性检验和白噪声检验

# 平稳性检验
from statsmodels.tsa.stattools import adfuller
result = adfuller(df.diff(1).dropna().diff(12).dropna())
# result = adfuller(no_season) # 与上面的等价
print(u'一阶12步差分序列的平稳性检验\n', result)

result:

一阶12步差分序列的平稳性检验
 (-9.08927532353749, 3.863646256069488e-15, 14, 332, {'1%': -3.4502011472639724, '5%': -2.8702852297358983, '10%': -2.5714292194077513}, -87.4608194311453)

看到 3.863646256069488e-15 << 0.01 or 0.05
p-value远小于0.01, 0.05
所以拒绝原假设,认为序列非白噪声,可以接着进行下一步。

4 白噪声检验

在消除趋势项(差分、指数平滑、或者小趋势法)之后,看是否是白噪声。
在消除季节项之后,需要进行白噪声检验。
原因:当你进行数据平稳化操作之后,如果是白噪声就不需要进行下面的分析了。即,处理之后所得数据无任何信息。

主要使用LB统计量,即使用Q函数。
H 0 : ρ 1 = ρ 2 = ⋯ = ρ k H_0: \quad \rho_1 = \rho_2 = \cdots =\rho_k H0:ρ1=ρ2==ρk
H 1 : ∃ i , s . t . ρ i ≠ 0 H_1: \quad \exist i, s.t. \rho_i \ne 0 H1:i,s.t.ρi=0
H 0 H_0 H0对应着序列是随机序列; H 1 H_1 H1:序列是不随机的。
同单位根检验,也是使用p值检验。

#白噪声检验
from statsmodels.stats.diagnostic import acorr_ljungbox
print(u'一阶12步序列的白噪声检验结果为:\n', acorr_ljungbox(df.diff(1).dropna().diff(12).dropna(), lags=6)) #返回统计量和p值

result:

一阶12步序列的白噪声检验结果为:
 (array([69.05945861, 69.10660643, 69.12487584, 70.00931964, 70.22520516,
       70.61247787]), array([9.55392347e-17, 9.85578186e-16, 6.57102236e-15, 2.25958202e-14,
       9.19954185e-14, 3.06166120e-13]))

主要看的是输出的第二个array,这里的 9.55392347e-17 << 0.05 ,所以可以拒绝原假设,认为不是白噪声。

5 模型拟合

在我们的模型中,主要是SARIMAX(p, d, q) × (P, D, Q, s).
其中每一个参数代表的意思可以在网上找到。
比如:
Python中的ARIMA模型、SARIMA模型和SARIMAX模型对时间序列预测
时间序列预测,非季节性ARIMA及季节性SARIMA
python 时间序列预测 —— SARIMA
我补充一下自己理解的。
p, d, q并不难理解,课本上一般都有解释,不多说。
P, D, Q, s
P是SAR项的周期性阶数,比如你的数据的周期是12,与此同时,偏自相关系数在24, 36时呈现出周期性,那么就需要将Q值 取为1, 2
D是季节项差分的阶数。一般是取1。
Q时SMA的周期性阶数,同理Q,只不过这时需要看自相关系数了。
s:代表你的周期是多少。比如我上面说的周期为12,则s=12.

6 模型定阶

主要有三种方法:1、利用残差方差图定阶法。2、F检验定阶法。3、准则函数(AIC和BIC准则)定阶法。
这里主要介绍利用AIC和BIC准则进行定阶。

AIC/ BIC 准则

AIC/BIC:是在模型的精度和模型的阶数之间进行的平衡。精度越高,阶数则越大。
我们希望在两者之间找到一个平衡,精度可接受阶数也不是特别大的模型来进行拟合。
两者有一个差别。(上面流程讲过
简单讲。当样本n比较小时,使用AIC准则进行定阶。当样本n比较大时,使用BIC准则进行定阶。具体公式也可以自己百度。定义、性质、适用情况,优缺点。
对上一步提及到的六个参数的选择,找到AIC或者BIC最小的,以这个参数建立模型,来进行拟合。

两个步骤:

  1. 找到各种阶数((p, d, q)×(P, D, Q, S))的上界。
  2. 对((p, d, q)×(P, D, Q, S))的各种组合来拟合模型。找到最小的AIC或者BIC,此为最优的模型。

(这个好像Bayes寻求样本容量呀(ENGS)

一些需要注意的地方:

  1. AIC和BIC可能为负,当模型拟合的方差特别小(<1)时,则可能为负,这是正常的。
  2. 在观察ACF和PACF的图形时,坚定的认为你的序列是MA或者AR模型时,如果在进行模型拟合时,出现AR或者MA的系数为nan的情形,则模型的系数的方差过大。此时应该换一个模型(阶数较小的)来进行拟合。找到方差不为nan,且AIC和BIC为最小的的模型作为最优模型。
  3. 在模型拟合时,若在步骤1中出现模型拟合报错的情形时,应调节参数最大值(一般是降低),再来寻求AIC/BIC的最小值。例如我就出现过MA阶数(12)等于季节项阶数(12)的问题,此时应该调低MA的阶数

生成所有可能参数组合:

from itertools import product
# ARIMA的参数
ps = range(0, 1)
d = range(0, 2)
qs = range(0, 12)
# 季节项相关的参数
Ps = range(0, 1)
D = range(1, 2)
Qs = range(1, 2)
# 将参数打包,传入下面的数据,是哦那个BIC准则进行参数选择
params_list = list(product(ps, d, qs, Ps, D, Qs))
print(params_list)

利用BIC准则找最优的参数:

from statsmodels.tsa.statespace.sarimax import SARIMAX
from tqdm import tqdm_notebook
from statsmodels.tsa.arima_model import ARIMA
import warnings
# 忽视在模型拟合中遇到的错误
warnings.filterwarnings("ignore")
# 找最优的参数 SARIMAX
def find_best_params(data:np.array, params_list):
    result = []
    best_bic = 100000
    for param in tqdm_notebook(params_list):
        # 模型拟合
        # model = SARIMAX(data,order=(param[0], param[1], param[2]),seasonal_order=(param[3], param[4], param[5], 12)).fit(disp=-1)
        model = SARIMAX(data, order=(param[0], param[1], param[2]), seasonal_order=(param[3], param[4], param[5], 12)).fit(disp=-1)
        bicc = model.bic # 拟合出模型的BIC值
        # print(bic)
        # 寻找最优的参数
        if bicc < best_bic:
            best_mode = model
            best_bic = bicc
            best_param = param
        param_1 = (param[0], param[1], param[2])
        param_2 = (param[3], param[4], param[5], 12)
        param = 'SARIMA{0}x{1}'.format(param_1, param_2)
        print(param)
        result.append([param, model.bic])

    result_table = pd.DataFrame(result)
    result_table.columns = ['parameters', 'bic']
    result_table = result_table.sort_values(by='bic',ascending=True).reset_index(drop=True)
    return result_table

result_table = find_best_params(df, params_list)
print(result_table)

在这里插入图片描述
由图可以看出,最优的参数组合为SARIMA(0, 1, 1)×(0, 1, 1, 12).

7 检查残差是否通过检验

为什么要进行残差检验?
因为这可以初步评价你建立模型的好坏。
残差检验主要检验的是什么?
去除了趋势和季节项,进行了ARIMA模型的拟合,剩下的数据应该是没有信息了。这里的残差检验,也就是检验剩下的数据中是否含有信息。如果含有信息,说明我们原来拟合的模型并不好,需要重新建模,从去除季节项和趋势项开始。

这里,进行残差检验:
关于图形检验有四种方法,python使用plot_diagnosis()查看。
1、时序图-------主观判断是否是有趋势或者季节项。
2、直方图-------拟合曲线看是否是正态分布的形状。
3、QQ图-------看是否在一条直线上。
4、自相关图检验-------除了在lags=0的时候,在95%的置信区间之外,其他都在置信区间里面。

画上面4个图

ma1 = SARIMAX(df, order=(0, 1, 1), seasonal_order=(0, 1, 1, 12)).fit(disp=-1)
resid = ma1.resid
fig = ma1.plot_diagnostics(figsize=(15, 12))
fig.savefig(r'.\test.png')

ma1.summary()

得到:
在这里插入图片描述
在这里插入图片描述

或者最直接,用数据表明,就是之前的白噪声检验

#白噪声检验
from statsmodels.stats.diagnostic import acorr_ljungbox
print(acorr_ljungbox(resid, lags=6))

result:

(array([0.04526319, 0.63662314, 1.56695527, 2.54810487, 3.8670859 ,
       4.56834073]), array([0.83152082, 0.72737612, 0.66690548, 0.63604308, 0.56870679,
       0.60024087]))

array([0.83152082, 0.72737612, 0.66690548, 0.63604308, 0.56870679,
0.60024087]) 中所有的数都大于0.05,这里不拒绝白噪声检验的原假设接受原假设,认为是一个残差是一个白噪声序列。

7.1 若通过检验

则转到8 模型的预测,来运用模型。

7.2 若未通过检验

则回到趋势项和季节项的剔除中,继续找寻方法;流程往下走。否则进行模型的评价。

8 模型的预测

predict函数。

# 预测的第一个数据是0,所以去掉第一个数据
import matplotlib.patches as mpatches

data_predict = ma1.predict(1, 371)
# print(data_predict.shape)
# print(data_predict[-11:])
# print(data_predict[-16:-5])
# print(data_predict[-5:])

init_data = pd.read_excel(path, sheet_name='NH.Ts+dSST', header=1, index_col=0).loc[1990:2020, 'Jan':'Dec']
plt.figure(figsize=(12, 8))
init_x = init_data.values.ravel()[:-1]# 最后一个数据是空的
oral_line, = plt.plot(init_x, color="b", label="原始数据")
# plt.fill_betweenx(np.arange(0.0, 2, 0.01), 120, 130, color='yellow', alpha=0.3)

# axvline_li = [0, 119, 120, 130, 131, 135]
axvline_li = [0, 359, 360, 370]
for i in axvline_li:
    plt.axvline(i, color='k', alpha=0.3)

x = list(range(len(data_predict)))
predict_line, = plt.plot(x, data_predict, color='r', label="预测数据")


plt.fill_betweenx(np.arange(0.0, 2, 0.01), 360, 370, color='yellow', alpha=0.3)
# yellow_patch = mpatches.Patch(color="yellow") 
green_patch = mpatches.Patch(color="green") 
plt.legend(fontsize=20, loc='upper left')
handles=[oral_line, predict_line, yellow_patch, green_patch]
labels=["原始数据", "预测数据", "验证区域"]
plt.legend(handles, labels, fontsize=20, loc='upper left')

plt.xticks(list(range(0, len(data_predict), 12)))
# plt.legend(loc='upper right')
plt.show()

result:
在这里插入图片描述

9 模型的评价

画图

1、人为主观判断。将原始数据和预测数据画到一张图上,看重合度如何。
将数据分为训练集和测试集。利用训练好的模型来进行预测。
也就是上面的那张图。

均方差等

2、计算MSE, MAE, R2-score。
参考:python、sklearn实现计算均方误差(MSE)、平均绝对误差(MAE)、决定系数(R2)、调整后的决定系数、皮尔逊相关系数
result:

predict_10 = init_x[-11:]
fact_10 = data_predict[-11:]
from sklearn.metrics import mean_squared_error # 均方误差
from sklearn.metrics import mean_absolute_error # 平方绝对误差
from sklearn.metrics import r2_score # R square
mse = mean_squared_error(predict_10, fact_10)
mae = mean_absolute_error(predict_10, fact_10)
r2s = r2_score(predict_10, fact_10)
print('MSE: ', mse, '\n', 'MAE: ', mae, '\n', 'R square: ', r2s)
# ma1.plot_predict(dynamic=False)

Result:

MSE:  0.032905749669850354 
 MAE:  0.16258440143847938 
 R square:  0.372977053535135

总的代码

Github-time-series-project

参考

时间序列模型 (七): 时间序列建模的基本步骤
【时序】概念理解:时间序列分析(意义)、平稳性(含义、对时序的作用、成分)、自协方差函数这里面有时间序列的课件,可以帮助我们回顾时序知识,相比于我们的教材,太简单了!
National Aeronautics and Space Administration Goddard Institute for Space Studies

第2章 时间序列的预处理
假设检验中的P值
平稳性检验和白噪声检验

Python中的ARIMA模型、SARIMA模型和SARIMAX模型对时间序列预测
时间序列预测,非季节性ARIMA及季节性SARIMA
python 时间序列预测 —— SARIMA
python、sklearn实现计算均方误差(MSE)、平均绝对误差(MAE)、决定系数(R2)、调整后的决定系数、皮尔逊相关系数

  • 47
    点赞
  • 318
    收藏
    觉得还不错? 一键收藏
  • 29
    评论
以下是一个使用Python进行季节差分的示例代码: ```python from numpy import sin, radians import matplotlib.pyplot as plt def difference(dataset, interval=1): diff = list() for i in range(interval, len(dataset)): value = dataset\[i\] - dataset\[i - interval\] diff.append(value) return diff def inverse_difference(last_ob, value): return value + last_ob data = \[sin(radians(i)) for i in range(360)\] + \[sin(radians(i)) for i in range(360)\] diff = difference(data, 360) inverted = \[inverse_difference(data\[i\], diff\[i\]) for i in range(len(diff))\] fig, axes = plt.subplots(3, 1) axes\[0\].plot(data) axes\[0\].title.set_text('data') axes\[1\].plot(diff) axes\[1\].title.set_text('diff') axes\[2\].plot(inverted) axes\[2\].title.set_text('inverted') plt.tight_layout() plt.show() ``` 这段代码首先定义了一个数据集`data`,其中包含了一个周期为360的正弦波。然后使用`difference`函数对数据进行季节差分,将差分后的结果存储在`diff`中。接着使用`inverse_difference`函数将差分后的数据复原,得到`inverted`。最后,使用Matplotlib库将原始数据、差分数据和复原数据绘制在三个子图中展示出来。 希望这个代码能够帮助到你! #### 引用[.reference_title] - *1* *3* [时间序列笔记:python中如何用差分消趋势和季节性因素](https://blog.csdn.net/htuhxf/article/details/105354693)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [SARIMA季节时间序列分析流程+python代码](https://blog.csdn.net/qq_35167821/article/details/111958925)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 29
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值