Pass multiple functions to purrr:map
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?
At the invoke_map() level,
fun
takes as argumentsparam
, which are the functions we want to apply tomtcars
.Next, at the
fun
level, these functions stored inparam
are applied bypmap()
, one at a time, to each column inmtcars
.
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.
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
Here is my baby-steps solution (depends what you mean by "at once"):
mtcars %>%
map_dbl(~{mean(.x, na.rm = TRUE)}) %>%
enframe() %>%
rename(mean = value) %>%
as_tibble %>%
left_join(mtcars %>%
map_dbl(~{median(.x, na.rm = TRUE)}) %>%
enframe() %>%
as_tibble %>%
rename(median = value))