Reputation: 21204
Some code:
mymtcars <- mtcars %>% head %>% rownames_to_column('model') %>% group_by(vs) %>% nest
mymtcars
vs data
<dbl> <list>
1 0 <tibble [3 × 11]>
2 1 <tibble [3 × 11]>
I can fit a linear model on this list column df like so:
mymtcars %>%
+ mutate(mod = map(.x = data, ~ lm(.x$mpg ~ .x$cyl)))
# A tibble: 2 x 3
# Groups: vs [2]
vs data mod
<dbl> <list> <list>
1 0 <tibble [3 × 11]> <lm>
2 1 <tibble [3 × 11]> <lm>
What if my function name is a field?
mymtcars2 <- mtcars %>% head %>% rownames_to_column('model') %>% group_by(vs) %>% nest %>% crossing(func = c('lm'))
> mymtcars2
# A tibble: 2 x 3
vs data func
<dbl> <list> <chr>
1 0 <tibble [3 × 11]> lm
2 1 <tibble [3 × 11]> lm
I gave it a try with:
mymtcars2 %>%
+ mutate(mod = map2(.x = data, .y = func, ~ .y(.x$mpg ~ .x$cyl)))
Error: Problem with `mutate()` input `mod`.
x could not find function ".y"
ℹ Input `mod` is `map2(.x = data, .y = func, ~.y(.x$mpg ~ .x$cyl))`.
How can I pass the function to call in map and then call it in the above block?
Upvotes: 7
Views: 165
Reputation: 18551
Since {dplyr} >= 1.0 this kind of problems can be solved with dplyr::rowwise
. We can use it either with a classic do.call
, in which case we have to wrap the arguments in list()
, or with rlang::exec
. With dlpyr::rowwise
we don't need map2
which makes things more readable since there is no lambda function with .x
.y
. However, since the output column stores lm
objects (and not an atomic vector), the result has to be wrapped in mod = list(...)
.
library(tidyverse)
mymtcars2 %>%
rowwise %>%
mutate(mod = list(do.call(func, list(mpg ~ cyl, data = data))))
#> # A tibble: 2 x 4
#> # Rowwise:
#> vs data func mod
#> <dbl> <list> <chr> <list>
#> 1 0 <tibble [3 × 11]> lm <lm>
#> 2 1 <tibble [3 × 11]> lm <lm>
mymtcars2 %>%
rowwise %>%
mutate(mod = list(exec(func, mpg ~ cyl, data = data)))
#> # A tibble: 2 x 4
#> # Rowwise:
#> vs data func mod
#> <dbl> <list> <chr> <list>
#> 1 0 <tibble [3 × 11]> lm <lm>
#> 2 1 <tibble [3 × 11]> lm <lm>
Created on 2021-08-28 by the reprex package (v0.3.0)
Upvotes: 1
Reputation: 39858
A different option could be:
mymtcars2 %>%
mutate(mod = map2(.x = data,
.y = func,
~ exec(.y, mpg ~ cyl, data = .x)))
vs data func mod
<dbl> <list> <chr> <list>
1 0 <tibble [3 × 11]> lm <lm>
2 1 <tibble [3 × 11]> lm <lm>
Upvotes: 3
Reputation: 21204
I also found that I can use get:
mymtcars2 %>%
mutate(mod = map2(.x = data, .y = func, ~ get(.y)(.x$mpg ~ .x$cyl)))
Am unsure of when to use one over the other.
Upvotes: 3
Reputation: 11128
May be using match.fun
inside map2 like below:
models <- mymtcars2 %>%
mutate(mod = map2(.x = data, .y = func, ~ match.fun(.y)(.x$mpg ~ .x$cyl)))
Output:
[[1]]
Call:
match.fun(.y)(formula = .x$mpg ~ .x$cyl)
Coefficients:
(Intercept) .x$cyl
36.926733 -2.728218
[[2]]
Call:
match.fun(.y)(formula = .x$mpg ~ .x$cyl)
Coefficients:
(Intercept) .x$cyl
41.9400 -3.8025
Upvotes: 6