如何为每个目标塑造具有多个特征的 RNN 的输入?

How to shape the input of a RNN with multiple features for each target?

我正在尝试学习如何使用 RNN 进行时间序列预测,在我看到的所有示例中,它们都使用一系列价格来预测以下价格。在示例中,每个目标 (Y_train[n]) 都与由最后 30 prices/steps ([X_train[[n-1],[n-2]....,[n-30]).

组成的序列或矩阵相关联

然而,在现实世界中,要准确预测您需要的不仅仅是最近 30 个价格的序列,您还需要其他……我应该说特征吗?比如成交量的最后 30 个值或情绪指数的最后 30 个值。

所以我的问题是: 您如何使用每个目标的两个序列(最近 30 个价格和最近 30 个交易量值)来调整 RNN 的输入?这是我使用的示例代码,仅使用 1 个序列作为参考:

import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from keras.layers import Dropout

# Dividing Dataset (Test and Train)
train_lim = int(len(df) * 2 / 3)
training_set = df[:train_lim][['Close']]
test_set = df[train_lim:][['Close']]

# Normalizing
sc = MinMaxScaler(feature_range=(0, 1))
training_set_scaled = sc.fit_transform(training_set)

# Shaping Input
X_train = []
y_train = []
X_test = []

for i in range(30, training_set_scaled.size):
    X_train.append(training_set_scaled[i - 30:i, 0])
    y_train.append(training_set_scaled[i, 0])
X_train, y_train = np.array(X_train), np.array(y_train)

for i in range(30, len(test_set)):
    X_test.append(test_set.iloc[i - 30:i, 0])
X_test = np.array(X_test)

# Adding extra dimension ???
X_train = np.reshape(X_train, [X_train.shape[0], X_train.shape[1], 1])
X_test = np.reshape(X_test, [X_test.shape[0], X_test.shape[1], 1])

regressor = Sequential()

# LSTM layer 1
regressor.add(LSTM(units=50, return_sequences=True, input_shape=(X_train.shape[1], 1)))
regressor.add(Dropout(0.2))

# LSTM layer 2,3,4
regressor.add(LSTM(units=50, return_sequences=True))
regressor.add(Dropout(0.2))
regressor.add(LSTM(units=50, return_sequences=True))
regressor.add(Dropout(0.2))
regressor.add(LSTM(units=50, return_sequences=True))
regressor.add(Dropout(0.2))
regressor.add(LSTM(units=50, return_sequences=True))
regressor.add(Dropout(0.2))

# LSTM layer 5
regressor.add(LSTM(units=50))
regressor.add(Dropout(0.2))

# Fully connected layer
regressor.add(Dense(units=1))

# Compiling the RNN
regressor.compile(optimizer='adam', loss='mean_squared_error')

# Fitting the RNN model
regressor.fit(X_train, y_train, epochs=120, batch_size=32)

我使用的数据框是带有日期时间索引的标准 OHLCV,因此它看起来像这样:

Datetime     Open         High      Low      Close     Volume
01/01/2021   102.42     103.33     100.57    101.23      1990
02/01/2021   101.23     105.22     99.45     100.11      1970
   ...         ...        ...       ...        ...        ...
 
01/12/2021   203.22     210.34     199.22    201.11      2600

你可以按照完全相同的过程,唯一的区别是输入序列(X_trainX_test)的数组最后一维的长度将大于一(因为它将等于外部回归器的数量加一,其中加一来自目标的过去值也用作输入的事实)。

import pandas as pd
import numpy as np
import yfinance as yf
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import Dense, LSTM, Dropout
pd.options.mode.chained_assignment = None

# define the target and features
target = ['Close']
features = ['Volume', 'High', 'Low']

# download the data
df = yf.download(tickers=['AAPL'], period='1y')
df = df[features + target]

# split the data
split = int(df.shape[0] * 2 / 3)
df_train = df.iloc[:split, :].copy()
df_test = df.iloc[split:, :].copy()

# scale the data
target_scaler = MinMaxScaler().fit(df_train[target])
df_train[target] = target_scaler.transform(df_train[target])
df_test[target] = target_scaler.transform(df_test[target])

features_scaler = MinMaxScaler().fit(df_train[features])
df_train[features] = features_scaler.transform(df_train[features])
df_test[features] = features_scaler.transform(df_test[features])

# extract the input sequences and output values
sequence_length = 30

X_train, y_train = [], []

for i in range(sequence_length, df_train.shape[0]):
    X_train.append(df_train[features + target].iloc[i - sequence_length: i])
    y_train.append(df_train[target].iloc[i])

X_train, y_train = np.array(X_train), np.array(y_train)

X_test, y_test = [], []

for i in range(sequence_length, df_test.shape[0]):
    X_test.append(df_test[features + target].iloc[i - sequence_length: i])
    y_test.append(df_test[target].iloc[i])

X_test, y_test = np.array(X_test), np.array(y_test)

print(X_train.shape)
# (138, 30, 4)

print(X_test.shape)
# (55, 30, 4)

# build and train the model
model = Sequential()
model.add(LSTM(units=50, return_sequences=True, input_shape=X_train.shape[1:]))
model.add(Dropout(0.2))
model.add(LSTM(units=50, return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(units=50, return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(units=50, return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(units=50, return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(units=50))
model.add(Dropout(0.2))
model.add(Dense(units=1))

model.compile(optimizer='adam', loss='mean_squared_error')

model.fit(X_train, y_train, epochs=120, batch_size=32)

model.evaluate(X_test, y_test)

# generate the test set predictions
y_pred = model.predict(X_test)
y_pred = target_scaler.inverse_transform(y_pred)

# plot the test set predictions
df['Predicted Close'] = np.nan
df['Predicted Close'].iloc[- y_pred.shape[0]:] = y_pred.flatten()
df[['Close', 'Predicted Close']].plot()