时间序列 - 快速指南


时间序列 - 简介

时间序列是特定时期内的一系列观察结果。单变量时间序列由单个变量在一段时间内的周期性时间实例处所取的值组成,多变量时间序列由多个变量在一段时间内的相同周期性时间实例处所取的值组成。我们所有人每天都会遇到的时间序列的最简单的例子是一天、一周、一个月或一年的温度变化。

时态数据的分析能够为我们提供有用的见解,了解变量如何随时间变化,或者它如何依赖于其他变量值的变化。可以分析变量与其先前值和/或其他变量的这种关系以进行时间序列预测,并且在人工智能中有许多应用。

时间序列 - 编程语言

对任何编程语言的基本了解对于用户处理或开发机器学习问题至关重要。下面给出了任何想要从事机器学习的人的首选编程语言列表 -

Python

它是一种高级解释性编程语言,快速且易于编码。Python 可以遵循过程式或面向对象的编程范例。各种库的存在使得复杂过程的实现变得更加简单。在本教程中,我们将使用 Python 进行编码,并且将在接下来的章节中讨论对时间序列建模有用的相应库。

与Python类似,R是一种解释型多范式语言,支持统计计算和图形。包的多样性使得在 R 中实现机器学习建模变得更加容易。

爪哇

它是一种解释型面向对象编程语言,以大量的软件包可用性和复杂的数据可视化技术而闻名。

C/C++

这些是编译语言,也是两种最古老的编程语言。这些语言通常更适合将 ML 功能合并到现有应用程序中,因为它们允许您轻松自定义 ML 算法的实现。

MATLAB

MATrix LABoratory 是一种多范式语言,提供了处理矩阵的功能。它允许对复杂问题进行数学运算。它主要用于数值运算,但某些软件包还允许图形多域仿真和基于模型的设计。

其他解决机器学习问题的首选编程语言包括 JavaScript、LISP、Prolog、SQL、Scala、Julia、SAS 等。

时间序列 - Python 库

Python 因其易于编写和易于理解的代码结构以及各种开源库而在进行机器学习的个人中广受欢迎。下面介绍了我们将在接下来的章节中使用的一些此类开源库。

数值模拟

Numerical Python 是一个用于科学计算的库。它适用于 N 维数组对象,并提供基本的数学功能,例如大小、形状、平均值、标准差、最小值、最大值以及一些更复杂的函数,例如线性代数函数和傅里叶变换。随着我们继续本教程,您将了解有关这些的更多信息。

pandas

该库提供了高效且易于使用的数据结构,例如系列、数据框和面板。它增强了Python的功能,从单纯的数据收集和准备到数据分析。Pandas 和 NumPy 这两个库使得对小型到非常大的数据集的任何操作都变得非常简单。要了解有关这些功能的更多信息,请遵循本教程。

科学Py

Science Python 是一个用于科学和技术计算的库。它提供优化、信号和图像处理、积分、插值和线性代数的功能。该库在执行机器学习时非常方便。我们将在本教程中讨论这些功能。

Scikit 学习

该库是一个广泛用于统计建模、机器学习和深度学习的 SciPy 工具包,因为它包含各种可定制的回归、分类和聚类模型。它与 Numpy、Pandas 和其他库配合良好,使其更易于使用。

统计模型

与 Scikit Learn 一样,该库用于统计数据探索和统计建模。它还可以与其他 Python 库配合良好。

Matplotlib

该库用于各种格式的数据可视化,例如线图、条形图、热图、散点图、直方图等。它包含从绘图到标签所需的所有图形相关功能。我们将在本教程中讨论这些功能。

这些库对于开始使用任何类型的数据进行机器学习都非常重要。

除了上面讨论的库之外,另一个对于处理时间序列特别重要的库是 -

约会时间

该库具有两个模块——日期时间和日历,提供了读取、格式化和操作时间所需的所有日期时间功能。

我们将在接下来的章节中使用这些库。

时间序列 - 数据处理和可视化

时间序列是按等距时间间隔索引的观察序列。因此,任何时间序列都应保持顺序和连续性。

我们将使用的数据集是一个多变量时间序列,包含大约一年的每小时数据,用于了解污染严重的意大利城市的空气质量。数据集可以从下面给出的链接下载 - https://archive.ics.uci.edu/ml/datasets/air+quality

有必要确保 -

  • 时间序列是等间隔的,并且

  • 其中没有多余的值或间隙。

如果时间序列不连续,我们可以对其进行上采样或下采样。

显示 df.head()

在[122]中:

import pandas

在[123]中:

df = pandas.read_csv("AirQualityUCI.csv", sep = ";", decimal = ",")
df = df.iloc[ : , 0:14]

在[124]中:

len(df)

输出[124]:

9471

在[125]中:

df.head()

输出[125]:

代码片段

为了预处理时间序列,我们确保数据集中不存在 NaN(NULL) 值;如果有,我们可以用 0 或平均值或之前或之后的值替换它们。替换是比丢弃更好的选择,这样可以保持时间序列的连续性。然而,在我们的数据集中,最后几个值似乎为 NULL,因此删除不会影响连续性。

删除 NaN(非数字)

在[126]中:

df.isna().sum()
Out[126]:
Date             114
Time             114
CO(GT)           114
PT08.S1(CO)      114
NMHC(GT)         114
C6H6(GT)         114
PT08.S2(NMHC)    114
NOx(GT)          114
PT08.S3(NOx)     114
NO2(GT)          114
PT08.S4(NO2)     114
PT08.S5(O3)      114
T                114
RH               114
dtype: int64

