LSTM RNN 预测的反向缩放输出中的错误

Error in reverse scaling outputs predicted by a LSTM RNN

我使用 LSTM 模型预测股票的未来 open 价格。这里数据经过预处理,模型构建和训练没有任何错误,我使用 Standard Scaler 缩小 DataFrame 中的值。但是在从模型中检索预测时,当我使用 scaler.reverse() 方法时,它给出了以下错误。

ValueError: non-broadcastable output operand with shape (59,1) doesn't match the broadcast shape (59,4)

完整代码jupyter notebook太大无法直接展示,所以上传到git repository

这是因为模型正在预测形状为 (59, 1) 的输出。但是您的 Scaler 适合 (251, 4) 数据框。在 y 值形状的数据框上创建一个新的缩放器,或者将模型密集层输出更改为 4 维而不是 1 维。 缩放器适合的数据形状,它只会在 scaler.inverse_transform.

期间采用该形状

旧代码 - 形状 (n,1)

trainY.append(df_for_training_scaled[i + n_future - 1:i + n_future, 0])

更新代码 - 形状 (n,4) - 使用全部 4 个输出

trainY.append(df_for_training_scaled[i + n_future - 1:i + n_future,:])

通常您会重新缩放自变量(特征),因为缩放差异会影响模型计算,但您尝试预测的因变量通常保持不变。通常没有理由重新缩放因变量并且缩放它使得解释结果变得极其困难。

StandardScaler 文档的第一行class甚至指定了这么多:

Standardize features by removing the mean and scaling to unit variance

您还可以选择缩放标签,但通常不需要这样做。

所以我会在你的地方做的是(假设你的原始数据框包含 3 个自变量和 1 个目标变量)是这样的:

X = some_df.iloc[:, :3].values
y = some_df.iloc[3].values

scaler = StandardScaler()
X = scaler.fit_transform(X)
# And then goes everything as usual

现在,当您预测值时,您只需要像以前一样使用缩放器转换输入。

不过,更好的方法是在模型中添加一个规范化层作为预处理步骤。通过这种方式,您只需将原始数据输入估算器,它就会为您处理所有细节。而且,类似地,您在生成预测时不需要规范化数据,模型会为您做所有事情。您可以添加如下内容:

from tensorflow.keras.layers.experimental.preprocessing import Normalization
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Input, Dense
from tensorflow.keras import Model

# this is your default batch_size
BATCH_SIZE = 128

# Here's your raw (non-normalized) X data
X = some_df.iloc[:, :3].values

norm = Normalization()
norm.adapt(X)
preprocess = Sequential([
    Input(shape=(BATCH_SIZE, 3)),
    norm
])

# Now finally, when you build your actual model you add 
# pre-processing step in the beginning
inp = preprocess()
x = Dense(64)(input)
x = Dense(128)(x)
x = Dense(1)(x)  
model = Model(inputs=inp, outputs=x) 

这里的预处理步骤是模型本身的一部分,所以一旦你这样做了,你就可以直接输入原始数据而无需任何额外的转换。

这就是它的作用:

# Skipping the imports as they are the same as above + numpy

X = np.array([[1, 2, 3], [10, 20, 40], [100, 200, 400]])

norm = Normalization()
norm.adapt(X)
preprocess = Sequential([
    Input(shape=(3, 3)),
    norm
]) 

x_new = preprocess(X)
print(x_new)

Out: tf.Tensor(
[[-0.80538726 -0.80538726 -0.807901  ]
 [-0.60404044 -0.60404044 -0.6012719 ]
 [ 1.4094278   1.4094278   1.4091729 ]], shape=(3, 3), dtype=float32)