Keras 中使用 LSTM 进行多元时间序列预测

多元预测需要利用多个与时间相关的变量来生成预测。这种预测方法结合了历史数据,同时考虑了模型内变量之间的相互依赖性。在本文中,我们将探索使用 LSTM 进行多元预测的世界,深入了解其核心,探索其应用,并掌握其对未来决策的革命性影响。

什么是多元预测?
多元预测是一种同时利用多个相互关联的变量的未来值的统计技术。多元预测的过程首先收集所有特征的历史数据,然后分析这些数据集以识别模式、基于关系的相关性,并预测未来值。

多元预测中使用的常用技术包括向量自回归 (VAR)(对多个时间序列变量之间的相互依赖性进行建模)和结构方程建模 (SEM)(允许检查变量之间的复杂关系)。此外,神经网络和梯度增强机等机器学习算法由于能够捕获数据中复杂的模式和非线性关系,也越来越多地应用于多元预测任务。

什么是 LSTM?
长期短期记忆代表了深度学习中循环神经网络 ( RNN )的重大进步。这种复杂的算法解决并实现了与中度灭绝相关的挑战,因其在自然语言处理、语音识别等数据排序方面的卓越技能而受到高度赞扬。提供了在各种应用中表现出色的能力。从本质上讲,LSTM 充当智能信息处理器,当它们受到信任时可以被识别,这是微妙的,并且在对时间关系的详细理解至关重要的项目中提供无与伦比的性能。

使用 LSTM 进行多元预测的要点
下面讨论使用 LSTM 进行多元预测的一些要点:

  1. 多元奇迹:多元时间序列预测不仅是预测一个变量,而且是随着时间的推移预测多个变量,提供数据动态的整体视图。
  2. 详细预测:想象一下,股票价格预测不仅限于收盘价预测,还包括开盘价、每日最高价、每日最低价等。多元预测为我们的数据预测带来了如此详细的信息。
  3. LSTM 超级明星:进入长短期记忆 (LSTM) 网络,神经网络的摇滚明星。与常规算法不同,LSTM 配备了记忆功能,使它们能够捕获数据中复杂的关系,从而非常适合解析复杂的多元模式。
  4. 使用 Keras 进行编码魔法: Keras 作为编码世界的巫师魔杖,介入使 LSTM 的使用变得轻而易举。它将复杂的事情变得易于管理,甚至为编码魔法注入了一点乐趣和时间效率。

使用 LSTM 逐步实施多元预测
导入所需模块
为了实现,我们将导入datatime模块、sklearn、numpy、pandas、math、keras、matplotlib.pyplot和TensorFlow。

import datetime
import sklearn
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import MinMaxScaler
from sklearn.decomposition import KernelPCA
import numpy as np
import pandas as pd
import math
import keras
import matplotlib.pyplot as plt
import tensorflow as tf
tf.random.set_seed(99)

数据集加载
现在,我们将加载一个时间序列数据集。

# Dataset loading
dataFrame = pd.read_csv('final_data_adj.csv') # https://github.com/SusmitSekharBhakta/Stock-market-price-prediction/blob/main/final_data_adj.csv

数据预处理
使用以下代码,我们将通过处理缺失值、删除不相关列、缩放特征和缩放目标变量来预处理数据,为进一步分析或建模做好准备。

imputer = SimpleImputer(missing_values=np.nan) # Handling missing values
dataFrame.drop(columns=['Date'], inplace=True)
dataFrame = pd.DataFrame(imputer.fit_transform(dataFrame), columns=dataFrame.columns)
dataFrame = dataFrame.reset_index(drop=True)
# Applying feature scaling
scaler = MinMaxScaler(feature_range=(0, 1))
df_scaled = scaler.fit_transform(dataFrame.to_numpy())
df_scaled = pd.DataFrame(df_scaled, columns=list(dataFrame.columns))
target_scaler = MinMaxScaler(feature_range=(0, 1))
df_scaled[['Open', 'Close']] = target_scaler.fit_transform(dataFrame[['Open', 'Close']].to_numpy())
df_scaled = df_scaled.astype(float)

数据准备
引入了名为 singleStepSampler 的函数,以方便准备用于单步时间序列预测的数据集。

