多因素回归循环实现问题:批量运行回归并存储系数与截距
我懂你现在的困扰——想按ID和group分组跑回归,提取每个组的截距和x1的回归系数,但第二种方法跑出来所有结果全一样,这大概率是循环里的分组筛选逻辑没处理对,导致每次都跑了整个数据集的回归,而不是对应组的子集。
下面给你几种靠谱的解决方案,从tidyverse的简洁写法到基础R的循环都有,你可以根据自己的习惯选:
方法一:用dplyr + broom 快速整理结果(最推荐)
这种写法简洁直观,能直接得到你想要的结构化结果:
library(dplyr) library(broom) # 假设你的数据集名为df final_result <- df %>% # 按ID和group分组 group_by(ID, group) %>% # 对每个组跑回归,并用tidy()把结果转成整洁数据框 do(tidy(lm(y ~ x1, data = .))) %>% # 只保留截距和x1的系数行 filter(term %in% c("(Intercept)", "x1")) %>% # 把行转成列,让每个组的截距和系数在同一行 pivot_wider(names_from = term, values_from = estimate) %>% # 取消分组状态 ungroup()
方法二:用purrr + nest 更现代的tidyverse写法
如果习惯用嵌套数据框的思路,这种写法也很清晰:
library(tidyverse) final_result <- df %>% # 把每个ID-group组合的数据嵌套成列表列 nest(data = -c(ID, group)) %>% # 对每个嵌套的数据集跑回归,再提取系数 mutate( model = map(data, ~ lm(y ~ x1, data = .x)), coefs = map(model, tidy) ) %>% # 展开系数数据框 unnest(coefs) %>% # 筛选需要的项 filter(term %in% c("(Intercept)", "x1")) %>% # 调整成宽格式 pivot_wider(names_from = term, values_from = estimate) %>% # 保留需要的列 select(ID, group, `(Intercept)`, x1) %>% ungroup()
方法三:基础R循环(如果偏好原生语法)
要是你坚持用基础R写循环,一定要注意每次循环都要筛选出当前组的子集——这应该就是你之前第二种方法出错的地方:
# 先获取所有唯一的ID-group组合 unique_groups <- unique(df[, c("ID", "group")]) # 创建空列表存结果 result_list <- list() for(i in 1:nrow(unique_groups)){ # 取出当前循环的ID和group current_id <- unique_groups$ID[i] current_group <- unique_groups$group[i] # 关键步骤:筛选当前组的数据集! current_data <- df[df$ID == current_id & df$group == current_group, ] # 跑回归 model <- lm(y ~ x1, data = current_data) # 提取截距和x1的系数 intercept_val <- coef(model)[["(Intercept)"]] beta_x1_val <- coef(model)[["x1"]] # 把当前组的结果存入列表 result_list[[i]] <- data.frame( ID = current_id, group = current_group, Intercept = intercept_val, Beta_x1 = beta_x1_val ) } # 把列表合并成最终数据框 final_result <- do.call(rbind, result_list)
为什么你的第二种方法结果全相同?
大概率是循环里没有像上面这样筛选当前组的子集,比如直接用了lm(y~x1, data=df)(整个数据集),而不是current_data,导致每次循环都跑了全量数据的回归,自然系数全一样。
内容的提问来源于stack exchange,提问作者Bruno Kluwe Schiavon
相关产品推荐
相关产品推荐