在[127]中:

df = df[df['Date'].notnull()]

在[128]中:

df.isna().sum()

输出[128]:

Date             0
Time             0
CO(GT)           0
PT08.S1(CO)      0
NMHC(GT)         0
C6H6(GT)         0
PT08.S2(NMHC)    0
NOx(GT)          0
PT08.S3(NOx)     0
NO2(GT)          0
PT08.S4(NO2)     0
PT08.S5(O3)      0
T                0
RH               0
dtype: int64

时间序列通常绘制为相对于时间的折线图。为此,我们现在将组合日期和时间列并将其从字符串转换为日期时间对象。这可以使用日期时间库来完成。

转换为日期时间对象

在[129]中:

df['DateTime'] = (df.Date) + ' ' + (df.Time)
print (type(df.DateTime[0]))

<类'str'>

在[130]中:

import datetime

df.DateTime = df.DateTime.apply(lambda x: datetime.datetime.strptime(x, '%d/%m/%Y %H.%M.%S'))
print (type(df.DateTime[0]))

<类'pandas._libs.tslibs.timestamps.Timestamp'>

让我们看看温度等一些变量如何随时间变化。

显示地块

在[131]中:

df.index = df.DateTime

在[132]中:

import matplotlib.pyplot as plt
plt.plot(df['T'])

输出[132]:

[<matplotlib.lines.Line2D at 0x1eaad67f780>]
代码片段 4

在[208]中:

plt.plot(df['C6H6(GT)'])

输出[208]:

[<matplotlib.lines.Line2D at 0x1eaaeedff28>]

箱线图是另一种有用的图表,它允许您将有关数据集的大量信息压缩到单个图表中。它显示一个或多个变量的平均值、25% 和 75% 四分位数以及异常值。当异常值数量较少且与平均值相差很大的情况下,我们可以通过将异常值设置为平均值或75%四分位值来消除异常值。

显示箱线图

在[134]中:

plt.boxplot(df[['T','C6H6(GT)']].values)

输出[134]:

{'whiskers': [<matplotlib.lines.Line2D at 0x1eaac16de80>,
   <matplotlib.lines.Line2D at 0x1eaac16d908>,
   <matplotlib.lines.Line2D at 0x1eaac177a58>,
   <matplotlib.lines.Line2D at 0x1eaac177cf8>],
   'caps': [<matplotlib.lines.Line2D at 0x1eaac16d2b0>,
   <matplotlib.lines.Line2D at 0x1eaac16d588>,
   <matplotlib.lines.Line2D at 0x1eaac1a69e8>,
   <matplotlib.lines.Line2D at 0x1eaac1a64a8>],
   'boxes': [<matplotlib.lines.Line2D at 0x1eaac16dc50>,
   <matplotlib.lines.Line2D at 0x1eaac1779b0>],
   'medians': [<matplotlib.lines.Line2D at 0x1eaac16d4a8>,
   <matplotlib.lines.Line2D at 0x1eaac1a6c50>],
   'fliers': [<matplotlib.lines.Line2D at 0x1eaac177dd8>,
   <matplotlib.lines.Line2D at 0x1eaac1a6c18>],'means': []
}
代码片段 5

时间序列 - 建模

介绍

时间序列有 4 个组成部分,如下所示 -

  • 水平- 这是系列变化的平均值。

  • 趋势- 它是变量随时间增加或减少的Behave。

  • 季节性- 这是时间序列的循环Behave。

  • 噪声- 这是由于环境因素而增加的观测误差。

时间序列建模技术

为了捕获这些组件,有许多流行的时间序列建模技术。本节简要介绍每种技术,但我们将在接下来的章节中详细讨论它们 -

朴素的方法

这些是简单的估计技术,例如预测值的值等于时间相关变量的先前值或先前实际值的平均值。这些用于与复杂的建模技术进行比较。

自回归

自动回归根据先前时间段的值来预测未来时间段的值。自回归的预测可能比朴素方法更适合数据,但它可能无法解释季节性。

ARIMA模型

自回归积分移动平均将变量的值建模为先前值和固定时间序列先前时间步的残差误差的线性函数。然而,现实世界的数据可能是非平稳的并且具有季节性,因此开发了Seasonal-ARIMA和Fractional-ARIMA。ARIMA 适用于单变量时间序列,为了处理多变量,引入了 VARIMA。

指数平滑

它将变量的值建模为先前值的指数加权线性函数。该统计模型还可以处理趋势和季节性。

长短期记忆网络

长短期记忆模型 (LSTM) 是一种循环神经网络,用于时间序列以解释长期依赖性。它可以用大量数据进行训练,以捕获多变量时间序列的趋势。

所述建模技术用于时间序列回归。在接下来的章节中,让我们一一探讨这些内容。

时间序列-参数校准

介绍

任何统计或机器学习模型都有一些参数,这些参数极大地影响数据的建模方式。例如,ARIMA 具有 p、d、q 值。这些参数的确定应使实际值与模型值之间的误差最小。参数校准被认为是模型拟合中最关键和最耗时的任务。因此,选择最优参数对我们来说非常重要。

参数校准方法

校准参数的方法有多种。本节详细讨论其中的一些内容。

试一试

