1

我正在学习使用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))

我可以创建一个函数,该函数有一个参数,我使用这样的 quosure 对数据进行分组:

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

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

例如

 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")

除非这不起作用,因为您显然不能将 quosures 放入向量中。应该可以以某种方式将 quosure 转换为字符串并具有字符串向量,但我不知道如何。

这是怎么做到的?

4

2 回答 2

2

我认为您需要quo_name(from dplyror rlang),它将带引号的符号转换为字符串:

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,还有许多其他选择,包括 base Ras.characteras_stringfrom rlang

于 2017-08-23T04:16:39.890 回答
1

quo_name()用于将任意表达式转换为文本,因此对于检查符号来说并不可靠。

如果您只期望符号,并且如果这些符号应该只表示数据框列,则不需要 quosures。在这种情况下,您可以使用enexpr()(并且将ensym()在 rlang 的下一个版本中)捕获:

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

这应该是首选的 UI,因为group_by()它具有 mutate 语义,因此您可以执行以下操作:df %>% group_by(as.factor(col)). 这也意味着尝试提供自定义错误消息是没有希望的,除非您想捕获错误,解析它以确保它是“未找到符号”,然后重新抛出另一个错误。

于 2017-08-23T06:08:58.480 回答