group_by 使用 tidyeval 的非标量字符向量

group_by with non-scalar character vectors using tidyeval

使用 R 3.2.2dplyr 0.7.2 我想知道如何有效地使用 group_by 以字符向量形式提供的字段。

选择很容易,我可以 select 通过字符串这样的字段

(function(field) { 
  mpg %>% dplyr::select(field) 
})("cyl")

像这样通过多个字符串的多个字段

(function(...) { 
  mpg %>% dplyr::select(!!!quos(...)) 
})("cyl", "hwy")

和多个字段,通过一个长度 > 1 的字符向量,像这样

(function(fields) {  
  mpg %>% dplyr::select(fields)  
})(c("cyl", "hwy"))

使用 group_by 我真的找不到一种方法来为多个字符串执行此操作,因为如果我设法获得输出,它最终会按我提供的字符串分组。

我设法像这样按一个字符串分组

(function(field) {  
  mpg %>% group_by(!!field := .data[[field]]) %>% tally() 
})("cyl")

已经很丑了

有谁知道我要写什么所以我可以运行

(function(field) {...})("cyl", "hwy")

(function(field) {...})(c("cyl", "hwy"))

分别是?我尝试了 !!!!!UQenquoquosunlist 等各种组合并保存它们在中间变量中,因为这有时似乎有所作为,但无法使其发挥作用。

select()在dplyr中很特别。它不接受 columns,但接受 namespositions 列。所以这是唯一接受字符串的主要动词。 (从技术上讲,当您向 select 提供像 cyl 这样的裸名时,它实际上会被评估为它自己的名称,而不是数据框中的向量。)

如果您希望您的函数采用简单的字符串,而不是简单的表达式或符号,则不需要 quosures。只需从字符串创建符号并取消引用它们:

myselect <- function(...) {
  syms <- syms(list(...))
  select(mtcars, !!! syms)
}
mygroup <- function(...) {
  syms <- syms(list(...))
  group_by(mtcars, !!! syms)
}

myselect("cyl", "disp")
mygroup("cyl", "disp")

要调试取消引用,用 expr() 换行并检查表达式是否正确:

syms <- syms(list("cyl", "disp"))
expr(group_by(mtcars, !!! syms))
#> group_by(mtcars, cyl, disp)    # yup, looks right!

有关此内容的更多信息,请参阅此演讲(我们将更新编程小插图以使概念更清晰):https://schd.ws/hosted_files/user2017/43/tidyeval-user.pdf

最后,请注意许多动词都有一个 _at 后缀变体,可以毫不费力地接受字符串和字符向量:

group_by_at(mtcars, c("cyl", "disp"))