Programming with dplyr: indirectly control by which variables to group by

Viewed 52

I want to write a simple function f(grouping) that summarises the data below:

d0 <- data.frame(
  V1 = rep(1:5, times = 2),
  V2 = rep(2:6, times = 2),
  V3 = rep(11:15, times = 2),
  V4 = rep(12:16, times = 2),
  X = 1:10
)

I want the user to be able to pick between two kinds of groupings: either by V1 or by V2, in that the user either writes f(grouping = V1) or f(grouping = V2). However, I want it to be such that if grouping = V1, it groups by V1 and V3. And if grouping = V2, then it groups by V2 and V4. Note that, since V3 and V4 originally have unintuitive names, they should not be used as arguments on the function call.

f(V1) should yield:

 # A tibble: 5 x 3
# Groups:   V1 [5]
     V1    V3     X
  <int> <int> <int>
1     1    11     7
2     2    12     9
3     3    13    11
4     4    14    13
5     5    15    15

And f(V2):

# A tibble: 5 x 3
# Groups:   V2 [5]
     V2    V4     X
  <int> <int> <int>
1     2    12     7
2     3    13     9
3     4    14    11
4     5    15    13
5     6    16    15
1 Answers

We create a condition with if/else to concatenate 'V3' or 'V4' based on the value of the input grouping. Inside the function, convert the unquoted grouping value to symbol (ensym), and then to string (as_string), then use if/else to concatenate the groups, pass the updated the groups ('grp') within across and summarise the 'X'

f1 <- function(data, grouping) {
        grp <- rlang::as_string(ensym(grouping))
        grp <- c(grp, if(grp == 'V1') 'V3' else 'V4')

        data %>%
            group_by(across(all_of(grp))) %>%
            summarise(X = sum(X), .groups = 'drop')

}

f1(d0, V1)
f1(d0, V2)
Related