用 `...` 向量化 tidyverse 函数

Vectorizing a tidyverse function with `...`

下面的函数 foo 将数字列 var1 重新编码为字符串列(1 --> "a"2 --> "b" 等) .

我想知道如何向量化这个函数,这样我们有参数 ...?

而不是参数 var1

也就是说,... 中提供的所有变量都应该经历 var1foo 中经历的事情。

可能有用的 post 可能是

library(tidyverse)

foo <- function(data, var1, caps = FALSE, reverse = FALSE){
  
let <-  if(caps) base::LETTERS else base::letters
FUN <- if(reverse) utils::tail else utils::head

data %>% mutate(var1 = factor(FUN(let, max(var1))[var1]))  
}

# EXAMPLE OF USE:
(dat <- data.frame(var1 = c(2,1,3,1,4:1), id = 1:8))

foo(dat, var1, caps = T, reverse = T)

我们可以用across-

foo <- function(data, caps = FALSE, reverse = FALSE, ...){
  vars <- rlang::ensyms(...) 
  let <-  if(caps) base::LETTERS else base::letters
  FUN <- if(reverse) utils::tail else utils::head
  
  data %>% mutate(across(as.character(vars), ~factor(FUN(let, max(.))[.])))  
}

dat <- data.frame(var1 = c(2,1,3,1,4:1), id = 1:8)
foo(dat, caps = T, reverse = T, var1)

#  var1 id
#1    X  1
#2    W  2
#3    Y  3
#4    W  4
#5    Z  5
#6    Y  6
#7    X  7
#8    W  8

foo(dat, caps = T, reverse = T, var1, id)

#  var1 id
#1    X  S
#2    W  T
#3    Y  U
#4    W  V
#5    Z  W
#6    Y  X
#7    X  Y
#8    W  Z

下面的方法应该可以满足您的需求。它不像我对你问题中链接 post 的回答那么干净,但它应该按预期工作(现在也更新了适用于所有变量的默认参数):

library(tidyverse)
library(rlang)

foo <- function(data, ..., caps = FALSE, reverse = FALSE){
  
  var_ls <- map(ensyms(..., .named = TRUE), as.character)
  l_varls <- length(var_ls) 
  
  if(l_varls != length(caps)) {
    caps <- rep(caps, l_varls)
  }
  if(l_varls != length(reverse)) {
    reverse <- rep(reverse, l_varls)
  }
  
  let <- ifelse(caps, list(base::LETTERS), list(base::letters))
  names(let) <- names(var_ls)
  FUN <- ifelse(reverse, list(utils::tail), list(utils::head))
  names(FUN) <- names(var_ls)
  
  mutate(data,
         purrr::map_dfc(var_ls,
                        ~ factor(FUN[[.x]](let[[.x]],max(data[[.x]]))[data[[.x]]]))
         )
  
}

# EXAMPLE OF USE:
(dat <- data.frame(var1 = c(2,1,3,1,4:1), var2 = c(8:1), id = 1:8))
#>   var1 var2 id
#> 1    2    8  1
#> 2    1    7  2
#> 3    3    6  3
#> 4    1    5  4
#> 5    4    4  5
#> 6    3    3  6
#> 7    2    2  7
#> 8    1    1  8

foo(dat, var1, var2, caps = c(TRUE,FALSE), reverse = c(FALSE, TRUE))
#>   var1 var2 id
#> 1    B    z  1
#> 2    A    y  2
#> 3    C    x  3
#> 4    A    w  4
#> 5    D    v  5
#> 6    C    u  6
#> 7    B    t  7
#> 8    A    s  8
foo(dat, var1, var2)
#>   var1 var2 id
#> 1    b    h  1
#> 2    a    g  2
#> 3    c    f  3
#> 4    a    e  4
#> 5    d    d  5
#> 6    c    c  6
#> 7    b    b  7
#> 8    a    a  8
foo(dat, var1, var2, caps = TRUE, reverse = TRUE)
#>   var1 var2 id
#> 1    X    Z  1
#> 2    W    Y  2
#> 3    Y    X  3
#> 4    W    W  4
#> 5    Z    V  5
#> 6    Y    U  6
#> 7    X    T  7
#> 8    W    S  8

reprex package (v0.3.0)

于 2021-09-18 创建