以编程方式删除dplyr中的`group_by`字段

JD *_*ong 10 r dplyr

我正在编写接受a data.frame然后执行某些操作的函数.我需要在group_by条件中添加和减去项目,以便到达我想去的地方.

如果我想为group_bydf 添加标准,那很容易:

library(tidyverse)
set.seed(42)
n <- 10
input <- data.frame(a = 'a', 
                    b = 'b' , 
                    vals = 1
)

input %>%
  group_by(a) -> 
grouped 

grouped
#> # A tibble: 1 x 3
#> # Groups:   a [1]
#>   a     b      vals
#>   <fct> <fct> <dbl>
#> 1 a     b        1.

## add a group:
grouped %>% 
  group_by(b, add=TRUE)
#> # A tibble: 1 x 3
#> # Groups:   a, b [1]
#>   a     b      vals
#>   <fct> <fct> <dbl>
#> 1 a     b        1.

## drop a group?
Run Code Online (Sandbox Code Playgroud)

但是,我如何以编程方式删除b我添加的分组,但保持所有其他分组相同?

jor*_*ran 10

也许是这样的,从列表末尾删除分组变量:

grouped %>% 
 group_by(b, add=TRUE) -> grouped
grouped %>% group_by_at(.vars = group_vars(.)[-2])
Run Code Online (Sandbox Code Playgroud)

或者在输出上使用head或者tail某些东西以group_vars获得更多控制.

更普遍地提供这种效用函数会很有趣:

peel_groups <- function(.data,n){
  .data %>%
    group_by_at(.vars = head(group_vars(.data),-n))
}
Run Code Online (Sandbox Code Playgroud)

一个更深思熟虑的版本可能包括更加仔细地检查n是否超出范围.

  • @Ryan我实际上并没有考虑过按名称删除(可能来自链内,而不是最后),并认为它有足够的不同以保证取消删除你的答案. (2认同)

eip*_*i10 10

这是一种使用tidyeval的方法,因此裸列名称可以用作函数参数.我不确定将裸列名称转换为文本是否有意义(正如我在下面所做的那样),或者是否有更优雅的方式直接使用裸列名称.

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))

}

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

groups(d %>% drop_groups(vs, cyl))
Run Code Online (Sandbox Code Playgroud)
[[1]]
am
Run Code Online (Sandbox Code Playgroud)
groups(d %>% drop_groups(a, vs, b, c))
Run Code Online (Sandbox Code Playgroud)
[[1]]
cyl

[[2]]
am

Warning message:
In drop_groups(., a, vs, b, c) :
  Input data frame is not grouped by the following groups: a, b, c
Run Code Online (Sandbox Code Playgroud)

更新:下面的方法直接使用quosured列名称,而不将它们转换为字符串.我不确定哪种方法在tidyeval范例中是"首选的",或者是否还有另一种更理想的方法.

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))

}
Run Code Online (Sandbox Code Playgroud)


Ice*_*can 8

按列名删除组的功能

drop_groups_at <- function(df, vars){
  df %>% 
    group_by_at(setdiff(group_vars(.), vars))
}


input %>%
  group_by(a, b) %>% 
  drop_groups_at('b') %>% 
  group_vars

# [1] "a"
Run Code Online (Sandbox Code Playgroud)