我正在学习使用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转换为字符串,并且有一个字符串向量,但我无法弄清楚如何。
这是怎么做到的?
答案 0 :(得分:2)
我认为您需要quo_name
(来自dplyr
或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
除外,还有许多其他选择,包括来自as.character
的基础R as_string
和rlang
。
答案 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;一,并重新抛出另一个错误。