dplyr中的标准评估:summarise_作为字符串给出的变量

时间:2014-11-03 22:06:11

标签: r dplyr

我想在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}}

我已经查看了several related questions,但到目前为止,所提出的解决方案都没有对我有用。

5 个答案:

答案 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;)作为变量名称,您只需:

  1. 使用rlang包中的sym()
  2. 将字符串转换为符号
  3. 在函数调用中,在符号前面写!!
  4. 例如,您可以执行以下操作:

    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()!!的使用情况的所有官方文档中,这些似乎是最容易访问的:

    1. dplyr vignette: Programming with dplyr

    2. The section of Hadley Wickham's book 'Advanced R' on metaprogramming

答案 2 :(得分:9)

使用.dotspaste或使用字符串插值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检查。