将字符向量映射到r中的lm公式

zes*_*sla 6 r purrr

我正在尝试使用purrr :: map制作lm对象的列表。以mtcars为例:

vars <- c('hp', 'wt', 'disp')
map(vars, ~lm(mpg~.x, data=mtcars))
Run Code Online (Sandbox Code Playgroud)

错误:model.frame.default(formula = mpg〜.x,data = mtcars,drop.unused.levels = TRUE)中的错误:可变长度不同(为'.x'找到)

我也尝试过:

map(vars, function(x) {x=sym(x); lm(mpg~!!x, data=mtcars)})
Run Code Online (Sandbox Code Playgroud)

我收到错误消息:

Error in !x : invalid argument type
Run Code Online (Sandbox Code Playgroud)

谁能告诉我我做错了什么?提前致谢。

ali*_*ire 7

通常的方法是将paste公式作为字符串组合在一起,通过mapping 转换它们as.formula(您不能创建公式的向量;它必须是列表),然后单击map lm。如果愿意,可以将所有功能组合到一个调用中,但是我更喜欢映射单个函数,这使代码更易于阅读:

library(purrr)

c('hp', 'wt', 'disp') %>% 
    paste('mpg ~', .) %>% 
    map(as.formula) %>% 
    map(lm, data = mtcars)
#> [[1]]
#> 
#> Call:
#> .f(formula = .x[[i]], data = ..1)
#> 
#> Coefficients:
#> (Intercept)           hp  
#>    30.09886     -0.06823  
#> 
#> 
#> [[2]]
#> 
#> Call:
#> .f(formula = .x[[i]], data = ..1)
#> 
#> Coefficients:
#> (Intercept)           wt  
#>      37.285       -5.344  
#> 
#> 
#> [[3]]
#> 
#> Call:
#> .f(formula = .x[[i]], data = ..1)
#> 
#> Coefficients:
#> (Intercept)         disp  
#>    29.59985     -0.04122
Run Code Online (Sandbox Code Playgroud)

实际上没有必要进行调用,map(as.formula)因为lm它会强制将其转换为公式,但是并非所有模型都如此慷慨(例如mgcv::gam)。

这种方法的缺点是,对象中列出的调用看起来很时髦,但是系数告诉您到底哪个是足够容易的。一个有用的替代方法是将公式保留为data.frame的一列中的字符串,将模型保留为list列中的模型,例如

library(tidyverse)

data_frame(formula = paste('mpg ~', c('hp', 'wt', 'disp')), 
           model = map(formula, lm, data = mtcars))
#> # A tibble: 3 x 2
#>      formula    model
#>        <chr>   <list>
#> 1   mpg ~ hp <S3: lm>
#> 2   mpg ~ wt <S3: lm>
#> 3 mpg ~ disp <S3: lm>
Run Code Online (Sandbox Code Playgroud)