使用j环境中的函数进行列选择

时间:2013-02-01 20:10:13

标签: r data.table

考虑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并将其限制为.ab的定义,同时避免传递数据表{{1到函数dt

.ab

发生了什么事?怎么解决这个问题?

我怀疑咬我的是R的词汇范围以及.eab <- function() eval(quote(list(a, b))) dt[, .eab()] # Error in eval(expr, envir, enclos) : object 'b' not found 的正确评估依赖于它在数据表list(a,b) J 环境中的事实。唉,我不知道如何获取对正确环境的引用,并将其用作dt中的envirenclos参数。

dt

修改

此方法几乎有效:

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

有两个缺点:(1)不返回列名,(2).eab <- function(e) eval(quote(list(a, b)), envir = e) dt[, .eab(dt)] 必须明确传递(我宁愿避免)。我还宁愿避免硬编码dt作为选择环境。这些考虑导致了另一种询问上述问题的方法:是否有一种以dt方式从dt获取环境的程序化方法?

2 个答案:

答案 0 :(得分:4)

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

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

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

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

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

但如果.ab由于某种原因确实需要成为一个函数,那么我们当然可以进一步思考。

答案 1 :(得分:2)

警告,如果[.data.table的内部机制发生变化,这可能是不稳定,缓慢和/或可能会中断,但如果由于某种原因无法绕过它,这里的功能似乎符合您的要求。如果你开始使用by中的[.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

同样,这有很好的理由颠覆/减少了很多代码。