使用递归神经网络的单变量时间序列

115 阅读11分钟

一个时间序列由各种数据点组成,这些数据点在一段时间内以相等的间隔依次排列。一个模型将分析时间序列中的复杂模式和关系,并预测未来的价值。

一个时间序列模型可以执行各种任务:天气预报、股票价格预测和加密货币预测。例如,一个时间序列模型将分析过去的比特币价格并预测未来的价格。它帮助投资者知道何时购买和出售比特币以获得利润。

一个单变量的时间序列只有一个单一的变量来训练这个模型。例如,一个天气预报模型使用过去记录的温度值来预测未来的温度。我们将建立一个单变量时间序列模型,预测每月的牛奶产量。我们将使用一个循环神经网络(RNN)来实现这个模型。

各种类型的RNN。我们将专注于长短时记忆(LSTM),它最适合于时间序列建模。

前提条件

开始使用递归神经网络(RNN)。

递归神经网络是典型的人工神经网络的一个变种,可以对连续数据进行建模。顺序数据依赖于历史/过去的数据点来进行未来预测。

循环神经网络使用一个内部存储器,帮助它们存储从以前的数据点检索的信息,并使用这些信息来生成其他数据点。递归神经网络在隐蔽层内实施反馈回路,这使它们与传统的人工神经网络有所区别。

下图显示了传统人工神经网络和递归神经网络之间的区别。

Traditional neural network vs RNN

图片来源。Simplilearn

隐蔽层中的反馈环帮助递归神经网络处理和分析连续的数据,以进行模型预测。反馈环路还引入了顺序记忆,帮助确定数据值被输入到递归神经网络的顺序。尽管递归神经网络比传统的人工神经网络有更好的改进,但它也存在着长期依赖性问题。

当递归神经网络的顺序记忆失效时,就会出现长期依赖性问题,而RNN不能确定数据点的顺序。当递归神经网络使用长时间记录的序列数据时,顺序记忆就会失效,例如,记录了多年的时间序列。

递归神经网络不会长期记住这些信息,因此会失去对输入的顺序以及数据点如何相互依赖的追踪。它无法处理和分析具有较长期依赖性的数据集。

解决这个问题的方法是引入长短期记忆(LSTM)。下面的图片显示了LSTM的基本结构。

LSTM structure

图片来源。中

LSTM实现了一个被称为门的概念,解决了长期依赖的问题。因此,它解决了复杂的深度学习问题,这些问题是内存密集型的,如语音识别、时间序列分析、机器翻译和其他复杂的自然语言处理,而不会损失其内部内存。

要详细了解LSTM的结构,请阅读这篇文章。在本教程中,我们将实现LSTM用于时间序列建模。LSTM的速度更快,使用的计算能力更少。我们将用它来处理时间序列中的复杂模式。

月度牛奶产量数据集

我们将使用月度牛奶产量数据集来建立时间序列模型。该数据集是单变量的,因为它只有一个训练时间序列模型的变量。你可以在这里下载月度牛奶产量数据集。

我们将使用Pandas加载月度牛奶产量数据集。让我们来导入这个必要的库。

import pandas as pd

为了加载月度牛奶产量数据集,请输入以下代码。

df = pd.read_csv('monthly-milk-production-dataset.csv',index_col='Date',parse_dates=True)

我们使用parse_dates 参数,使Pandas库能够识别Date 列中的DateTime。因此,我们可以进行时间序列分析和操作。

然后我们将数据集转换为有月度间隔,如下所示。

df.index.freq='MS'

为了打印月度牛奶产量数据集中的一些数据点,应用这段代码。

df.head()

它打印出以下数据点。

Milk production dataset

图片显示了Date 列和其相应的月度产量。然后我们用Matplotlib绘制月度牛奶产量数据集。

导入Matplotlib

要导入Matplotlib库,应用这个命令。

import matplotlib.pyplot as plt

然后,我们可以通过应用这段代码绘制月度牛奶产量数据集。

df.plot(figsize=(12,6))

它显示了以下的图。

Milk production plot

从上面的图中,我们可以看到月度牛奶产量数据集具有季节性或重复模式。它也有一个随时间增长的总趋势。

将时间序列分解为组成部分

一个时间序列有各种成分,构成了一般的时间序列模式。我们使用seasonal_decompose 进行时间序列分解。

from statsmodels.tsa.seasonal import seasonal_decompose

为了将时间序列分解成成分,应用这段代码。

decomposable_components = seasonal_decompose(df['Production'])
decomposable_components.plot()

该代码绘制了以下分量。

Time series components

该代码产生了ObservedTrendSeasonalResidual 等分量。

  • Observed:它显示了每月牛奶生产数据集的一般模式。
  • Trend:它显示了时间序列随时间的上升趋势。
  • Seasonal:显示时间序列中的季节性或重复性模式。
  • Residual:它显示了去除季节性和趋势成分后的时间序列。

将时间序列数据集分割成训练和测试日期

我们必须把时间序列数据集分成训练和测试日期。我们将使用训练日期和其相应的月度产量进行模型训练。然后我们将使用测试日期进行模型预测。

train_dates = df.iloc[:156]
test_dates = df.iloc[156:]

我们将使用前156个月作为训练日期。其余的月份将是测试日期。

缩放时间序列数据集

我们必须将时间序列数据集转换成0和1之间的比例,这将确保所有的数据点适合LSTM。我们将使用MinMaxScaler 进行缩放。

from sklearn.preprocessing import MinMaxScaler

为了初始化缩放方法,执行这段代码。

scaler = MinMaxScaler()

我们对训练和测试日期都适合我们的缩放器。

scaler.fit(train_dates)
scaler.fit(test_dates)

