dplyr 函数中的动态变量名称跨多列

Dynamic variables names in dplyr function across multiple columns

我正在尝试编写一个函数,该函数使用 dplyr::summarise 获取数据框多列的均值,并使用新的 rlang 粘合语法和 := 运算符.

这是我使用 mtcars 数据集遇到的问题的简单示例。

仅对一列进行汇总时 - 粘合语法有效(即汇总列名称为 mean_mpg):

mean_fun <- function(data, group_cols, summary_col) {
 data %>%
 group_by(across({{ group_cols }})) %>%
 summarise("mean_{{ summary_col }}" := mean({{ summary_col }}, na.rm = T))
}
mean_fun(mtcars, c(cyl, gear), mpg)

   cyl  gear mean_mpg
  <dbl> <dbl>    <dbl>
1     4     3     21.5
2     4     4     26.9
3     4     5     28.2
4     6     3     19.8
5     6     4     19.8
6     6     5     19.7
7     8     3     15.0
8     8     5     15.4

但是当对多列进行汇总时,等价物没有正确命名列:

mean_fun_multicols <- function(data, group_cols, summary_cols) {
  data %>%
    group_by(across({{ group_cols }})) %>%
    summarise("mean_{{ summary_cols }}" := across({{ summary_cols }}, ~ mean(., na.rm = T)))
}
mean_fun_multicols(mtcars, c(cyl, gear), c(mpg, wt))

    cyl  gear `mean_c(mpg, wt)`$mpg   $wt
  <dbl> <dbl>                 <dbl> <dbl>
1     4     3                  21.5  2.46
2     4     4                  26.9  2.38
3     4     5                  28.2  1.83
4     6     3                  19.8  3.34
5     6     4                  19.8  3.09
6     6     5                  19.7  2.77
7     8     3                  15.0  4.10
8     8     5                  15.4  3.37

如何获取汇总的列名称以读取 mean_mpgmean_wt?为什么这不起作用?

我意识到可能有许多其他方法可以执行此任务,但我想知道如何使用此方法(即在定制函数中使用 tidy eval、rlang 语法)以用于教学目的和我自己的目的理解!

谢谢

我们可以在across中使用.names重命名

mean_fun_multicols <- function(data, group_cols, summary_cols) {
  data %>%
    group_by(across({{group_cols}})) %>%
     summarise(across({{ summary_cols }},
         ~ mean(., na.rm = TRUE), .names = "mean_{.col}"), .groups = "drop")
}

-测试

mean_fun_multicols(mtcars, c(cyl, gear), c(mpg, wt))
# A tibble: 8 × 4
    cyl  gear mean_mpg mean_wt
  <dbl> <dbl>    <dbl>   <dbl>
1     4     3     21.5    2.46
2     4     4     26.9    2.38
3     4     5     28.2    1.83
4     6     3     19.8    3.34
5     6     4     19.8    3.09
6     6     5     19.7    2.77
7     8     3     15.0    4.10
8     8     5     15.4    3.37

注意::=主要用于tidyverse

中只有一列的情况

如果我们使用 OP 的函数,我们会将多个列分配给一个列,而这个 returns 一个 tibble 而不是一个普通的列。我们可能需要 unpack

library(tidyr)
> mean_fun_multicols(mtcars, c(cyl, gear), c(mpg, wt)) %>% str
`summarise()` has grouped output by 'cyl'. You can override using the `.groups` argument.
grouped_df [8 × 3] (S3: grouped_df/tbl_df/tbl/data.frame)
 $ cyl            : num [1:8] 4 4 4 6 6 6 8 8
 $ gear           : num [1:8] 3 4 5 3 4 5 3 5
 $ mean_c(mpg, wt): tibble [8 × 2] (S3: tbl_df/tbl/data.frame)
  ..$ mpg: num [1:8] 21.5 26.9 28.2 19.8 19.8 ...
  ..$ wt : num [1:8] 2.46 2.38 1.83 3.34 3.09 ...
 - attr(*, "groups")= tibble [3 × 2] (S3: tbl_df/tbl/data.frame)
  ..$ cyl  : num [1:3] 4 6 8
  ..$ .rows: list<int> [1:3] 
  .. ..$ : int [1:3] 1 2 3
  .. ..$ : int [1:3] 4 5 6
  .. ..$ : int [1:2] 7 8
  .. ..@ ptype: int(0) 
  ..- attr(*, ".drop")= logi TRUE

> mean_fun_multicols(mtcars, c(cyl, gear), c(mpg, wt)) %>% 
        unpack(where(is_tibble))
`summarise()` has grouped output by 'cyl'. You can override using the `.groups` argument.
# A tibble: 8 × 4
# Groups:   cyl [3]
    cyl  gear   mpg    wt
  <dbl> <dbl> <dbl> <dbl>
1     4     3  21.5  2.46
2     4     4  26.9  2.38
3     4     5  28.2  1.83
4     6     3  19.8  3.34
5     6     4  19.8  3.09
6     6     5  19.7  2.77
7     8     3  15.0  4.10
8     8     5  15.4  3.37