该函数有两个参数:一个数据帧(表示为 df)和一个指定的窗口大小。在该函数中,两个列表(即 xRes 和 yRes)被初始化,分别作为输入特征和目标值的容器。该函数利用两个嵌套循环迭代数据帧的行,根据提供的窗口大小创建输入特征 (xRes) 序列和相应的目标值 (yRes)。输入特征被构造为一系列窗口数据点,其中每个数据点都是一个包含数据帧每列值的列表。来自每个窗口的“打开”和“关闭”列的目标值附加到 yRes。

最终,该函数返回numpy数组xRes和yRes,封装了准备好的输入特征和后续时间序列预测的目标值。

# Single step dataset preparation
def singleStepSampler(df, window):
    xRes = []
    yRes = []
    for i in range(0, len(df) - window):
        res = []
        for j in range(0, window):
            r = []
            for col in df.columns:
                r.append(df[col][i + j])
            res.append(r)
        xRes.append(res)
        yRes.append(df[['Open', 'Close']].iloc[i + window].values)
    return np.array(xRes), np.array(yRes)


数据分割
现在我们将以 85:15 的比例将数据集分为训练集和测试集。

# Dataset splitting
SPLIT = 0.85
(xVal, yVal) = singleStepSampler(df_scaled, 20)
X_train = xVal[:int(SPLIT * len(xVal))]
y_train = yVal[:int(SPLIT * len(yVal))]
X_test = xVal[int(SPLIT * len(xVal)):]
y_test = yVal[int(SPLIT * len(yVal)):]


定义 LSTM 模型
在此阶段,使用 TensorFlow 的 Keras API 构建多元长短期记忆神经网络模型。该模型被初始化为顺序模型,表示线性的层堆栈。该架构包含一个包含 200 个单元的 LSTM 层,旨在处理形状由训练数据 (X_train) 中的特征(列)数量定义的输入序列。为了防止过度拟合,引入了 dropout 层。输出层是一个具有 2 个单元的密集层,与两个预测变量(“Open”和“Close”)的预测值对齐。该输出层的激活函数设置为线性。对于训练,该模型是利用均方误差作为损失函数来编译的,并以平均绝对误差(MAE)作为进一步评估的指标。 Adam 优化器用于促进训练过程。 summary() 方法提供了模型架构的全面概述,详细说明了参数数量和层配置以增强理解。

multivariate_lstm = keras.Sequential()
multivariate_lstm.add(keras.layers.LSTM(200, input_shape=(X_train.shape[1], X_train.shape[2])))
multivariate_lstm.add(keras.layers.Dropout(0.2))
multivariate_lstm.add(keras.layers.Dense(2, activation='linear'))
multivariate_lstm.compile(loss = 'MeanSquaredError', metrics=['MAE'], optimizer='Adam')
multivariate_lstm.summary()

输出:

Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 lstm (LSTM)                 (None, 200)               172800    
                                                                 
 dropout (Dropout)           (None, 200)               0         
                                                                 
 dense (Dense)               (None, 2)                 402       
                                                                 
=================================================================
Total params: 173202 (676.57 KB)
Trainable params: 173202 (676.57 KB)
Non-trainable params: 0 (0.00 Byte)
_________________________________________________________________


模型训练
现在,我们将在 20 个 epoch 上训练我们的模型。

history = multivariate_lstm.fit(X_train, y_train, epochs=20)

输出:

Epoch 1/20 48/48 [==============================] - 6s 8ms/step - loss: 0.0187 - MAE: 0.0877 Epoch 2/20 48/48 [==============================] - 1s 12ms/step - loss: 0.0023 - MAE: 0.0363 Epoch 3/20 48/48 [==============================] - 0s 9ms/step - loss: 0.0019 - MAE: 0.0330 Epoch 4/20 48/48 [==============================] - 0s 8ms/step - loss: 0.0014 - MAE: 0.0289 Epoch 5/20 48/48 [==============================] - 0s 5ms/step - loss: 0.0014 - MAE: 0.0282 Epoch 6/20 48/48 [==============================] - 0s 5ms/step - loss: 0.0013 - MAE: 0.0275 Epoch 7/20 48/48 [==============================] - 0s 5ms/step - loss: 0.0011 - MAE: 0.0258 Epoch 8/20 48/48 [==============================] - 0s 5ms/step - loss: 0.0011 - MAE: 0.0252 Epoch 9/20 48/48 [==============================] - 0s 5ms/step - loss: 0.0011 - MAE: 0.0249 Epoch 10/20 48/48 [==============================] - 0s 5ms/step - loss: 0.0010 - MAE: 0.0241

