使用 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 变量。

最好在直接传入输入数据的地方创建适当的函数(而不是他们需要自己查找的变量名)。

我们可以用 missingcur_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