使用扫帚从分组线性模型中提取斜率和 r 平方

Extract slope and r squared from grouped linear models using broom

我有一个数据框,我想按组 运行 线性模型,然后使用 broom 包提取每个模型的斜率和 r 平方。到目前为止我正在尝试这个:

library(tidyverse)
library(broom)

#read in the dataset
data(mtcars) 

#add a group variable
mtcars <- mtcars %>% as_tibble() %>% mutate(LC = 1)

#create a second group
mtcars2 <- mtcars 
mtcars2 <- mtcars2 %>% mutate(LC = 2)

#bind together
mtcars <- rbind(mtcars, mtcars2)

#groupby and run regressions
all_regress <-  mtcars %>% group_by(LC) %>%
  do(mod1 = lm(mpg ~ disp, data = .),
     mod2 = lm(mpg ~ wt, data = .))

#use broom the extract the slope and rsq per group
glance <-all_regress %>% mutate(tidy = map(mod1, broom::tidy),
                                   glance = map(mod1, broom::glance),
                                   augment = map(mod1, broom::augment),
                                   rsq = glance %>% map_dbl('r.squared'),
                                   slope = tidy %>% map_dbl(function(x) x$estimate[2])) 

但这失败了:

Error: Problem with `mutate()` input `tidy`.
x No tidy method for objects of class qr
ℹ Input `tidy` is `map(mod1, broom::tidy)`.
ℹ The error occurred in row 1.

如果我在没有组的情况下执行此操作,例如:

    #read in the dataset
    data(mtcars) 
    
    mtcars <- mtcars %>% as_tibble()
   
    #run regressions
    all_regress <-  mtcars %>%
      do(mod1 = lm(mpg ~ disp, data = .),
         mod2 = lm(mpg ~ wt, data = .))
    
    #use broom the extract the slope and rsq per group
    glance <- all_regress %>% mutate(tidy = map(mod1, broom::tidy),
                                       glance = map(mod1, broom::glance),
                                       augment = map(mod1, broom::augment),
                                       rsq = glance %>% map_dbl('r.squared'),
                                       slope = tidy %>% map_dbl(function(x) x$estimate[2])) 

没有错误。

我认为只需添加 ungroup() 即可实现您的需求:

all_regress <-  mtcars %>% group_by(LC) %>%
  do(mod1 = lm(mpg ~ disp, data = .),
     mod2 = lm(mpg ~ wt, data = .)) %>% ungroup()

#use broom the extract the slope and rsq per group
glance <-all_regress %>% mutate(tidy = map(mod1, broom::tidy),
                                   glance = map(mod1, broom::glance),
                                   augment = map(mod1, broom::augment),
                                   rsq = glance %>% map_dbl('r.squared'),
                                   slope = tidy %>% map_dbl(function(x) x$estimate[2])) 

我使用了这种方法,它的时间更长,但我认为在各个步骤中有更多的控制。最后,我创建了一个小标题,其中包含包含每个模型的列表列。

library(tidyverse)
library(broom)

#read in the dataset
data(mtcars) 

#add a group variable
mtcars <- mtcars %>% as_tibble() %>% dplyr::select(-c(vs, am, gear, carb, cyl)) %>% mutate(LC = 1)

#create a second group
mtcars2 <- mtcars 
mtcars2 <- mtcars2 %>% mutate(LC = 2)

#bind together
mtcars <- bind_rows(mtcars2, mtcars)

#group_split and run regressions
all_regress <-  mtcars %>% group_split(LC) %>% 

    
       map(~ list(mod1 = lm(mpg ~ disp, data = .),
       mod2 = lm(mpg ~ wt, data = .)))


# example <- all_regress[[2]][[1]] %>% glance()
#the list has 2 levels with 2 models each
data <- all_regress %>% 
    map(~
            map(.x, function(model){
                #column lists are needed because each function output different objects
                tibble(mod = list(model),
                       tidy = list(broom::tidy(model)),
                       glance = list(broom::glance(model)),
                       augment = list(broom::augment(model))) %>%
                    mutate(
                        rsq = list(glance[[1]]$r.squared),
                        slope = list(tidy[[1]]$estimate[2]))

                       
            } ))

data_final <- 
data %>% map2(unique(mtcars$LC), ~
                 map2(.x, .y, function(each_model, lc){
                     mutate(each_model, LC = lc)
                 }))

final_format <- #because of the list structure i need to bind the two datasets in each level and then bind them again.
map(data_final, ~reduce(.x, rbind)) %>% reduce(rbind)


#acces the data
final_format[1, 1][[1]]