【问题标题】:R multicore ultra-high dimensional univariate analysisR多核超高维单变量分析
【发布时间】:2015-11-28 04:05:39
【问题描述】:

我有一个由 1M 协变量组成的数据框,我想在其中使用 R 独立地在数据框的特定列上回归每一个协变量,但采用多核方式。我所说的单变量分析是指二项式回归或 wilcoxon 检验。

我当前的代码是这样的

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

我想知道如何改进它以提高效率?

【问题讨论】:

    标签: r multithreading parallel-processing parallel-foreach


    【解决方案1】:

    这是一个很好的例子,说明了将问题分解为多个部分的步骤如何真正影响并行计算的好处。我遗漏了您的一些代码(例如,协变量的对数转换和缺失值的消除),这对问题不是必不可少的。我认为您希望避免在每次调用时转置整个矩阵——只需在脚本顶部执行一次即可。 AFAIK R 以列的主要顺序存储数据,因此通过处理列来避免该步骤可能已经为您节省了一些时间。

    在第一次试用中,我首先连续运行了一个版本,看看有多少改进。这是在 AMD Phenom 9850 Quad core 上,频率为 2.5 GHz,内存为 8 GB(太旧了)。

    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() 的调用。

    【讨论】:

    • 你能更新你的答案,当有阻塞因素时如何做到这一点,例如 glm(y~cc[,x] | team + week, family = "binomial") 这样的事情。我问是因为在每次迭代中,我们还需要保存“周”和“团队”信息。
    • 我不确定你所说的阻塞因子是什么意思,但如果因子团队和周在你的大数据框的列中是恒定的,只需在调用 glm() 时使用它们,比如 glm (y~cc[,x] * 团队 + 周,家庭=二项式)
    猜你喜欢
    • 2014-06-14
    • 1970-01-01
    • 2020-11-08
    • 2014-12-19
    • 2019-03-01
    • 2018-07-09
    • 1970-01-01
    • 2017-09-09
    • 1970-01-01
    相关资源
    最近更新 更多