如何用 ... (dot-dot-dot) 编写一个也可以接受 tidyselect 助手的函数?

问题描述

我想编写一个处理数据的自定义函数函数的输入应该是:

  1. data.frame 对象
  2. 数据中与函数将要执行的操作相关的列的名称

我想对这个函数进行编程,以便指定列名的参数尽可能灵活。因此,我决定使用 dot-dot-dot (...)

但是,我不知道如何合并tidyselect选择助手(即containsstarts_with等)

示例

举个例子,假设我想为 dplyr::coalesce() 编写一个包装器。

library(rlang)
library(dplyr)

my_coalesce_func <- function(dat,...) {
  
  # step 1: save `...` into cols (https://tidyeval.tidyverse.org/multiple.html)
  cols <- enquos(...)
  
  # step 2: mutate new column `new_col` that coalesces columns of interest
  mutate(dat,new_col = coalesce(!!!cols))
}

# toy data
my_df <-
  data.frame(
    col_a = c(2,2,5,3),col_b = c(NA,4,3,1),col_c = c(4,1,2),col_d = c(1,NA,4),col_e = c(3,5),extra_col = 1:5
  )

# run the function -- works fine when we explicitly provide column names 
my_coalesce_func(dat = my_df,col_a,col_b,col_c,col_d,col_e)
#>   col_a col_b col_c col_d col_e extra_col new_col
#> 1     2    NA     4     1     3         1       2
#> 2     2     4     5    NA     3         2       2
#> 3     5     2     3     4     1         3       5
#> 4     5     3     1     2     4         4       5
#> 5     3     1     2     4     5         5       3


# run the function -- fails to use a select helper
my_coalesce_func(dat = my_df,starts_with("col"))
#> Error: Problem with `mutate()` column `new_col`.
#> i `new_col = coalesce(starts_with("col"))`.
#> x `starts_with()` must be used within a *selecting* function.
#> i See <https://tidyselect.r-lib.org/reference/faq-selection-context.html>.

reprex package (v2.0.0) 于 2021 年 7 月 1 日创建

我需要向 my_coalesce_func() 添加什么才能成功运行

my_coalesce_func(dat = my_df,starts_with("col"))

或任何其他传递给 ... 的选择助手。

谢谢!

解决方法

基于这个answer,一个技巧是依赖dplyr::select()

library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter,lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect,setdiff,setequal,union

my_coalesce_func = function(data,...) {
  data %>%
    select(...) %>%
    transmute(new_col = coalesce(!!!.)) %>% 
    bind_cols(data,.)
}

my_df <-
  data.frame(
    col_a = c(2,2,5,3),col_b = c(NA,4,3,1),col_c = c(4,1,2),col_d = c(1,NA,4),col_e = c(3,5),extra_col = 1:5
  )

# explicitly provide column names
my_coalesce_func(dat = my_df,col_d,col_e)
#>   col_a col_b col_c col_d col_e extra_col new_col
#> 1     2    NA     4     1     3         1       1
#> 2     2     4     5    NA     3         2       3
#> 3     5     2     3     4     1         3       4
#> 4     5     3     1     2     4         4       2
#> 5     3     1     2     4     5         5       4

# use tidyselect helpers
my_coalesce_func(dat = my_df,starts_with("col"),-(col_a:col_c))
#>   col_a col_b col_c col_d col_e extra_col new_col
#> 1     2    NA     4     1     3         1       1
#> 2     2     4     5    NA     3         2       3
#> 3     5     2     3     4     1         3       4
#> 4     5     3     1     2     4         4       2
#> 5     3     1     2     4     5         5       4

reprex package (v1.0.0) 于 2021 年 7 月 1 日创建

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...