What is the difference between ensym and enquo when programming with dplyr?

筅森魡賤 提交于 2020-02-22 07:37:06

问题


Relatively new to tidy evaluation and while the functions I'm making work, I want to know why different helper functions are used. For example, what is the difference between enquo and ensym? In the function I made below to capture daily average and moving average they're interchangeable:

library(dplyr)
library(lubridate)
library(rlang)
library(zoo)

manipulate_for_ma <- function(data, group_var, da_col_name, summary_var, ma_col_name) {
  group_var <- ensym(group_var) 
  summary_var <- enquo(summary_var)
  da_col_name <- ensym(da_col_name) 
  ma_col_name <- enquo(ma_col_name)

  data %>% 
    group_by(!!group_var) %>%
    summarise(!!da_col_name := mean(!!summary_var, na.rm = TRUE)) %>% 
    mutate(!!ma_col_name := rollapply(!!da_col_name,
                                      30,
                                      mean,
                                      na.rm = TRUE,
                                      partial = TRUE,
                                      fill = NA)) %>% 
    rename(date = !!group_var)
}

lakers %>%
 mutate(date = ymd(date)) %>%
 manipulate_for_ma(group_var = date,
                   da_col_name = points_per_play_da,
                   summary_var = points,
                   points_per_play_ma)

# A tibble: 78 x 3
   date       points_per_play_da points_per_play_ma
   <date>                  <dbl>              <dbl>
 1 2008-10-28              0.413              0.458
 2 2008-10-29              0.431              0.459
 3 2008-11-01              0.408              0.456
 4 2008-11-05              0.386              0.457

I've read about enquo here and ensym (here)[https://adv-r.hadley.nz/quasiquotation.html]. Is the difference that ensym is more restrictive and only takes strings or string-like objects?


回答1:


Another take :

library(rlang)
library(dplyr, warn.conflicts = FALSE)

test <- function(x){
  Species <- "bar"
  cat("--- enquo builds a quosure from any expression\n")
  print(enquo(x))
  cat("--- ensym captures a symbol or a literal string as a symbol\n")
  print(ensym(x))
  cat("--- evaltidy will evaluate the quosure in its environment\n")
  print(eval_tidy(enquo(x)))
  cat("--- evaltidy will evaluate a symbol locally\n")
  print(eval_tidy(ensym(x)))
  cat("--- but both work fine where the environment doesn't matter\n")
  identical(select(iris,!!ensym(x)), select(iris,!!enquo(x)))
}

Species = "foo"
test(Species)
#> --- enquo builds a quosure from any expression
#> <quosure>
#> expr: ^Species
#> env:  global
#> --- ensym captures a symbol or a literal string as a symbol
#> Species
#> --- evaltidy will evaluate the quosure in its environment
#> [1] "foo"
#> --- evaltidy will evaluate a symbol locally
#> [1] "bar"
#> --- but both work fine where the environment doesn't matter
#> [1] TRUE

test("Species")
#> --- enquo builds a quosure from any expression
#> <quosure>
#> expr: ^"Species"
#> env:  empty
#> --- ensym captures a symbol or a literal string as a symbol
#> Species
#> --- evaltidy will evaluate the quosure in its environment
#> [1] "Species"
#> --- evaltidy will evaluate a symbol locally
#> [1] "bar"
#> --- but both work fine where the environment doesn't matter
#> [1] TRUE
test(paste0("Spec","ies"))
#> --- enquo builds a quosure from any expression
#> <quosure>
#> expr: ^paste0("Spec", "ies")
#> env:  global
#> --- ensym captures a symbol or a literal string as a symbol
#> Only strings can be converted to symbols

Created on 2019-09-23 by the reprex package (v0.3.0)




回答2:


Here is one example illustrating one difference (namely that enquo captures the calling environment and ensym doesn't). Hopefully it speaks for itself:

library(rlang)

f <- function(x) {
  foo <- 42
  print(eval_tidy(quo(!! ensym(x))))
  print(eval_tidy(quo(!! enquo(x))))
}
foo <- 3
f(foo)
# [1] 42
# [1] 3

Or the slightly more convoluted:

library(rlang)

myenv <- new.env()

local(envir = myenv, {
  foo <- 17
  g <- function(x) {
    print(eval_tidy(quo(!! ensym(x))))
    print(eval_tidy(quo(!! enquo(x))))
  }
})

foo <- 123
myenv$g(foo)
#> [1] 17
#> [1] 123

Created on 2019-09-18 by the reprex package (v0.3.0)

The difference is often not noticeable when using dplyr since it is foolproof enough to always look up names in the context of the .data argument first.



来源:https://stackoverflow.com/questions/57960245/what-is-the-difference-between-ensym-and-enquo-when-programming-with-dplyr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!