【问题标题】:How to speed up summarise and ddply?如何加快汇总和ddply?
【发布时间】:2011-03-09 18:57:06
【问题描述】:

我有一个包含 200 万行和 15 列的数据框。我想用 ddply 对这些列中的 3 个进行分组(所有 3 个都是因子,并且这些因子有 780,000 个唯一组合),并获得 3 个列的加权平均值(权重由我的数据集定义)。以下是相当快的:

system.time(a2 <- aggregate(cbind(col1,col2,col3) ~ fac1 + fac2 + fac3, data=aggdf, FUN=mean))
   user  system elapsed 
 91.358   4.747 115.727 

问题是我想使用 weighted.mean 而不是 mean 来计算我的聚合列。

如果我在同一个数据帧上尝试以下 ddply(注意,我转换为不可变),则以下内容在 20 分钟后不会完成:

x <- ddply(idata.frame(aggdf), 
       c("fac1","fac2","fac3"), 
       summarise, 
       w=sum(w), 
       col1=weighted.mean(col1, w), 
       col2=weighted.mean(col2, w),
       col3=weighted.mean(col3, w))

此操作似乎占用大量 CPU,但并不占用大量 RAM。

编辑: 所以我最终写了这个小函数,它通过利用加权平均值的一些属性来“作弊”,并对整个对象而不是切片进行乘法和除法。

weighted_mean_cols <- function(df, bycols, aggcols, weightcol) {
    df[,aggcols] <- df[,aggcols]*df[,weightcol]
    df <- aggregate(df[,c(weightcol, aggcols)], by=as.list(df[,bycols]), sum)
    df[,aggcols] <- df[,aggcols]/df[,weightcol]
    df
}

当我运行时:

a2 <- weighted_mean_cols(aggdf, c("fac1","fac2","fac3"), c("col1","col2","col3"),"w")

我获得了良好的性能,以及一些可重用的优雅代码。

【问题讨论】:

  • this question 中有一大堆 plyr 优化技巧。另外,不要忘记您可以通过将ddply 链接到foreach 包来并行运行它。
  • 已经看到了 - 尝试了我喜欢的技巧,而不是我不喜欢的技巧。相反,我使用了上面的编辑,它使用了基础 R,保持相当灵活,并且执行速度很快(仍然不到 2 分钟)。仍然希望解释为什么这在 ddply 中很慢 - 喜欢语法和并行功能!
  • ddply 太慢了,因为它适用于数据帧,不幸的是,数据帧相当慢。更快的方法直接使用向量,这要快得多
  • 感谢哈德利的解释。

标签: r plyr


【解决方案1】:

虽然ddply 在代码的优雅性和易用性方面很难被击败,但我发现对于大数据,tapply 的速度要快得多。在你的情况下,我会使用

do.call("cbind", list((w <- tapply(..)), tapply(..)))

对于问题的点和可能有错误的理解,我们深表歉意;但我有点赶时间,必须在五分钟内赶上公共汽车!

【讨论】:

    【解决方案2】:

    如果您要使用您的编辑,为什么不使用rowsum 并节省几分钟的执行时间?

    nr <- 2e6
    nc <- 3
    aggdf <- data.frame(matrix(rnorm(nr*nc),nr,nc),
                        matrix(sample(100,nr*nc,TRUE),nr,nc), rnorm(nr))
    colnames(aggdf) <- c("col1","col2","col3","fac1","fac2","fac3","w")
    
    system.time({
    aggsums <- rowsum(data.frame(aggdf[,c("col1","col2","col3")]*aggdf$w,w=aggdf$w), 
      interaction(aggdf[,c("fac1","fac2","fac3")]))
    agg_wtd_mean <- aggsums[,1:3]/aggsums[,4]
    })
    #   user  system elapsed 
    #  16.21    0.77   16.99 
    

    【讨论】:

    • 如果您对此答案投赞成票,请务必也对Marek's answer 投赞成票...
    • 这很好,很高效,谢谢!我的真正目的是了解导致该操作在 ddply 中如此缓慢的原因,但我想我可以进行一些分析并找出原因。
    猜你喜欢
    • 1970-01-01
    • 2011-12-05
    • 1970-01-01
    • 1970-01-01
    • 2013-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多