如何在dplyr中使用NSE来引用一个变量?

时间:2016-09-29 20:34:11

标签: r dplyr

我想编写一个在dplyr链中使用的函数,用于按给定变量排列分组数据,然后检查该变量是否严格增加整数(例如,1,2,3,... )。为了澄清,我的意思是按顺序排列每个整数,而不仅仅是增加整数。所以1,2,4 ......应该失败。

这个想法最终会有这样的东西,看起来像这样,并且如果x不是1,2,3,则为每个组提供错误。

d %>% group_by(group) %>% check(x) 

我已经写了一个似乎有效的SE版本,如下所示,但我仍坚持使用NSE版本。

check_ <- function(.data, var) {
  checkint <- function(x) { stopifnot(x == seq_along(x)) }
  do(.data, {
    . <- dplyr::arrange_(., var)
    checkint(lazyeval::lazy_eval(var, data=.))
    .
  })
}

在文档中,看起来我应该使用lazy来处理单个变量,但是当我传入的变量也存在于全局环境中时,这不起作用

checkX <- function(.data, var) {
  check_(.data, lazyeval::lazy(var))
}

d <- expand.grid(group=1:2, x=3:1)
x <- 5 ## put an "x" in the global environment
d %>% group_by(group) %>% checkX(x)

## Error: incorrect size (1), expecting : 3 

我确实有一个似乎有效的NSE版本,但调用lazy_dots感觉不对,因为我只想要一个变量。

check <- function(.data, ...) {
  check_(.data, lazyeval::lazy_dots(...)[[1]])
}

1 个答案:

答案 0 :(得分:2)

看起来lazyeval一直在变化。 latest vignette甚至没有引用lazy()函数。它似乎确实存在范围内变量的问题(更多内容在底部)。现在我们的功能受到了鼓励,尽管他们还没有进入所有“整齐的”。

看起来你想要的功能是expr_find。如果我们将checkX定义为

checkX <- function(.data, var) {
  check_(.data, lazyeval::expr_find(var))
}

然后这将起作用

x <- 5
d %>% group_by(group) %>% checkX(x)

(或者至少与lazyeval_0.2.0dplyr_0.5.0相同)

但回到old vignette

的第一个例子
library(lazyeval)
# `x` does not exist here
f <- function(x = a - b) {
  lazy(x)
}
f()
# <lazy>
#   expr: a - b
#   env:  <environment: 0x000000000663d618>
exists("x")
# [1] FALSE
f(x)
# <lazy>
#   expr: x
#   env:  <environment: R_GlobalEnv>
x <- 101
f(x)
# <lazy>
#   expr: 101
#   env:  <environment: R_GlobalEnv>

或另一个更简单的例子

# rm(x)
lazy(x)
# <lazy>
#   expr: x
#   env:  <environment: R_GlobalEnv>
x <- 100
lazy(x)
#  <lazy>
#   expr: 100
#   env:  <environment: R_GlobalEnv>

它在某处评估参数x,因此如果它存在于它所来自的环境中,它就永远不会保存在惰性对象中。