不在dplyr tidyeval时抛出错误

时间:2018-03-29 17:32:44

标签: r dplyr nse tidyeval

我正在使用dplyr并尝试整洁的评估。我很困惑如何检查以确保有人放入裸对象而不是NSE的字符串。例如,我想过滤非缺失数据:


library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
df = data_frame(
  myvar = c(rep("yes", 2), NA)
)
myfun <- function(x){
  x = enquo(x)
  num = df %>%
    filter(!is.na( !! x)) 
  return(num)
}

myfun(myvar)
#> # A tibble: 2 x 1
#>   myvar
#>   <chr>
#> 1 yes  
#> 2 yes

如果可能的话,我希望字符串相当于失败。这当前给出“错误”结果,因为is.na("myvar")永远不会错误。

myfun("myvar") # wrong result
#> # A tibble: 3 x 1
#>   myvar
#>   <chr>
#> 1 yes  
#> 2 yes  
#> 3 <NA>

在查看What is the tidyeval way of using dplyr::filter?之后,似乎filter_at将允许这两种方案正常工作:

myfun <- function(x){
  x = enquo(x)
  num = df %>%
    filter_at(vars( !! x), all_vars(!is.na(.)))
  return(num)
}

myfun(myvar)
#> # A tibble: 2 x 1
#>   myvar
#>   <chr>
#> 1 yes  
#> 2 yes
myfun("myvar") # correct result
#> # A tibble: 2 x 1
#>   myvar
#>   <chr>
#> 1 yes  
#> 2 yes

但有没有办法让myfun("myvar")失败?除非使用colnames(),否则我无法使用as.name和if语句作为未加引号的表达式失败。

2 个答案:

答案 0 :(得分:3)

您可以使用类似

的字符串测试字符串文字
myfun <- function(x){
  x = enquo(x)
  stopifnot(!is.character(rlang::f_rhs(x)))
  num = df %>%
    filter(!is.na( !! x)) 
  return(num)
}

由于quosures与公式非常相似,rlang::f_rhs部分提取传入的“thing”,因此您可以检查它是什么类型的语言元素。也许不是检查一个字符串,你可能只想确保它是一个符号。你可以用

做到这一点
myfun <- function(x){
  x = enquo(x)
  stopifnot(rlang::quo_is_symbol(x))
  num = df %>%
    filter(!is.na( !! x)) 
  return(num)
}

然后这些做你想做的事情

myfun(myvar) #works
myfun("myvar") #error

答案 1 :(得分:0)

在取消引用之前,您可以在函数中测试if。如果您将x作为带引号的字符串传递,则其长度= 1,函数将返回x或您想要的任何失败条件。如果您(正确地)传入了一个不带引号的变量名,那么NA将失败(使用length)但错误将被Error: object 'knockdown' not found静音,并且该函数将正常进行。

try()