2011-03-09 68 views
7

我有一個200萬行,15列的數據框。我想用ddply對這3列進行分組(所有3個因子,並且有780,000個這些因子的獨特組合),並獲得3列的加權平均值(權重由我的數據集定義)。以下是相當快:如何加速彙總和ddply?

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平均值來計算我的集合列。

如果我嘗試了相同的數據幀(注意,我投給不變),下列情況不20分鐘後完成上ddply如下:

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餓,但不是非常內存密集。

編輯: 所以我最終寫了這個小函數,它通過利用加權平均的一些性質來「欺騙」一些,並對整個對象而不是片上進行乘法和除法。

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") 

我獲得很好的性能,而且有些可重用的,優雅的代碼。

+3

在[這個問題]中有堆和plyr優化技巧堆(http://stackoverflow.com/questions/3685492/r-speeding-up-group-by-operations)。另外,不要忘記,您可以通過將'ddply'連接到'foreach'軟件包來並行運行。 – 2011-03-09 19:16:58

+0

已經看到了 - 嘗試了我喜歡的技巧,而不是我沒有的技巧。相反,我使用上面的使用base R的編輯,保持相當的靈活性,並且很快執行(仍然不到2分鐘)。仍然會喜歡解釋爲什麼ddply的速度很慢 - 喜歡語法和並行性特性! – evanrsparks 2011-03-09 20:54:23

+4

'ddply'太慢了,因爲它可以處理數據幀,不幸的是它很慢。更快的方法直接處理矢量,速度要快得多 – hadley 2011-03-10 14:01:35

回答

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 
+0

如果您對此答案投了贊成票,請務必對[馬立克的答案](http://stackoverflow.com/questions/3685492/r-speeding-up-group-by-operations/3686241#3686241)進行投票表決。 .. – 2011-03-09 21:57:02

+0

這很好,很高效,謝謝!我真正的目的是想知道在ddply中操作如此緩慢的原因,但我想我可以做一些分析並找出原因。 – evanrsparks 2011-03-09 22:41:22

5

雖然ddply很難打敗優雅和易用的代碼,但我發現對於大數據,tapply要快得多。在你的情況下,我會用一個

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

對不起,並可能錯誤的理解問題;但我有點匆忙,必須在大約五分鐘內趕上巴士!