考虑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
中的envir
或enclos
参数。
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
获取环境的程序化方法?
答案 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
同样,这有很好的理由颠覆/减少了很多代码。