Keras(R语言版):二分类任务中所有输入的预测概率为何相同?
用R语言Keras实现滑动窗口式时间序列二分类(全连接神经网络)
我来分享一套完整的实现方案,刚好匹配你提到的「多输入时间序列+滑动窗口转结构化数据+MLP二分类」的需求,一步步来拆解:
1. 先明确滑动窗口的转换逻辑
就像你举的例子:1个二分类标签、2条输入序列(a、b)、回溯步长为2的情况下,转换后的数据结构会是这样(我补全了完整的样本逻辑):
| label | a | b | a.1 | b.1 | a.2 | b.2 |
|---|---|---|---|---|---|---|
| 1 | 1.0 | 0.1 | NA | NA | NA | NA |
| 1 | 0.2 | 0.2 | 1.0 | 0.1 | NA | NA |
| 0 | 0.5 | 0.3 | 0.2 | 0.2 | 1.0 | 0.1 |
| ... | ... | ... | ... | ... | ... | ... |
这里的a.1是a序列的前1步值,a.2是前2步值;前回溯步长个样本因为没有足够的历史数据会出现NA,后续我们可以直接丢弃这些样本,或者用填充法处理。
2. 实现滑动窗口数据转换(R代码)
首先我们先构造模拟数据,然后写一个通用的滑动窗口转换函数:
# 构造模拟时间序列数据(替换成你的真实数据即可) set.seed(123) n <- 100 # 样本量 df <- data.frame( label = sample(c(0,1), n, replace = TRUE), # 二分类标签 a = rnorm(n, mean = 0, sd = 1), # 输入序列a b = rnorm(n, mean = 1, sd = 0.5) # 输入序列b ) # 滑动窗口转换函数:生成滞后特征 create_sliding_window <- function(data, input_cols, label_col, window_size) { result <- data.frame() # 从第window_size+1个样本开始,因为前window_size个没有足够历史数据 for(i in (window_size + 1):nrow(data)) { # 提取当前样本的标签 current_label <- data[i, label_col] # 提取当前样本的原始输入特征 current_inputs <- data[i, input_cols] # 提取window_size步的滞后特征,按步长命名(比如a.1、a.2) lag_features <- do.call(cbind, lapply(input_cols, function(col) { lag_vals <- rev(data[(i - window_size):(i - 1), col]) names(lag_vals) <- paste0(col, ".", 1:window_size) lag_vals })) # 合并当前样本的所有特征和标签 current_row <- cbind(current_label, current_inputs, lag_features) result <- rbind(result, current_row) } # 重命名标签列 colnames(result)[1] <- label_col return(result) } # 调用函数:输入列是c("a","b"),标签列是"label",窗口大小2 window_df <- create_sliding_window(df, input_cols = c("a","b"), label_col = "label", window_size = 2)
运行完后,window_df就是适合MLP输入的结构化数据,已经自动跳过了前2个有NA的样本。
3. 数据预处理:标准化+划分数据集
全连接神经网络对数据尺度很敏感,必须做标准化,同时划分训练/测试集:
library(keras) # 分离特征矩阵和标签向量 X <- as.matrix(window_df[, !colnames(window_df) %in% "label"]) y <- as.matrix(window_df$label) # 按7:3划分训练测试集 train_idx <- sample(1:nrow(X), 0.7*nrow(X)) X_train <- X[train_idx, ] X_test <- X[-train_idx, ] y_train <- y[train_idx] y_test <- y[-train_idx] # 标准化特征(只用训练集的统计量,避免数据泄露) scaler <- preprocessing_scale() X_train_scaled <- fit_transform(scaler, X_train) X_test_scaled <- transform(scaler, X_test)
4. 构建并训练全连接神经网络
接下来用Keras搭建MLP模型,针对二分类任务做配置:
# 构建MLP模型 model <- keras_model_sequential() %>% # 输入层+第一个隐藏层:32个神经元,ReLU激活 layer_dense(units = 32, activation = "relu", input_shape = ncol(X_train_scaled)) %>% # Dropout层:随机丢弃20%神经元,防止过拟合 layer_dropout(rate = 0.2) %>% # 第二个隐藏层:16个神经元,ReLU激活 layer_dense(units = 16, activation = "relu") %>% # 输出层:1个神经元,Sigmoid激活(二分类专属) layer_dense(units = 1, activation = "sigmoid") # 编译模型:用Adam优化器,二元交叉熵损失,监控准确率 model %>% compile( optimizer = optimizer_adam(learning_rate = 0.001), loss = "binary_crossentropy", metrics = c("accuracy") ) # 查看模型结构 summary(model) # 训练模型:用训练集的20%做验证,训练50轮 history <- model %>% fit( x = X_train_scaled, y = y_train, batch_size = 8, epochs = 50, validation_split = 0.2, verbose = 1 ) # 绘制训练曲线(查看训练/验证集的损失和准确率变化) plot(history)
5. 模型评估与预测
最后在测试集上验证模型效果,并生成预测结果:
# 在测试集上评估模型性能 model %>% evaluate(X_test_scaled, y_test) # 生成预测概率 y_pred_prob <- model %>% predict(X_test_scaled) # 转换为类别标签(阈值设为0.5,可根据需求调整) y_pred <- ifelse(y_pred_prob > 0.5, 1, 0) # 生成混淆矩阵,查看分类效果 table(Actual = y_test, Predicted = y_pred)
几个关键注意事项
- 滑动窗口大小选择:别凭感觉定,建议用交叉验证尝试不同的窗口大小(比如1、2、5、10),选验证集性能最好的。
- 缺失值处理:如果不想丢弃前
window_size个样本,可以用滚动均值、中位数或者前向填充(比如zoo包的na.locf()函数)来补NA。 - 过拟合应对:除了Dropout层,还可以加L2正则化(比如
layer_dense(..., kernel_regularizer = regularizer_l2(0.001))),或者用早停法(callback_early_stopping(patience = 5)),防止模型在训练集上过拟合。
内容的提问来源于stack exchange,提问作者hokage555
相关产品推荐
相关产品推荐

