如何使用LSTM模型基于多特征输入实现单输出时序预测?
多变量LSTM单目标预测实现方案
你需要实现的是*多输入单输出(MISO)*时序预测任务:用全量股票技术特征、多标的行情数据的时序信息,拟合指定单一目标(如标普500收盘价)的走势。
现有代码存在两处核心偏差:
- 标签拆分逻辑硬编码取数据集最后一列,未手动指定目标列位置
- 输入形状重构时将时间步长设为1,未构造时序滑动窗口样本,LSTM无法学习长短期时序依赖
以下是标准化实现流程:
1. 明确目标列,正确拆分特征与标签
不要用[:, -1]的默认方式取标签,先在数据集中定位你要预测的目标列,建议对特征和目标值分别做缩放,方便后续逆转换还原真实价格:
import numpy as np from sklearn.preprocessing import MinMaxScaler from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dropout, Dense # 替换为你的目标列名,例如标普500收盘价列 TARGET_COL = "sp500_close" # 数据集需提前按时间升序排列,禁止随机打乱 feature_data = feature_data.sort_values("trade_date").reset_index(drop=True) # 拆分特征、目标列 X = feature_data.drop(columns=[TARGET_COL, "trade_date"]).values y = feature_data[[TARGET_COL]].values # 先切分数据集再做缩放,避免数据泄露 train_size = int(len(X) * 0.8) X_train, X_test = X[:train_size], X[train_size:] y_train, y_test = y[:train_size], y[train_size:] scaler_X = MinMaxScaler(feature_range=(0,1)) scaler_y = MinMaxScaler(feature_range=(0,1)) X_train_scaled = scaler_X.fit_transform(X_train) X_test_scaled = scaler_X.transform(X_test) y_train_scaled = scaler_y.fit_transform(y_train) y_test_scaled = scaler_y.transform(y_test)
2. 构造时序滑动窗口样本
LSTM输入要求形状为(样本数, 时间步长, 特征数),需要用过去N个时间步的全量特征,预测当前/未来时间步的目标值。时间步长可根据预测周期调整,常用值为5、10、20、60(对应单周、双周、单月、单季度交易日):
def build_ts_dataset(X, y, time_steps=10): X_seq, y_seq = [], [] for i in range(time_steps, len(X)): # 取过去time_steps步的所有特征 X_seq.append(X[i-time_steps:i, :]) # 取当前步的目标值 y_seq.append(y[i, 0]) return np.array(X_seq), np.array(y_seq) # 设定时间步长 TIME_STEPS = 10 X_train_seq, y_train_seq = build_ts_dataset(X_train_scaled, y_train_scaled, TIME_STEPS) X_test_seq, y_test_seq = build_ts_dataset(X_test_scaled, y_test_scaled, TIME_STEPS)
3. 模型训练与预测
你现有堆叠LSTM的结构可直接复用,仅需调整输入形状匹配、输出层激活函数适配回归任务即可:
model = Sequential() model.add(LSTM(50, return_sequences=True, input_shape=(X_train_seq.shape[1], X_train_seq.shape[2]))) model.add(Dropout(0.2)) model.add(LSTM(units=50, return_sequences=True)) model.add(Dropout(0.2)) model.add(LSTM(units=50, return_sequences=True)) model.add(Dropout(0.2)) model.add(LSTM(units=50)) model.add(Dropout(0.2)) # 回归任务用linear激活,避免relu截断0值导致预测偏差 model.add(Dense(units=1, activation='linear')) model.compile(optimizer='adam', loss='mse') history = model.fit( X_train_seq, y_train_seq, batch_size=32, epochs=50, validation_data=(X_test_seq, y_test_seq), shuffle=False # 时序训练禁止打乱样本顺序 ) # 预测后用scaler_y还原真实价格尺度 y_pred_scaled = model.predict(X_test_seq) y_pred = scaler_y.inverse_transform(y_pred_scaled) y_true = scaler_y.inverse_transform(y_test_seq.reshape(-1,1))
注意事项
- 所有缩放操作必须在训练/测试集拆分后完成,仅用训练集统计量拟合scaler,否则会造成数据泄露,验证结果虚高
- 输入特征建议提前做共线性筛选,剔除和目标列相关性极低的噪声特征,避免干扰模型学习
- 若要预测多步之后的价格,仅需调整
build_ts_dataset函数中y的取值偏移量即可 - 模型评估不要直接用缩放后的MSE,需还原到真实价格尺度后计算指标,结果才有实际参考意义
内容的提问来源于stack exchange,提问作者WILLIAM
相关产品推荐
相关产品推荐

