Программно отбрасывая поле `group_by` в dplyr - PullRequest
0 голосов
/ 08 мая 2018

Я пишу функции, которые принимают data.frame, а затем выполняют некоторые операции. Мне нужно складывать и вычитать предметы из критериев group_by, чтобы добраться туда, куда я хочу.

Если я хочу добавить критерий group_by к df, это довольно просто:

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, которую я добавил, но при этом сохранить все остальные группировки одинаковыми?

Ответы [ 3 ]

0 голосов
/ 08 мая 2018

Функция удаления групп по имени столбца

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"
0 голосов
/ 08 мая 2018

Вот подход, который использует 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))
[[1]]
am
groups(d %>% drop_groups(a, vs, b, c))
[[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

ОБНОВЛЕНИЕ: Подход, приведенный ниже, работает непосредственно с именами столбцов в кавычках, без преобразования их в строки. Я не уверен, какой подход является «предпочтительным» в парадигме тидьеваля, или есть ли другой, более желательный метод.

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

}
0 голосов
/ 08 мая 2018

Может быть, что-то вроде этого, чтобы удалить группирующие переменные из конца списка обратно:

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 выходит за пределы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...