然后我们调用transform 方法来转换训练和测试日期。

scaled_train_dates = scaler.transform(train_dates)
scaled_test_dates = scaler.transform(test_dates)

要看到一些缩放的时间序列值,执行这段代码。

scaled_train_dates[:10]

该代码显示了以下的标度点。

Scaled data points

输出显示了位于0和1之间的经过缩放的数据点。

将缩放后的数据点格式化为批次

我们必须把按比例排列的数据点分成几批。这些批次是LSTM在训练阶段作为输入使用的数值序列。我们使用TimeseriesGenerator 类来生成数据集的批次。

我们可以按以下方式导入这个必要的库。

from keras.preprocessing.sequence import TimeseriesGenerator

我们定义每个批次的大小如下。

n_input = 12
n_features = 1

每个批次将有12个缩放的数据点(n_input = 12)。然后我们用n_features ,设置时间序列数据集的变量数量。由于我们处理的是一个单变量时间序列,所以我们将该值设置为1。

让我们将TimeseriesGenerator 到我们的缩放数据点。

generated_batches = TimeseriesGenerator(scaled_train_dates, scaled_test_dates, length=n_input, batch_size=1)

该代码将对训练和测试日期应用类函数。每个批次将有一个特定的大小。

建立时间序列模型

我们将使用LSTM建立一个顺序的时间序列模型。顺序模型将使我们能够一个接一个地添加多个层(逐层)。LSTM将是顺序模型的输入层。

我们将从Keras中导入LSTM,并直接将其添加为顺序模型的输入层。然后,我们将使用Dense 层添加顺序模型的输出层。让我们从Keras中导入LSTM、顺序模型和密集层。

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

让我们将顺序模型初始化如下。

lstm_model = Sequential()

之后,我们添加LSTM 层,如下所示。

lstm_model.add(LSTM(100, activation='relu', input_shape=(n_input, n_features)))

LSTM层将有100个神经元。它使用relu 作为激活函数,因为该层的输出将在0和无限的正时间序列值之间。它使用生成的数据集批次作为输入。然后,该模型将使用Dense 层来输出预测的时间序列值。

让我们添加Dense 层,如下所示。

lstm_model.add(Dense(1))

密集层将只有一个神经元来输出预测的每月牛奶产量。

编译顺序时间序列模型

为了编译顺序时间序列模型,应用这个代码。

lstm_model.compile(optimizer='adam', loss='mse')

我们使用compile 函数编译顺序时间序列模型。为了使编译过程顺利进行,我们传入了以下参数。

  • 优化器。它将改善和提高顺序时间序列模型的性能。我们把adam 作为模型编译过程中的优化器,以便工作。

  • 损失。它将跟踪和计算所有的模型误差。我们传递mse 作为参数值。

打印顺序时间序列模型的摘要

为了打印顺序时间序列模型的摘要,应用这段代码。

lstm_model.summary()

该代码显示如下。

Summary

摘要显示了编译后的连续时间序列模型中的各层以及参数。让我们将顺序模型拟合到生成的批次上。

拟合生成的批次的顺序模型

为了拟合顺序模型,应用这段代码。

lstm_model.fit(generated_batches,epochs=100)

生成的批次将训练和测试序列模型。我们应用100个epochs来减少序列模型的错误(损失)。顺序模型将在生成的批次中运行100次。

上面的代码将给出以下输出。

The sequential model

我们已经用生成的批次训练了顺序模型。从输出结果来看,模型的损失已经随着时间的推移而减少。让我们使用训练好的顺序模型来进行预测。

使用训练好的顺序模型进行预测

经过训练的顺序模型将使用测试日期来预测每月的牛奶产量。我们必须重塑按比例的测试时间序列值,使其具有原始格式。

prediction_result = []

test_batches = scaled_train_dates[-n_input:]
reshaping_batches = test_batches.reshape((1, n_input, n_features))

reshape 方法将对测试时间序列值进行重塑。然后,我们将把预测的输出保存在prediction_result 变量中。然后,我们使用下面的for 循环函数来循环浏览测试数据集。它将分析数据点并进行预测。

for i in range(len(test_dates)):

    predicted_output = lstm_model.predict(reshaping_batches )[0]

    prediction_result.append(predicted_output) 

    reshaping_batches = np.append(reshaping_batches [:,1:,:],[[predicted_output]],axis=1)

检查预测的结果,应用这段代码。

prediction_result

该代码显示以下预测值。

Predicted values

最后一步是使用Matplotlib绘制线图,显示测试数据集中的实际数据点和预测的数据点。该折线图将评估顺序时间序列模型的性能。

绘制折线图

要绘制折线图,请执行此代码段。

actual_values = scaler.inverse_transform(prediction_result)
test_dates['Predictions'] = actual_values
test_dates.plot(figsize=(14,5))

上面的代码片断绘制了以下折线图。

Line graph

该折线图显示了每月的实际牛奶产量和预测的每月牛奶产量。

  • 橙色线显示预测的牛奶产量。
  • 蓝线表示实际牛奶产量。

如果我们观察这两条线,它们保持相同的模式。此外,这些线也是相互接近的。这意味着顺序时间序列模型训练有素,可以做出准确的预测(预测值位于实际值之内)。

总结

在本教程中,我们建立了一个预测每月牛奶产量的单变量时间序列。我们使用LSTM实现了这个模型,因为它最适合于时间序列建模。

我们解释了RNN和LSTM的区别,以及LSTM如何解决长期依赖性问题。我们从Keras中导入LSTM,并使用它来建立顺序时间序列模型。最后我们用线图来评估顺序时间序列模型的性能。

在这里查看单变量时间序列模型的完整Python代码。

编码愉快!

参考文献