安全版本的子集

作为subset()手册指出:

警告 :这是一个旨在交互使用的便利功能

我从这篇大文章,不仅这样的警告背后的秘密,但有很好的理解了解到substitute() match.call() eval()quote() callpromise和其他相关的研究课题,是一个有点复杂。

现在我明白了上面的警告是什么。 subset()一个超简单实现可以如下所示:

subset = function(x, condition) x[eval(substitute(condition), envir=x),]

虽然subset(mtcars, cyl==4)返回满足cyl==4 mtcars中的行的表,但在另一个函数中包含subset()失败:

sub = function(x, condition) subset(x, condition)

sub(mtcars, cyl == 4)
# Error in eval(expr, envir, enclos) : object 'cyl' not found

使用原始版本的subset()也会产生完全相同的错误条件。 这是由于substitute()-eval()对的限制造成的:当conditioncyl==4时它工作正常,但是当condition通过包络函数sub()subset()condition参数将会是不再是cyl==4 ,而是sub()体中的嵌套condition ,而eval()失败 - 这有点复杂。

但它是否存在具有完全相同的参数subset()任何其他实现, 这些参数是编程安全的 - 也就是说,当它被另一个函数调用时能够评估它的条件吗?


仅仅因为它是这种引人入胜的乐趣(??),这里有一个稍微不同的解决方案,解决了Hadley在我接受的解决方案中提出的问题。

哈德利发表了一个要点,表明了我接受的功能出错的情况。 该例中的扭曲(复制如下)是传递给SUBSET()的符号在其中一个调用函数的主体(而不是参数)中定义; 它因此被substitute()而不是预期的全局变量捕获。 我知道,令人困惑的东西。

f <- function() {
  cyl <- 4
  g()
}

g <- function() {
  SUBSET(mtcars, cyl == 4)$cyl
}
f()

这是一个更好的函数,它只会替代调用函数参数列表中找到的符号值。 它适用于Hadley或我迄今为止提出的所有情况。

SUBSET <- function(`_dat`, expr) {
   ff <- sys.frames()
   n <- length(ff)
   ex <- substitute(expr)
   ii <- seq_len(n)
   for(i in ii) {
       ## 'which' is the frame number, and 'n' is # of frames to go back.
       margs <- as.list(match.call(definition = sys.function(n - i),
                                   call = sys.call(sys.parent(i))))[-1]
       ex <- eval(substitute(substitute(x, env = ll),
                             env = list(x = ex, ll = margs)))
   }
   `_dat`[eval(ex, envir = `_dat`),]
}

## Works in Hadley's counterexample ...
f()
# [1] 4 4 4 4 4 4 4 4 4 4 4

## ... and in my original test cases.
sub <- function(x, condition) SUBSET(x, condition)
sub2 <- function(AA, BB) sub(AA, BB)

a <- SUBSET(mtcars, cyl == 4)  ## Direct call to SUBSET()
b <- sub(mtcars, cyl == 4)     ## SUBSET() called one level down
c <- sub2(mtcars, cyl == 4)
all(identical(a, b), identical(b, c))
# [1] TRUE

重要提示:请注意,这仍然不是(也不能成为)通常有用的功能。 当函数调用调用堆栈时,函数根本无法知道您希望它在所有替换中使用哪些符号。 在许多情况下,用户希望它使用分配给函数体内的符号值,但是这个函数总是忽略这些符号值。


[功能就是你要找的东西。 ? “[”。 mtcars[mtcars$cyl == 4,]等同于子集命令,并且是“编程”安全的。

sub = function(x, condition) {
 x[condition,]
}

sub(mtcars, mtcars$cyl==4)

如果在函数调用中没有使用隐含with() ,你会问什么。 具体情况很复杂,但功能如下:

sub = function(x, quoted_condition) {
  x[with(x, eval(parse(text=quoted_condition))),]
}

sub(mtcars, 'cyl==4')

Sorta做你正在寻找的东西,但有边缘情况下,这将有意想不到的结果。


使用data.table[子集函数,你可以得到隐含with(...)你正在寻找。

library(data.table)
MT = data.table(mtcars)

MT[cyl==4]

data.table有更好更快的方法来完成这个子集,但这很好地说明了这一点。


使用data.table你也可以构造表达式来稍后评估

cond = expression(cyl==4)

MT[eval(cond)]

这两个现在可以通过函数传递:

wrapper = function(DT, condition) {
  DT[eval(condition)]
}

以下是subset()的一个替代版本,它甚至在嵌套时也能继续工作 - 至少只要逻辑子集表达式(例如cyl == 4 )被提供给顶层函数调用。

它通过爬上调用堆栈来工作,在每个步骤中substitute()以最终捕获由用户传入的逻辑子集表达式。 在调用sub2()以下,例如,在for循环从调用堆栈的工作原理向上exprxAA和最后到cyl ==4

SUBSET <- function(`_dat`, expr) {
    ff <- sys.frames()
    ex <- substitute(expr)
    ii <- rev(seq_along(ff))
    for(i in ii) {
        ex <- eval(substitute(substitute(x, env=sys.frames()[[n]]),
                              env = list(x = ex, n=i)))
    }
    `_dat`[eval(ex, envir = `_dat`),]
}

## Define test functions that nest SUBSET() more and more deeply
sub <- function(x, condition) SUBSET(x, condition)
sub2 <- function(AA, BB) sub(AA, BB)

## Show that it works, at least when the top-level function call
## contains the logical subsetting expression
a <- SUBSET(mtcars, cyl == 4)  ## Direct call to SUBSET()
b <- sub(mtcars, cyl == 4)     ## SUBSET() called one level down
c <- sub2(mtcars, cyl == 4)    ## SUBSET() called two levels down

identical(a,b)
# [1] TRUE
> identical(a,c)
# [1] TRUE
a[1:5,]
#                 mpg cyl  disp  hp drat    wt  qsec vs am gear carb
# Datsun 710     22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
# Merc 240D      24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
# Merc 230       22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
# Fiat 128       32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
# Honda Civic    30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2

**有关for循环内结构的一些解释,请参见R语言定义手册的第6.2节第6段。

链接地址: http://www.djcxy.com/p/70901.html

上一篇: safe version of subset

下一篇: How to convert multiple columns in R