Keras LSTM 预测的时间序列被挤压和移位

Posted

技术标签:

【中文标题】Keras LSTM 预测的时间序列被挤压和移位【英文标题】:Keras LSTM predicted timeseries squashed and shifted 【发布时间】:2018-06-10 14:29:55 【问题描述】:

我正试图在假期中获得一些使用 Keras 的经验,我想我会从教科书的股票数据时间序列预测示例开始。所以我要做的是给定过去 48 小时的平均价格变化(自上一小时以来的百分比),预测未来一小时的平均价格变化是多少。

但是,在针对测试集(甚至是训练集)进行验证时,预测序列的幅度相差甚远,有时会转移为始终为正或始终为负,即偏离 0% 的变化,我认为这对于这种事情是正确的。

我想出了以下最小示例来说明问题:

df = pandas.DataFrame.from_csv('test-data-01.csv', header=0)
df['pct'] = df.value.pct_change(periods=1)

seq_len=48
vals = df.pct.values[1:] # First pct change is NaN, skip it
sequences = []
for i in range(0, len(vals) - seq_len):
    sx = vals[i:i+seq_len].reshape(seq_len, 1)
    sy = vals[i+seq_len]
    sequences.append((sx, sy))

row = -24
trainSeqs = sequences[:row]
testSeqs = sequences[row:]

trainX = np.array([i[0] for i in trainSeqs])
trainy = np.array([i[1] for i in trainSeqs])

model = Sequential()
model.add(LSTM(25, batch_input_shape=(1, seq_len, 1)))
model.add(Dense(1))
model.compile(loss='mse', optimizer='adam')
model.fit(trainX, trainy, epochs=1, batch_size=1, verbose=1, shuffle=True)

pred = []
for s in trainSeqs:
    pred.append(model.predict(s[0].reshape(1, seq_len, 1)))
pred = np.array(pred).flatten()

plot(pred)
plot([i[1] for i in trainSeqs])
axis([2500, 2550,-0.03, 0.03])

如您所见,我创建了训练和测试序列,方法是选择最后 48 小时,然后将下一步放入一个元组,然后前进 1 小时,重复该过程。该模型是一个非常简单的 1 个 LSTM 和 1 个密集层。

我本来希望各个预测点的图与训练序列图很好地重叠(毕竟这是他们训练的同一组),并且与测试序列相匹配。但是,我在 训练数据 上得到以下结果:

橙色:真实数据 蓝色:预测数据

知道会发生什么吗?我是不是误会了什么?

更新:为了更好地展示我所说的移位和压扁的意思,我还绘制了预测值,方法是将其移回以匹配真实数据并相乘以匹配幅度。

plot(pred*12-0.03)
plot([i[1] for i in trainSeqs])
axis([2500, 2550,-0.03, 0.03])

正如您所看到的,预测与真实数据非常吻合,只是以某种方式被挤压和偏移,我不知道为什么。

【问题讨论】:

它仍在训练数据上,因此我期望“非常合适”。我完全理解,如果对新数据执行预测,那么它可能会发散,但在训练集上,我希望模型能够返回一个很好的近似值,而无需重新缩放和移动。 可以分享一下 test-data-01.csv 吗? 当然:我上传到这里gist.github.com/anonymous/50dc9e36616605bfbf021642b47a4336 @cdecker 你能解决这个问题吗?特别是转移到总是积极或总是消极的部分?因为我当前的 lstm 遇到了完全相同的问题。 【参考方案1】:

我认为你过度拟合了,因为你的数据的维数是 1,对于这样一个低维数据集来说,具有 25 个单元的 LSTM 似乎相当复杂。以下是我会尝试的事情列表:

减小 LSTM 维度。 添加某种形式的正则化来对抗过拟合。例如,dropout 可能是一个不错的选择。 训练更多 epoch 或更改学习率。模型可能需要更多的时期或更大的更新才能找到合适的参数。

更新。让我总结一下我们在 cmets 部分讨论的内容。

为了澄清起见,第一个图没有显示验证集的预测序列,而是训练集的预测序列。因此,我的第一个过度拟合解释可能不准确。我认为一个合适的问题是:真的有可能从这样一个低维数据集预测未来的价格变化吗?机器学习算法并不神奇:它们只有在数据存在的情况下才能在数据中找到模式。

如果过去价格变化本身确实不能很好地说明未来价格变化,那么:

您的模型将学习预测价格变化的平均值(可能在 0 左右),因为在没有信息特征的情况下,该值会产生最低的损失。 由于时间步长 t+1 的价格变化与时间步长 t 的价格变化略有相关,因此预测可能看起来略有“偏移”(但仍然,预测接近 0 的值是最安全的选择)。这确实是我作为非专家能够观察到的唯一模式(即时间步 t+1 的值有时与时间步 t 的值相似)。

如果时间步长 t 和 t+1 处的值恰好通常更相关,那么我假设模型会对这种相关性更有信心,并且预测的幅度会更大。

【讨论】:

