将多个调用参数传递给 dplyr 自定义函数中的形式参数而不使用“...”
Pass multiple calling arguments to a formal argument in dplyr custom function without using "..."
为了使自定义函数灵活地接收每个形式参数的一个或多个调用参数,我目前依赖于“...”:
library(dplyr)
foo <- function(data, ..., dv){
groups <- enquos(...)
dv <- enquo(dv)
data %>%
group_by(!!!groups) %>%
summarise(group_mean = mean(!!dv))
}
mtcars %>% foo(am, dv = mpg)
mtcars %>% foo(vs, am, dv = mpg)
但是“...”模糊了函数的逻辑,它不能用于具有 2 个或更多形式参数且需要多个调用参数的自定义函数。
有没有办法编写上述函数以利用形式参数(例如,"groups")而不是“...”,它可以接收单个矢量名称或矢量名称的矢量作为其参数参数?类似于:
foo <- function(data, groups, dv){
groups <- enquos(groups)
dv <- enquo(dv)
data %>%
group_by(!!!groups) %>%
summarise(group_mean = mean(!!dv))
}
# Failing code
mtcars %>% foo(groups = c(vs, am), dv = mpg)
请注意,此代码可以运行,但需要用户记住在函数体中使用 quos():
foo <- function(data, groups, dv){
dv <- enquo(dv)
data %>%
group_by(!!!groups) %>%
summarise(group_mean = mean(!!dv))
}
mtcars %>% foo(groups = quos(vs, am), dv = mpg)
我更愿意在函数体中依赖 enquos() 。
我们可以把...
放在最后
foo <- function(data, dv, ...){
groups <- enquos(...)
dv <- enquo(dv)
data %>%
group_by(!!!groups) %>%
summarise(group_mean = mean(!!dv))
}
如果我们想传递 'group' 的 vector
,那么一个选项是 group_by_at
foo <- function(data, groups, dv){
dv <- enquo(dv)
data %>%
group_by_at(vars(groups)) %>%
summarise(group_mean = mean(!!dv))
}
mtcars %>%
foo(groups = c("vs", "am"), dv = mpg)
# A tibble: 4 x 3
# Groups: vs [?]
# vs am group_mean
# <dbl> <dbl> <dbl>
#1 0 0 15.0
#2 0 1 19.8
#3 1 0 20.7
#4 1 1 28.4
如果我们想通过 c
传递不带引号的表达式,一个选项是将其转换为表达式,然后对其求值
foo <- function(data, groups, dv){
groups <- as.list(rlang::enexpr(groups))[-1]
dv <- enquo(dv)
data %>%
group_by(!!! groups) %>%
summarise(group_mean = mean(!!dv))
}
mtcars %>%
foo(groups = c(vs, am), dv = mpg)
# A tibble: 4 x 3
# Groups: vs [?]
# vs am group_mean
# <dbl> <dbl> <dbl>
#1 0 0 15.0
#2 0 1 19.8
#3 1 0 20.7
#4 1 1 28.4
或者正如@Joe 在评论中提到的那样,enquo
也应该与 group_by_at
一起使用
foo <- function(data, groups, dv){
dv <- enquo(dv)
groups <- enquos(groups)
data %>%
group_by_at(vars(!!!groups)) %>%
summarise(group_mean = mean(!!dv))
}
mtcars %>%
foo(groups = c(vs, am), dv = mpg)
# A tibble: 4 x 3
# Groups: vs [?]
# vs am group_mean
# <dbl> <dbl> <dbl>
#1 0 0 15.0
#2 0 1 19.8
#3 1 0 20.7
#4 1 1 28.4
为了使自定义函数灵活地接收每个形式参数的一个或多个调用参数,我目前依赖于“...”:
library(dplyr)
foo <- function(data, ..., dv){
groups <- enquos(...)
dv <- enquo(dv)
data %>%
group_by(!!!groups) %>%
summarise(group_mean = mean(!!dv))
}
mtcars %>% foo(am, dv = mpg)
mtcars %>% foo(vs, am, dv = mpg)
但是“...”模糊了函数的逻辑,它不能用于具有 2 个或更多形式参数且需要多个调用参数的自定义函数。
有没有办法编写上述函数以利用形式参数(例如,"groups")而不是“...”,它可以接收单个矢量名称或矢量名称的矢量作为其参数参数?类似于:
foo <- function(data, groups, dv){
groups <- enquos(groups)
dv <- enquo(dv)
data %>%
group_by(!!!groups) %>%
summarise(group_mean = mean(!!dv))
}
# Failing code
mtcars %>% foo(groups = c(vs, am), dv = mpg)
请注意,此代码可以运行,但需要用户记住在函数体中使用 quos():
foo <- function(data, groups, dv){
dv <- enquo(dv)
data %>%
group_by(!!!groups) %>%
summarise(group_mean = mean(!!dv))
}
mtcars %>% foo(groups = quos(vs, am), dv = mpg)
我更愿意在函数体中依赖 enquos() 。
我们可以把...
放在最后
foo <- function(data, dv, ...){
groups <- enquos(...)
dv <- enquo(dv)
data %>%
group_by(!!!groups) %>%
summarise(group_mean = mean(!!dv))
}
如果我们想传递 'group' 的 vector
,那么一个选项是 group_by_at
foo <- function(data, groups, dv){
dv <- enquo(dv)
data %>%
group_by_at(vars(groups)) %>%
summarise(group_mean = mean(!!dv))
}
mtcars %>%
foo(groups = c("vs", "am"), dv = mpg)
# A tibble: 4 x 3
# Groups: vs [?]
# vs am group_mean
# <dbl> <dbl> <dbl>
#1 0 0 15.0
#2 0 1 19.8
#3 1 0 20.7
#4 1 1 28.4
如果我们想通过 c
传递不带引号的表达式,一个选项是将其转换为表达式,然后对其求值
foo <- function(data, groups, dv){
groups <- as.list(rlang::enexpr(groups))[-1]
dv <- enquo(dv)
data %>%
group_by(!!! groups) %>%
summarise(group_mean = mean(!!dv))
}
mtcars %>%
foo(groups = c(vs, am), dv = mpg)
# A tibble: 4 x 3
# Groups: vs [?]
# vs am group_mean
# <dbl> <dbl> <dbl>
#1 0 0 15.0
#2 0 1 19.8
#3 1 0 20.7
#4 1 1 28.4
或者正如@Joe 在评论中提到的那样,enquo
也应该与 group_by_at
foo <- function(data, groups, dv){
dv <- enquo(dv)
groups <- enquos(groups)
data %>%
group_by_at(vars(!!!groups)) %>%
summarise(group_mean = mean(!!dv))
}
mtcars %>%
foo(groups = c(vs, am), dv = mpg)
# A tibble: 4 x 3
# Groups: vs [?]
# vs am group_mean
# <dbl> <dbl> <dbl>
#1 0 0 15.0
#2 0 1 19.8
#3 1 0 20.7
#4 1 1 28.4