我正在编写接受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?
但是,我如何以编程方式删除b我添加的分组,但保持所有其他分组相同?
jor*_*ran 10
也许是这样的,从列表末尾删除分组变量:
grouped %>% 
 group_by(b, add=TRUE) -> grouped
grouped %>% group_by_at(.vars = group_vars(.)[-2])
或者在输出上使用head或者tail某些东西以group_vars获得更多控制.
更普遍地提供这种效用函数会很有趣:
peel_groups <- function(.data,n){
  .data %>%
    group_by_at(.vars = head(group_vars(.data),-n))
}
一个更深思熟虑的版本可能包括更加仔细地检查n是否超出范围.
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
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
更新:下面的方法直接使用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))
}
按列名删除组的功能
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"