预测
此代码段重点关注使用 LSTM 模型可视化多元时间序列预测结果。最初,使用“日期”列作为索引重新加载数据集。 “日期”列将转换为日期时间格式,并相应地设置索引。 LSTM 模型(“multivariate_lstm”)用于预测测试集(“X_test”)的值。预测与实际值 (`y_test`) 一起组织到 DataFrame (`d`) 中。正确的日期索引被分配给此 DataFrame,使其与原始数据集对齐。随后,使用 Matplotlib 创建绘图来展示随时间变化的实际值和预测值。绘制了“开盘”和“收盘”的实际值,而预测值则用虚线表示。此外,该图的一部分以不同的颜色突出显示,表示为“浅绿色”,对应于预测期间。这种视觉区别有助于轻松识别整个图中的预测部分。生成的图清楚地表示了模型的性能,可以对预测值和实际值进行直观比较,并突出显示预测期间以供进一步分析。

# 使用日期索引重新加载数据
dataFrame = pd.read_csv('/content/final_data_adj.csv') # Assuming the CSV file contains a 'Date' column
dataFrame['Date'] = pd.to_datetime(dataFrame['Date'])
dataFrame.set_index('Date', inplace=True)

以日期为 X 轴的预测图
predicted_values = multivariate_lstm.predict(X_test)

d = {
    'Predicted_Open': predicted_values[:, 0],
    'Predicted_Close': predicted_values[:, 1],
    'Actual_Open': y_test[:, 0],
    'Actual_Close': y_test[:, 1],
}

d = pd.DataFrame(d)
d.index = dataFrame.index[-len(y_test):] # Assigning the correct date index

fig, ax = plt.subplots(figsize=(10, 6))
突出预测
highlight_start = int(len(d) * 0.9) 
highlight_end = len(d) - 1 # Adjusted to stay within bounds
绘制实际值
plt.plot(d[['Actual_Open', 'Actual_Close']][:highlight_start], label=['Actual_Open', 'Actual_Close'])

用虚线绘制预测值
plt.plot(d[['Predicted_Open', 'Predicted_Close']], label=['Predicted_Open', 'Predicted_Close'], linestyle='--')

# 用不同颜色突出显示预测部分
plt.axvspan(d.index[highlight_start], d.index[highlight_end], facecolor='lightgreen', alpha=0.5, label='Forecast')

plt.title('Multivariate Time-Series forecasting using LSTM')
plt.xlabel('Dates')
plt.ylabel('Values')
ax.legend()
plt.show()

模型评估
现在我们将根据每个预测变量的MSE、MAE 和 R2-Score来评估模型的性能。

# Model Evaluation
def eval(model):
    return {
        'MSE': sklearn.metrics.mean_squared_error(d[f'Actual_{model.split("_")[1]}'].to_numpy(), d[model].to_numpy()),
        'MAE': sklearn.metrics.mean_absolute_error(d[f'Actual_{model.split(
"_")[1]}'].to_numpy(), d[model].to_numpy()),
        'R2': sklearn.metrics.r2_score(d[f'Actual_{model.split(
"_")[1]}'].to_numpy(), d[model].to_numpy())
    }

result = dict()

for item in ['Predicted_Open', 'Predicted_Close']:
    result[item] = eval(item)

result
输出:

{'Predicted_Open': {'MSE': 0.0003399016874267341,
  'MAE': 0.014677578549558692,
  'R2': 0.9175119938700349},
 'Predicted_Close': {'MSE': 0.0007753355953061959,
  'MAE': 0.02312380270519607,
  'R2': 0.8091037332332098}}

结论
总之,我们可以看到两个预测变量的误差都非常小,R2 分数也足够高。这说明我们的 LSTM 模型性能很好,但如果进行超参数调整和提前减少损失,性能会更好。