使用 dplyr() 检索通过 group_by() 和 do() 创建的模型对象

Ste*_*ven 2 r dplyr

我正在尝试使用dplyr管道运算符 ( %>%) 来检索存储在数据框中的模型对象。

带有示例数据

library(dplyr)

set.seed(256)
dat <- 
  data.frame(x = rnorm(100), 
           y = rnorm(100, 10), 
           spec = sample(c("1", "2"), 100, TRUE)) %>%
  group_by(spec) %>%
  do(lm = lm(y ~ x, data = .))
Run Code Online (Sandbox Code Playgroud)

我可以子集并检索实际的模型对象

> dat$lm[dat$spec == "1"][[1]]

Call:
lm(formula = y ~ x, data = .)

Coefficients:
(Intercept)            x  
     9.8171      -0.2292  

> dat$lm[dat$spec == "1"][[1]] %>% class()
[1] "lm
Run Code Online (Sandbox Code Playgroud)

但我认为这是检索lm()其中包含的模型对象的一种不优雅的方式,特别是考虑到我的代码的其余部分是按“dplyr方式”构建的。我想使用dplyr,但不知道如何使用。例如,使用

dat %>% filter(spec == "1") %>% select(lm) 
Run Code Online (Sandbox Code Playgroud)

返回时不起作用

Source: local data frame [1 x 1]
Groups: <by row>

# A tibble: 1 x 1
  lm      
  <list>  
1 <S3: lm>
Run Code Online (Sandbox Code Playgroud)

dat %>% filter(spec == "1") %>% .$lm
Run Code Online (Sandbox Code Playgroud)

只能让我找到列表中的第一个对象,例如,

> dat %>% filter(spec == "1") %>% .$lm
[[1]]

Call:
lm(formula = y ~ x, data = .)

Coefficients:
(Intercept)            x  
   10.01495     -0.07438  
Run Code Online (Sandbox Code Playgroud)

我无法找到一种方法来获取 with 中的实际模型dat对象dplyr。当然,我可以用broomtidy()来浓缩一切

library(broom)
tidy(dat, lm)
Run Code Online (Sandbox Code Playgroud)

但这仍然不会返回实际的模型对象:

> tidy(dat, lm)
# A tibble: 4 x 6
# Groups: spec [2]
  spec  term        estimate std.error statistic                        p.value
  <fct> <chr>          <dbl>     <dbl>     <dbl>                          <dbl>
1 1     (Intercept)  10.0        0.120    83.3                         1.91e-54
2 1     x           - 0.0744     0.111   - 0.671                       5.05e- 1
3 2     (Intercept)   9.86       0.131    75.0                         1.42e-50
4 2     x           - 0.0793     0.148   - 0.535                       5.95e- 1
Run Code Online (Sandbox Code Playgroud)

我什至可以使用dplyr调用summarise()的输出do()并从模型中检索系数,但这仍然没有给我模型对象本身:

dat %>% 
  select(spec) %>%
  bind_cols(dat %>%
              summarize(lm_i = coefficients(lm)[[1]], 
                        lm_s = coefficients(lm)[[2]]))
Run Code Online (Sandbox Code Playgroud)

有没有办法dplyr从使用创建的模型中检索实际的模型对象do()

ali*_*ire 5

do返回一个列表列,因此要提取其各个元素,您需要使用列表子集。有多种方法可以做到这一点,但在 tidyverse 中,purrr::pluck提取单个[可能深度嵌套]元素是一个不错的选择:

library(tidyverse)

dat %>% pluck('lm', 1)
#> 
#> Call:
#> lm(formula = y ~ x, data = .)
#> 
#> Coefficients:
#> (Intercept)            x  
#>    10.01495     -0.07438
Run Code Online (Sandbox Code Playgroud)

它主要相当于[[子集化,即

dat[['lm']][[1]]
Run Code Online (Sandbox Code Playgroud)

为了得到你必须工作的东西,你需要继续子集化,因为.$lm返回列表列,在本例中是模型的列表。.[[1]](类似于上面1)从列表中提取模型:

dat %>% filter(spec == "1") %>% .$lm %>% .[[1]]
Run Code Online (Sandbox Code Playgroud)

或混合方法,如果您愿意的话:

dat %>% filter(spec == "1") %>% pluck('lm', 1)
Run Code Online (Sandbox Code Playgroud)

或使用pullNSE 语义提取列:

dat %>% filter(spec == "1") %>% pull(lm) %>% pluck(1)
Run Code Online (Sandbox Code Playgroud)

全部返回相同的东西。