9

考虑 a 中的以下列选择data.table

library(data.table) # using 1.8.7 from r-forge
dt <- data.table(a = 1:5, b = i <- rnorm(5), c = pnorm(i))
dt[, list(a,b)]  #ok

为了在具有许多可变列的某些计算中简化我的代码,我想list(a,b)用一个函数替换。这是第一次尝试:

.ab <- function()  quote(list(a, b))
dt[, eval(.ab())] #ok - same as above

理想情况下,我想摆脱eval()调用[.data.table并将其限制在 while 的定义中,.ab同时避免将数据表传递dt给函数.ab

.eab <- function()  eval(quote(list(a, b)))
dt[, .eab()] 
# Error in eval(expr, envir, enclos) : object 'b' not found

发生了什么?如何解决这个问题?

我怀疑困扰我的是 R 的词法作用域以及正确评估list(a,b)依赖于它在数据表的J环境中的事实dt。唉,我不知道如何获取对正确环境的引用并将envirenclos用作dt.

# .eab <- function()  eval(quote(list(a, b)), envir = ?, enclos = ?)

编辑

这种方法几乎有效:

.eab <- function(e)  eval(quote(list(a, b)), envir = e)
dt[, .eab(dt)]

有两个缺点:(1)不返回列名,(2)dt必须显式传递(我宁愿避免)。我也宁愿避免硬编码dt作为选择环境。这些考虑导致了提出上述问题的另一种方式:是否有一种dt从内部获取环境的程序化方式.eab

4

2 回答 2

5

目的是创建一个表达式而不是一个函数。

DT[, list(a,b), by=...]  # ok

.ab = quote(list(a, b))    # simpler here, no need for function()

DT[, eval(.ab), by=...]  # same

这种方法是在 data.table 中快速分组的原因之一:j在静态环境中对所有组进行评估,因此可以避免每个函数调用的(小)开销。

但是如果.ab真的因为某种原因需要成为一个函数,那么我们当然可以进一步考虑。

于 2013-02-01T22:12:29.280 回答
2

警告,如果内部机制发生变化,这可能不可靠、缓慢和/或可能会中断[.data.table,但如果由于某种原因无法绕过它,这里的函数似乎可以满足您的要求。by如果您开始使用其他选项(例如in ),我也可以想象它不起作用[.data.table

.eab <- function() {
  foo <- quote(list(a,b))
  ans <- eval(foo, envir = parent.frame(3)$x)
  names(ans) <- vapply(as.list(foo)[-1], deparse, character(1))
  ans
}

identical(dt[, .eab()], dt[, list(a,b)])
# TRUE

同样,这是颠覆/减少大量存在的充分理由的代码。

于 2013-02-02T02:59:34.027 回答