Working with model lists using channel syntax

I often like to pick up and explore several models that bind two variables in the data frame R.

I can do this with the syntax:

require(tidyverse) require(broom) models <- list(hp ~ exp(cyl), hp ~ cyl) map_df(models, ~tidy(lm(data=mtcars, formula=.x))) 

But I got used to the channel syntax and hoped that I could something like this:

 mtcars %>% map_df(models, ~tidy(lm(data=., formula=.x))) 

This makes it clear that I start with mtcars and then do stuff for this to generate my output. But this syntax does not work, giving the error Error: Index 1 must have length 1 .

Is there a way to write my purrr:map() function so that I can mtcars in it to get the same result as the working code above? I.e

 mtcars %>% <<<something>>> 
+5
source share
3 answers

tl / dr: mtcars %>% {map_df(models, function(.x) tidy(lm(data=., formula=.x)))}

Or mtcars %>% map_df(models, ~tidy(lm(..1,..2)), ..2 = .)


There are problems with the solution you tried.

First, you need to use curly braces if you want to place a point in an unusual place.

 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 equivalent to this one 1 %>% {divide_by(2,mean(.,3))} # but this one works as it forces all dots to be explicit. 

Secondly, you cannot use the dot with the wording ~ as you planned, try map(c(1,2), ~ 3+.) And map(c(1,2), ~ 3+.x) ( or even map(c(1,2), ~ 3+..1) ), and you will see that you get the same result. By the time you use the point in the ~ formula, it is no longer associated with the pipe function.

To make sure the dot is interpreted as mtcars , you need to use the old definition of function(x) ...

It works:

 mtcars %>% {map_df(models, function(.x) tidy(lm(data=., formula=.x)))} 

Finally, as a bonus, this is what I came up with when trying to find a solution without braces:

 mtcars %>% map(models,lm,.) %>% map_df(tidy) mtcars %>% map_df(models, ~tidy(lm(..1,..2)), ..2 = .) 
+4
source

This should work and is not related to the complexity of function or {} . Clean solution 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 
+2
source

This is at odds with the way purrr::map works. You are comparing a list of models (one list item at a time), rather than a data frame (which will be one column of a data frame at a time). Since the dataframe remains constant even with other model expressions, I don’t think the mapping will work for this situation.

However, you can get the syntax you want from a user-defined function definition based on what you have above.

 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 
0
source

Source: https://habr.com/ru/post/1275137/


All Articles