2013-01-31 28 views
3

我有一個data.frames的列表。在每個data.frame中,我想通過分組(z)運行一個函數,將結果放回到一起,然後將嵌套的lapply的所有結果放在一起放入一個data.frame中,然後將結果列表展平data.frame s變成一個data.frame嵌套樂譜表現,如何優化?

library(plyr) 
df <- data.frame(x = sample(1:200, 30000, replace = TRUE), 
       y = sample(1:200, 30000, replace = TRUE), 
       z = sample(LETTERS, 30000, replace = TRUE)) 

alist <- list(df,df,df) # longer in real life 
answer <- lapply(alist, function(q) { 
    a <- split(q,q$z) 
    result.1 <- lapply(a, function(w) { 
     neww <- cbind(w[,1],w[,2]) 
     result.2 <- colSums(neww) 
    }) 
    ldply(result.1) 
}) 
# cor(neww) can actually be a variey of foos I just use cor() for easy reproducibility 
ldply(answer) 

這有一些非常艱難的內存使用,也很慢。由於@Andrie我知道如何清除我的工作區之前,我開始喜歡:

rm(list=setdiff(ls(), "alist")) 

但有修改我的做法就像在第二lapply等廢棄,另外添購w儘量減少內存使用和速度的東西了呢?在這種情況下foo喜歡矩陣,所以data.table不會是我的答案。在其他foo的I將所有需要w和類將需要一個data.frame

+0

請讓您的代碼具有可重複性。你需要顯示'foo'。 – Roland

+2

一種策略可能是將所有'data.frame's合併爲一個'data.table',然後將其拆分應用合併。 – Roland

+0

我使用了許多'foo'作爲參數,你可以使它成爲'cor'。我關注的是'foo'的代碼,但也許我錯過了這一點。 – user1320502

回答

9

試試像這樣:

ldply(alist, ddply, "z", summarize, xy.foo = foo(x, y)) 

如果你想xy在您的最終data.frame展現出來,替換summarizetransform。另外,查看foo的用法,您可能需要用cbind(x, y)替換(x, y)

此外,我會建議你剖析你的代碼。最後,foo可能會降低你的速度,而不是分割/合併部分。

+0

+1謝謝@ flodel這看起來顯得不那麼冗長和吸引人,並且似乎保存在'ldply's上,但我想我應該在思考速度時自然地擺脫'ddply'。在這裏節省內存的一部分不太明確的對象創建?如果你想添加任何簡短的解釋,我會很高興。肯定'foo'是可怕的瓶頸,但很難改變。因此,周圍的'富'方法是我的焦點。 – user1320502

+0

@ user1320502如果'foo'是真正的瓶頸,那麼並行化可能是一條可行的路。 – Roland

+0

如果要實現並行化,「plyr」確實具有內置的能力。請參閱'.parallel'參數和相關參數。 –

6

你爲什麼不使用來自plyrddplyllply但只有ldply

# Note: @Flodel has a very nice, simple one-line plyr solution 
# Please use that. 
out <- ldply(alist, function(q) { 
    ddply(q, .(z), function(w) { 
     neww <- w[, -3] 
     result.2 <- colSums(neww) # dummy function 
    }) 
}) 

第一ldply經過一個列表alist一個的元素。因此,每個時間q因此包含在list的每個元素中的data.frame。然後,在這裏,我們想分割z。由於輸入是qdata.frame並且輸出也應該是data.frame我們使用ddply而第二個參數.(z)分裂爲z。在這裏,你做你的計算,返回任何你想要的(在這種情況下爲colSums)。 ldply返回爲data.frame

Data.table方案:一種替代快速的解決辦法是使用該組合data.frame一個data.table可以實現如下(什麼@Roland在他的評論中提到一樣):

require(data.table) 
# for creating a group 
group <- vapply(alist, nrow, integer(1)) 
dt <- data.table(do.call(rbind, alist)) 
# create group 
dt[ , grp := rep(1:3, group)] 
setkey(dt, "grp", "z") 
# call your function (here column means) 
dt[, lapply(.SD, mean), by="grp,z"] 
# or if its correlation 
dt[, list(cor_x_y = cor(x,y)), by="grp,z"] 
+3

不是'ldply(llply(...))'和ldply(...)'一樣,所以你可以保存不必要的處理? – flodel

+0

另外,你不需要定義一個'function(q)ddply(q,...)'函數,就像我一樣,直接使用'ddply'。 – flodel

+0

你在兩種情況下都是對的。第一個,我以這種方式使用它,因爲我觀察到這比使用'ldply'快,但也許它是一個錯誤的預感(我會測試它)。第二條評論,非常真實,沒有必要按照我的方式去做!感謝指針。 – Arun