使用 dplyr 在自定义函数中无法识别默认参数
default arguments not being recognized in custom function using dplyr
利用这个功能foo()
。我希望它有一个默认参数 cyl
因为这是它通常处理的字段的名称。
library(tidyverse)
foo <- function(x = cyl){
case_when(
x == 6 ~ TRUE,
x == 8 ~ FALSE,
x == 4 ~ NA
)
}
# works:
mtcars %>%
mutate(cyl_refactor = foo(cyl)) %>%
select(cyl, cyl_refactor)
但令我惊讶的是,除非我明确提供默认参数,否则该函数将无法运行。请参阅下面的失败代码
# fails:
mtcars %>%
mutate(cyl_refactor = foo()) %>%
select(cyl, cyl_refactor)
Error: Problem with `mutate()` column `cyl_refactor`. ℹ `cyl_refactor = foo()`. x object 'cyl' not found
似乎只有当还有如下数据参数时才会处理默认参数。
foo2 <- function(data, x = cyl){
data %>%
mutate(cyl_refactor = case_when(
{{x}} == 6 ~ TRUE,
{{x}} == 8 ~ FALSE,
{{x}} == 4 ~ NA
))
}
mtcars %>%
foo2() %>%
select(cyl, cyl_refactor)
我确信我对准引用的知识存在一些差距,但我想了解如何在 foo()
.
中使用默认参数
虽然我不推荐,但这是一个“有效”的方法
foo <- function(x = cyl){
x <- enquo(x)
eval.parent(rlang::quo_squash(rlang::quo(case_when(
!!x == 6 ~ TRUE,
!!x == 8 ~ FALSE,
!!x == 4 ~ NA
))))
}
# Both run without error
mtcars %>%
mutate(cyl_refactor = foo(cyl)) %>%
select(cyl, cyl_refactor)
mtcars %>%
mutate(cyl_refactor = foo()) %>%
select(cyl, cyl_refactor)
问题是,为了使 case_when
正常工作,您不能只传递列名而不传递数据。为了在这种情况下“找到”数据,我使用 eval.parent()
沿着调用链向上移动以尝试找到 cyl
变量。
最好在直接传入输入数据的地方创建适当的函数(而不是他们需要自己查找的变量名)。
我们可以用 missing
和 cur_data_all
来做到这一点
foo <- function(x = cyl){
if(missing(x)) x <- cur_data_all()[["cyl"]]
case_when(
x == 6 ~ TRUE,
x == 8 ~ FALSE,
x == 4 ~ NA
)
}
-测试
> out1 <- mtcars %>%
+ mutate(cyl_refactor = foo(cyl)) %>%
+ select(cyl, cyl_refactor)
> out2 <- mtcars %>%
+ mutate(cyl_refactor = foo()) %>%
+ select(cyl, cyl_refactor)
>
> identical(out1, out2)
[1] TRUE
利用这个功能foo()
。我希望它有一个默认参数 cyl
因为这是它通常处理的字段的名称。
library(tidyverse)
foo <- function(x = cyl){
case_when(
x == 6 ~ TRUE,
x == 8 ~ FALSE,
x == 4 ~ NA
)
}
# works:
mtcars %>%
mutate(cyl_refactor = foo(cyl)) %>%
select(cyl, cyl_refactor)
但令我惊讶的是,除非我明确提供默认参数,否则该函数将无法运行。请参阅下面的失败代码
# fails:
mtcars %>%
mutate(cyl_refactor = foo()) %>%
select(cyl, cyl_refactor)
Error: Problem with `mutate()` column `cyl_refactor`. ℹ `cyl_refactor = foo()`. x object 'cyl' not found
似乎只有当还有如下数据参数时才会处理默认参数。
foo2 <- function(data, x = cyl){
data %>%
mutate(cyl_refactor = case_when(
{{x}} == 6 ~ TRUE,
{{x}} == 8 ~ FALSE,
{{x}} == 4 ~ NA
))
}
mtcars %>%
foo2() %>%
select(cyl, cyl_refactor)
我确信我对准引用的知识存在一些差距,但我想了解如何在 foo()
.
虽然我不推荐,但这是一个“有效”的方法
foo <- function(x = cyl){
x <- enquo(x)
eval.parent(rlang::quo_squash(rlang::quo(case_when(
!!x == 6 ~ TRUE,
!!x == 8 ~ FALSE,
!!x == 4 ~ NA
))))
}
# Both run without error
mtcars %>%
mutate(cyl_refactor = foo(cyl)) %>%
select(cyl, cyl_refactor)
mtcars %>%
mutate(cyl_refactor = foo()) %>%
select(cyl, cyl_refactor)
问题是,为了使 case_when
正常工作,您不能只传递列名而不传递数据。为了在这种情况下“找到”数据,我使用 eval.parent()
沿着调用链向上移动以尝试找到 cyl
变量。
最好在直接传入输入数据的地方创建适当的函数(而不是他们需要自己查找的变量名)。
我们可以用 missing
和 cur_data_all
foo <- function(x = cyl){
if(missing(x)) x <- cur_data_all()[["cyl"]]
case_when(
x == 6 ~ TRUE,
x == 8 ~ FALSE,
x == 4 ~ NA
)
}
-测试
> out1 <- mtcars %>%
+ mutate(cyl_refactor = foo(cyl)) %>%
+ select(cyl, cyl_refactor)
> out2 <- mtcars %>%
+ mutate(cyl_refactor = foo()) %>%
+ select(cyl, cyl_refactor)
>
> identical(out1, out2)
[1] TRUE