在dplyr函数中跨多列使用动态变量名

3
我正在尝试编写一个函数,使用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?为什么这个方法不起作用呢?

我知道可能有许多其他方法来完成这个任务,但是出于教学目的和自己的理解,我想知道如何使用整洁评估和rlang语法在自定义函数中实现这种方法!

谢谢

1个回答

2
我们可以在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 的函数,我们将多列分配给一个单独的列,这将返回一个 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

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