使用 tidyr::expand 的非标准评估
Non-standard Evaluation using tidyr::expand
我在使用 tidyr
包时遇到 运行 非标准求值 (nse) 表达式的问题。
基本上,我想做的是扩展可能相同或不同的两列,以实现具有所有可能组合的数据框。问题是这将是一个函数,所以我不会提前知道列名。
这是一个最小的例子:
library(tidyr)
dummy <- data.frame(x = c("ex1", "ex2"), y = c('cat1', 'cat2')) # dataset
tidyr::expand(dummy, x, y) # using standard evaluation works
tidyr::expand_(dummy, c("x", "y")) # using the deprecated syntax works
# The following did not work:
tidyr::expand(dummy, one_of('x'), y) # using select syntax
tidyr::expand(dummy, vars('x', 'y')) # mutate_at style
tidyr::expand(dummy, .data[[cnae_agg]], .data[[cnae_agg]]) # mutate current style
tidyr::expand(dummy, sym('x'), sym('y')) # trying to convert to symbols
tidyr::expand(dummy, !!!enquos('x', 'y'))
tidyr::expand(dummy, !!('x'), y) # unquosure just one element
tidyr::expand(dummy, !!!c("x", "y")) # unquosure vector of strings
tidyr::expand(dummy, !!!c(quo("x"), quo("y"))) # unquosure vector that is being quosured before
所以,我有两个问题:
1) tidyr 扩展函数应用的正确语法是什么?
2) 我可能已经读过好几遍关于准引用的 Advanced R 章节,但我仍然不清楚为什么有几种不同的 'styles' 来使用 nse
tidyverse,以及分别在哪里使用。
我基本上可以向 select/summarise 抛出任何它会起作用的东西,但是当使用 mutate 时,事情会有不同的反应。
例如:
# mutate
mutate(dummy, new_var = .data[['x']]) # mutate basic style
mutate(dummy, new_var = !!'x') # this just attributes 'x' to all rows
# mutate at
mutate_at(dummy, .vars=vars('y'), list(~'a')) # this works
mutate_at(dummy, .vars=vars(!!'y'), list(~'a')) # this also works
mutate_at(dummy, .vars=vars('y'), list(~`<-`(.,!!'x'))) # if we try to use unquote to create an attribution it does not work
mutate_at(dummy, .vars=vars('y'), list(~`<-`(.,vars(!!'x')))) # even using vars, which works for variable selection, doesnt suffice
# select
select(dummy, x) # this works
select(dummy, 'x') # this works
select_at(dummy, vars(!!'x')) # this works
select_at(dummy, 'x') # this works
select_at(dummy, !!'x') # this doesnt work
这让我想到了我的 2) 问题。
是否有针对 tidyverse 样式的所有当前语法的更新指南,重点关注每个 'verb' 的用法差异,例如 'mutate' 与 'select'(即一个工作,另一个不工作)?
以及如何知道我是否必须在其他 tidyverse 包(例如 tidyr)中使用 nse
的 mutate 或 select 样式?
我们需要评估 (!!
) sym
bols
tidyr::expand(dummy, !!! syms(c('x', 'y')))
# A tibble: 4 x 2
# x y
# <fct> <fct>
#1 ex1 cat1
#2 ex1 cat2
#3 ex2 cat1
#4 ex2 cat2
当列名存储在 vector
中并且想要执行 expand
时,这将特别有用
nm1 <- c('x', 'y')
tidyr::expand(dummy, !!! syms(nm1))
在其他一些组合中,!!!
或 sym
bol 的转换从 character
向量中丢失
nse
上的更新指南是 tidy evaluation guide。特别是,第 8 章介绍了它与 dplyr
的关系以及一般模式。在您的情况下,有几种可能的模式,具体取决于您要向用户公开的内容。
模式 1: 只需 pass the dots to expand,让用户完全控制底层 expand()
:
f <- function(...) {tidyr::expand(dummy, ...)}
f( x, y ) # End users specifies the columns via NSE
模式 2: 在每个变量的基础上捕获用户的输入并使用 new "curly curly" operator:
将其传递给 expand()
g <- function( var1, var2 ) {tidyr::expand(dummy, {{var1}}, {{var2}})}
g( x, y ) # Once again, NSE, but the number of arguments is controlled
模式 3: 允许用户以变量名或字符串的形式提供参数。使用rlang::ensyms
将字符串转换为变量名:
h <- function(...) {tidyr::expand(dummy, !!!rlang::ensyms(...))}
# The interface now works with strings or NSE
h( "x", "y" )
h( x, y )
模式 3b: 如果您想禁用 NSE 支持,并强制用户仅将参数作为字符串提供,则对上述模式进行微小修改将仅接受字符串:
h2 <- function(...) {tidyr::expand(dummy, !!!rlang::syms(list(...)))}
h2( "x", "y" ) # Strings OK
h2( x, y ) # Error: object 'x' not found
请注意,NSE 函数需要 quasiquotation 来处理存储在外部变量中的符号:
# Handling strings in external variables
str_name <- "x"
h( !!str_name, "y" )
h2( str_name, "y" ) # h2 doesn't support NSE; no !! needed
# Handling variable names as unevaluated expressions (NOT strings)
var_name <- quote(y)
f( x, !!var_name )
g( x, !!var_name )
h( x, !!var_name )
# Handling lists of variable names using !!! unquote-splice
# Works with functions that accept dots
arg_names <- rlang::exprs( x, y )
f( !!!arg_names )
h( !!!arg_names )
我在使用 tidyr
包时遇到 运行 非标准求值 (nse) 表达式的问题。
基本上,我想做的是扩展可能相同或不同的两列,以实现具有所有可能组合的数据框。问题是这将是一个函数,所以我不会提前知道列名。
这是一个最小的例子:
library(tidyr)
dummy <- data.frame(x = c("ex1", "ex2"), y = c('cat1', 'cat2')) # dataset
tidyr::expand(dummy, x, y) # using standard evaluation works
tidyr::expand_(dummy, c("x", "y")) # using the deprecated syntax works
# The following did not work:
tidyr::expand(dummy, one_of('x'), y) # using select syntax
tidyr::expand(dummy, vars('x', 'y')) # mutate_at style
tidyr::expand(dummy, .data[[cnae_agg]], .data[[cnae_agg]]) # mutate current style
tidyr::expand(dummy, sym('x'), sym('y')) # trying to convert to symbols
tidyr::expand(dummy, !!!enquos('x', 'y'))
tidyr::expand(dummy, !!('x'), y) # unquosure just one element
tidyr::expand(dummy, !!!c("x", "y")) # unquosure vector of strings
tidyr::expand(dummy, !!!c(quo("x"), quo("y"))) # unquosure vector that is being quosured before
所以,我有两个问题:
1) tidyr 扩展函数应用的正确语法是什么?
2) 我可能已经读过好几遍关于准引用的 Advanced R 章节,但我仍然不清楚为什么有几种不同的 'styles' 来使用 nse
tidyverse,以及分别在哪里使用。
我基本上可以向 select/summarise 抛出任何它会起作用的东西,但是当使用 mutate 时,事情会有不同的反应。
例如:
# mutate
mutate(dummy, new_var = .data[['x']]) # mutate basic style
mutate(dummy, new_var = !!'x') # this just attributes 'x' to all rows
# mutate at
mutate_at(dummy, .vars=vars('y'), list(~'a')) # this works
mutate_at(dummy, .vars=vars(!!'y'), list(~'a')) # this also works
mutate_at(dummy, .vars=vars('y'), list(~`<-`(.,!!'x'))) # if we try to use unquote to create an attribution it does not work
mutate_at(dummy, .vars=vars('y'), list(~`<-`(.,vars(!!'x')))) # even using vars, which works for variable selection, doesnt suffice
# select
select(dummy, x) # this works
select(dummy, 'x') # this works
select_at(dummy, vars(!!'x')) # this works
select_at(dummy, 'x') # this works
select_at(dummy, !!'x') # this doesnt work
这让我想到了我的 2) 问题。
是否有针对 tidyverse 样式的所有当前语法的更新指南,重点关注每个 'verb' 的用法差异,例如 'mutate' 与 'select'(即一个工作,另一个不工作)?
以及如何知道我是否必须在其他 tidyverse 包(例如 tidyr)中使用 nse
的 mutate 或 select 样式?
我们需要评估 (!!
) sym
bols
tidyr::expand(dummy, !!! syms(c('x', 'y')))
# A tibble: 4 x 2
# x y
# <fct> <fct>
#1 ex1 cat1
#2 ex1 cat2
#3 ex2 cat1
#4 ex2 cat2
当列名存储在 vector
中并且想要执行 expand
nm1 <- c('x', 'y')
tidyr::expand(dummy, !!! syms(nm1))
在其他一些组合中,!!!
或 sym
bol 的转换从 character
向量中丢失
nse
上的更新指南是 tidy evaluation guide。特别是,第 8 章介绍了它与 dplyr
的关系以及一般模式。在您的情况下,有几种可能的模式,具体取决于您要向用户公开的内容。
模式 1: 只需 pass the dots to expand,让用户完全控制底层 expand()
:
f <- function(...) {tidyr::expand(dummy, ...)}
f( x, y ) # End users specifies the columns via NSE
模式 2: 在每个变量的基础上捕获用户的输入并使用 new "curly curly" operator:
将其传递给expand()
g <- function( var1, var2 ) {tidyr::expand(dummy, {{var1}}, {{var2}})}
g( x, y ) # Once again, NSE, but the number of arguments is controlled
模式 3: 允许用户以变量名或字符串的形式提供参数。使用rlang::ensyms
将字符串转换为变量名:
h <- function(...) {tidyr::expand(dummy, !!!rlang::ensyms(...))}
# The interface now works with strings or NSE
h( "x", "y" )
h( x, y )
模式 3b: 如果您想禁用 NSE 支持,并强制用户仅将参数作为字符串提供,则对上述模式进行微小修改将仅接受字符串:
h2 <- function(...) {tidyr::expand(dummy, !!!rlang::syms(list(...)))}
h2( "x", "y" ) # Strings OK
h2( x, y ) # Error: object 'x' not found
请注意,NSE 函数需要 quasiquotation 来处理存储在外部变量中的符号:
# Handling strings in external variables
str_name <- "x"
h( !!str_name, "y" )
h2( str_name, "y" ) # h2 doesn't support NSE; no !! needed
# Handling variable names as unevaluated expressions (NOT strings)
var_name <- quote(y)
f( x, !!var_name )
g( x, !!var_name )
h( x, !!var_name )
# Handling lists of variable names using !!! unquote-splice
# Works with functions that accept dots
arg_names <- rlang::exprs( x, y )
f( !!!arg_names )
h( !!!arg_names )