rlang和enquo在括号内不起作用

时间:2018-06-22 06:46:02

标签: r dplyr rlang

我正在尝试编写一个在data.frame上运行的函数,该函数将接受dplyr样式的参数,即使用dplyr的pronous(或我们称为它的东西)未引用的列名。

但是在带括号的表达式中使用!!时遇到了一个问题(请参见下面的示例)。

示例:

首先是一个data.frame:

df <- data.frame(gah=c('a','a','a','a','b','b','b','b'), 
                 fruit=c('apple','apple','apple','banana','banana','banana','dog','dog'),
                 val=1:8, 
                 sss=-7:0,
                 mean=0)

第一个函数,它对固定列(val)和参数指定的列取平均值。它不会修改分组:

a_func <- function(df, value=val) {
  value_ = enquo(value)
  df %>% summarise(mean=mean(!!value_), mean_val=mean(val), n=n())
}
a_func(df, sss)
df %>% group_by(gah) %>% a_func()
df %>% group_by(gah) %>% a_func(sss)
df %>% group_by(gah, fruit) %>% a_func

这按预期工作。

下一个函数在使用summarise之前添加分组变量:

c_func <- function(df, gr) {
  gr_ = enquo(gr)
  df %>% group_by(!!gr_) %>% summarise(n=n())
}
c_func(df, gah)
c_func(df, gr=gah)
c_func(df, fruit)

这也按预期工作。

接下来,我将两者结合起来。那应该可行-实际上是!赞美圣小猫!

b_func <- function(df, value=val, gr=NA) {
  value_ = enquo(value)
  gr_ = enquo(gr)
  df %>% group_by(!!gr_, add=TRUE) %>%
    summarise(mean=mean(!!value_), mean_val=mean(val))
}
b_func(df, sss)
df %>% group_by(gah) %>% b_func(gr=fruit)
b_func(df, gr=fruit)
df %>% group_by(gah) %>% b_func(sss, fruit)

显然,它与可选参数gr一样可以正常工作,我只想在gr不是 NA时添加分组变量。

这是中断吗? 添加条件以仅在gr不是NA时进行分组, 在支架内寻找担保不起作用。

d_func <- function(df, value=val, gr=NA) {
  value_ = enquo(value)
  gr_ = enquo(gr)
  if (!is.na(gr)) {
    df <- df %>% group_by(!!gr_)
  }
  df %>% 
    summarise(mean=mean(!!value_), mean_val=mean(val))
}
d_func(df, sss) # works
df %>% group_by(gah) %>% d_func(gr=fruit)
# Error in d_func(., gr = fruit) : object 'fruit' not found
d_func(df, gr=fruit) 
# Error in d_func(df, gr = fruit) : object 'fruit' not found
df %>% group_by(gah) %>% d_func(sss, fruit)
# Error in d_func(., sss, fruit) : object 'fruit' not found

显然是由于!!gr_在附加括号的范围内被称为;删除if和它的方括号,d_func等效于b_func,并且两个组都由列NA组成。

我不明白为什么会这样或如何解决。

已使用sessionInfo更新

R version 3.4.4 (2018-03-15)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows >= 8 x64 (build 9200)

Matrix products: default

locale:
[1] LC_COLLATE=Danish_Denmark.1252  LC_CTYPE=Danish_Denmark.1252    LC_MONETARY=Danish_Denmark.1252
[4] LC_NUMERIC=C                    LC_TIME=Danish_Denmark.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] rlang_0.2.0          bindrcpp_0.2.2       lemon_0.4.0          tidyr_0.8.0          magrittr_1.5        
[6] dplyr_0.7.4          odbc_1.1.5           RevoUtils_10.0.9     RevoUtilsMath_10.0.1

loaded via a namespace (and not attached):
 [1] Rcpp_0.12.16       pillar_1.2.1       compiler_3.4.4     plyr_1.8.4         bindr_0.1.1        tools_3.4.4       
 [7] bit_1.1-12         tibble_1.4.2       gtable_0.2.0       lattice_0.20-35    pkgconfig_2.0.1    openxlsx_4.0.17   
[13] cli_1.0.0          rstudioapi_0.7     DBI_0.8            yaml_2.1.18        gridExtra_2.3      knitr_1.20        
[19] hms_0.4.2          bit64_0.9-7        grid_3.4.4         tidyselect_0.2.4   glue_1.2.0         R6_2.2.2          
[25] ggplot2_2.2.1.9000 purrr_0.2.4        blob_1.1.1         scales_0.5.0       assertthat_0.2.0   colorspace_1.3-2  
[31] utf8_1.1.3         lazyeval_0.2.1     munsell_0.4.3      crayon_1.3.4     

1 个答案:

答案 0 :(得分:1)

一个较晚的答案,但是实现d_func的问题在于,您正在混合使用同一变量的标准和非标准评估。您正在使用enquo捕获调用环境中给gr的表达式(非标准评估),同时测试变量gr所保存的值是否为NA(标准评估)。

在进行标准求值的情况下(如!is.na(gr)),gr将求值到变量fruit所保存的值,而不是表达式fruit。在您的情况下,从未定义变量fruit。在akrun的情况下-library(tidyverse)可能是谁-fruit得出的预定义字符串向量来自stringr::fruit,其中包含各种水果名称。

在任何一种情况下,这种行为都是不希望的。您的目标是仅在指定gr的情况下执行特定的操作。 R提供了可用于此目的的原始函数missing()。如果您更换

if (!is.na(gr)) {

if (!missing(gr)) {

所有四个测试用例都能按预期工作。