我想在summarise
内引用未知的列名。 dplyr 0.3
中引入的标准评估函数允许使用变量引用列名称,但是当您在例如base
内调用summarise
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
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
df看起来像这样:
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
我想删除v1,按v3分组,并为每个组加上v2:
select()
group_by()
的NSE版本可以正常工作,因为它可以匹配字符串。 SE版本的dplyr
工作正常,因为它现在可以接受变量作为参数并对其进行评估。但是,在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
函数中使用基本R函数时,我还没有找到实现类似结果的方法。
不起作用的事情:
{{1}}
答案 0 :(得分:53)
请注意,此答案不会 适用于dplyr >= 0.7.0
,而是适用于以前的版本。
[
中有详细描述dplyr 0.7.0
]有一种称为tidyeval的非标准评估(NSE)新方法。它在vignette("programming")
。
dplyr
vignette on non-standard evalutation在这里很有帮助。检查“混合常量和变量”部分,您会发现可以使用包interp
中的函数lazyeval
,如果您有一个字符串,则可以使用“[u] se 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
答案 1 :(得分:23)
随着rlang软件包的发布和对dplyr的0.7.0更新,现在相当简单。
如果您想使用字符串(例如&#34; v1&#34;)作为变量名称,您只需:
sym()
!!
例如,您可以执行以下操作:
my_var <- "Sepal.Length"
my_sym <- sym(my_var)
summarize(iris, Mean = mean(!!my_sym))
更紧凑的是,在编写函数调用时,您可以将将字符串转换为带有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))
其他详细信息
在解释sym()
和!!
的使用情况的所有官方文档中,这些似乎是最容易访问的:
答案 2 :(得分:9)
使用.dots
,paste
或使用字符串插值gsubfn通过sprintf
代替{{1},将fn$list
参数传递给构造字符串的字符串列表就像我们在这里一样:
list
,并提供:
library(gsubfn)
df %>%
group_by_(key) %>%
summarise_(.dots = fn$list(mean = "mean($val)", sd = "sd($val)"))
答案 3 :(得分:9)
新的dplyr更新:
dplyr的新功能可以帮助解决这个问题。我们使用quosures quo()
而不是需要非标准评估的变量的字符串。我们使用另一个函数!!
撤消引用。有关这些see this vignette的更多信息。在完整发布之前,您需要developer's version of 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
答案 4 :(得分:0)
dplyr
1.0改变了有关该问题以及所有答案的几乎所有内容。在此处查看dplyr
编程小插图:
https://cran.r-project.org/web/packages/dplyr/vignettes/programming.html
当列的标识符存储为字符向量时,引用列的新方法是使用.data
中的rlang
代词,然后使用基数R中的子集。
library(dplyr)
key <- "v3"
val <- "v2"
drp <- "v1"
df <- tibble(v1 = 1:5, v2 = 6:10, v3 = c(rep("A", 3), rep("B", 2)))
df %>%
select(-matches(drp)) %>%
group_by(.data[[key]]) %>%
summarise(total = sum(.data[[val]], na.rm = TRUE))
#> `summarise()` ungrouping output (override with `.groups` argument)
#> # A tibble: 2 x 2
#> v3 total
#> <chr> <int>
#> 1 A 21
#> 2 B 19
如果您的代码在包函数中,则可以@importFrom rlang .data
避免对未定义的全局变量进行R检查。