Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass multiple functions to purrr:map

Tags:

r

purrr

tidyverse

I would like to pass multiple functions at once to one purrr::map call, where the functions need some arguments. As pseudo code:

funs <- c(median, mean)

mtcars %>% 
  purrr::map(funs, na.rm = TRUE) 

This code does not run, but is intended to show what I am looking for: passing over multiple functions to map along with some arguments.

I looked at compose but that function does something different.

like image 886
Sebastian Sauer Avatar asked Nov 21 '17 14:11

Sebastian Sauer


2 Answers

You want to apply multiple functions to a dataframe with map(), but (apparently) there is no map() variation that does exactly this, only parts of it. For the multiple function part we have invoke_map() and for the multiple argument part over a dataframe we have pmap().

invoke_map() allows the use of multiple functions at once. For example, if we want to generate 5 random variates for a uniform and normal distributions, the code is:

func <- list(runif, rnorm) 
invoke_map(func, n = 5)

pmap() is just like map, but it allows to pass multiple arguments to a single function. For example, if we want to generate 10 random variates from a normal distribution with mean = 0 and sd = 1, but also 100 random variates from a normal distribution with mean = 100 and sd = 20, the code looks like this:

args <- list(mean = c(0, 100), sd = c(1, 20), n = c(10, 100))
pmap(args, rnorm)

To solve your question, we have to combine both functions in the following way:

fun <- function(f) pmap(list(x = mtcars, na.rm = TRUE), f)
param <- list(list(mean), list(median))

invoke_map(.f = fun, .x = param)

How does this work?

  1. At the invoke_map() level, fun takes as arguments param, which are the functions we want to apply to mtcars.

  2. Next, at the fun level, these functions stored in param are applied by pmap(), one at a time, to each column in mtcars.

Note: For the solution to really make sense, keep in mind the arguments invoke_map() and pmap() take.

More info about how invoke_map() and pmap() work.

like image 170
Josue Alvarado Avatar answered Oct 19 '22 23:10

Josue Alvarado


invoke() and its map variants have been retired in favour of rlang::exec(). From the documentation:

These functions are retired in favour of exec(). They are no longer under active development but we will maintain them in the package indefinitely.

invoke() is retired in favour of the simpler exec() function reexported from rlang. exec() evaluates a function call built from its inputs and supports tidy dots

invoke_map() is retired without replacement because it is more complex to understand than the corresponding code using map(), map2() and exec()

So the equivalent method now is:

library(dplyr)
library(purrr)

funs <- c(mean = mean, median = median)
args <- list(na.rm = TRUE, trim = .1) # trim argument non-matching and ignored for median

mtcars %>%
  map_df(~ funs %>%
           map(exec, .x, !!!args), .id = "var")

# A tibble: 11 x 3
   var      mean median
   <chr>   <dbl>  <dbl>
 1 mpg    19.7    19.2 
 2 cyl     6.23    6   
 3 disp  223.    196.  
 4 hp    141.    123   
 5 drat    3.58    3.70
 6 wt      3.15    3.32
 7 qsec   17.8    17.7 
 8 vs      0.423   0   
 9 am      0.385   0   
10 gear    3.62    4   
11 carb    2.65    2  
like image 22
Ritchie Sacramento Avatar answered Oct 19 '22 23:10

Ritchie Sacramento