校准模型的一种常见方法是手动校准,首先将时间序列可视化,然后直观地尝试一些参数值,然后一遍又一遍地更改它们,直到达到足够好的拟合效果。它需要对我们正在尝试的模型有很好的理解。对于 ARIMA 模型,借助“p”参数的自相关图、“q”参数的部分自相关图和 ADF 测试来完成手动校准,以确认时间序列的平稳性并设置“d”参数。我们将在接下来的章节中详细讨论所有这些。

网格搜索

校准模型的另一种方法是通过网格搜索,这本质上意味着您尝试为所有可能的参数组合构建模型,并选择误差最小的模型。这是耗时的,因此当要校准的参数数量和它们采用的值范围较少时非常有用,因为这涉及多个嵌套的 for 循环。

遗传算法

遗传算法基于生物学原理,即好的解决方案最终会演变成最“最优”的解决方案。它利用变异、交叉和选择等生物学操作,最终达到最优解。

要了解更多知识,您可以阅读其他参数优化技术,例如贝叶斯优化和群体优化。

时间序列 - 朴素方法

介绍

Naïve 方法(例如假设时间“t”的预测值是时间“t-1”变量的实际值或序列的滚动平均值)用于衡量统计模型和机器学习模型的执行效果并强调他们的需要。

在本章中,让我们在时间序列数据的一个特征上尝试这些模型。

首先,我们将看到数据“温度”特征的平均值及其周围的偏差。查看最大和最小温度值也很有用。我们可以在这里使用 numpy 库的功能。

显示统计数据

在[135]中:

import numpy
print (
   'Mean: ',numpy.mean(df['T']), '; 
   Standard Deviation: ',numpy.std(df['T']),'; 
   \nMaximum Temperature: ',max(df['T']),'; 
   Minimum Temperature: ',min(df['T'])
)

我们拥有等间隔时间线上所有 9357 个观测值的统计数据,这对于我们理解数据很有用。

现在我们将尝试第一种朴素方法,将当前时间的预测值设置为等于前一时间的实际值,并计算其均方根误差(RMSE)以量化该方法的性能。

显示第一种简单方法

在[136]中:

df['T']
df['T_t-1'] = df['T'].shift(1)

在[137]中:

df_naive = df[['T','T_t-1']][1:]

在[138]中:

from sklearn import metrics
from math import sqrt

true = df_naive['T']
prediction = df_naive['T_t-1']
error = sqrt(metrics.mean_squared_error(true,prediction))
print ('RMSE for Naive Method 1: ', error)

朴素方法 1 的 RMSE:12.901140576492974

让我们看看下一个简单的方法,其中当前时间的预测值等于其之前时间段的平均值。我们也将计算此方法的 RMSE。

显示第二种简单方法

在[139]中:

df['T_rm'] = df['T'].rolling(3).mean().shift(1)
df_naive = df[['T','T_rm']].dropna()

在[140]中:

true = df_naive['T']
prediction = df_naive['T_rm']
error = sqrt(metrics.mean_squared_error(true,prediction))
print ('RMSE for Naive Method 2: ', error)

朴素方法 2 的 RMSE:14.957633272839242

在这里,您可以尝试不同数量的先前时间段(也称为您想要考虑的“滞后”),此处保留为 3。在此数据中可以看出,随着滞后数量的增加,误差也会增加。如果 lag 保持为 1,则与之前使用的 naïve 方法相同。

注意事项

  • 您可以编写一个非常简单的函数来计算均方根误差。在这里,我们使用了“sklearn”包中的均方误差函数,然后取其平方根。

  • 在 pandas 中,df['column_name'] 也可以写为 df.column_name,但是对于此数据集,df.T 的工作方式与 df['T'] 不同,因为 df.T 是转置数据帧的函数。因此,仅使用 df['T'] 或考虑在使用其他语法之前重命名此列。

时间序列 - 自回归

对于平稳时间序列,自动回归模型将时间“t”处的变量值视为其之前的值“p”个时间步长的线性函数。从数学上来说,它可以写成 -

$$y_{t} = \:C+\:\phi_{1}y_{t-1}\:+\:\phi_{2}Y_{t-2}+...+\phi_{p}y_ {tp}+\epsilon_{t}$$

 

其中,“p”是自回归趋势参数

$\epsilon_{t}$ 是白噪声,并且

$y_{t-1}, y_{t-2}\:\: ...y_{tp}$ 表示变量在之前时间段的值。

p的值可以使用各种方法来校准。找到“p”的适当值的一种方法是绘制自相关图。

注意- 在对数据进行任何分析之前,我们应该以可用总数据的 8:2 比例将数据分为训练和测试,因为测试数据只是为了找出我们模型的准确性,并且假设它不可用于我们直到做出预测之后。对于时间序列,数据点的顺序非常重要,因此在分割数据时应记住不要丢失顺序。

自相关图或相关图显示变量在先前时间步骤与其自身的关系。它利用 Pearson 相关性并显示 95% 置信区间内的相关性。让我们看看数据的“温度”变量是什么样子的。

显示 ACP

在[141]中:

split = len(df) - int(0.2*len(df))
train, test = df['T'][0:split], df['T'][split:]

在[142]中:

from statsmodels.graphics.tsaplots import plot_acf

plot_acf(train, lags = 100)
plt.show()
代码片段 9

假设位于蓝色阴影区域之外的所有滞后值都具有相关性。

时间序列 - 移动平均线

