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

如何使用LSTM模型预测现有数据集范围外的未来时序数据

LSTM价格预测程序:未来外推预测实现及代码问题修正

问题背景

学习时序预测技术过程中编写了基于LSTM的基础价格预测程序,目前程序可正常运行,但仅能在已有数据集覆盖的时间范围内输出预测结果。期望实现突破现有数据集时间边界,预测尚未观测的未来数据(例如额外输出15个时间步的未来预测值),同时排查现有代码的逻辑缺陷。

当前使用的完整代码

from cProfile import label
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.pylab import rcParams

rcParams['figure.figsize'] = 20,10

from keras.models import Sequential
from keras.layers import LSTM, Dropout, Dense

from sklearn.preprocessing import MinMaxScaler

df = pd.read_csv('./Data/market-price-3y.csv')

# 仅保留日期和收盘价列
df = df[['Date', 'Close']]

# 将日期列从object类型转为datetime类型
df['Date'] = pd.to_datetime(df.Date, format='%Y-%m-%d %H:%M:%S')

# 将日期设为索引
df.index = df['Date']

print(df.head())

# 可视化历史收盘价
# plt.plot(df['Close'], label='Close Price History', color='red')
# plt.show()

df = df.sort_index(ascending=True, axis=0)

data = pd.DataFrame(index=range(0, len(df)), columns=['Date', 'Close'])

for i in range(0, len(data)):
    data['Date'][i] = df['Date'][i]
    data['Close'][i] = df['Close'][i]

scaler = MinMaxScaler(feature_range=(0,1))

data.index = data.Date
data.drop('Date', axis=1, inplace=True)

# 拆分训练集、验证集
final_data = data.values
train_data = final_data[0:900,:]
valid_data = final_data[900:,:]

scaler = MinMaxScaler(feature_range=(0,1))

scaled_data = scaler.fit_transform(final_data)
x_train_data, y_train_data = [], []
for i in range(60, len(train_data)):
    x_train_data.append(scaled_data[i-60:i,0])
    y_train_data.append(scaled_data[i,0])

x_train_data = np.asarray(x_train_data)
y_train_data = np.asarray(y_train_data)
x_train_data = np.reshape(x_train_data, (x_train_data.shape[0], x_train_data.shape[1],1))

# 构建LSTM模型
lstm_model = Sequential()
lstm_model.add(LSTM(units=50, return_sequences=True, input_shape=(np.shape(x_train_data)[1], 1)))
lstm_model.add(LSTM(units=50))
lstm_model.add(Dense(1))

model_data = data[len(data) - len(valid_data)-60:].values
model_data = model_data.reshape(-1,1)
model_data = scaler.transform(model_data)

# 训练模型
lstm_model.compile(loss='mean_squared_error', optimizer='adam')
lstm_model.fit(x_train_data, y_train_data, epochs=1, batch_size=1, verbose=2)

# 构造测试集
X_test = []
for i in range(60, model_data.shape[0]):
    X_test.append(model_data[i-60:i,0])
X_test = np.array(X_test)
X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1], 1))

# 得到验证集预测结果
predicted_price = lstm_model.predict(X_test)
predicted_price = scaler.inverse_transform(predicted_price)

train_data = data[:900]
valid_data = data[900:]
valid_data['Predictions'] = predicted_price
plt.plot(train_data['Close'])
plt.plot(valid_data[['Close', 'Predictions']])

plt.show()

当前程序运行效果

Matplotlib输出的预测结果图

当前预测结果在测试数据终点处停止,无法向外延伸预测未来时段数据。


现有代码存在的逻辑欠缺

  • 数据泄露问题:代码中MinMaxScaler在包含训练集、验证集的全量数据集上执行fit_transform,训练过程提前获取了验证集的数值分布信息,会导致验证集预测效果虚高,模型实际泛化能力差。
  • 训练配置不合理:模型仅训练1个epoch,且batch_size=1,没有充分学习时序数据规律,预测稳定性差;同时模型未加入Dropout正则化层,训练时容易出现过拟合。
  • 冗余代码拉低运行效率:通过for循环逐行复制DataFrame列的操作完全多余,pandas原生的索引、复制接口1行代码即可实现相同功能,运行效率更高。
  • 预测逻辑不支持时间外推:构造测试集时输入序列完全依赖已有的真实观测值,没有设计滚动迭代预测逻辑,因此只能输出已有数据覆盖时间范围内的结果,无法生成未来时段的预测值。

