Programmatically dropping groups in dplyr

Yesterday I answered a Stack Overflow question (asked by @jdlong) regarding how to programmatically drop groups from a grouped data frame. I provided two potential options that both work, but I really don't know if either one is in any sense "good", "preferred" or "the right way" in terms of the tidyeval paradigm and the appropriate use of quosures and other tidyeval concepts.

The two functions are listed below, followed by a few examples. The first function converts the bare column names to strings. The second works directly with quosured bare column names. Both functions use setdiff() to drop desired groups from the data frame.

I'm interested in whether these are good ways to drop groups programmatically or whether there's a simpler, more elegant, or more tidyeval-ish method.

library(tidyverse) 

drop_groups = function(data, ...) {

  groups = map_chr(groups(data), rlang::quo_text)
  drop = map_chr(quos(...), rlang::quo_text)

  if(any(!drop %in% groups)) {
    warning(paste("Input data frame is not grouped by the following groups:", 
                  paste(drop[!drop %in% groups], collapse=", ")))
  }

  data %>% group_by_at(setdiff(groups, drop))
}
drop_groups2 = function(data, ...) {

  groups = map(groups(data), quo)
  drop = quos(...)

  if(any(!drop %in% groups)) {
    warning(paste("Input data frame is not grouped by the following groups:", 
                  paste(drop[!drop %in% groups], collapse=", ")))
  }

  data %>% group_by(!!!setdiff(groups, drop))
}

Usage examples:

d = mtcars %>% group_by(cyl, vs, am)

groups(d %>% drop_groups(vs, cyl))
groups(d %>% drop_groups2(vs, cyl))

groups(d %>% drop_groups(a, vs, b, c))
groups(d %>% drop_groups2(a, vs, b, c))
2 Likes

I'm glad you brought this over here for discussion. It would be nice to get some more opinions. I think this functionality would be useful to have built into dplyr.