6

I am trying to write a custom function that uses rlang's non-standard evaluation to group a dataframe by more than one variable.

This is what I've-

library(rlang)

# function definition
tryfn <- function(data, groups, ...) {

  # preparing data
  df <- dplyr::group_by(data, !!!rlang::enquos(groups))
  print(head(df))

  # applying some function `.f`  on df that absorbs `...`
  # .f(df, ...)
}

This works with a single grouping variable-

# works
tryfn(mtcars, am)

#> # A tibble: 6 x 11
#> # Groups:   am [2]
#>     mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
#>   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1  21       6   160   110  3.9   2.62  16.5     0     1     4     4
#> 2  21       6   160   110  3.9   2.88  17.0     0     1     4     4
#> 3  22.8     4   108    93  3.85  2.32  18.6     1     1     4     1
#> 4  21.4     6   258   110  3.08  3.22  19.4     1     0     3     1
#> 5  18.7     8   360   175  3.15  3.44  17.0     0     0     3     2
#> 6  18.1     6   225   105  2.76  3.46  20.2     1     0     3     1

But if try to use more than one grouping variable, this doesn't work-

# doesn't work
tryfn(mtcars, c(am, cyl))
#> Error: Column `c(am, cyl)` must be length 32 (the number of rows) or one, not 64

# doesn't work
tryfn(mtcars, list(am, cyl))
#> Error: Column `list(am, cyl)` must be length 32 (the number of rows) or one, not 2
Indrajeet Patil
  • 4,673
  • 2
  • 20
  • 51
  • One option might be to switch to `group_by_at()` since `vars()` can be pretty handy for passing all different kinds of variables in the "at" variants (bare, vectors, strings): `dplyr::group_by_at(data, dplyr::vars( !! rlang::enquo(groups) ) )` – aosmith Jan 01 '20 at 15:46
  • See https://stackoverflow.com/questions/52718604/passing-a-list-of-arguments-to-a-function-with-quasiquotation/52726906#52726906. It has the answer you're looking for. Something along the lines of: `sum_fun <- function(d, grp) d %>% group_by_at(grp); sum_fun(mtcars, grp = vars(cyl, am))` – cimentadaj Jan 01 '20 at 15:47
  • Does this answer your question? [Passing a list of arguments to a function with quasiquotation](https://stackoverflow.com/questions/52718604/passing-a-list-of-arguments-to-a-function-with-quasiquotation) – cimentadaj Jan 01 '20 at 15:51
  • I reopened it because the linked question solution modifies the OP's input to make it work with `group_by_at`. Here, the OP is looking for a solution where the input is passed as `c(...)` – akrun Jan 01 '20 at 16:27
  • Why is this question being down voted when I already accepted the suggestion that the solution for this question is already provided in https://stackoverflow.com/questions/52718604/passing-a-list-of-arguments-to-a-function-with-quasiquotation ?! – Indrajeet Patil Jan 01 '20 at 16:32

1 Answers1

4

We could parse as an expression with enexpr and use !!!

tryfn <- function(data, groups, ...) {

 groups <- as.list(rlang::enexpr(groups))

  groups <- if(length(groups) > 1) groups[-1] else groups

  group_by(data, !!!groups)

 }

-testing

tryfn(mtcars, am)
# A tibble: 32 x 11
# Groups:   am [2]
#     mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
# * <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1  21       6  160    110  3.9   2.62  16.5     0     1     4     4
# 2  21       6  160    110  3.9   2.88  17.0     0     1     4     4
# 3  22.8     4  108     93  3.85  2.32  18.6     1     1     4     1
# 4  21.4     6  258    110  3.08  3.22  19.4     1     0     3     1
# 5  18.7     8  360    175  3.15  3.44  17.0     0     0     3     2
# 6  18.1     6  225    105  2.76  3.46  20.2     1     0     3     1
# 7  14.3     8  360    245  3.21  3.57  15.8     0     0     3     4
# 8  24.4     4  147.    62  3.69  3.19  20       1     0     4     2
# 9  22.8     4  141.    95  3.92  3.15  22.9     1     0     4     2
#10  19.2     6  168.   123  3.92  3.44  18.3     1     0     4     4
# … with 22 more rows





tryfn(mtcars, c(am, cyl))
# A tibble: 32 x 11
# Groups:   am, cyl [6]
#     mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
# * <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1  21       6  160    110  3.9   2.62  16.5     0     1     4     4
# 2  21       6  160    110  3.9   2.88  17.0     0     1     4     4
# 3  22.8     4  108     93  3.85  2.32  18.6     1     1     4     1
# 4  21.4     6  258    110  3.08  3.22  19.4     1     0     3     1
# 5  18.7     8  360    175  3.15  3.44  17.0     0     0     3     2
# 6  18.1     6  225    105  2.76  3.46  20.2     1     0     3     1
# 7  14.3     8  360    245  3.21  3.57  15.8     0     0     3     4
# 8  24.4     4  147.    62  3.69  3.19  20       1     0     4     2
# 9  22.8     4  141.    95  3.92  3.15  22.9     1     0     4     2
#10  19.2     6  168.   123  3.92  3.44  18.3     1     0     4     4
# … with 22 more rows
akrun
  • 874,273
  • 37
  • 540
  • 662