2

拿这个功能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)

我确信我对 quasiquotation 的了解存在一些差距,但我想了解如何在foo().

4

2 回答 2

3

这是一个可以“工作”的,虽然我不推荐它

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

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

于 2021-09-08T20:22:51.563 回答
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
于 2021-09-08T20:31:58.813 回答