对于平稳时间序列,移动平均模型将时间“t”处的变量值视为其之前“q”个时间步的残差误差的线性函数。通过将时间“t”处的值与之前值的移动平均值进行比较来计算残差。

从数学上来说,它可以写成 -

$$y_{t} = c\:+\:\epsilon_{t}\:+\:\theta_{1}\:\epsilon_{t-1}\:+\:\theta_{2}\:\ epsilon_{t-2}\:+\:...+:\theta_{q}\:\epsilon_{tq}\:$$

其中“q”是移动平均趋势参数

$\epsilon_{t}$ 是白噪声,并且

$\epsilon_{t-1}, \epsilon_{t-2}...\epsilon_{tq}$ 是之前时间段的误差项。

“q”的值可以使用各种方法来校准。找到“q”的适当值的一种方法是绘制部分自相关图。

部分自相关图显示了变量在先前时间步骤中与其自身的关系,并删除了间接相关性,与显示直接相关性和间接相关性的自相关图不同,让我们看看我们的“温度”变量的样子数据。

显示 PACP

在[143]中:

from statsmodels.graphics.tsaplots import plot_pacf

plot_pacf(train, lags = 100)
plt.show()
代码片段 10

部分自相关的读取方式与相关图相同。

时间序列 - ARIMA

我们已经了解,对于平稳时间序列,时间“t”的变量是先前观测值或残差的线性函数。因此,现在是我们将两者结合起来并建立自回归移动平均(ARMA)模型的时候了。

然而,有时时间序列不是平稳的,即序列的统计特性(如均值、方差)随时间变化。到目前为止,我们研究的统计模型假设时间序列是平稳的,因此,我们可以包括一个对时间序列进行差分以使其平稳的预处理步骤。现在,对我们来说重要的是要弄清楚我们正在处理的时间序列是否平稳。

查找时间序列平稳性的各种方法包括寻找时间序列图中的季节性或趋势、检查不同时间段的均值和方差的差异、增强迪基富勒 (ADF) 检验、KPSS 检验、赫斯特指数等。

让我们使用 ADF 测试来看看数据集的“温度”变量是否是平稳时间序列。

在[74]中:

from statsmodels.tsa.stattools import adfuller

result = adfuller(train)
print('ADF Statistic: %f' % result[0])
print('p-value: %f' % result[1])
print('Critical Values:')
for key, value In result[4].items()
   print('\t%s: %.3f' % (key, value))

ADF 统计数据:-10.406056

p 值:0.000000

关键值:

1%:-3.431

5%:-2.862

10%:-2.567

现在我们已经运行了 ADF 测试,让我们解释一下结果。首先,我们将 ADF 统计量与临界值进行比较,较低的临界值告诉我们该序列很可能是非平稳的。接下来,我们看到 p 值。p 值大于 0.05 也表明时间序列是非平稳的。

或者,p 值小于或等于 0.05,或 ADF 统计量小于临界值表明时间序列是平稳的。

因此,我们正在处理的时间序列已经是平稳的。对于平稳时间序列,我们将“d”参数设置为 0。

我们还可以使用 Hurst 指数来确认时间序列的平稳性。

在[75]中:

import hurst

H, c,data = hurst.compute_Hc(train)
print("H = {:.4f}, c = {:.4f}".format(H,c))

H = 0.1660,C = 5.0740

H<0.5表示反持久性Behave,H>0.5表示持久性Behave或趋势序列。H=0.5 显示随机游走/布朗运动。H<0.5 的值,证实我们的序列是平稳的。

对于非平稳时间序列,我们将“d”参数设置为 1。此外,自回归趋势参数“p”和移动平均趋势参数“q”的值是在平稳时间序列上计算的,即通过绘制对时间序列进行差分后的 ACP 和 PACP。

ARIMA 模型的特征是 3 个参数 (p,d,q),现在我们已经清楚了,所以让我们对时间序列进行建模并预测温度的未来值。

在[156]中:

from statsmodels.tsa.arima_model import ARIMA

model = ARIMA(train.values, order=(5, 0, 2))
model_fit = model.fit(disp=False)

在[157]中:

predictions = model_fit.predict(len(test))
test_ = pandas.DataFrame(test)
test_['predictions'] = predictions[0:1871]

在[158]中:

plt.plot(df['T'])
plt.plot(test_.predictions)
plt.show()
代码片段 13

在[167]中:

error = sqrt(metrics.mean_squared_error(test.values,predictions[0:1871]))
print ('Test RMSE for ARIMA: ', error)

测试 ARIMA 的 RMSE:43.21252940234892

时间序列 - ARIMA 的变体

在上一章中,我们已经了解了 ARIMA 模型的工作原理,以及它无法处理季节性数据或多变量时间序列的局限性,因此引入了新模型来包含这些功能。

这里给出了这些新模型的一瞥 -

向量自回归 (VAR)

它是多元平稳时间序列自回归模型的广义版本。它的特点是“p”参数。

矢量移动平均线 (VMA)

它是多元平稳时间序列的移动平均模型的广义版本。它的特征是“q”参数。

向量自回归移动平均线 (VARMA)

它是VAR和VMA的结合,是多元平稳时间序列ARMA模型的推广版本。它的特征是“p”和“q”参数。很像,ARMA 能够通过将“q”参数设置为 0 来充当 AR 模型,通过将“p”参数设置为 0 来充当 MA 模型,VARMA 也能够通过设置“q”参数来充当 VAR 模型作为 0 并通过将“p”参数设置为 0 作为 VMA 模型。

