首页 > 解决方案 > 使用 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)

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

标签: rdplyrquasiquotes

解决方案


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

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

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


推荐阅读