如何将变量名传递给dplyr的group_by()函数?

38

我可以使用以下代码计算数据框 df 中组 name1 中的值(val)的排名:

res  <- df %>% arrange(val) %>% group_by(name1) %>% mutate(RANK=row_number()) 

我希望在代码中不用写" name1 "这一列名称,而是将它作为变量传递,例如 crit = "name1"。然而,下面的代码并不能正常工作,因为crit1被认为是列名而不是变量名。

res  <- df %>% arrange(val) %>% group_by(crit1) %>% mutate(RANK=row_number()) 

我该如何在代码中传递crit1参数?

谢谢。

3个回答

45

我们可以使用group_by_

library(dplyr)
df %>%
    arrange(val) %>% 
    group_by_(.dots=crit1) %>%
    mutate(RANK=row_number()) 
#Source: local data frame [10 x 4]
#Groups: name1, name2 [7]

#            val name1 name2  RANK
#          <dbl> <chr> <chr> <int>
#1  -0.848370044     b     c     1
#2  -0.583627199     a     a     1
#3  -0.545880758     a     a     2
#4  -0.466495124     b     b     1
#5   0.002311942     a     c     1
#6   0.266021979     c     a     1
#7   0.419623149     c     b     1
#8   0.444585270     a     c     2
#9   0.536585304     b     a     1
1#0  0.847460017     a     c     3

更新

group_by_ 已经在最新版本中弃用(当前使用 dplyr 版本 - 0.8.1),所以我们可以使用 group_by_at,它将一个字符串向量作为输入变量。

df %>%
  arrange(val) %>% 
  group_by_at(crit1) %>%
  mutate(RANK=row_number())
或者另一个选项是将其转换为符号(使用 rlang 中的 syms)并进行评估(使用 !!!)。
df %>%
   arrange(val) %>% 
   group_by(!!! rlang::syms(crit1)) %>% 
   mutate(RANK = row_number())

数据

set.seed(24)
df <- data.frame(val = rnorm(10), name1= sample(letters[1:3], 10, replace=TRUE), 
         name2 = sample(letters[1:3], 10, replace=TRUE), 
 stringsAsFactors=FALSE)

crit1 <- c("name1", "name2")

4
group_by_() 已经被弃用。 - Helen
1
@Helen 感谢您的通知。我添加了两个选项,可以与当前版本的 dplyr 兼容。 - akrun
dplyr 还有 syms 函数,不需要显式指定 rlang - Ömer An

19

使用dplyr 1.0.0进行更新

新的across语法消除了需要使用!!! rlang::syms()的必要性。因此,现在您可以通过以下方式简化代码:

df %>%
   arrange(val) %>% 
   group_by(across(all_of(crit1))) %>% 
   mutate(RANK = row_number())

1
如果您要按任何其他列进行分组,则为:group_by(across(all_of(crit1)),additional_column_not_in_crit1)%>% - thunt
这里需要使用 all_of 吗?我似乎在使用和不使用它时得到了相同的结果。 - Dylan S.

2

面对类似的任务,我可以成功地使用这两个选项。

使用 across()

for (crit in names(df)) {
  print(df |> 
          # all_of() is not needed here
          group_by(across(crit)) |> 
          count())
}

使用syms()!!

crits = syms(names(df))

for (crit in crits) {
  print(df |> 
          # the use of !! instead of !!! is now encouraged 
          group_by(!!crit) |> 
          count())
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接