我在假期期间尝试使用 Keras 进行一些实际操作经验,我认为我可以从教科书上的股票数据时间序列预测例子开始。因此,我试图做的是根据过去48小时的平均价格变化(与之前的百分比变化),预测接下来一小时的平均价格变化。
然而,当我用测试集(甚至训练集)进行验证时,预测序列的幅度完全不对,有时会移位到始终为正或始终为负,即从0%的变化移开,我认为对于这种情况这应该是正确的。
我提出了以下最小示例来展示这个问题:
df = pandas.DataFrame.from_csv('test-data-01.csv', header=0)df['pct'] = df.value.pct_change(periods=1)seq_len=48vals = df.pct.values[1:] # First pct change is NaN, skip itsequences = []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 = -24trainSeqs = 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小时,重复这个过程来创建训练和测试序列。模型非常简单,只有一个LSTM层和一个密集层。
我原本期望单个预测点的图表能很好地与训练序列的图表重叠(毕竟这是它们训练的同一组数据),并且在测试序列上也应该大致匹配。然而,我在训练数据上得到了以下结果:
- 橙色:真实数据
- 蓝色:预测数据
你有什么想法吗?这可能是我误解了什么地方?
更新:为了更好地展示我所说的移位和压缩的意思,我还绘制了通过移位和乘以一个因子来匹配真实数据的预测值。
plot(pred*12-0.03)plot([i[1] for i in trainSeqs])axis([2500, 2550,-0.03, 0.03])
如你所见,预测很好地拟合了真实数据,只是不知为何被压缩和偏移了,我无法弄清楚原因。
回答:
我认为你可能存在过拟合,因为你的数据维度是1,而一个25单元的LSTM对于这样低维度的数据集似乎过于复杂了。以下是我会尝试的一些方法:
- 降低LSTM的维度。
- 添加某种形式的正则化来对抗过拟合。例如,dropout可能是一个好的选择。
- 增加训练轮数或改变学习率。模型可能需要更多的轮数或更大的更新来找到合适的参数。
更新。让我总结一下我们在评论部分讨论的内容。
为了澄清,第一张图表显示的不是验证集的预测系列,而是训练集的。因此,我最初的过拟合解释可能不准确。我认为一个合适的问题是:从这样低维度的数据集中是否真的可以预测未来的价格变化?机器学习算法并不是魔法:它们只有在数据中存在模式时才能找到模式。
如果过去的价格变化本身确实对未来的价格变化没有太多信息,那么:
- 你的模型会学会预测价格变化的平均值(可能接近0),因为在没有信息性特征的情况下,这是产生最低损失的值。
- 预测可能会看起来略有“移位”,因为时间步t+1的价格变化与时间步t的价格变化略有相关性(但预测接近0仍然是最安全的选择)。这确实是我作为一个非专业人士能观察到的唯一模式(即时间步t+1的值有时与时间步t的值相似)。
如果时间步t和t+1的值在一般情况下更相关,那么我推测模型会对这种相关性更有信心,预测的幅度也会更大。