在[209]中:

df_multi = df[['T', 'C6H6(GT)']]
split = len(df) - int(0.2*len(df))
train_multi, test_multi = df_multi[0:split], df_multi[split:]

在[211]中:

from statsmodels.tsa.statespace.varmax import VARMAX

model = VARMAX(train_multi, order = (2,1))
model_fit = model.fit()
c:\users\naveksha\appdata\local\programs\python\python37\lib\site-packages\statsmodels\tsa\statespace\varmax.py:152: 
   EstimationWarning: Estimation of VARMA(p,q) models is not generically robust, 
   due especially to identification issues. 
   EstimationWarning)
c:\users\naveksha\appdata\local\programs\python\python37\lib\site-packages\statsmodels\tsa\base\tsa_model.py:171: 
   ValueWarning: No frequency information was provided, so inferred frequency H will be used. 
  % freq, ValueWarning)
c:\users\naveksha\appdata\local\programs\python\python37\lib\site-packages\statsmodels\base\model.py:508: 
   ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals 
  "Check mle_retvals", ConvergenceWarning)

在[213]中:

predictions_multi = model_fit.forecast( steps=len(test_multi))
c:\users\naveksha\appdata\local\programs\python\python37\lib\site-packages\statsmodels\tsa\base\tsa_model.py:320: 
   FutureWarning: Creating a DatetimeIndex by passing range endpoints is deprecated.  Use `pandas.date_range` instead.
   freq = base_index.freq)
c:\users\naveksha\appdata\local\programs\python\python37\lib\site-packages\statsmodels\tsa\statespace\varmax.py:152: 
   EstimationWarning: Estimation of VARMA(p,q) models is not generically robust, due especially to identification issues.
   EstimationWarning)

在[231]中:

plt.plot(train_multi['T'])
plt.plot(test_multi['T'])
plt.plot(predictions_multi.iloc[:,0:1], '--')
plt.show()

plt.plot(train_multi['C6H6(GT)'])
plt.plot(test_multi['C6H6(GT)'])
plt.plot(predictions_multi.iloc[:,1:2], '--')
plt.show()
代码片段 14

代码片段 14

上面的代码显示了如何使用 VARMA 模型对多元时间序列进行建模,尽管该模型可能不是最适合我们的数据。

具有外生变量的 VARMA (VARMAX)

它是 VARMA 模型的扩展,其中使用称为协变量的额外变量来对我们感兴趣的主要变量进行建模。

季节性自回归综合移动平均线 (SARIMA)

这是 ARIMA 模型处理季节性数据的扩展。它将数据分为季节性和非季节性部分,并以类​​似的方式对它们进行建模。它有 7 个参数,非季节性部分 (p,d,q) 参数与 ARIMA 模型相同,季节性部分 (P,D,Q,m) 参数,其中“m”是季节周期数, P、D、Q 与 ARIMA 模型的参数类似。这些参数可以使用网格搜索或遗传算法来校准。

具有外生变量的 SARIMA (SARIMAX)

这是 SARIMA 模型的扩展,包含外生变量,帮助我们对感兴趣的变量进行建模。

在将变量作为外生变量之前对其进行相关分析可能会很有用。

在[251]中:

from scipy.stats.stats import pearsonr
x = train_multi['T'].values
y = train_multi['C6H6(GT)'].values

corr , p = pearsonr(x,y)
print ('Corelation Coefficient =', corr,'\nP-Value =',p)
Corelation Coefficient = 0.9701173437269858
P-Value = 0.0

皮尔逊相关性显示了两个变量之间的线性关系,为了解释结果,我们首先查看 p 值,如果它小于 0.05,则系数值显着,否则系数值不显着。对于显着性 p 值,相关系数的正值表示正相关,负值表示负相关。

因此,对于我们的数据来说,“温度”和“C6H6”似乎具有高度正相关性。因此,我们将

在[297]中:

from statsmodels.tsa.statespace.sarimax import SARIMAX

model = SARIMAX(x, exog = y, order = (2, 0, 2), seasonal_order = (2, 0, 1, 1), enforce_stationarity=False, enforce_invertibility = False)
model_fit = model.fit(disp = False)
c:\users\naveksha\appdata\local\programs\python\python37\lib\site-packages\statsmodels\base\model.py:508: 
   ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
   "Check mle_retvals", ConvergenceWarning)

在[298]中:

y_ = test_multi['C6H6(GT)'].values
predicted = model_fit.predict(exog=y_)
test_multi_ = pandas.DataFrame(test)
test_multi_['predictions'] = predicted[0:1871]

在[299]中:

plt.plot(train_multi['T'])
plt.plot(test_multi_['T'])
plt.plot(test_multi_.predictions, '--')

输出[299]:

[<matplotlib.lines.Line2D at 0x1eab0191c18>]

与单变量 ARIMA 建模相比,这里的预测现在似乎需要更大的变化。

不用说,只需将相应参数设置为非零值,SARIMAX 就可以用作 ARX、MAX、ARMAX 或 ARIMAX 模型。

分数自回归综合移动平均线 (FARIMA)

有时,我们的级数可能不是平稳的,但与取值 1 的“d”参数进行差分可能会过度差分。因此,我们需要使用小数值对时间序列进行差分。

