dplyr中的标准评估:sumrise_以variablesforms给出的string

我想在summarise引用一个未知的列名。 dplyr 0.3引入的标准评估函数允许使用variables引用列名,但是当您在summarise调用base R函数时,这似乎不起作用。

 library(dplyr) key <- "v3" val <- "v2" drp <- "v1" df <- data_frame(v1 = 1:5, v2 = 6:10, v3 = c(rep("A", 3), rep("B", 2))) 

DF如下所示:

 > df Source: local data frame [5 x 3] v1 v2 v3 1 1 6 A 2 2 7 A 3 3 8 A 4 4 9 B 5 5 10 B 

我想放弃v1,按v3分组,然后为每个组添加v2:

 df %>% select(-matches(drp)) %>% group_by_(key) %>% summarise_(sum(val, na.rm = TRUE)) Error in sum(val, na.rm = TRUE) : invalid 'type' (character) of argument 

select()的NSE版本工作正常,因为它可以匹配一个string。 group_by()的SE版本正常工作,因为它现在可以接受variables作为参数并对它们进行评估。 但是,我还没有find一种方法来实现在dplyr函数中使用基本R函数的类似结果。

事情不起作用:

 df %>% group_by_(key) %>% summarise_(sum(get(val), na.rm = TRUE)) Error in get(val) : object 'v2' not found df %>% group_by_(key) %>% summarise_(sum(eval(as.symbol(val)), na.rm = TRUE)) Error in eval(expr, envir, enclos) : object 'v2' not found 

我已经检查了几个 相关的 问题 ,但迄今为止,所提出的解决scheme都没有为我工作。

随着rlang软件包的发布和dplyr的0.7.0更新,现在相当简单了。

当你想使用一个string(例如“v1”)作为variables名,你只需要:

    1. 使用rlang包中的sym()将string转换为符号
    1. 在你的函数调用中,使用来自rlang的UQ()来取消引用符号

例如,你会做以下几点:

 my_var <- "Sepal.Length" my_sym <- sym(my_var) summarize(iris, Mean = mean(UQ(my_sym))) 

此外,为了节省时间打字,而不是使用UQ()你可以input!! 在符号的前面,就像mean(!!my_sym) ,这就是使用!! 来自rlang包的运算符。

你也可以结合把你的string转换成一个带有sym()的符号的步骤,并用!! 当你写你的函数调用。

例如,你可以写:

 my_var <- "Sepal.Length" summarize(iris, mean(!!sym(my_var))) 

要返回到您的原始示例,您可以执行以下操作:

 library(rlang) key <- "v3" val <- "v2" drp <- "v1" df <- data_frame(v1 = 1:5, v2 = 6:10, v3 = c(rep("A", 3), rep("B", 2))) df %>% # NOTE: we don't have to do anything to `drp` # since the matches() function expects a character string select(-matches(drp)) %>% group_by(!!sym(key)) %>% summarise(sum(!!sym(val), na.rm = TRUE)) 

请注意,从dplyr 0.7.0

dplyr有一种新的非标准评估方法(NSE),称为tidyeval。 它在vignette("programming")中详细描述。

这个答案不适用于dplyr 0.7.0 ,而是适用于以前的版本。


非标准评估的dplyr小插曲在这里很有帮助。 检查“混合常量和variables”部分,你会发现可以使用包lazyeval函数,如果你有一个string给出一个variables名,你就可以使用as.name

 library(lazyeval) df %>% select(-matches(drp)) %>% group_by_(key) %>% summarise_(sum_val = interp(~sum(var, na.rm = TRUE), var = as.name(val))) # v3 sum_val # 1 A 21 # 2 B 19 

.dotsparameter passing给使用pastesprintf构造string的string列表,或者使用来自程序包gsubfn的string插值通过fn$list代替list如下所示:

 library(gsubfn) df %>% group_by_(key) %>% summarise_(.dots = fn$list(mean = "mean($val)", sd = "sd($val)")) 

赠送:

 Source: local data frame [2 x 3] v3 mean sd 1 A 7.0 1.0000000 2 B 9.5 0.7071068 

新的dplyr更新:

dplyr的新function可以帮助解决这个问题。 我们使用quos quo()替代需要非标准评估的variables的string。 我们用另一个函数来取消引用!! 。 欲了解更多关于这些看到这个小插曲 。 直到完整版本,您将需要dplyr的开发者版本 。

 library(dplyr) #0.5.0.9004+ key <- quo(v3) val <- quo(v2) drp <- "v1" df <- data_frame(v1 = 1:5, v2 = 6:10, v3 = c(rep("A", 3), rep("B", 2))) df %>% select(-matches("v1")) %>% group_by(!!key) %>% summarise(sum(!!val, na.rm = TRUE)) # # A tibble: 2 × 2 # v3 `sum(v2, na.rm = TRUE)` # <chr> <int> # 1 A 21 # 2 B 19