Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

working with lists of models using the pipe syntax

I often like to fit and examine multiple models that relate two variables in an R dataframe.

I can do that using syntax like this:

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

But I'm used to the pipe syntax and was hoping to be able to something like this:

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

That makes it clear that I'm "starting" with mtcars and then doing stuff to it to generate my output. But that syntax doesn't work, giving an error Error: Index 1 must have length 1.

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

mtcars %>% <<<something>>>
like image 864
Curt F. Avatar asked Feb 02 '18 17:02

Curt F.


People also ask

What is the use of %>% in R?

%>% is called the forward pipe operator in R. It provides a mechanism for chaining commands with a new forward-pipe operator, %>%. This operator will forward a value, or the result of an expression, into the next function call/expression. It is defined by the package magrittr (CRAN) and is heavily used by dplyr (CRAN).

How do pipes work in R?

What does the pipe do? The pipe operator, written as %>% , has been a longstanding feature of the magrittr package for R. It takes the output of one function and passes it into another function as an argument. This allows us to link a sequence of analysis steps.

What is a pipe in Dplyr?

Pipes let you take the output of one function and send it directly to the next, which is useful when you need to many things to the same data set. Pipes in R look like %>% and are made available via the magrittr package installed as part of dplyr .


1 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 2 problems with the solution you've tried.

The first is that you need to use curly braces if you want to place the dot 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's equivalent to this one
1 %>% {divide_by(2,mean(.,3))} #  but this one works as it forces all dots to be explicit.

The second is that you can't use the dot with the ~ formulation in the way you intended, try map(c(1,2), ~ 3+.) and map(c(1,2), ~ 3+.x) (or even map(c(1,2), ~ 3+..1)) and you'll see you get the same result. By the time you use the dot in a ~ formula it's not linked to the pipe function anymore.

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

This works:

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

Finally, as a bonus, here's what I came up with, trying to find a solution without curly braces :

mtcars %>% map(models,lm,.) %>% map_df(tidy)
mtcars %>% map_df(models, ~tidy(lm(..1,..2)), ..2 = .)
like image 128
Moody_Mudskipper Avatar answered Nov 02 '22 04:11

Moody_Mudskipper