使用 dplyr 在自定义函数中无法识别默认参数
Posted
技术标签:
【中文标题】使用 dplyr 在自定义函数中无法识别默认参数【英文标题】:default arguments not being recognized in custom function using dplyr 【发布时间】:2021-11-05 14:00:48 【问题描述】:使用这个函数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() 提供默认参数?我是否需要使用带引号的列名,如果需要,case_when() 可以处理带引号的列名吗? 在我的实际用例中,最好避免使用数据参数 所以当我尝试 sym() 方法时出现错误:只有字符串可以转换为符号 retain_92dv2 duration & is.na(!!cancel_date) ~ TRUE, # 烘焙 + 不取消 = 保留 !!cancel_date - !!gns_date > duration ~ TRUE, !!cancel_date - !!gns_date 是这个主意吗?传递带引号的参数,然后在函数中使用 arg 【参考方案1】:虽然我不推荐,但这是一个“有效”的方法
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
变量。
最好在直接传入输入数据的地方创建适当的函数(而不是他们需要自己查找的变量名)。
【讨论】:
所以听起来好像在没有数据参数的自定义函数中使用 case_when() 对于它无法“找到”的默认参数会有问题 @Joe 当您不直接将数据作为参数传递时,对于任何函数来说都是一个问题。case_when
没什么特别的。如果函数的默认参数是变量名而不是实际值,那么如果该变量未在函数中定义并且仅存在于调用环境中,则会出现问题。这与 R 使用词法作用域查找变量的正常行为相冲突。【参考方案2】:
我们可以使用 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
【讨论】:
以上是关于使用 dplyr 在自定义函数中无法识别默认参数的主要内容,如果未能解决你的问题,请参考以下文章
如何在自定义 cmdlet 中正确使用 -verbose 和 -debug 参数