Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass a vector of arguments to map function

Tags:

r

purrr

I'm trying to create a function that will map across a nested tibble. This function needs to take a vector of parameters that will vary for each row.

When I call purrr:map2() on the nested data, purrr tries to loop over all values of the parameter vector and all rows in the dataset. What can I do to pass the entire vector as a single argument?

library(tidyverse)

myf <- function(x, params) {
  print(params)
  x %>%
    mutate(new_mpg = mpg + rnorm(n(), params[1], params[2])) %>%
    summarise(old = mean(mpg), new = mean(new_mpg)) %>%
    as.list()
}

# Calling function with params defined is great!
myf(mtcars, params = c(5, 10))
#> [1]  5 10
#> $old
#> [1] 20.09062
#> 
#> $new
#> [1] 25.62049

# Cannot work in purr as vector, tries to loop over param
mtcars %>%
  group_by(cyl) %>% # from base R
  nest()   %>%
  mutate(
    newold = map2(data, c(5, 10), myf),
  )
#> [1] 5
#> Warning in rnorm(n(), params[1], params[2]): NAs produced
#> [1] 10
#> Warning in rnorm(n(), params[1], params[2]): NAs produced
#> Error: Problem with `mutate()` column `newold`.
#> ℹ `newold = map2(data, c(5, 10), myf)`.
#> ℹ `newold` must be size 1, not 2.
#> ℹ The error occurred in group 1: cyl = 4.

# New function wrapper with hard-coded params
myf2 <- function(x){
  myf(x, c(5, 10))
}

# works great! but not what I need
mtcars %>%
  group_by(cyl) %>% # from base R
  nest()   %>%
  mutate(
    mean = 5, 
    sd = 10,
    newold = map(data, myf2),
  )
#> [1]  5 10
#> [1]  5 10
#> [1]  5 10
#> # A tibble: 3 × 5
#> # Groups:   cyl [3]
#>     cyl data                mean    sd newold          
#>   <dbl> <list>             <dbl> <dbl> <list>          
#> 1     6 <tibble [7 × 10]>      5    10 <named list [2]>
#> 2     4 <tibble [11 × 10]>     5    10 <named list [2]>
#> 3     8 <tibble [14 × 10]>     5    10 <named list [2]>

Created on 2021-11-29 by the reprex package (v2.0.0)

like image 424
gregmacfarlane Avatar asked Nov 19 '25 19:11

gregmacfarlane


1 Answers

Skip the group_by() step and just use nest() - otherwise your data will remain grouped after nesting and need to be ungrouped. To get your function to work, just pass the parameters as a list.

library(tidyverse)

mtcars %>%
  nest(data = -cyl) %>%
  mutate(
    newold = map2_df(data, list(c(5, 10)), myf)
  ) %>%
  unpack(newold)

# A tibble: 3 x 4
    cyl data                 old   new
  <dbl> <list>             <dbl> <dbl>
1     6 <tibble [7 x 10]>   19.7  30.7
2     4 <tibble [11 x 10]>  26.7  31.1
3     8 <tibble [14 x 10]>  15.1  17.0
like image 108
Ritchie Sacramento Avatar answered Nov 21 '25 10:11

Ritchie Sacramento



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!