从函数返回多个输出创建聚合输出data.table

时间:2014-08-21 11:24:43

标签: r group-by data.table aggregate

我正在努力解决我遇到的一个特定问题,并且我已经搜索了stackoverflow并找到了接近但不完全符合我想要的示例。 最接近的示例是here

这篇文章(here)也接近但我无法使用我的多输出函数来处理list()

我想要做的是创建具有按键分组的聚合值(min,max,mean,MyFunc)的表。 我还有一些复杂的函数可以返回多个输出。我可以返回单个输出但这意味着多次运行复杂功能并且需要太长时间。

使用来自this post的Matt Dowle示例进行了一些更改......

x <- data.table(a=1:3,b=1:6)[]
   a b
1: 1 1
2: 2 2
3: 3 3
4: 1 4
5: 2 5
6: 3 6

这是我想要的输出类型。聚合表(此处仅包含均值和总和)

agg.dt <- x[ , list(mean=mean(b), sum=sum(b)), by=a][]
   a mean sum
1: 1  2.5   5
2: 2  3.5   7
3: 3  4.5   9

此示例函数f返回3个输出。我的真正功能要复杂得多,而且成分也不能像这样分开。

f <- function(x) {list(length(x), min(x), max(x))}

Matt Dowle对以前帖子的建议很有效,但是没有生成和聚合表,而是将聚合添加到主表中(这在其他情况下也非常有用)

x[, c("length","min", "max"):= f(b), by=a][]
   a b length min max
1: 1 1      2   1   4
2: 2 2      2   2   5
3: 3 3      2   3   6
4: 1 4      2   1   4
5: 2 5      2   2   5
6: 3 6      2   3   6

我真正想做的事情(如果可能的话)是这样的......

agg.dt <- x[ , list(mean=mean(b)
                       , sum=sum(b)
                       , c("length","min", "max") = f(b)
), by=a]

并返回一个类似于此的聚合表...

     a mean sum length min max
1: 1  2.5   5           2   1   4
2: 2  3.5   7           2   2   5
3: 3  4.5   9           2   3   6

我真的只能看到一个解决方案,这是一个两阶段的过程,并将表合并/连接在一起?

1 个答案:

答案 0 :(得分:5)

library(data.table)
x <- data.table(a=1:3,b=1:6)
#have the function return a named list
f <- function(x) {list(length=length(x), 
                       min=min(x), 
                       max=max(x))}

# c can combine lists
# c(vector, vector, 3-list) is a 5-list
agg.dt <- x[ , c(mean=mean(b),
                 sum=sum(b),
                 f(b)), 
            by=a]

#   a mean sum length min max
#1: 1  2.5   5      2   1   4
#2: 2  3.5   7      2   2   5
#3: 3  4.5   9      2   3   6

或者,从f()删除名称,以节省为每个组创建相同名称的时间和成本:

f <- function(x) {list(length(x), 
                       min(x), 
                       max(x))}

agg.dt <- x[ , c(mean(b),
                 sum(b),
                 f(b)),
            by=a]

setnames(agg.dt, c("a", "mean","sum","length", "min", "max"))

这个后续名字和后面放置的技巧(当你有很多小组时速度)不会到达f()内部。 f()可以返回任何内容,以便data.table更难自动优化。

仅提及base::list()不再复制命名输入,如R 3.1。因此,函数f()执行一些复杂步骤然后在末尾返回list()局部变量的常见R惯用语现在应该更快。