2015-11-28 10 views
1

我有一個數據幀,由1M個協變量組成,我希望每個單獨一個數據幀在R數據幀的特定列上獨立迴歸,但採用多核方式。通過單變量分析,我是指二項迴歸或wilcoxon檢驗。R多核超高維單變量分析

我當前的代碼是這樣的

library(MASS) 
library(doParallel) 
tt=dat.at.fil 
nm.cores = detectCores() - 1 
cl=makeCluster(nm.cores) 
registerDoParallel(cl) 
x <- foreach(cnt=1:nrow(tt),.combine=cbind) %dopar% { 
whol.dat = data.frame(log10(t(tt)[,cnt]), y=factor(my.y)) 
deviance(glm(y~., data = whol.dat[-which(whol.dat[,1] == -Inf),], family = "binomial")) 
} 

library(MASS) 
library(doParallel) 
tt=dat.at.fil 
nm.cores = detectCores() - 1 
cl=makeCluster(nm.cores) 
registerDoParallel(cl) 
x <- foreach(cnt=1:nrow(tt),.combine=cbind) %dopar% { 
whol.dat = data.frame(t(tt)[,cnt], y=factor(my.y)) 
wilcoxon.test(y~., data = whol.dat)) 
    } 

我不知道如何可以改善它是更有效?

回答

2

這是如何將問題分解成碎片的一個很好的例子,它可以真正影響並行計算的好處。我遺漏了一些代碼(例如,記錄協變量的變換以及消除缺失值),這對於這個問題並不重要。我想你應該避免在每次調用時調換整個矩陣 - 只需在腳本的頂部執行一次即可。 AFAIK R按列的主要順序存儲數據,所以通過在列上工作避免這一步可能已經爲您節省了一些時間。

在第一個試驗中,我首先運行了一個版本,看看它有多少改進。這是一款2.5 GHz的AMD Phenom 9850四核處理器,擁有8 GB的RAM(如此之久)。

library(doParallel) 
library(iterators) 
#make covariate data 
N = 100 
P = 100000 # number of predictors 
tt = as.data.frame(matrix(rnorm(N*P),nrow=N,ncol=P)) 
my.y = rbinom(N,p=0.5,size=1) 
y = factor(my.y) 

# How fast to do it serially? 
system.time(x1 <- foreach(cc = iter(tt, by='col'),.combine=c) %do% { 
    deviance(glm(y~cc, family = "binomial")) 
}) # elapsed 718 s 

nm.cores = detectCores() - 1 
cl=makeCluster(nm.cores) 
registerDoParallel(cl) 

# send entire dataframe to each worker, pull out the desired column 
system.time(x2 <- foreach(cnt=1:ncol(tt),.combine=c) %dopar% { 
    whol.dat = data.frame(tt[,cnt], y=factor(my.y)) 
    deviance(glm(y~., data = whol.dat, family = "binomial")) 
}) # elapsed 276 s, so 3 x faster 

all.equal(x1,x2) # TRUE, just checkin' ... 

我首先想到的是,整個矩陣,每次發送給每個工人可能攜帶一些開銷,所以我改寫了foreach()使用iter()只是每一列發送到工人:

system.time(x3 <- foreach(cc = iter(tt, by='col'),.combine=c) %dopar% { 
    deviance(glm(y~cc, family = "binomial")) 
}) # not much faster, 248s 

這確實加快了一些,但並不多。我之前沒有使用過迭代器,所以在閱讀foreach時,我遇到了一個自定義迭代器iblkcol(),它將data.frame分解爲塊,併發送每個塊以節省數據調度和從工作人員返回的開銷。該代碼爲is hidden away on Github(見行199-218)。

## from vignette on foreach: 
## use iblkcol() instead of iter in loop to send blocks of columns instead of one at a time 
system.time(x4 <- foreach(cc = iblkcol(tt, chunks = nm.cores),.combine=c,.packages='foreach') %dopar% { 
    foreach(x = 1:col(cc),.combine=c) %do% { 
    deviance(glm(y~cc[,x], family = "binomial")) 
    } 
}) # 193 s! 

這對於逐列發送每一列是一個很大的改進。我認爲可以通過調用glm()來調用一些額外的加速,以充分利用大部分模型幀從一次調用重用到另一次調用的事實。對wilcoxon()的調用應該是一樣的。

+0

你能否更新你的回答如何在存在障礙因子的情況下做出回答,例如glm(y〜cc [,x] | team + week,family =「binomial」)。我在問,因爲在每一次迭代中,我們都需要持有「周」和「團隊」信息。 – user702846

+0

我並不完全確定阻塞因子的含義,但如果因素團隊和周在大數據框的列中保持不變,請在glm()的調用中使用它們,如glm(y〜cc [,x ] *團隊+周,家庭=二項) – atiretoo