在R中合并多次lm回归训练输出至单个数据框的技术问询
我完全懂你要做的事——重复上千次拆分数据集训练线性模型,然后把所有结果规整到数据框里做后续分析,这在做模型稳定性验证或者蒙特卡洛模拟的时候太常用了!下面我用mtcars数据集给你写个完整的示例,一步步帮你实现需求:
方法一:Base R 原生实现
如果习惯用Base R的话,我们可以用循环来完成重复抽样、建模和结果存储:
# 设置核心参数 n_repeats <- 1000 # 重复次数 train_prop <- 0.63 # 训练集比例 data <- mtcars # 示例数据集 # 初始化存储结果的结构 # 1. 存储系数:每行对应一次重复,每列对应一个模型变量 coef_matrix <- matrix(NA, nrow = n_repeats, ncol = length(coef(lm(mpg ~ ., data = data)))) colnames(coef_matrix) <- names(coef(lm(mpg ~ ., data = data))) # 2. 存储R²:每个元素对应一次重复的R²值 r_squared_vec <- numeric(n_repeats) # 3. 存储拟合值:用列表存储每次重复的拟合值(因为每次训练集大小可能略有差异) fit_values_list <- vector("list", n_repeats) # 开始循环执行 for (i in 1:n_repeats) { # 随机拆分训练集索引 train_indices <- sample(nrow(data), size = floor(train_prop * nrow(data))) train_data <- data[train_indices, ] # 训练线性模型(这里以mpg为因变量,其他所有变量为自变量,你可以根据需求修改公式) fit <- lm(mpg ~ ., data = train_data) # 提取并存储系数 coef_matrix[i, ] <- coef(fit) # 提取并存储R² r_squared_vec[i] <- summary(fit)$r.squared # 提取并存储拟合值,同时标记重复ID和原数据行号 fit_values_list[[i]] <- data.frame( repeat_id = i, original_row = train_indices, fitted_value = predict(fit) ) } # 把结果转成整洁的数据框 # 系数+R²的汇总表 model_summary_df <- cbind(as.data.frame(coef_matrix), repeat_id = 1:n_repeats, r_squared = r_squared_vec) # 拟合值的合并表 fitted_values_df <- do.call(rbind, fit_values_list)
方法二:Tidyverse + Broom 更简洁的实现
如果你熟悉tidyverse生态,用purrr做批量处理、broom整理模型结果会更高效,代码可读性也更强:
library(tidyverse) library(broom) # 设置参数 n_repeats <- 1000 train_prop <- 0.63 data <- mtcars # 生成1000次抽样的索引列表 sample_indices <- map(1:n_repeats, ~sample(nrow(data), floor(train_prop * nrow(data)))) # 批量处理:抽样→建模→提取结果 results <- map2_dfr(1:n_repeats, sample_indices, function(repeat_id, indices) { train_data <- data[indices, ] fit <- lm(mpg ~ ., data = train_data) # 提取系数(转成宽格式) coef_df <- tidy(fit) %>% pivot_wider(names_from = term, values_from = estimate) %>% mutate(repeat_id = repeat_id) # 提取模型整体指标(包括R²) model_metrics <- glance(fit) %>% select(r.squared, adj.r.squared) %>% mutate(repeat_id = repeat_id) # 提取拟合值 fitted_df <- augment(fit) %>% mutate(repeat_id = repeat_id, original_row = indices) %>% select(repeat_id, original_row, fitted_value = .fitted) # 返回三个结果部分,方便后续拆分 list( model_summary = left_join(coef_df, model_metrics, by = "repeat_id"), fitted_values = fitted_df ) }) # 拆分出最终的数据框 model_summary_df <- results %>% pluck("model_summary") %>% bind_rows() fitted_values_df <- results %>% pluck("fitted_values") %>% bind_rows()
一些注意事项
- 如果你需要的是测试集的预测值,只需要把
predict(fit)改成predict(fit, newdata = data[-indices, ]),同时存储测试集的行号即可。 - 对于你的1000条观测的数据集,1000次循环生成的拟合值数据框会有大约63万行,这在R里完全可以轻松处理,不用担心内存问题。
- 两种方法的核心逻辑都是给每个重复的结果打上唯一ID,这样后续合并、分析时能准确对应每次建模的结果。
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

