LSTM预测标普500未来5日涨跌幅出现输出近似平线问题求助
我一直在尝试搭建一个简单的LSTM网络,用于预测标普500(S&P500)未来5个交易日的涨跌幅百分比,但是我的神经网络输出结果几乎是完全平的直线。
图中为未来5日涨跌幅走势,红色为模型预测结果:
我知道不应该在训练集上验证模型效果,但这一步只是合理性校验,确认模型最基础的拟合能力是否正常。
sc = MinMaxScaler(feature_range=(0,1)) dataset = dataset[5:-1] dataset = dataset.dropna() close = sc.fit_transform(dataset['Close'].values.reshape(-1,1)) volume = sc.fit_transform(dataset['Volume'].values.reshape(-1,1)) pct = sc.fit_transform(dataset['pct5'].values.reshape(-1,1)) close_train = [] volume_train = [] y = [] pc = [] leng = 60 for i in range(leng, len(close)): close_train.append(close[i - 60 : i, 0]) volume_train.append(volume[i - 60 : i, 0]) y.append(close[i, 0]) pc.append(pct[i, 0]) close_train = np.array(close_train, dtype=np.float64) volume_train = np.array(volume_train, dtype=np.float64) y = np.array(y) pc = np.array(pc, dtype=np.float64) #This is just adjusted pct in case you got lost close_train = np.reshape(close_train, (close_train.shape[0], close_train.shape[1], 1)) volume_train = np.reshape(volume_train, (volume_train.shape[0], volume_train.shape[1], 1)) def buildModel(dataLength, labelLength): price = Input(shape=(dataLength, 1), name='price') volumen = Input(shape=(dataLength, 1), name='volumen') priceLayers1 = LSTM(60, return_sequences=True)(price) volumeLayers1 = LSTM(60, return_sequences=True)(volumen) priceLayers2 = LSTM(60, return_sequences=True)(price) volumeLayers2 = LSTM(60, return_sequences=True)(volumen) priceLayers3 = LSTM(60, return_sequences=False)(price) volumeLayers3 = LSTM(60, return_sequences=False)(volumen) output = concatenate( [ price, volumen ] ) output = Dense(1, activation='linear', name='dense')(output) model = Model( [ price, volumen ], [ output ] ) opt = tf.keras.optimizers.Adam(learning_rate=0.001) model.compile(optimizer=opt, loss='mse') print(output) return model rnn = buildModel(60, 4) hist = rnn.fit( [ close_train, volume_train ], [ pc ], epochs = 100, batch_size=50 ) nsamples, nx, ny = close_train.shape test_close = close_train.reshape((nsamples,nx*ny)) test_vol = volume_train.reshape((nsamples,nx*ny)) pred = rnn.predict([test_close[0, :60], test_vol[0, :60]]) print(pred_dim) pred1 = sc.inverse_transform(pred_dim) final = [] for i in range(0, len(pred1)+60): if i <60: final.append(None) continue final.append(pred1[i-60, 0]) plt.figure(figsize=(30,20)) plt.plot(dataset['pct5']) plt.plot(final, c='r') plt.axvline(60, c='r') print(final)
注:我并不要求这个模型预测非常准确,毕竟金融时序精准预测几乎不可能,只希望它能表现出最基础的拟合效果,方便我后续迭代优化:)
问题修复方案
核心错误点
- 模型结构逻辑错误:你定义了多层LSTM但最终拼接的是原始输入,没有把LSTM的输出接入后续计算层,模型本质就是原始特征的线性回归,完全没有用到时序特征提取能力
- 归一化逻辑错误:三个特征共用同一个MinMaxScaler对象,后拟合的特征会覆盖之前的归一化参数,最后反归一化用的scaler参数和预测目标不匹配
- 预测输入维度错误:预测前对输入做了不必要的reshape,导致输入维度不符合模型要求的
(样本数, 60, 1)格式,输出自然异常
修改后的核心代码
1. 归一化部分(每个特征单独用独立的scaler)
sc_price = MinMaxScaler(feature_range=(0,1)) sc_volume = MinMaxScaler(feature_range=(0,1)) sc_pct = MinMaxScaler(feature_range=(0,1)) close = sc_price.fit_transform(dataset['Close'].values.reshape(-1,1)) volume = sc_volume.fit_transform(dataset['Volume'].values.reshape(-1,1)) pct = sc_pct.fit_transform(dataset['pct5'].values.reshape(-1,1))
2. 模型结构部分(接入LSTM输出)
def buildModel(dataLength, labelLength): price = Input(shape=(dataLength, 1), name='price') volumen = Input(shape=(dataLength, 1), name='volumen') # 串联价格分支LSTM层 price_lstm = LSTM(60, return_sequences=True)(price) price_lstm = LSTM(60, return_sequences=False)(price_lstm) # 串联成交量分支LSTM层 volume_lstm = LSTM(60, return_sequences=True)(volumen) volume_lstm = LSTM(60, return_sequences=False)(volume_lstm) # 拼接两个分支的LSTM输出,而非原始输入 concat = concatenate([price_lstm, volume_lstm]) output = Dense(1, activation='linear', name='dense')(concat) model = Model([price, volumen], output) opt = tf.keras.optimizers.Adam(learning_rate=0.001) model.compile(optimizer=opt, loss='mse') return model
3. 预测部分(修正输入维度和反归一化逻辑)
# 直接用符合维度要求的训练集输入预测 pred = rnn.predict([close_train, volume_train]) # 用涨跌幅对应的scaler反归一化 pred1 = sc_pct.inverse_transform(pred) final = [None]*60 + pred1.flatten().tolist()
修改后重新训练,训练集上就能看到明显的拟合效果,不会再输出平直线。
内容的提问来源于stack exchange,提问作者Fatafim
相关产品推荐
相关产品推荐

