【问题标题】:Create aggregate output data.table from function returning multiple output从返回多个输出的函数创建聚合输出 data.table
【发布时间】:2014-10-15 00:22:05
【问题描述】:

我正在努力解决我遇到的一个特定问题,我搜索了 stackoverflow 并找到了一些接近但不是我想要的示例。 最接近的例子是here

这篇帖子(here) 也很接近,但我无法让我的多输出函数与 list() 一起使用

我想要做的是创建表,其中包含按键分组的聚合值(最小值、最大值、平均值、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

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

【问题讨论】:

  • 为什么到处都加[]。这是不必要的。另外,你试过agg.dt &lt;- x[, f(b), by=a] ; setnames(agg.dt, names(agg.dt), c("a","length","min", "max"))吗?或者你可以修改你的函数然后简单地运行它f &lt;- function(x) {list(length = length(x), min = min(x), max = max(x))}; agg.dt &lt;- x[, f(b), by=a]
  • 感谢您的建议。尾随的 [] 是从上一篇文章中复制的,您是正确的,在我的代码示例中它们是不必要的。但是,它们在赋值语句中很有用,例如这里的 x[,c("mean","sum"):=list(mean(b),sum(b)),by=a][],因为赋值会默默地更新 data.table。添加尾随方括号只是强制 data.table 将输出打印到控制台。
  • @KAE 你应该使用print。这是更好的代码风格,甚至可能更高效。

标签: r group-by data.table aggregate


【解决方案1】:
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"))

这个drop-names-and-put-them-back-afterwards 技巧(当你有很多组时为了提高速度)不会到达f() 内部。 f() 可以返回任何东西,因此 data.table 很难自动优化。

顺便提一下,base::list() 不再复制命名输入,从 R 3.1 开始。因此,函数f() 执行一些复杂步骤然后在最后返回局部变量的list() 的常见 R 习惯用法现在应该更快了。

【讨论】:

  • 感谢@MattDowle 的意见。
猜你喜欢
  • 2019-02-07
  • 1970-01-01
  • 2021-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-28
  • 1970-01-01
相关资源
最近更新 更多