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名,你只需要:
-
- 使用rlang包中的
sym()
将string转换为符号
- 使用rlang包中的
-
- 在你的函数调用中,使用来自rlang的
UQ()
来取消引用符号
- 在你的函数调用中,使用来自rlang的
例如,你会做以下几点:
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
将.dots
parameter passing给使用paste
, sprintf
构造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