19

该包data.table有一些特殊的语法,需要使用表达式作为iandj参数。

这对于如何编写接受参数并将参数传递给数据表的函数有一些影响,正如常见问题解答的第 1.16 节中所解释的那样。

但我不知道如何提高这一水平。

这是一个例子。假设我想编写一个包装器函数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的函数的函数?

4

2 回答 2

14

这将起作用:

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()in的调用plotfoo()类似于以下内容之一:

foo(data, eval(by))
foo(data, by)

foo处理这些调用时,它会尽职地substitute第二个形式参数( by) 获取符号或by。但是你希望' 值是,如在电话中。eval(by)bybygearfoo(data, gear)

do.call()通过在构造它然后评估的调用之前评估其第二个参数的元素来解决这个问题。结果,当您传递它时,它会在构造看起来(基本上)如下所示的调用之前by将其评估为它的值(符号):gear

foo(data, gear)
于 2013-02-12T18:00:15.070 回答
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
于 2013-02-12T17:44:39.287 回答