rlang 和 enquo 在括号内不起作用

rlang and enquo does not work inside brackets

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

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

示例:

先一个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 时进行分组, 从括号内寻找 quosure 是行不通的。

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     

有点晚了,但是您实施 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)) {

您的所有四个测试用例都将按预期工作。