R语言构建循环对比神经网络与逻辑回归的Bootstrap MSE问题
我明白你现在的困境——想用Bootstrap对比神经网络和逻辑回归的MSE,但自定义统计量让boot函数卡壳,而且对神经网络的循环实现有点懵。刚好我对Günther & Fritsch (2010)的模拟框架很熟悉,咱们一步步解决这个问题:
解决Bootstrap MSE对比的问题:神经网络 vs 逻辑回归
首先明确核心问题:boot包要求自定义统计量函数必须接受数据和Bootstrap索引两个参数,很多时候出错就是因为没正确处理索引提取样本。另外神经网络的拟合需要注意收敛参数,避免中途报错。
1. 准备模拟数据(贴合Günther & Fritsch 2010的风格)
先生成非线性的回归/分类数据,这里先做回归场景(分类场景我后面会补充):
# 加载必备包 library(boot) library(nnet) set.seed(123) # 固定随机种子保证可复现 n <- 200 x1 <- runif(n, -pi, pi) x2 <- runif(n, -pi, pi) # 生成非线性响应变量 y <- sin(x1) + cos(x2) + rnorm(n, 0, 0.3) data <- data.frame(x1, x2, y)
2. 定义Bootstrap统计量函数
这是关键!统计量函数必须接受data和indices两个参数,用indices从原数据中抽取Bootstrap样本,再拟合模型计算MSE。
线性/逻辑回归的统计量函数
如果是回归问题(你提到的逻辑回归可能是笔误?如果是分类我后面补),先写线性回归的:
boot_lm_mse <- function(data, indices) { # 提取Bootstrap样本 boot_sample <- data[indices, ] # 拟合模型 lm_model <- lm(y ~ x1 + x2, data = boot_sample) # 计算MSE pred <- predict(lm_model, newdata = boot_sample) mse <- mean((boot_sample$y - pred)^2) return(mse) }
如果是分类问题(逻辑回归),调整数据和函数:
# 生成二分类数据 y_prob <- plogis(sin(x1) + cos(x2)) y_bin <- rbinom(n, 1, y_prob) data_bin <- data.frame(x1, x2, y_bin) # 逻辑回归的MSE统计量(预测概率与实际标签的均方误差) boot_glm_mse <- function(data, indices) { boot_sample <- data[indices, ] glm_model <- glm(y_bin ~ x1 + x2, data = boot_sample, family = binomial) pred_prob <- predict(glm_model, newdata = boot_sample, type = "response") mse <- mean((boot_sample$y_bin - pred_prob)^2) return(mse) }
神经网络的统计量函数
神经网络拟合要注意设置足够的迭代次数(maxit)避免收敛失败,关闭trace减少冗余输出:
# 回归神经网络的统计量函数 boot_nnet_mse <- function(data, indices) { boot_sample <- data[indices, ] # 1个隐藏层节点,迭代1000次,关闭训练日志 nnet_model <- nnet(y ~ x1 + x2, data = boot_sample, size = 1, maxit = 1000, trace = FALSE) pred <- predict(nnet_model, newdata = boot_sample) mse <- mean((boot_sample$y - pred)^2) return(mse) } # 分类神经网络的统计量函数 boot_nnet_bin_mse <- function(data, indices) { boot_sample <- data[indices, ] # 加entropy=TRUE用交叉熵损失,适合分类 nnet_model <- nnet(y_bin ~ x1 + x2, data = boot_sample, size = 1, maxit = 1000, trace = FALSE, entropy = TRUE) pred_prob <- predict(nnet_model, newdata = boot_sample, type = "raw") mse <- mean((boot_sample$y_bin - pred_prob)^2) return(mse) }
3. 运行Bootstrap并对比结果
用boot包快速运行,或者用你熟悉的for循环实现:
用boot包实现
B <- 1000 # Bootstrap次数 # 回归场景 boot_lm_results <- boot(data = data, statistic = boot_lm_mse, R = B) boot_nnet_results <- boot(data = data, statistic = boot_nnet_mse, R = B) # 查看结果 cat("线性回归Bootstrap MSE均值:", mean(boot_lm_results$t), "\n") cat("神经网络Bootstrap MSE均值:", mean(boot_nnet_results$t), "\n") # 可视化分布 par(mfrow = c(1,2)) hist(boot_lm_results$t, main = "线性回归MSE分布", xlab = "MSE", col = "lightblue") hist(boot_nnet_results$t, main = "神经网络MSE分布", xlab = "MSE", col = "lightgreen") par(mfrow = c(1,1))
用for循环实现(你提到的传统循环方式)
如果你更习惯手动写循环,这样做:
B <- 1000 mse_lm <- numeric(B) mse_nnet <- numeric(B) set.seed(123) for (i in 1:B) { # 抽取Bootstrap样本(有放回抽样) boot_indices <- sample(1:nrow(data), nrow(data), replace = TRUE) boot_sample <- data[boot_indices, ] # 拟合线性回归并计算MSE lm_model <- lm(y ~ x1 + x2, data = boot_sample) mse_lm[i] <- mean((boot_sample$y - predict(lm_model, boot_sample))^2) # 拟合神经网络并计算MSE nnet_model <- nnet(y ~ x1 + x2, data = boot_sample, size = 1, maxit = 1000, trace = FALSE) mse_nnet[i] <- mean((boot_sample$y - predict(nnet_model, boot_sample))^2) } # 结果汇总 cat("线性回归MSE均值(循环版):", mean(mse_lm), "\n") cat("神经网络MSE均值(循环版):", mean(mse_nnet), "\n")
常见坑点提醒
- 统计量函数参数:必须包含
data和indices,不能直接用全局数据,否则boot函数无法正确抽样; - 神经网络收敛:一定要设置
maxit(比如1000),默认迭代次数太少容易导致拟合失败; - 分类问题注意事项:神经网络要加
entropy=TRUE,预测时用type="raw"获取概率值,否则会得到分类标签,MSE计算就没意义了。
内容的提问来源于stack exchange,提问作者JWH2006
相关产品推荐
相关产品推荐

