使用%dopar%和自定义函数

时间:2014-10-18 21:24:11

标签: r foreach parallel-processing

所以我有这个功能,用于将来自多个探针的测量值分组到属于定义的区域。

HMkit.dmr<-function(Mat,Classes,method.fdr=c("BH","bonferroni"),probe.features) {

   #Annotate first...
   require(plyr)
   require(dplyr)


   #Filter matrix for testing and stuff...

   message("Setting up merged table")
   Mat2<-Mat[match(probe.features$probe,rownames(Mat)),]

   #Split by classes

   if(!is.factor(Classes)) {
       Classes<-as.factor(Classes)
   }
   Class.1<-levels(Classes)[[1]]
   Class.2<-levels(Classes)[[2]]

   C1.Mat<-Mat2[,Classes==Class.1]
   C2.Mat<-Mat2[,Classes==Class.2]

   #Summarise and run wilcoxon's test for each dmr...
   num.regions<-length(unique(as.character(probe.features$region.id)))
   pvals.vec<-numeric(length=num.regions)
   unique.regions<-unique(as.character(probe.features$region.id))
   message(num.regions)
   Meds.1<-numeric(length=num.regions);Meds.2<-numeric(length=num.regions)

   for (i in 1:num.regions) {
       region<-probe.features%>%filter(region.id %in% unique.regions[[i]])
       Set1.Mat<-as.numeric(C1.Mat[rownames(C1.Mat) %in% region$probe,])
       Set2.Mat<-as.numeric(C2.Mat[rownames(C2.Mat) %in% region$probe,])
       pvals.vec[[i]]<-wilcox.test(Set1.Mat,Set2.Mat)$p.value
       Meds.1[[i]]<-median(Set1.Mat)
       Meds.2[[i]]<-median(Set2.Mat)
       message(i)
   }

    #Output frame
    dmrs.frame<-data.frame(region=unique.regions,pval=pvals.vec,G1=Meds.1,G2=Meds.2,dB=Meds.1-Meds.2)
    dmrs.frame$q.val<-p.adjust(dmrs.frame$pval,method=method.fdr)
    groups.ids<-levels(Classes)
    return(list(dmrs=dmrs.frame,groups=groups.ids))
}

代码基本上通过样本将矩阵分​​成两组,然后拉入定义为在区域中的所有探测器的值,调用wilcox.test和中值汇总步骤并使用它来填充预先创建的向量。

我试图在foreach包中使用doparallel函数替换for循环中的for,但是却无法使用正确的结果填充向量。我想知道如何正确使用上述函数的并行化 - 通过修改for循环,或者通过修改函数调用,以便将区域分解为并行处理的块。

示例对象如下所示......

Mat<-matrix(runif(200,0,1), ncol=10,nrow=20)
rownames(Mat)<-paste0("p",1:20)
colnames(Mat)<-paste0("S",1:10)

Classes<-as.character(c(rep("G1",6),rep("G2",4)))
probe.features<-data.frame(probe=paste0("p",1:20),region.id=c(rep("R1",5),rep("R2",3),rep("R3",4),rep("R5",4),rep("R6",4))

并使用

运行该功能
x<-HMkit.dmr(Mat,Classes,method.fdr=c("BH"),probe.features=probe.features)

实际上,我正在寻找30,000个区域,并希望在Windows上跨多个核心并行化功能,因为串行执行最多可能需要40分钟。我该怎么做呢?

附录 - 我试图用

做到这一点
 library(doParallel)
 ncores<-2
 Cl<-makeCluster(2)
 registerDoParallel(Cl)
x<-foreach(i=1:length(unique(probe.features$region.id)),packages=c("plyr","dplyr"))%dopar%HMkit.dmr(Mat,Classes,probe.features=probe.features,method.fdr="BH")

然而,这样做只返回了与串行函数相同结果的两个副本,我想要它做的是将probe.features $ region.id中的区域分解为转到不同内核的块。

1 个答案:

答案 0 :(得分:0)

在我看来,你的&#34; for&#34;循环可以很容易地并行化。它只是构建了三个向量,每次迭代一个元素,其中每个向量将成为&#34; dmrs.frame&#34;的列。因此,每次迭代都会计算结果的一行。

要使用&#34; foreach&#34;,您可以简单地将这三个值连接到一个向量中。 .combine选项用于将所有这些向量组合成一个矩阵,其中包含&#34; rbind&#34;:

m <- foreach(uregion=unique.regions, .combine='rbind',
             .packages=c('plyr', 'dplyr')) %dopar% {
    region<-probe.features%>%filter(region.id %in% uregion)
    Set1.Mat<-as.numeric(C1.Mat[rownames(C1.Mat) %in% region$probe,])
    Set2.Mat<-as.numeric(C2.Mat[rownames(C2.Mat) %in% region$probe,])
    c(wilcox.test(Set1.Mat, Set2.Mat)$p.value,
      median(Set1.Mat), median(Set2.Mat))
}

我摆脱了&#34;我&#34;变量,因为我认为简单地迭代&#34; unique.regions&#34;的元素更具可读性。

现在你可以创建&#34; dmrs.frame&#34;使用矩阵的列&#34; m&#34;:

dmrs.frame <- data.frame(region=unique.regions,
        pval=m[,1] G1=m[,2] G2=m[,3], dB=m[,2]-m[,3])