用 `...` 向量化 tidyverse 函数
Vectorizing a tidyverse function with `...`
下面的函数 foo
将数字列 var1
重新编码为字符串列(1 -->
"a"
、2 -->
"b"
等) .
我想知道如何向量化这个函数,这样我们有参数 ...
?
而不是参数 var1
也就是说,...
中提供的所有变量都应该经历 var1
在 foo
中经历的事情。
可能有用的 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 创建
下面的函数 foo
将数字列 var1
重新编码为字符串列(1 -->
"a"
、2 -->
"b"
等) .
我想知道如何向量化这个函数,这样我们有参数 ...
?
var1
也就是说,...
中提供的所有变量都应该经历 var1
在 foo
中经历的事情。
可能有用的 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 创建