在数据科学的世界中,没有一种更好的模型,适用于您的数据的模型在很大程度上取决于您的数据集。了解各种模型使我们能够选择一种适用于我们的数据的模型,并尝试该模型以获得最佳结果。结果应该被视为绘图和误差指标,有时一个小误差也可能是不好的,因此,绘制和可视化结果是至关重要的。

在下一章中,我们将讨论另一个统计模型:指数平滑。

时间序列 - 指数平滑

在本章中,我们将讨论时间序列指数平滑所涉及的技术。

简单指数平滑

指数平滑是一种通过为一段时间内的数据分配指数递减的权重来平滑单变量时间序列的技术。

从数学上讲,给定时间 t 时的值的变量在时间 't+1' 的值 y_(t+1|t) 定义为 -

$$y_{t+1|t}\:=\:\alpha y_{t}\:+\:\alpha\lgroup1 -\alpha\rgroup y_{t-1}\:+\alpha\lgroup1-\ alpha\rgroup^{2}\:y_{t-2}\:+\:...+y_{1}$$

其中,$0\leq\alpha\leq1$ 是平滑参数,并且

$y_{1},....,y_{t}$ 是时间 1、2、3、...、t 处的网络流量的先前值。

这是一种对没有明确趋势或季节性的时间序列进行建模的简单方法。但指数平滑也可用于具有趋势和季节性的时间序列。

三重指数平滑

三重指数平滑 (TES) 或 Holt 的 Winter 方法,应用三次指数平滑 - 水平平滑 $l_{t}$、趋势平滑 $b_{t}$ 和季节性平滑 $S_{t}$,其中 $\alpha$ 、$\beta^{*}$ 和 $\gamma$ 作为平滑参数,“m”作为季节性频率,即一年中的季节数。

根据季节性成分的性质,TES 有两​​类 -

  • Holt-Winter 的加法法- 当季节性本质上是加法时。

  • Holt-Winter 的乘法方法- 当季节性本质上是乘法时。

对于非季节时间序列,我们只有趋势平滑和水平平滑,这就是霍尔特线性趋势法。

让我们尝试对数据应用三重指数平滑。

在[316]中:

from statsmodels.tsa.holtwinters import ExponentialSmoothing

model = ExponentialSmoothing(train.values, trend= )
model_fit = model.fit()

在[322]中:

predictions_ = model_fit.predict(len(test))

在[325]中:

plt.plot(test.values)
plt.plot(predictions_[1:1871])

输出[325]:

[<matplotlib.lines.Line2D at 0x1eab00f1cf8>]
代码片段 17

在这里,我们使用训练集对模型进行了一次训练,然后继续进行预测。一种更现实的方法是在一个或多个时间步后重新训练模型。当我们从训练数据“直到时间“t”获得时间“t+1”的预测时,可以使用训练数据“直到时间“t+1”作为实际数据来进行时间“t+2”的下一个预测。然后就知道“t+1”处的值。这种对一个或多个未来步骤进行预测然后重新训练模型的方法称为滚动预测或前向验证。

时间序列 - 向前验证

在时间序列建模中,随着时间的推移,预测变得越来越不准确,因此,当模型可用于进一步预测时,使用实际数据重新训练模型是一种更现实的方法。由于统计模型的训练并不耗时,因此前向验证是获得最准确结果的首选解决方案。

让我们对数据应用一步一步验证,并将其与我们之前获得的结果进行比较。

在[333]中:

prediction = []
data = train.values
for t In test.values:
   model = (ExponentialSmoothing(data).fit())
   y = model.predict()
   prediction.append(y[0])
   data = numpy.append(data, t)

在[335]中:

test_ = pandas.DataFrame(test)
test_['predictionswf'] = prediction

在[341]中:

plt.plot(test_['T'])
plt.plot(test_.predictionswf, '--')
plt.show()
代码片段 18

在[340]中:

error = sqrt(metrics.mean_squared_error(test.values,prediction))
print ('Test RMSE for Triple Exponential Smoothing with Walk-Forward Validation: ', error)
Test RMSE for Triple Exponential Smoothing with Walk-Forward Validation:  11.787532205759442

我们可以看到我们的模型现在表现明显更好。事实上,趋势被如此紧密地遵循,以至于绘图上的预测与实际值重叠。您也可以尝试在 ARIMA 模型上应用前向验证。

时间序列 - 先知模型

2017年,Facebook开源了Prophet模型,能够对日、周、年等具有较强多重季节性的时间序列和趋势进行建模。它具有直观的参数,不太专业的数据科学家可以调整这些参数以获得更好的预测。它的核心是一个加性回归模型,可以检测变化点来对时间序列进行建模。

Prophet 将时间序列分解为趋势 $g_{t}$、季节性 $S_{t}$ 和假期 $h_{t}$ 的组成部分。

$$y_{t}=g_{t}+s_{t}+h_{t}+\epsilon_{t}$$

其中,$\epsilon_{t}$ 是误差项。

google 和 twitter 分别在 R 中引入了类似的时间序列预测包,例如因果影响和异常检测。

时间序列 - LSTM 模型

现在,我们已经熟悉了时间序列的统计建模,但机器学习现在很流行,因此熟悉一些机器学习模型也很有必要。我们将从时间序列领域最流行的模型开始——长短期记忆模型。

LSTM 是一类循环神经网络。因此,在我们学习 LSTM 之前,有必要了解神经网络和循环神经网络。

神经网络

