1. Time Series 时间序列简介#

Open In Colab

时间序列预测是根据过去的观测值预测未来值的问题。它可以被定义为监督学习问题,因为它需要发现过去观察到的数据和未来值之间的模式。因此,在本章中,我们将构建一个基于神经网络结构通过监督学习来预测未来值的模型。

时间序列预测是许多领域都需要的技术。最有代表性的例子就是能源领域。发电厂需要预测未来的电力需求,以确保有效的备用电力,城市燃气公司需要未来城市燃气用量预测模型,以针对抄表器故障和抄表作弊采取先发制人的措施。事实上,这些问题也以数据竞赛(电力、城市燃气)(电力, 城市燃气)的形式举办,以发现新的模型。此外,流通领域也对按商品预测销量以实现高效的产品管理感兴趣,还举办了数据竞赛(流通)。

在本教程中,我们将使用约翰·霍普金斯大学系统科学与工程中心提供的冠状病毒确诊病例数据,构建一个模型,根据过去的确诊病例数据来预测未来的确诊病例。在第一章中,我们将了解构建时间序列预测模型时可以使用的神经网络结构,并检查评估模型性能时可以使用的评估指标。在第2章中,我们将通过探索性数据分析加深对确诊的冠状病毒数据的理解,在第3章中,我们将学习如何将时间序列数据转换为监督学习的数据格式。在第 4 章和第 5 章中,我们将使用深度学习模型来预测未来的确诊病例。

1.1可用的深度学习结构#

1.1.1 CNN#

  • 图 1-1 CNN 应用示例(来源:Lim et al. 2020. Time Series Forecasting With Deep Learning: A Survey)

总的来说,CNN是一种在计算机视觉问题上表现出优异性能的网络结构。然而,CNN也可以应用于时间序列预测。使用一维卷积滤波器,可以通过计算输入序列数据之间的加权和来计算作为预测目标的未来值。然而,CNN 结构没有考虑过去和未来数据之间的时间依赖性。

1.1.2 RNN#

  • 图 1-2 RNN 应用示例(来源:Lim et al. 2020.Time Series Forecasting With Deep Learning: A Survey)

RNN 是自然语言处理问题中经常使用的结构,它使用从先前状态积累的隐藏状态信息来预测未来。因此,您可以使用过去的信息来计算未来的预测。然而,如果给定的输入序列太大,可能会出现梯度消失问题,对模型学习产生负面影响。因此,我们主要使用解决问题的LSTM结构,在本教程中我们也将使用LSTM结构。

1.1.3 Attention Mechanism#

  • 图1-3 注意力机制应用示例(来源:Lim et al. 2020. Time Series Forecasting With Deep Learning: A Survey)

当根据过去的信息预测未来时,会有有用和无用的信息。例如,当经销商想要预测周末销售额时,考虑一周前同一天的周末销售额而不是前一天的工作日销售额可能会有所帮助。如果利用注意力机制,这样的预测就成为可能。计算过去每个点对要预测的时间点的影响并在预测未来值时使用。通过给予与您想要预测的时间和过去的值直接相关的值更多的权重,可以实现更准确的预测。

1.2 评价指标#

在本教程中,我们将为确诊的冠状病毒病例建立一个预测模型。由于确诊病例具有连续值,因此可以通过预测值与实际值之间的差异来衡量模型的性能。在本节中,我们将研究计算预测值和实际值之间差异的不同方法。在解释评价指标之前,我们先定义一下各个符号。

\(y_i\): 要预测的实际值
\(\hat{y}_i\): 模型的预测值
\(n\): 测试数据集的大小

从1.2.1节到1.2.4节,使用了上述符号,在1.2.5节中,符号的定义发生了变化,所以请注意。

1.2.1 MAE (Mean Absolute Error)#

\(MAE=\frac{1}{n}\displaystyle\sum_{i=1}^{n} |y_i-\hat{y}_i|\)

MAE,也称为L1 Loss,可以通过取预测值与实际值之间的差值的绝对值相加,然后除以计算出的样本数(n)来获得。由于相加和除以样本数都是求平均值,所以后面的评价指标就采用求平均值的表达式。由于MAE的尺度与被预测的目标变量的尺度相同,有利于直观地理解值的含义。如果用代码实现的话,如下。

import numpy as np 

def MAE(true, pred):
    '''
    true: np.array 
    pred: np.array
    '''
    return np.mean(np.abs(true-pred))

TRUE = np.array([10, 20, 30, 40, 50])
PRED = np.array([30, 40, 50, 60, 70])

MAE(TRUE, PRED)
20.0

1.2.2 MSE (Mean Squared Error)#

\(MSE=\frac{1}{n}\displaystyle\sum_{i=1}^{n} (y_i-\hat{y}_i)^2\)

\(RMSE=\sqrt{\frac{1}{n}\displaystyle\sum_{i=1}^{n} (y_i-\hat{y}_i)^2}\)

