您如何使用非标准评估指定函数中可能的参数状态?
How do you specify of possible arguments states in functions using non-standard evaluation?
我正在学习使用 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)
Error in grouped_df_impl(data, unname(vars), drop) : Column GROUP_THREE
is unknown
我想在函数的开头添加一个步骤,以便在组参数不是 GROUP_ONE 或 GROUP_TWO
时函数停止并显示自定义错误消息
类似于:
if(!group %in% c(~GROUP_ONE, ~GROUP_TWO)) stop("CUSTOM ERROR MESSAGE")
除非这不起作用,因为您显然不能将 quosures 放入向量中。应该可以以某种方式将 quosure 转换为字符串并具有字符串向量,但我不知道如何实现。
这是怎么做到的?
我认为您需要 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
,还有许多其他替代方案,包括来自 rlang
.[=18= 的基础 R as.character
和 as_string
]
quo_name()
用于将任意表达式转换为文本,因此不适合检查符号。
如果您只需要符号,并且这些符号应该只表示数据帧列,则不需要 quosures。在这种情况下你可以用enexpr()
来捕获(在下一个版本的rlang中会有ensym()
):
group <- enexpr(group)
stopifnot(is_symbol(group)) # Or some custom error
然后转成字符串进行校验:
as_string(group) %in% names
然后您可以像取消引号一样取消对符号的引用。
df %>% group_by(!! group)
或者,如果您需要 quosures,您可以检查包含的表达式:
expr <- get_expr(quo)
is_symbol(expr) && as_string(expr) %in% names
那应该是首选 UI,因为 group_by()
具有变异语义,因此您可以这样做:df %>% group_by(as.factor(col))
。这也意味着尝试提供自定义错误消息是没有希望的,除非您想捕获错误,解析它以确保它是 "symbol not found" 错误,然后重新抛出另一个错误。
我正在学习使用 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)
Error in grouped_df_impl(data, unname(vars), drop) : Column
GROUP_THREE
is unknown
我想在函数的开头添加一个步骤,以便在组参数不是 GROUP_ONE 或 GROUP_TWO
时函数停止并显示自定义错误消息类似于:
if(!group %in% c(~GROUP_ONE, ~GROUP_TWO)) stop("CUSTOM ERROR MESSAGE")
除非这不起作用,因为您显然不能将 quosures 放入向量中。应该可以以某种方式将 quosure 转换为字符串并具有字符串向量,但我不知道如何实现。
这是怎么做到的?
我认为您需要 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
,还有许多其他替代方案,包括来自 rlang
.[=18= 的基础 R as.character
和 as_string
]
quo_name()
用于将任意表达式转换为文本,因此不适合检查符号。
如果您只需要符号,并且这些符号应该只表示数据帧列,则不需要 quosures。在这种情况下你可以用enexpr()
来捕获(在下一个版本的rlang中会有ensym()
):
group <- enexpr(group)
stopifnot(is_symbol(group)) # Or some custom error
然后转成字符串进行校验:
as_string(group) %in% names
然后您可以像取消引号一样取消对符号的引用。
df %>% group_by(!! group)
或者,如果您需要 quosures,您可以检查包含的表达式:
expr <- get_expr(quo)
is_symbol(expr) && as_string(expr) %in% names
那应该是首选 UI,因为 group_by()
具有变异语义,因此您可以这样做:df %>% group_by(as.factor(col))
。这也意味着尝试提供自定义错误消息是没有希望的,除非您想捕获错误,解析它以确保它是 "symbol not found" 错误,然后重新抛出另一个错误。