如何编写一个调用调用data.table的函数的函数?

And*_*rie 18 r data.table

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

这对于一个接受并将参数传递给数据表的写函数有一些影响,正如常见问题解答第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)
Run Code Online (Sandbox Code Playgroud)

好的,这是有效的,因为我得到了我的表格结果:

   by  N
1:  4 12
2:  3 15
3:  5  5
Run Code Online (Sandbox Code Playgroud)

现在,我在写作的时候尝试的plotfoo()却是一样但是我悲惨地失败了:

plotfoo <- function(data, by){
  by <- substitute(by)
  foo(data, eval(by))
}
plotfoo(DT, gear)
Run Code Online (Sandbox Code Playgroud)

但这次我收到一条错误消息:

Error: evaluation nested too deeply: infinite recursion / options(expressions=)?
Run Code Online (Sandbox Code Playgroud)

好的,所以eval()导致了问题.我们将其删除:

plotfoo <- function(data, by){
  by <- substitute(by)
  foo(data, by)
}
plotfoo(DT, gear)
Run Code Online (Sandbox Code Playgroud)

哦不,我收到一条新的错误信息:

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))]
Run Code Online (Sandbox Code Playgroud)

这就是我一直困在的地方.

问题:如何编写一个调用调用data.table的函数的函数?

Jos*_*ien 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
Run Code Online (Sandbox Code Playgroud)

说明:

问题是您对foo()in 的调用plotfoo()看起来像下列之一:

foo(data, eval(by))
foo(data, by)
Run Code Online (Sandbox Code Playgroud)

foo处理这些呼叫,它忠实地substituteS对于所述第二形式参数(by)得到尽可能by价值中的符号eval(by)by.但是你想要by的价值gear就像在电话中一样foo(data, gear).

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

foo(data, gear)
Run Code Online (Sandbox Code Playgroud)


42-*_*42- 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')
Run Code Online (Sandbox Code Playgroud)

并且该方法支持传入字符值:

> gg <- 'gear'
> plotfoo <- function(data, by){
+   foo(data, by)
+ }
> plotfoo(DT, gg)
   gear  N
1:    4 12
2:    3 15
3:    5  5
Run Code Online (Sandbox Code Playgroud)