MSE,也称为L2 Loss,通过对预测值和实际值之间的差值进行平方,然后求平均值来计算。预测值与实际值的偏差越大,MSE 值呈指数增长就越大。由于计算值是平方的,因此该值的标度与目标变量的标度不同。为了匹配目标变量和尺度,可以将根应用于MSE值,这个值称为RMSE。如果用代码实现的话,如下。

def MSE(true, pred):
    '''
    true: np.array 
    pred: np.array
    '''
    return np.mean(np.square(true-pred))

TRUE = np.array([10, 20, 30, 40, 50])
PRED = np.array([30, 40, 50, 60, 70])

MSE(TRUE, PRED)
400.0

1.2.3 MAPE (Mean Absolute Percentage Error)#

\(MAPE=\frac{1}{n}\displaystyle\sum_{i=1}^{n} |\frac{y_i-\hat{y}_i}{y_i}|\)

(来源: https://en.wikipedia.org/wiki/Mean_absolute_percentage_error)

MAPE通过将实际值与预测值之间的差值除以实际值来计算误差与实际值的相对比例。然后,取绝对值,然后计算平均值。由于误差程度以百分比值表示,因此很容易直观地了解模型的性能,并且当目标变量有多个时,很容易评估模型对每个变量的性能。

然而,如果实际值中存在0,则存在未定义MAPE的问题。此外,即使绝对值误差相同,也存在根据实际值与预测值之间的大小关系对高估预测值施加惩罚的问题(Makridakis,1993)。让我们用下面的代码来检查一下。(Makridakis, 1993).

def MAPE(true, pred):
    '''
    true: np.array 
    pred: np.array
    '''
    return np.mean(np.abs((true-pred)/true))

TRUE_UNDER = np.array([10, 20, 30, 40, 50])
PRED_OVER = np.array([30, 40, 50, 60, 70])
TRUE_OVER = np.array([30, 40, 50, 60, 70])
PRED_UNDER = np.array([10, 20, 30, 40, 50])


print('平均误差为20时实际值和预测值的大小关系对应的MAE、MAPE比较 \n')

print('实际值小于预测值时(预测值高估)')
print('MAE:', MAE(TRUE_UNDER, PRED_OVER))
print('MAPE:', MAPE(TRUE_UNDER, PRED_OVER))


print('\n实际值大于预测值时(预测值低估)')
print('MAE:', MAE(TRUE_OVER, PRED_UNDER))
print('MAPE:', MAPE(TRUE_OVER, PRED_UNDER))
平均误差为20时实际值和预测值的大小关系对应的MAE、MAPE比较 

实际值小于预测值时(预测值高估)
MAE: 20.0
MAPE: 0.9133333333333333

实际值大于预测值时(预测值低估)
MAE: 20.0
MAPE: 0.4371428571428571

由于公式的性质,MAPE 是一个实际值,以便将其转换为百分比。y 我们采取分享的方式。因此,导出的值为y 它具有依赖性特征。即使分子相同,如果分母变小,误差也会增大。

在上面的代码中,我们通过显示( TRUE_UNDER, ) 表明实际值比预测值小 20,而 ( , )PRED_OVER表明实际值比预测值大 20,从而证实了这一点。 、 、 和 的MAE值均等于 20。然而,当实际值为 时, MAPE计算出0.913,当实际值为 时,MAPE 计算出 0.437。TRUE_OVERPRED_UNDERTRUE_UNDERPRED_OVERTRUE_OVERPRED_UNDERTRUE_UNDERTRUE_OVER

1.2.4 SMAPE (Symmetric Mean Absolute Percentage Error)#

\(SMAPE=\frac{100}{n}\displaystyle\sum_{i=1}^{n} \frac{|y_i-\hat{y}_i|}{|y_i| + |\hat{y}_i|}\)

(来源: https://en.wikipedia.org/wiki/Symmetric_mean_absolute_percentage_error)

SMAPE 的开发是为了弥补上述示例中 MAPE 的局限性(Makridakis,1993)。我们用下面的代码来检查一下。(Makridakis, 1993).

def SMAPE(true, pred):
    """
    计算对称平均绝对百分比误差(SMAPE)。

    参数:
    true (numpy.ndarray): 真实值数组。
    pred (numpy.ndarray): 预测值数组。

    返回:
    float: SMAPE值。
    """
    # 计算SMAPE公式的分子
    numerator = np.abs(true - pred)
    # 计算SMAPE公式的分母
    denominator = np.abs(true) + np.abs(pred)
    # 计算SMAPE值
    return np.mean(numerator / denominator)

print('平均误差为20时实际值和预测值的大小关系对应的MAE、SMAPE比较 \n')

print('实际值小于预测值时(预测值高估)')
print('MAE:', MAE(TRUE_UNDER, PRED_OVER))
print('SMAPE:', SMAPE(TRUE_UNDER, PRED_OVER))


print('\n实际值大于预测值时(预测值低估)')
print('MAE:', MAE(TRUE_OVER, PRED_UNDER))
print('SMAPE:', SMAPE(TRUE_OVER, PRED_UNDER))
平均误差为20时实际值和预测值的大小关系对应的MAE、SMAPE比较 

实际值小于预测值时(预测值高估)
MAE: 20.0
SMAPE: 0.29

实际值大于预测值时(预测值低估)
MAE: 20.0
SMAPE: 0.29

您可以看到 MAPE 产生了不同的值 0.91 和 0.43,但 SMAPE 产生了相同的值 0.29。然而,SMAPE 的分母中有预测值。y^i 进去然后y^i 它具有依赖性特征。当预测值被低估时,分母会变小,从而增加计算误差。我们用下面的代码来检查一下。

# 定义真实值数组
TRUE2 = np.array([40, 50, 60, 70, 80])
# 定义预测值数组(低估)
PRED2_UNDER = np.array([20, 30, 40, 50, 60])
# 定义预测值数组(高估)
PRED2_OVER = np.array([60, 70, 80, 90, 100])

print('平均误差为20时,高估和低估情况下的MAE、SMAPE比较 \n')

print('高估时')
# 计算并打印MAE
print('MAE:', MAE(TRUE2, PRED2_OVER))
# 计算并打印SMAPE
print('SMAPE:', SMAPE(TRUE2, PRED2_OVER))

print('\n低估时')
# 计算并打印MAE
print('MAE:', MAE(TRUE2, PRED2_UNDER))
# 计算并打印SMAPE
print('SMAPE:', SMAPE(TRUE2, PRED2_UNDER))
平均误差为20时,高估和低估情况下的MAE、SMAPE比较 

高估时
MAE: 20.0
SMAPE: 0.14912698412698414

低估时
MAE: 20.0
SMAPE: 0.21857142857142856

PRED2_UNDERPRED2_OVER尽管和 的TRUE2平均误差均为 20,但 SMAPE 计算出的 被低估的值为 0.218,而PRED2_UNDER被高估PRED2_OVER的 的值为 0.149 。

1.2.5 RMSSE (Root Mean Squared Scaled Error)#

\(RMSSE=\sqrt{\displaystyle\frac{\frac{1}{h}\sum_{i=n+1}^{n+h} (y_i-\hat{y}_i)^2}{\frac{1}{n-1}\sum_{i=2}^{n} (y_i-y_{i-1})^2}}\)

让我们从定义 RMSSE 公式的符号开始。每个符号具有以下含义。

\(y_i\): 要预测的实际值

\(\hat{y}_i\): 模型的预测值

\(n\): 训练数据集的大小

\(h\): 测试数据集的大小

RMSSE 是平均绝对标度误差(Hyndman, 2006)的修改形式,解决了上述 MAPE 和 SMAPE 的问题。由于MAPE和SMAPE使用测试数据的实际值和预测值来缩放MAE,即使误差的绝对值相同,根据是否低估或高估,给出的惩罚也不均匀。

RMSSE 避免了这些问题,因为它在扩展 MSE 时利用了训练数据。由于在对训练数据进行朴素预测时将其除以 MSE 值,因此误差值不会受到模型预测值低估或高估的影响。朴素预测方法是一种使用最近观测值进行预测的方法,其定义如下。

\(\hat{y}_i = y_{i-1}\)

\(i\) 当时的预测值 \(i-1\) 这是一种根据当时的实际值进行预测的方法。由于它是除以朴素预测方法的 MSE 值,因此如果 RMSSE 值大于 1,则意味着它的预测能力比朴素预测方法差,如果它小于 1,则意味着它比朴素预测方法更差。比朴素预测方法更擅长预测。让我们使用下面的代码来实现 RMSSE。

def RMSSE(true, pred, train): 
    '''
    true: np.array 
    pred: np.array
    train: np.array
    '''
    
    n = len(train)

    numerator = np.mean(np.sum(np.square(true - pred)))
    
    denominator = 1/(n-1)*np.sum(np.square((train[1:] - train[:-1])))
    
    msse = numerator/denominator
    
    return msse ** 0.5
TRAIN = np.array([10, 20, 30, 40, 50]) 
print(RMSSE(TRUE_UNDER, PRED_OVER, TRAIN))
print(RMSSE(TRUE_OVER, PRED_UNDER, TRAIN))
print(RMSSE(TRUE2, PRED2_OVER, TRAIN))
print(RMSSE(TRUE2, PRED2_UNDER, TRAIN))
4.47213595499958
4.47213595499958
4.47213595499958
4.47213595499958

尽管误差的绝对值相同,但您可以看到,MAPE 和 SMAPE 惩罚不均匀的四个示例受到了同等的惩罚,并且也进行了缩放。

到目前为止,我们已经了解了预测时间序列时可以使用的深度学习结构和评估指标。在下一章中,我们将探索用于构建模型的新冠确诊患者数据集。