You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.19 15:15:04