Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using mutate with map2 and exec instead of invoke_map

This example in "R for Data Science" uses invoke_map which is now retired.

sim <- tribble(
  ~f, ~params,
  "runif", list(min = -1, max = 1),
  "rnorm", list(sd = 5),
  "rpois", list(lambda = 10)
)

sim %>% 
  mutate(sim = invoke_map(f, params, n = 10))

If I extract the columns separately then it works with map2 and exec

map2(sim$f, sim$params, function(fn, args) exec(fn, !!!args, n = 10))

However, I cannot get mutate to work with map2 and exec

sim %>% 
  mutate(sim = map2(f, params, function(fn, args) exec(fn, !!!args, n = 10)))

I get the error "Error: Can't splice an object of type closure because it is not a vector"

Can anyone help with this?

like image 772
stats101 Avatar asked Oct 14 '20 15:10

stats101


2 Answers

The !!! operator takes precedence over the creation of the anonymous function. As a result, it evaluates args immediately in the scope of the data frame and, when it finds no such column, in the global scope. One solution is to move the function definition outside the map2 call:

myfun <- function(fn, args) exec(fn, !!!args, n = 10)

sim %>% 
  mutate(sim = map2(f, params, myfun))        # Now works

Another solution is to concatenate the function name and all parameters into a single list, and then pass that list to exec with its domain lifted:

sim %>%
    mutate(temp = map2(f, params, c, n=10),
           sim  = map(temp, lift(exec)),
           temp = NULL)
like image 137
Artem Sokolov Avatar answered Nov 18 '22 06:11

Artem Sokolov


I think the problem lies somewhere in exec or, more specifically, the big-bang (!!!) part, which for some reason tries to splice not your variable args, but the function base::args (thus, the error message you receive). You can try renaming args to something else and you'll get a different error:

> sim %>% 
  mutate(sim = map2(f, params, .f = function(fn, x) {exec(fn, !!!x, n = 10)}))
Error in splice(dot_call(capture_dots, frame_env = frame_env, named = named,  : 
  object 'x' not found

I must say I'm not in deep enough to disentangle this, but if you need a quick resolution, use do.call instead and pull n = 10 into the args using c:

sim %>% 
  mutate(sim = map2(f, params, .f = function(fn, args) {do.call(fn, c(args, n = 10))}))
like image 25
alex_jwb90 Avatar answered Nov 18 '22 07:11

alex_jwb90