如何将fun.aggregate作为参数传递给dcast.data.table?

时间:2014-07-03 00:03:38

标签: r data.table

TL; DR:当fun.aggregate的调用是在一个函数内完成的dcast.data.table时,如何将dcast.data.table传递给fun.aggregate

我有一张这样的表:

library(data.table)
t <- data.table(id=rep(1:2, c(3,4)), k=c(rep(letters[1:3], 2), 'c'), v=1:7)
t
   id k v
1:  1 a 1
2:  1 b 2
3:  1 c 3
4:  2 a 4
5:  2 b 5
6:  2 c 6
7:  2 c 7  # note the duplicate (2, c)

我重塑为长格式,保留重复的最后一次出现

dcast.data.table(t, id ~ k, value.var='v', fun.aggregate=last) # last is in data.table
   id a b c
1:  1 1 2 3
2:  2 4 5 7

但是,如果我将dcast.data.table调用包装到函数中:

f <- function (tbl, fun.aggregate) {
    dcast.data.table(tbl, id ~ k, value.var='v', fun.aggregate=fun.aggregate)
}
f(t, last)
Error in `[.data.table`(data, , eval(fun.aggregate), by = c(ff_)) : 
  could not find function "fun.aggregate"

看起来符号fun.aggregate正在被评估(eval(fun.aggregate))而未找到(因为函数“fun.aggregate”不存在)。

我应该如何将我想要的fun.aggregate传递给f

(我确定它与quotesubstitute等有关,但我对这些功能非常困难,我通常只是将它们链接在一起,直到有效的方式。)


编辑:

> sessionInfo()
R version 3.1.0 (2014-04-10)
Platform: x86_64-pc-linux-gnu (64-bit)

...

other attached packages:
[1] data.table_1.9.3
哎呀,我刚刚意识到这个bug出现在1.9.3(开发版,我升级为避免无关的bug)和1.9.2(当前CRAN发行版)中的

我宁愿不降级到1.9.2(前面提到的我要避免的错误),所以通常有一种方法可以保护eval()调用函数的参数吗?

1 个答案:

答案 0 :(得分:4)

现在已在commit 1303 v 1.9.3中修复此问题 - 当前的开发版本。来自NEWS

  当从接受dcast.data.table参数的函数中调用并传递给fun.aggregate时,

fun.aggregate正确处理dcast.data.table()参数。关闭#713。感谢mathematicalcoffee在SO上报告here


请注意dcast.data.table中的另一个小疏忽现在已修复 - #715

问题是last函数不会为所有输入值生成长度为1的值 - 这是fun.aggregate的要求。

last(integer(0))
# [1] integer(0)

如果未设置fill参数,则此值是用于填充缺失组合的值。此案件之前没有被发现,但现在已经修复。

以下是(正确)行为的示例:

tt <- t[1:5] # t is from your example
dcast.data.table(tt, id ~ k, fun.aggregate=last)
# Error in dcast.data.table(tt, id ~ k, fun.aggregate = last) : 
#   Aggregating function provided to argument 'fun.aggregate' should always return 
#   a length 1 vector, but returns 0-length value for fun.aggregate(integer(0)). 
#   This value will have to be used to fill missing combinations, if any, and 
#   therefore can not be of length 0. Either override by setting the 'fill' argument 
#   explicitly or modify your function to handle this case appropriately.

dcast.data.table(tt, id ~ k, fun.aggregate=last, fill=NA)
#    id a b  c
# 1:  1 1 2  3
# 2:  2 4 5 NA