使用管道语法处理模型列表
working with lists of models using the pipe syntax
我经常喜欢拟合和检查多个模型,这些模型与 R 数据框中的两个变量相关。
我可以使用这样的语法来做到这一点:
require(tidyverse)
require(broom)
models <- list(hp ~ exp(cyl), hp ~ cyl)
map_df(models, ~tidy(lm(data=mtcars, formula=.x)))
但我已经习惯了管道语法,并希望能够做到这样的事情:
mtcars %>% map_df(models, ~tidy(lm(data=., formula=.x)))
这清楚地表明我是 "starting" 和 mtcars
,然后对其进行处理以生成我的输出。但是那个语法不起作用,报错 Error: Index 1 must have length 1
.
有没有一种方法可以编写我的 purrr:map()
函数,使我可以通过管道将 mtcars
传递给它以获得与上面的工作代码相同的输出? IE。
mtcars %>% <<<something>>>
这与 purrr::map
的工作方式有点不一致。您正在映射模型列表(一次是列表的一项),而不是数据框(一次是数据框的一列)。因为即使使用其他模型表达式,数据帧也保持不变,所以我认为映射不适用于这种情况。
但是,您可以根据上面的函数定义自定义函数来获得所需的语法。
library(tidyverse)
library(broom)
models <- list(hp ~ exp(cyl), hp ~ cyl)
models_to_rows <- function(data, models_list) {
models_list %>%
map_df(~tidy(lm(data=data, formula=.x)))
}
mtcars %>%
models_to_rows(models)
#> term estimate std.error statistic p.value
#> 1 (Intercept) 89.60052274 9.702303069 9.234975 2.823542e-10
#> 2 exp(cyl) 0.04045315 0.004897717 8.259594 3.212750e-09
#> 3 (Intercept) -51.05436157 24.981944312 -2.043650 4.985522e-02
#> 4 cyl 31.95828066 3.883803355 8.228604 3.477861e-09
tl/dr: mtcars %>% {map_df(models, function(.x) tidy(lm(data=., formula=.x)))}
或mtcars %>% map_df(models, ~tidy(lm(..1,..2)), ..2 = .)
您尝试的解决方案有 2 个问题。
首先,如果你想把点放在不寻常的地方,你需要使用花括号。
library(magrittr)
1 %>% divide_by(2) # 0.5 -> this works
1 %>% divide_by(2,.) # 2 -> this works as well
1 %>% divide_by(2,mean(.,3)) # this doesn't
1 %>% divide_by(.,2,mean(.,3)) # as it's equivalent to this one
1 %>% {divide_by(2,mean(.,3))} # but this one works as it forces all dots to be explicit.
第二个是你不能按照你想要的方式使用带有 ~
公式的点,尝试 map(c(1,2), ~ 3+.)
和 map(c(1,2), ~ 3+.x)
(甚至 map(c(1,2), ~ 3+..1)
),你会看到你得到了相同的结果。当您在 ~
公式中使用点时,它不再链接到管道函数。
要确保点被解释为 mtcars
,您需要使用良好的旧 function(x) ...
定义。
这个有效:
mtcars %>% {map_df(models, function(.x) tidy(lm(data=., formula=.x)))}
最后,作为奖励,这是我想出的,试图找到一个没有花括号的解决方案:
mtcars %>% map(models,lm,.) %>% map_df(tidy)
mtcars %>% map_df(models, ~tidy(lm(..1,..2)), ..2 = .)
这应该可行,不涉及 function
或 {}
的复杂性。纯粹的 purrr
解决方案。
library(tidyverse)
library(broom)
models <- list(hp ~ exp(cyl), hp ~ cyl)
mtcars %>%
list %>% # make it a list
cross2(models) %>% # get combinations
transpose %>% # put into a nice format
set_names("data", "formula") %>% # set names to lm arg names
pmap(lm) %>% # fit models
map_df(tidy) # tidy it up
我经常喜欢拟合和检查多个模型,这些模型与 R 数据框中的两个变量相关。
我可以使用这样的语法来做到这一点:
require(tidyverse)
require(broom)
models <- list(hp ~ exp(cyl), hp ~ cyl)
map_df(models, ~tidy(lm(data=mtcars, formula=.x)))
但我已经习惯了管道语法,并希望能够做到这样的事情:
mtcars %>% map_df(models, ~tidy(lm(data=., formula=.x)))
这清楚地表明我是 "starting" 和 mtcars
,然后对其进行处理以生成我的输出。但是那个语法不起作用,报错 Error: Index 1 must have length 1
.
有没有一种方法可以编写我的 purrr:map()
函数,使我可以通过管道将 mtcars
传递给它以获得与上面的工作代码相同的输出? IE。
mtcars %>% <<<something>>>
这与 purrr::map
的工作方式有点不一致。您正在映射模型列表(一次是列表的一项),而不是数据框(一次是数据框的一列)。因为即使使用其他模型表达式,数据帧也保持不变,所以我认为映射不适用于这种情况。
但是,您可以根据上面的函数定义自定义函数来获得所需的语法。
library(tidyverse)
library(broom)
models <- list(hp ~ exp(cyl), hp ~ cyl)
models_to_rows <- function(data, models_list) {
models_list %>%
map_df(~tidy(lm(data=data, formula=.x)))
}
mtcars %>%
models_to_rows(models)
#> term estimate std.error statistic p.value
#> 1 (Intercept) 89.60052274 9.702303069 9.234975 2.823542e-10
#> 2 exp(cyl) 0.04045315 0.004897717 8.259594 3.212750e-09
#> 3 (Intercept) -51.05436157 24.981944312 -2.043650 4.985522e-02
#> 4 cyl 31.95828066 3.883803355 8.228604 3.477861e-09
tl/dr: mtcars %>% {map_df(models, function(.x) tidy(lm(data=., formula=.x)))}
或mtcars %>% map_df(models, ~tidy(lm(..1,..2)), ..2 = .)
您尝试的解决方案有 2 个问题。
首先,如果你想把点放在不寻常的地方,你需要使用花括号。
library(magrittr)
1 %>% divide_by(2) # 0.5 -> this works
1 %>% divide_by(2,.) # 2 -> this works as well
1 %>% divide_by(2,mean(.,3)) # this doesn't
1 %>% divide_by(.,2,mean(.,3)) # as it's equivalent to this one
1 %>% {divide_by(2,mean(.,3))} # but this one works as it forces all dots to be explicit.
第二个是你不能按照你想要的方式使用带有 ~
公式的点,尝试 map(c(1,2), ~ 3+.)
和 map(c(1,2), ~ 3+.x)
(甚至 map(c(1,2), ~ 3+..1)
),你会看到你得到了相同的结果。当您在 ~
公式中使用点时,它不再链接到管道函数。
要确保点被解释为 mtcars
,您需要使用良好的旧 function(x) ...
定义。
这个有效:
mtcars %>% {map_df(models, function(.x) tidy(lm(data=., formula=.x)))}
最后,作为奖励,这是我想出的,试图找到一个没有花括号的解决方案:
mtcars %>% map(models,lm,.) %>% map_df(tidy)
mtcars %>% map_df(models, ~tidy(lm(..1,..2)), ..2 = .)
这应该可行,不涉及 function
或 {}
的复杂性。纯粹的 purrr
解决方案。
library(tidyverse)
library(broom)
models <- list(hp ~ exp(cyl), hp ~ cyl)
mtcars %>%
list %>% # make it a list
cross2(models) %>% # get combinations
transpose %>% # put into a nice format
set_names("data", "formula") %>% # set names to lm arg names
pmap(lm) %>% # fit models
map_df(tidy) # tidy it up