未来多步外推预测实现方法

当前搭建的是单步预测LSTM模型:输入长度为60的历史序列,输出1个时间步的预测值。不需要修改模型结构,新增滚动自回归预测逻辑即可实现数据集边界外的预测,以额外预测15个时间步为例,核心流程如下:

  1. 取数据集末尾最后60个真实值,作为第一轮预测的初始输入序列
  2. 将序列输入模型,得到第1个未来时间步的预测值
  3. 把刚生成的预测值追加到输入序列尾部,同时删除序列最开头的1个值,始终保持输入序列长度为60
  4. 重复步骤2、3,直到累计生成15个未来预测值

关键修改代码

首先修正数据泄露问题,调整归一化逻辑:

# 修正:scaler仅在训练集上拟合,避免数据泄露
scaler = MinMaxScaler(feature_range=(0,1))
scaled_train = scaler.fit_transform(train_data)
# 全量数据、待预测数据仅用训练集得到的scaler做转换
scaled_full_data = scaler.transform(final_data)

# 构造训练集逻辑保持不变,可适当调整训练参数
# 建议增加Dropout层、适当提高epoch数、调大batch_size提升训练效果
lstm_model = Sequential()
lstm_model.add(LSTM(units=50, return_sequences=True, input_shape=(60, 1)))
lstm_model.add(Dropout(0.2))
lstm_model.add(LSTM(units=50))
lstm_model.add(Dropout(0.2))
lstm_model.add(Dense(1))
lstm_model.compile(loss='mean_squared_error', optimizer='adam')
lstm_model.fit(x_train_data, y_train_data, epochs=20, batch_size=32, verbose=2)

在原有验证集预测逻辑后,追加未来15步滚动预测代码:

# 保留原有验证集预测、逆归一化逻辑
# --- 新增未来预测部分 ---
future_steps = 15
# 取全量数据最后60个值作为初始输入
last_seq = scaled_full_data[-60:].tolist()
future_preds = []

for _ in range(future_steps):
    # 转换为模型要求的输入shape: (样本数, 时间步, 特征数)
    input_seq = np.array(last_seq[-60:]).reshape(1, 60, 1)
    # 预测下一个时间步
    next_val = lstm_model.predict(input_seq, verbose=0)[0]
    future_preds.append(next_val)
    # 将预测值加入输入序列,供下一轮预测使用
    last_seq.append(next_val.tolist())

# 逆归一化得到真实价格尺度的预测结果
future_preds = scaler.inverse_transform(future_preds)

最后修改可视化代码,把未来预测结果绘制到图上:

# 生成未来时间索引(按数据日度频率顺延,若数据采样频率不是天可自行修改freq参数)
last_date = data.index[-1]
future_dates = pd.date_range(start=last_date + pd.Timedelta(days=1), periods=future_steps, freq='D')
future_df = pd.DataFrame(future_preds, index=future_dates, columns=['未来预测值'])

# 绘图
plt.figure(figsize=(20,10))
plt.plot(train_data['Close'], label='训练集真实价格')
plt.plot(valid_data['Close'], label='验证集真实价格')
plt.plot(valid_data['Predictions'], label='验证集预测价格')
plt.plot(future_df['未来预测值'], label='未来15步预测价格', linestyle='--', color='red')
plt.legend()
plt.show()

提示:这种单步滚动预测的方式,误差会随着预测步长增加不断累积,预测时长越久结果可靠性越低。如果需要做更长周期的预测,可以考虑直接构建多步输出的LSTM结构,或者采用Seq2Seq类的时序预测模型。

内容的提问来源于stack exchange,提问作者Timmy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 23:39:20