人工神经网络是受生物神经网络启发的连接神经元的分层结构。它不是一种算法,而是各种算法的组合,使我们能够对数据进行复杂的操作。

循环神经网络

它是一类专门用于处理时态数据的神经网络。RNN 的神经元具有细胞状态/记忆,输入根据该内部状态进行处理,这是借助神经网络中的循环来实现的。RNN 中存在“tanh”层的重复模块,允许它们保留信息。然而,不会持续很长时间,这就是我们需要 LSTM 模型的原因。

长短期记忆网络

它是一种特殊的循环神经网络,能够学习数据的长期依赖性。这是因为模型的循环模块具有相互交互的四层组合。

神经网络

上图在黄色框中描绘了四个神经网络层,在绿色圆圈中描绘了逐点运算符,在黄色圆圈中描绘了输入,在蓝色圆圈中描绘了细胞状态。LSTM 模块具有一个单元状态和三个门,使它们能够选择性地学习、忘记或保留每个单元的信息。LSTM 中的单元状态仅允许少量线性交互,从而帮助信息在单元中流动而不被改变。每个单元都有一个输入、输出和一个遗忘门,可以向单元状态添加或删除信息。遗忘门决定使用 sigmoid 函数来忘记先前细胞状态中的哪些信息。输入门分别使用“sigmoid”和“tanh”的逐点乘法运算来控制流向当前单元状态的信息流。最后,输出门决定哪些信息应该传递到下一个隐藏状态

现在我们已经了解了 LSTM 模型的内部工作原理,让我们来实现它。为了理解 LSTM 的实现,我们将从一个简单的例子开始——一条直线。让我们看看,LSTM 是否能够学习直线的关系并进行预测。

首先让我们创建描绘直线的数据集。

在[402]中:

x = numpy.arange (1,500,1)
y = 0.4 * x + 30
plt.plot(x,y)

输出[402]:

[<matplotlib.lines.Line2D at 0x1eab9d3ee10>]
代码片段 19

在[403]中:

trainx, testx = x[0:int(0.8*(len(x)))], x[int(0.8*(len(x))):]
trainy, testy = y[0:int(0.8*(len(y)))], y[int(0.8*(len(y))):]
train = numpy.array(list(zip(trainx,trainy)))
test = numpy.array(list(zip(trainx,trainy)))

现在数据已创建并分为训练和测试。让我们根据回顾周期的值将时间序列数据转换为监督学习数据的形式,回顾周期本质上是预测时间“t”时的值的滞后数。

所以像这样的时间序列 -

time variable_x
t1  x1
t2  x2
 :   :
 :   :
T   xT

当回顾周期为 1 时,转换为 -

x1   x2
x2   x3
 :    :
 :    :
xT-1 xT

在[404]中:

def create_dataset(n_X, look_back):
   dataX, dataY = [], []
   for i in range(len(n_X)-look_back):
      a = n_X[i:(i+look_back), ]
      dataX.append(a)
      dataY.append(n_X[i + look_back, ])
   return numpy.array(dataX), numpy.array(dataY)

在[405]中:

look_back = 1
trainx,trainy = create_dataset(train, look_back)
testx,testy = create_dataset(test, look_back)

trainx = numpy.reshape(trainx, (trainx.shape[0], 1, 2))
testx = numpy.reshape(testx, (testx.shape[0], 1, 2))

现在我们将训练我们的模型。

将小批量的训练数据显示给网络,将整个训练数据分批显示给模型并计算误差的一次运行称为一个时期。纪元将一直运行到错误减少为止。

在 [ ]:

from keras.models import Sequential
from keras.layers import LSTM, Dense

model = Sequential()
model.add(LSTM(256, return_sequences = True, input_shape = (trainx.shape[1], 2)))
model.add(LSTM(128,input_shape = (trainx.shape[1], 2)))
model.add(Dense(2))
model.compile(loss = 'mean_squared_error', optimizer = 'adam')
model.fit(trainx, trainy, epochs = 2000, batch_size = 10, verbose = 2, shuffle = False)
model.save_weights('LSTMBasic1.h5')

在[407]中:

model.load_weights('LSTMBasic1.h5')
predict = model.predict(testx)

现在让我们看看我们的预测是什么样的。

在[408]中:

plt.plot(testx.reshape(398,2)[:,0:1], testx.reshape(398,2)[:,1:2])
plt.plot(predict[:,0:1], predict[:,1:2])

输出[408]:

[<matplotlib.lines.Line2D at 0x1eac792f048>]
代码片段 22

现在,我们应该尝试以类似的方式对正弦波或余弦波进行建模。您可以运行下面给出的代码并使用模型参数来查看结果如何变化。

在[409]中:

x = numpy.arange (1,500,1)
y = numpy.sin(x)
plt.plot(x,y)

输出[409]:

[<matplotlib.lines.Line2D at 0x1eac7a0b3c8>]
代码片段 23

在[410]中:

trainx, testx = x[0:int(0.8*(len(x)))], x[int(0.8*(len(x))):]
trainy, testy = y[0:int(0.8*(len(y)))], y[int(0.8*(len(y))):]
train = numpy.array(list(zip(trainx,trainy)))
test = numpy.array(list(zip(trainx,trainy)))

在[411]中:

look_back = 1
trainx,trainy = create_dataset(train, look_back)
testx,testy = create_dataset(test, look_back)
trainx = numpy.reshape(trainx, (trainx.shape[0], 1, 2))
testx = numpy.reshape(testx, (testx.shape[0], 1, 2))

