如何使用非标准评估在函数中指定可能的参数状态?

时间:2017-08-23 04:03:01

标签: r tidyverse tidyeval

我正在学习使用tidy评估和非标准评估进行编程,并且一直在努力研究如何约束函数中参数的可能状态。

例如给定一个数据集:

set.seed(123)
data <- data_frame(GROUP_ONE = sample(LETTERS[1:3], 10, replace = TRUE), 
                   GROUP_TWO = sample(letters[4:6], 10, replace = TRUE), 
                   result = rnorm(10))

我可以创建一个函数,它有一个参数,我用它来组合数据,如下所示:

my_function <- function(data, group = GROUP_ONE){

  require(dplyr)
  require(magrittr)

  group <- enquo(group)

  result <- data %>% 
    group_by(!!group) %>% 
    summarise(mean=mean(result))

  return(result)
}

这就是我想做的事情

my_function(data)

# A tibble: 3 x 2
  GROUP_ONE       mean
      <chr>      <dbl>
1         A  1.5054975
2         B  0.2817966
3         C -0.5129904

我可以提供不同的小组:

my_function(data, group = GROUP_TWO)

# A tibble: 3 x 2
  GROUP_TWO       mean
      <chr>      <dbl>
1         d -0.3308130
2         e  0.2352483
3         f  0.7347437

但是,我无法按数据中不存在的列进行分组。

e.g。

 my_function(data, group = GROUP_THREE)
  

grouped_df_impl(data,unname(vars),drop)出错:列GROUP_THREE未知

我想在函数开头添加一个步骤,以便在group参数不是GROUP_ONE或GROUP_TWO的情况下,函数会停止并显示自定义错误消息

类似的东西:

if(!group %in% c(~GROUP_ONE, ~GROUP_TWO)) stop("CUSTOM ERROR MESSAGE")

除了这不起作用,因为你显然不能将quouts放在向量中。应该可以将quosure转换为字符串,并且有一个字符串向量,但我无法弄清楚如何。

这是怎么做到的?

2 个答案:

答案 0 :(得分:2)

我认为您需要quo_name(来自dplyrrlang),它会将带引号的符号转换为字符串:

my_function <- function(data, group = GROUP_ONE){

    require(dplyr)
    require(magrittr)

    group <- enquo(group)

    if(!quo_name(group) %in% names(data)) stop("CUSTOM ERROR MESSAGE")

    result <- data %>% 
        group_by(!!group) %>% 
        summarise(mean=mean(result))

    return(result)
}

# > my_function(data, GROUP_THREE)
# Error in my_function(data, GROUP_THREE) : CUSTOM ERROR MESSAGE

修改

正如lionel在评论中指出的那样:quo_name除外,还有许多其他选择,包括来自as.character的基础R as_stringrlang

答案 1 :(得分:1)

quo_name()用于将任意表达式转换为文本,因此无法检查符号。

如果您只想要符号,并且这些符号只应代表数据框列,那么您就不需要使用符号。在这种情况下,您可以使用enexpr()进行捕获(并且在下一版本的rlang中将会有ensym()):

group <- enexpr(group)
stopifnot(is_symbol(group))  # Or some custom error

然后将其转换为字符串以进行检查:

as_string(group) %in% names

然后你可以取消引用符号,就像你取消引用quosure一样。

df %>% group_by(!! group)

或者,如果您需要quosures,您可以检查包含的表达式:

expr <- get_expr(quo)
is_symbol(expr) && as_string(expr) %in% names

这应该是首选用户界面,因为group_by()具有变异语义,因此您可以执行以下操作:df %>% group_by(as.factor(col))。这也意味着尝试提供自定义错误消息是没有希望的,除非你想捕获错误,解析它以确保它没有找到&#34;符号&#34;一,并重新抛出另一个错误。