包data.table
有一些特殊的语法,需要使用表达式作为i
和j
参数。
这对于一个写函数如何接受并将参数传递给数据表有一些影响,正如section 1.16 of the FAQs中所解释的那样。
但我无法弄清楚如何采取这一额外的水平。
这是一个例子。假设我想编写一个包装函数foo()
,它会对我的数据进行特定的摘要,然后是第二个包装器plotfoo()
,它会调用foo()
并绘制结果:
library(data.table)
foo <- function(data, by){
by <- substitute(by)
data[, .N, by=list(eval(by))]
}
DT <- data.table(mtcars)
foo(DT, gear)
好的,这很有效,因为我得到了我的表格结果:
by N
1: 4 12
2: 3 15
3: 5 5
现在,我在撰写plotfoo()
时尝试的却是一样的但我却悲惨地失败了:
plotfoo <- function(data, by){
by <- substitute(by)
foo(data, eval(by))
}
plotfoo(DT, gear)
但是这次我收到一条错误消息:
Error: evaluation nested too deeply: infinite recursion / options(expressions=)?
好的,所以eval()
导致了问题。我们将其删除:
plotfoo <- function(data, by){
by <- substitute(by)
foo(data, by)
}
plotfoo(DT, gear)
哦不,我收到一条新的错误消息:
Error in `[.data.table`(data, , .N, by = list(eval(by))) :
column or expression 1 of 'by' or 'keyby' is type symbol. Do not quote column names. Useage: DT[,sum(colC),by=list(colA,month(colB))]
这就是我被困住的地方。
问题:如何编写一个调用调用data.table函数的函数?
答案 0 :(得分:13)
这将有效:
plotfoo <- function(data, by) {
by <- substitute(by)
do.call(foo, list(quote(data), by))
}
plotfoo(DT, gear)
# by N
# 1: 4 12
# 2: 3 15
# 3: 5 5
<强>解释强>
问题是,您对foo()
中的plotfoo()
的呼叫如下所示:
foo(data, eval(by))
foo(data, by)
当foo
处理这些调用时,它会substitute
为{strong>第二个正式参数(by
)尽职尽责地by
获取eval(by)
的< strong>值符号by
或by
。但是,您希望gear
的值为foo(data, gear)
,与调用do.call()
一样。
by
通过在构造然后计算的调用之前评估其第二个参数的元素来解决此问题。因此,当您传递gear
时,它会在构建一个看起来(基本上)像这样的调用之前将其计算为其值(符号foo(data, gear)
):
{{1}}
答案 1 :(得分:5)
我认为你可能会把自己捆绑在一起。这有效:
library(data.table)
foo <- function(data, by){
by <- by
data[, .N, by=by]
}
DT <- data.table(mtcars)
foo(DT, 'gear')
plotfoo <- function(data, by){
foo(data, by)
}
plotfoo(DT, 'gear')
该方法支持传入字符值:
> gg <- 'gear'
> plotfoo <- function(data, by){
+ foo(data, by)
+ }
> plotfoo(DT, gg)
gear N
1: 4 12
2: 3 15
3: 5 5