如何将常规多变量DataFrame转换为Keras中LSTM适配的3D格式?
多变量DataFrame转Keras LSTM适配的3D输入形状方案
问题背景
在RStudio中用Keras构建LSTM模型,目标是用股票历史数据、新冠疫情数据等多特征预测股价。已完成数据归一化,训练/测试数据结构如下:
训练数据片段
> head(X_train) date BNTX.Open BNTX.High BNTX.Low BNTX.Volume VIX.Kurs 1 -1.726310 -0.9389774 -0.9147491 -0.9406800 -1.0391883 -1.044287 2 -1.718655 -0.9171379 -0.8772236 -0.9010828 -0.9745892 -1.060324 3 -1.710999 -0.8416828 -0.8386974 -0.8894619 -0.8806268 -1.065984 4 -1.703344 -0.8737693 -0.8639145 -0.8571816 -1.0318373 -1.098059 5 -1.695688 -0.8504807 -0.8601119 -0.8729989 -1.0149996 -1.183905 6 -1.688033 -0.8666275 -0.8773236 -0.9214194 -0.9598871 -1.182018 New_deaths New_cases 1 -1.900206 -1.529246 2 -1.900206 -1.529233 3 -1.900206 -1.529246 4 -1.900206 -1.529246 5 -1.900206 -1.529246 6 -1.900206 -1.529246 > head(y_train) BNTX.Adjusted 1 -0.9144203 2 -0.8675775 3 -0.8803998 4 -0.8622004 5 -0.8811237 6 -0.9182463
当前模型代码
dim(X_train)#[1] 452 8 modelLSTM <- keras_model_sequential() %>% layer_lstm(input_shape = c(8, 1), units = 8, activation = "relu", return_sequences = FALSE) %>% layer_dense(units = 8, activation = "relu") %>% layer_dense(units = 1) summary(modelLSTM) modelLSTM %>% compile(loss = "mse", optimizer ="rmsprop", metrics = "mae") modelLSTM <- modelLSTM %>% fit(X_train,y_train, epochs = 100, batch_size = 32, callback =list(callback_early_stopping(monitor = "val_loss", patience = 10, restore_best_weights = TRUE)) , validation_split = 0.2) modelLSTM %>% evaluate(X_test, y_test) pred_testy <- modelLSTM %>% predict(X_test) mean((y_test-pred_testy)^2) plot(y_test,pred_testy )
遇到的问题:直接设置input_shape后模型可能未正常工作;用生成器函数时无法区分特征集与目标集,无法完成测试集预测。
解决方案:多变量数据转3D张量
LSTM要求输入为3D张量:(样本数, 时间步长, 特征数)。核心是确定时间步长(用过去N个时间点的特征预测下一个时间点的股价),再将二维DataFrame转换为符合要求的3D结构。
1. 定义数据转换函数
该函数可明确区分特征集与目标集,完成训练/测试数据的格式转换:
create_lstm_dataset <- function(X, y, time_steps = 1) { # 初始化空列表存储转换后的数据 X_data <- list() y_data <- list() # 遍历生成每个样本的时间序列窗口 for (i in 1:(nrow(X) - time_steps)) { # 取连续time_steps行的特征作为一个样本 X_window <- X[i:(i + time_steps - 1), ] # 取窗口下一个时间点的目标值 y_target <- y[i + time_steps, ] X_data[[length(X_data) + 1]] <- as.matrix(X_window) y_data[[length(y_data) + 1]] <- as.matrix(y_target) } # 转换为3D张量:(样本数, 时间步长, 特征数) X_array <- array(unlist(X_data), dim = c(length(X_data), time_steps, ncol(X))) y_array <- array(unlist(y_data), dim = c(length(y_data), ncol(y))) return(list(X = X_array, y = y_array)) }
2. 转换训练和测试数据
假设选择时间步长为5(用过去5天的数据预测第6天的股价),执行转换:
# 设置时间步长 time_steps <- 5 # 转换训练数据 train_dataset <- create_lstm_dataset(X_train, y_train, time_steps) X_train_lstm <- train_dataset$X y_train_lstm <- train_dataset$y # 转换测试数据 test_dataset <- create_lstm_dataset(X_test, y_test, time_steps) X_test_lstm <- test_dataset$X y_test_lstm <- test_dataset$y # 查看转换后的数据维度 dim(X_train_lstm) # 输出应为 (452-5, 5, 8) = (447,5,8) dim(y_train_lstm) # 输出应为 (447,1)
3. 调整LSTM模型输入
根据转换后的3D张量调整input_shape,格式为(时间步长, 特征数):
modelLSTM <- keras_model_sequential() %>% # input_shape = (time_steps, 特征数),这里特征数是8 layer_lstm(input_shape = c(time_steps, ncol(X_train)), units = 8, activation = "relu", return_sequences = FALSE) %>% layer_dense(units = 8, activation = "relu") %>% layer_dense(units = 1) summary(modelLSTM)
4. 重新训练和评估模型
用转换后的3D数据训练模型,测试集同样使用转换后的结构:
modelLSTM %>% compile(loss = "mse", optimizer ="rmsprop", metrics = "mae") # 训练模型 modelLSTM <- modelLSTM %>% fit( x = X_train_lstm, y = y_train_lstm, epochs = 100, batch_size = 32, callbacks = list(callback_early_stopping(monitor = "val_loss", patience = 10, restore_best_weights = TRUE)), validation_split = 0.2 ) # 评估测试集 modelLSTM %>% evaluate(X_test_lstm, y_test_lstm) # 生成预测 pred_testy <- modelLSTM %>% predict(X_test_lstm) mean((y_test_lstm - pred_testy)^2) plot(y_test_lstm, pred_testy)
关键说明
- 时间步长
time_steps是超参数,可根据数据特点调整(如尝试3、5、7天等) - 转换函数确保了特征窗口与目标值的对应关系:每个样本窗口对应下一个时间点的股价
- 转换后的3D张量完全符合Keras LSTM的输入要求,避免了维度不匹配问题
内容的提问来源于stack exchange,提问作者magNGHI
相关产品推荐
相关产品推荐

