inferator
inferator

Reputation: 494

simplifying tidyeval with multiple symbols

The following function behaves as desired: several variables can be passed to group_by without the need to put them into alist() or dplyr::vars:


mean_by_grp <- function(df, meanvar, grp) {
  
  grouping <- enexpr(grp) %>% 
    expr_deparse %>% 
    str_split(",",simplify = T) %>% `[`(1,) %>% 
    map(str_remove,"c\\(") %>% map(str_remove,"\\)") %>% map(str_trim) %>% 
    unlist %>% syms
  
  df %>% 
    group_by(!!!syms(grouping)) %>% 
    summarise("average_{{meanvar}}" := mean({{meanvar}}, na.rm = TRUE),
              .groups = 'drop')
}

starwars %>% mean_by_grp(height, species)
starwars %>% mean_by_grp(height, c(species, homeworld))

However, it is complicated. I need to turn c(var1,....varn) into a string, split it and turn it into a list of symbols so I can use with with syms.

Isn't there a much easier way to do this?

Of course, I could use ellipses instead of grp, but then I can only have one argument that passes multiple symbols to another function.

Upvotes: 1

Views: 293

Answers (1)

stefan
stefan

Reputation: 123768

One option would be dplyr::across:

mean_by_grp <- function(df, meanvar, grp) {
  df %>% 
    group_by(across({{ grp }})) %>% 
    summarise("average_{{meanvar}}" := mean({{meanvar}}, na.rm = TRUE),
              .groups = 'drop')
}

library(dplyr)

starwars %>% mean_by_grp(height, species)
#> # A tibble: 38 × 2
#>    species   average_height
#>    <chr>              <dbl>
#>  1 Aleena               79 
#>  2 Besalisk            198 
#>  3 Cerean              198 
#>  4 Chagrian            196 
#>  5 Clawdite            168 
#>  6 Droid               131.
#>  7 Dug                 112 
#>  8 Ewok                 88 
#>  9 Geonosian           183 
#> 10 Gungan              209.
#> # … with 28 more rows
starwars %>% mean_by_grp(height, c(species, homeworld))
#> # A tibble: 58 × 3
#>    species  homeworld   average_height
#>    <chr>    <chr>                <dbl>
#>  1 Aleena   Aleen Minor             79
#>  2 Besalisk Ojom                   198
#>  3 Cerean   Cerea                  198
#>  4 Chagrian Champala               196
#>  5 Clawdite Zolan                  168
#>  6 Droid    Naboo                   96
#>  7 Droid    Tatooine               132
#>  8 Droid    <NA>                   148
#>  9 Dug      Malastare              112
#> 10 Ewok     Endor                   88
#> # … with 48 more rows

Upvotes: 3

Related Questions