【问题标题】:How to summarize by sets of grouping variables in R and dplyr?如何通过 R 和 dplyr 中的分组变量集进行总结?
【发布时间】:2021-01-04 17:16:53
【问题描述】:

我想使用不同的分组变量集对数据框进行分组。对于每个组,我想计算观察次数(或以任何其他方式总结),然后将所有结果收集到一个数据框中。

重要提示:我想以编程方式定义分组变量集,例如作为列表。

如何在 tidyverse 中实现这一点?

这是我的尝试:

library(tidyverse)

count_by_group <- function(...) {
  mtcars %>%
    count(...) %>%
    mutate(
      grouping_variable = paste(ensyms(...), collapse = "."),
      group = paste(!!!enquos(...), sep = ".")
    ) %>%
    select(grouping_variable, group, n)
}

# I want this ...
bind_rows(
  count_by_group(cyl),
  count_by_group(gear),
  count_by_group(cyl, gear)
)
#>    grouping_variable group  n
#> 1                cyl     4 11
#> 2                cyl     6  7
#> 3                cyl     8 14
#> 4               gear     3 15
#> 5               gear     4 12
#> 6               gear     5  5
#> 7           cyl.gear   4.3  1
#> 8           cyl.gear   4.4  8
#> 9           cyl.gear   4.5  2
#> 10          cyl.gear   6.3  2
#> 11          cyl.gear   6.4  4
#> 12          cyl.gear   6.5  1
#> 13          cyl.gear   8.3 12
#> 14          cyl.gear   8.5  2

# ... but without the repetition of "count_by_group(var)".
# The following does not work:
map_dfr(
  list(
    cyl,
    gear,
    c(cyl, gear)
  ),
  count_by_group
)
#> Error in map(.x, .f, ...): object 'cyl' not found

reprex package (v0.3.0) 于 2020-09-17 创建

【问题讨论】:

  • 也许你需要rollup聚合即rollup(as.data.table(mtcars), j = .N, by = c("cyl","gear"))
  • 你所做的有什么问题?
  • @AllanCameron 我猜 Op 的代码不适用于帖子末尾的 map
  • 如果您使用 map_dfr(rlang::exprs(cyl, gear), count_by_group) 应该可以工作,但最后一个带有 c 的表达式不是您在工作案例中显示的预期行为

标签: r dplyr purrr tidyeval


【解决方案1】:

更新(2020-10-12):更透明的解决方案(感谢@LionelHenry)

library(tidyverse)

count_by_group <- function(...) {
  dots <- enquos(..., .named = TRUE)
  names <- names(dots)

  counted <- count(mtcars, !!!dots)

  group <- counted %>%
    select(-n) %>%
    rowwise() %>%
    mutate(paste(c_across(), collapse = ".")) %>%
    pull()

  # # Equivalently:
  # group <- counted %>%
  #   select(-n) %>%
  #   pmap(counted, paste, sep = ".")

  counted %>%
    mutate(
      grouping_variable = paste(names, collapse = "."),
      group = group
    ) %>%
    select(grouping_variable, group, n)
}

grouping_variables <- list(
  vars(cyl),
  vars(gear),
  vars(cyl, gear)
)

map_dfr(grouping_variables, ~ count_by_group(!!! .x))
#>    grouping_variable group  n
#> 1                cyl     4 11
#> 2                cyl     6  7
#> 3                cyl     8 14
#> 4               gear     3 15
#> 5               gear     4 12
#> 6               gear     5  5
#> 7           cyl.gear   4.3  1
#> 8           cyl.gear   4.4  8
#> 9           cyl.gear   4.5  2
#> 10          cyl.gear   6.3  2
#> 11          cyl.gear   6.4  4
#> 12          cyl.gear   6.5  1
#> 13          cyl.gear   8.3 12
#> 14          cyl.gear   8.5  2

reprex package (v0.3.0) 于 2020 年 10 月 12 日创建


我刚刚发现这行得通!

library(tidyverse)

count_by_group <- function(...) {
  mtcars %>%
    count(...) %>%
    mutate(
      grouping_variable = paste(ensyms(...), collapse = "."),
      group = paste(!!!enquos(...), sep = ".")
    ) %>%
    select(grouping_variable, group, n)
}

grouping_variables <- list(
  vars(cyl),
  vars(gear),
  vars(cyl, gear)
)

map_dfr(grouping_variables, ~count_by_group(!!! .))
#>    grouping_variable group  n
#> 1                cyl     4 11
#> 2                cyl     6  7
#> 3                cyl     8 14
#> 4               gear     3 15
#> 5               gear     4 12
#> 6               gear     5  5
#> 7           cyl.gear   4.3  1
#> 8           cyl.gear   4.4  8
#> 9           cyl.gear   4.5  2
#> 10          cyl.gear   6.3  2
#> 11          cyl.gear   6.4  4
#> 12          cyl.gear   6.5  1
#> 13          cyl.gear   8.3 12
#> 14          cyl.gear   8.5  2

reprex package (v0.3.0) 于 2020 年 10 月 12 日创建

【讨论】:

  • modify_depth(grouping_variables, 2, sym)map(grouping_variables, ~map(., sym)) 的替代品
  • 我会做list(vars(foo, bar), vars(baz))vars() 运算符适用于这种从外部捕获多个表达式的用例。
  • paste()将几个变量放在一起以获得组标识符似乎不是很健壮,但在简单的情况下(整数、字符等)可以工作。
  • 如果您使用外部vars() 化解参数,那么您将不会使用带有ensyms() 的内部化解。关于组识别,一种方法是使用vctrs::vec_group_id(),它用于 dplyr 内部。请注意,此 API 仍在成熟中,我们可能会在某个时候更改名称,但有一个弃用期。
  • 如果您的函数使用点并且您想传递使用vars() 创建的参数列表,您需要使用!!! 将列表转换为单个参数。试试map_dfr(grouping_variables, ~ count_by_group(!!!.x))
猜你喜欢
  • 1970-01-01
  • 2020-08-24
  • 1970-01-01
  • 1970-01-01
  • 2018-04-01
  • 2021-08-21
  • 1970-01-01
  • 2020-05-02
  • 1970-01-01
相关资源
最近更新 更多