【问题标题】:R: What is the expected output of passing a character vector to dplyr::all_of()?R:将字符向量传递给 dplyr::all_of() 的预期输出是什么?
【发布时间】:2021-08-04 22:52:26
【问题描述】:

我试图了解dplyr::group_by() 的预期输出以及dplyr::all_of() 的使用。我的理解是使用dplyr::all_of() 应该将包含变量名的字符向量转换为裸名,以便group_by(),但这似乎不会发生。

下面,我生成一些假数据,将不同的对象传递给group_by() with(out) all_of(),并计算每组的观察次数。在示例中,传递一个没有dplyr::all_of() 的裸列名称会产生正确的输出:每个列的唯一值一行。但是,传递字符向量或使用 dplyr::all_of() 会产生不正确的输出:不管一列中有多少值,都是一行。

使用 all_of 时会发生什么?我如何将字符向量传递给 group_by 以将其作为裸名向量进行处理?

library(dplyr)

# Create a 20-row data.frame with
# 2 variables each with 2 unique values.
df <- data.frame(var = rep(c("a", "b"), 10),
                 bar = rep(c(1, 2), 20))

# Output 1: 2x2 tibble - GOOD
df %>% group_by(var) %>% summarize(n = n())

# Output 2: 1x2 tibble - BAD
foo <- "var"
df %>% group_by(all_of(foo)) %>% summarize(n = n())

# Output 3: 1x2 tibble
df %>% group_by("var") %>% summarize(n = n())

# Output 4: Error in_var not found - BAD
foo2 <- list("var", "bar")
lapply(foo2, function(in_var) {
  df %>%
    group_by(in_var) %>%
    summarize(n = n())
})

# Output 5: list of length 2 where
# each element is a 1x2 tibble - BAD
foo2 <- list("var", "bar")
lapply(foo2, function(in_var) {
  df %>%
    group_by(all_of(in_var)) %>%
    summarize(n = n())
})

【问题讨论】:

  • 如果您使用的是 dplyr >= 1.0.0,第二个问题的选项是使用 group_byacross
  • 我想你想要df %&gt;% group_by(across(all_of(foo))) %&gt;% summarize(n = n()) 和最新版本的dplyr

标签: r vector dplyr summarize data-wrangling


【解决方案1】:

我们可以使用group_by_at

lapply(foo2, function(in_var) df %>% 
      group_by_at(all_of(in_var)) %>% 
      summarise(n = n()))

-输出

#[[1]]
# A tibble: 2 x 2
#  var       n
#* <chr> <int>
#1 a        20
#2 b        20

#[[2]]
# A tibble: 2 x 2
#    bar     n
#* <dbl> <int>
#1     1    20
#2     2    20

由于across 替换了group_by_at 的部分功能,我们可以用all_of 代替它:

lapply(foo2, function(in_var) df %>% 
      group_by(across(all_of(in_var))) %>% 
      summarise(n = n()))

或转换为symbol 并评估 (!!)

lapply(foo2, function(in_var) df %>% 
      group_by(!! rlang::sym(in_var)) %>% 
      summarise(n = n()))

或使用map

library(purrr)
map(foo2, ~ df %>%
              group_by(!! rlang::sym(.x)) %>%
              summarise(n = n()))

或者代替group_by,可以是count

map(foo2, ~ df %>%
              count(across(all_of(.x))))
                       

【讨论】:

  • 这太好了,谢谢。我认为问题在于我对为什么需要across() 的理解。我仍然不清楚为什么group_by 需要across() 才能适当地使用all_of。我知道这是一个范围界定问题。如果有一个很好的链接可以阅读dplyr 中不同功能的范围,我们将不胜感激。
  • @user3614648 您可以查看 dplyr 的 vignette,其中将包含有关这些新功能的信息
【解决方案2】:

要添加到@akrun 的多种方法来实现所需输出的答案-我对all_of() 的理解是,它是选择存储为dplyr 函数的字符的变量的助手,并在下面使用vctrs。与any_of() 相比,all_of() 的严格版本不那么严格,还有一些方便的用例。 阅读?tidyselect::all_off() 很有帮助。这个页面也有助于跟上dplyr的变化和整理评估https://dplyr.tidyverse.org/articles/programming.html

根据 RStudio 开发人员的决定,across 将来会取代范围内的 dplyr 动词。请参阅 ?group_by_at() 或其他 *_if*_at*_all 文档。所以我想这真的取决于您在工作流程中使用的dplyr 版本以及最适合您的版本。

这个SO post 还通过将字符传递给dplyr 函数提供了解决方案随时间变化的上下文,并且可能还有更多帖子。

【讨论】:

    猜你喜欢
    • 2021-01-30
    • 1970-01-01
    • 1970-01-01
    • 2016-10-17
    • 1970-01-01
    • 2014-12-17
    • 1970-01-01
    • 1970-01-01
    • 2016-12-13
    相关资源
    最近更新 更多