在 [ ]:

model = Sequential()
model.add(LSTM(512, return_sequences = True, input_shape = (trainx.shape[1], 2)))
model.add(LSTM(256,input_shape = (trainx.shape[1], 2)))
model.add(Dense(2))
model.compile(loss = 'mean_squared_error', optimizer = 'adam')
model.fit(trainx, trainy, epochs = 2000, batch_size = 10, verbose = 2, shuffle = False)
model.save_weights('LSTMBasic2.h5')

在[413]中:

model.load_weights('LSTMBasic2.h5')
predict = model.predict(testx)

在[415]中:

plt.plot(trainx.reshape(398,2)[:,0:1], trainx.reshape(398,2)[:,1:2])
plt.plot(predict[:,0:1], predict[:,1:2])

输出[415]:

[<matplotlib.lines.Line2D at 0x1eac7a1f550>]
代码片段 23

现在您已准备好继续处理任何数据集。

时间序列 - 误差指标

对我们来说,量化模型的性能以将其用作反馈和比较非常重要。在本教程中,我们使用了最流行的误差度量均方根误差之一。还有各种其他可用的错误指标。本章简要讨论它们。

均方误差

它是预测值与真实值之差的平方平均值。Sklearn 将其作为函数提供。它与真实值和预测值的平方具有相同的单位,并且始终为正值。

$$MSE = \frac{1}{n} \displaystyle\sum\limits_{t=1}^n \lgroup y'_{t}\:-y_{t}\rgroup^{2}$$

其中$y'_{t}$ 是预测值,

$y_{t}$ 是实际值,并且

n 是测试集中的值总数。

从方程中可以清楚地看出,MSE 对较大误差或异常值的惩罚更大。

根均方误差

它是均方误差的平方根。它也始终为正值并且在数据范围内。

$$RMSE = \sqrt{\frac{1}{n} \displaystyle\sum\limits_{t=1}^n \lgroup y'_{t}-y_{t}\rgroup ^2}$$

其中,$y'_{t}$为预测值

$y_{t}$ 是实际值,并且

n 是测试集中的值总数。

它具有统一的力量,因此与 MSE 相比更容易解释。对于较大的错误,RMSE 也会受到更大的惩罚。我们在教程中使用了 RMSE 指标。

平均绝对误差

它是预测值与真实值之间的绝对差的平均值。它与预测值和真实值具有相同的单位,并且始终为正值。

$$MAE = \frac{1}{n}\displaystyle\sum\limits_{t=1}^{t=n} | y'{t}-y_{t}\lvert$$

其中,$y'_{t}$为预测值,

$y_{t}$ 是实际值,并且

n 是测试集中的值总数。

平均百分比误差

它是预测值与真实值之间的绝对差值的平均值除以真实值的百分比。

$$MAPE = \frac{1}{n}\displaystyle\sum\limits_{t=1}^n\frac{y'_{t}-y_{t}}{y_{t}}*100\: \%$$

其中,$y'_{t}$为预测值,

$y_{t}$ 是实际值,n 是测试集中的值总数。

然而,使用该误差的缺点是正误差和负误差可以相互抵消。因此使用平均绝对百分比误差。

平均绝对百分比误差

它是预测值与真实值之间的绝对差值的平均值除以真实值的百分比。

$$MAPE = \frac{1}{n}\displaystyle\sum\limits_{t=1}^n\frac{|y'_{t}-y_{t}\lvert}{y_{t}}* 100\:\%$$

其中$y'_{t}$ 是预测值

$y_{t}$ 是实际值,并且

n 是测试集中的值总数。

时间序列 - 应用

我们在本教程中讨论了时间序列分析,这使我们了解到时间序列模型首先从现有观察中识别趋势和季节性,然后根据该趋势和季节性预测值。这种分析在各个领域都很有用,例如 -

  • 财务分析- 包括销售预测、库存分析、股市分析、价格估计。

  • 天气分析- 包括温度估计、气候变化、季节变化识别、天气预报。

  • 网络数据分析- 包括网络使用预测、异常或入侵检测、预测性维护。

  • 医疗保健分析- 包括人口普查预测、保险福利预测、患者监测。

时间序列 - 进一步范围

机器学习处理各种类型的问题。事实上,几乎所有领域都可以借助机器学习实现自动化或改进。下面给出了一些正在进行大量工作的此类问题。

时间序列数据

这是根据时间变化的数据,因此时间在其中起着至关重要的作用,我们在本教程中主要讨论了这一点。

非时间序列数据

它是与时间无关的数据,大部分 ML 问题都涉及非时间序列数据。为了简单起见,我们将其进一步分类为 -

  • 数值数据- 计算机与人类不同,只能理解数字,因此各种数据最终都转换为数值数据以供机器学习使用,例如图像数据转换为(r,b,g)值,字符转换为ASCII码或者单词被索引为数字,语音数据被转换为包含数字数据的 mfcc 文件。

  • 图像数据- 计算机视觉彻底改变了计算机世界,它在医学、卫星成像等领域有各种应用。

  • 文本数据- 自然语言处理 (NLP) 用于文本分类、释义检测和语言摘要。这就是谷歌和 Facebook 变得聪明的原因。

  • 语音数据- 语音处理涉及语音识别和情感理解。它在赋予计算机类似人类的品质方面发挥着至关重要的作用。