过度拟合不会导致训练数据几乎完美匹配吗?这实际上是朝着相反的方向发展。我也得到了迄今为​​止我尝试过的所有模型(简单和复杂的模型)的这个结果 哦,我误解了你的情节。你是对的,它应该与训练数据相匹配。我对股票数据没有经验,但在那种情况下,你认为真的有可能从这样一个低维数据集预测未来的价格变化吗?换句话说,专家能否仅根据过去的价格变化来预测未来的价格变化? 如果答案是“否”,那么您的结果对我来说非常有意义。如果数据中没有明确的模式,您的模型将学习预测价格变化的平均值(可能非常接近于 0,对吗?),因为这是在没有信息特征的情况下产生最低损失的值。然后,预测可能会出现轻微的“偏移”,因为时间步 t+1 的价格变化与时间步 t 的价格变化略有相关(但仍然,预测接近 0 的值是最安全的选择)。 如果特征不包含足够的信息,确实指向平均值是一个“好”的预测。然而,这并不能解释为什么它会转移到一侧或另一侧。有趣的是,如果我将预测序列乘以 4 或 5 并将其移回真实数据,它给了我一个非常好的拟合(见编辑的问题) 好吧,我认为预测序列可能“移位”的原因是因为目标值与之前的值略有相关。也就是说,如果时间步 t 处的值是 0.02,则模型知道 t+1 处的值很可能接近 0.02。但是,这种影响会被我们之前讨论的内容减弱。这确实是我作为一个非专家能够观察到的唯一模式(即时间步 t+1 的值有时与时间步 t 的值相似)。【参考方案2】:
    增加纪元数。您可以使用 EarlyStopping 来避免过度拟合。 您的数据是如何缩放的?时间序列对数据中的异常值非常敏感。例如尝试 MinMax((0.1, 0.9)),然后 RobustScaler 也是一个不错的选择。 我不确定 LSTM(seq_len) 是否真的有必要,直到您拥有 大量 数据。为什么不试试更小的尺寸?

尝试所有这些并尝试过拟合(在真实数据集上,mse 应该在零左右)。然后应用正则化。

更新

让我解释一下你为什么会通过

plot(pred*12-0.03)

很合适。

好的,让我们将 LSTM 层视为黑盒并忘记它。它返回给我们 25 个值——仅此而已。 这个值会传递到 Dense 层,我们将其应用于 25 值函数的向量:

y = w * x + b

这里 wb - 由 NN 定义的向量在开始时通常接近于零。 x - LSTM 层和 y - 目标(单个值)之后的值。

虽然您只有 1 个时期:w 和 b 根本不适合您的数据(实际上它们大约为零)。但是如果你申请呢

plot(pred*12-0.03)

达到您的预测值?您(以某种方式)应用到目标变量 wb。现在 wb 是单个值,而不是向量,它们应用于单个值。但它们(几乎)做与 Dense 层相同的工作。

所以,增加 epoch 的数量以获得更好的拟合。

更新2 顺便说一句,我在数据中看到了一些异常值。您也可以尝试使用 MAE 作为损失/准确度指标。

【讨论】:

我相信这里的问题不是过拟合(我也是先想到的情节涉及验证数据集),如果我理解正确的话,数据已经在合理的范围内(-1, 1 ),因为它是百分比价格变化。正如我在我的一个 cmets 中所说的那样,我宁愿认为此功能可能提供的信息不够多。 我同意 - 在提供的代码中现在存在过度拟合,因为时期数 = 1。我刚刚为 TS 提到了它。在接下来的步骤中会出现过拟合问题。关于缩放。我再次同意缩放,但不确定重新缩放是否无济于事。简直不知道。可能,非常小的输入值可能不好。不知道也没有合适的数据集在我手上检查。也许这是一个噪音。在这种情况下,预测几乎毫无意义。 感谢密集的指针是一个线性逼近函数。遗憾的是,使用 epochs=100 运行并没有真正改变任何东西。 您的预测值仍然接近于零?您是否对数据进行了重新调整?【参考方案3】:

本周我遇到了同样的问题,我找到了解决方案。唯一对我有用的是使用此处描述的窗口标准化方法:

https://www.altumintelligence.com/articles/a/Time-Series-Prediction-Using-LSTM-Deep-Neural-Networks

(查看sp500预测部分)

祝你有美好的一天:)

【讨论】:

嗨 Yanick,您可以分享您的代码吗?我也想试试。我无法完全理解上述链接中的代码。从cdecker的代码看,不知道上面链接中sy = vals[i+seq_len]是怎么处理的。【参考方案4】:

因为我在这一点上以及batch_size的增加完全有助于SimpleRNN修复LSTM问题与relu,elu作为激活,学习率必须从默认增加,并尝试配置一些SmoteRNN灵魂以获得更多过去的数据,或者更改行之间的时间段以获取更多数据以供模型查找模式,这似乎对我有用,atm,仍然试图将准确率提高到 80% 以上, 准确率 = (mean_abosule_error / test.mean()) * 100

【讨论】:

以上是关于Keras LSTM 预测的时间序列被挤压和移位的主要内容,如果未能解决你的问题,请参考以下文章

Keras深度学习实战(32)——基于LSTM预测股价

Keras深度学习实战(33)——基于LSTM的序列预测模型

使用 LSTM 和 keras 进行时间序列预测的分类变量

Keras中的LSTM

时间序列 Keras LSTM 回显而不是预测

Keras 在训练分类 LSTM 序列到序列模型时给出 nan