【问题标题】:Using 'foreach' to run on all possible permutations in R使用“foreach”在 R 中所有可能的排列上运行
【发布时间】:2017-05-27 20:40:21
【问题描述】:

我无法理解如何使我的代码并行化。我的愿望是从 20 个矩阵中找到 3 个向量,它们产生与我的测量变量最接近的线性回归(这意味着总共有 1140 种不同的组合)。目前,我能够使用 3 个嵌套的 foreach 循环来返回最佳向量。但是,我的愿望是让外循环(或全部?)并行工作。任何帮助将不胜感激!

这是我的代码:

NIR= matrix(rexp(100, rate=0.01),ncol=20, nrow = 4) #Creating the matrix with 20 vectors
colnames(NIR)=c(1:20)

S.measured=c(7,9,11,13) #Measured variable

bestvectors<-matrix(data=NA,ncol = 3+1, nrow= 1) #creating a vector to save in it the best results 

###### Parallel stuff
no_cores <- detectCores() - 1
cl<-makeCluster(no_cores)
registerDoParallel(cl)

#nested foreach loop to exhaustively find the best vectors
foreach(i=1:numcols) %:% 
  foreach(j=i:numcols) %:% 
    foreach(k=j:numcols) %do% {
      if(i==j|i==k|j==k){ #To prevent same vector from being used twice 
      }
      else{
        lm<-lm(S.measured~NIR[,c(i,j,k)]-1) # package that calculates the linear regression 
        S.pred<-as.matrix(lm$fitted.values) # predicted vector to be compared with the actual measured one
        error<-sqrt(sum(((S.pred-S.measured)/S.measured)^2)) # The 'Error' which is the product of the comparison which we want to minimize 


#if the error is smaller than the last best one, it replaces it. If not nothing changes

if(error<as.numeric(bestvectors[1,3+1])|is.na(bestvectors[1,3+1])){
          bestvectors[1,]<-c(colnames(NIR)[i],colnames(NIR)[j],colnames(NIR)[k],as.numeric(error))
          bestvectors[,3+1]<-as.numeric(bestvectors[,3+1])
        }
      }
    }

【问题讨论】:

  • 枚举 1140 个组合然后并行化而不是使用多个嵌套循环可能是最简单的。 (我没有用过foreach,所以没有完整的答案。)
  • 我使用的例子是一个简单的例子。实际上,我正在寻找 150 个中最好的 5 个向量,最终得到 591,600,030 个组合。我认为列举所有的组合并不实用。
  • 也许它比 R 编程相关的更多 stats.stackexchange.com。有一些方法可以处理组合爆炸,例如逐步选择
  • 详尽的搜索变量选择对​​于这么大的集合是不切实际的。 leaps 包使向前/向后选择变得简单,或者只使用套索。阅读:Chapter 6 of the venerable ISLR.
  • 不幸的是,向前和向后选择并不一定会给我最好的结果。我知道详尽的搜索并不是最实用的方法,但我仍然有兴趣将其应用到我的研究中。 leaps 包也有详尽的计算,但我相信他们的方法和我的没有区别。我想做的是让我的外循环并行工作,这意味着在这种情况下,如果我有 20 个处理器同时工作,那么它所花费的时间将相当于 2 个for 循环而不是 3 个。知道如何这个可以吗?

标签: r foreach linear-regression parallel.foreach


【解决方案1】:

使用foreach的一般建议:

  1. 如果您希望代码在多个内核上运行,请使用 foreach(i=1:numcols) %dopar% { ... }%do% 装饰器不能完美地模拟并行性,但在单核上运行。

  2. %dopar% 生成的进程在循环运行时无法相互通信。因此,设置您的代码以输出 R 对象,例如 data.framevector,然后进行比较。在您的情况下,if(error&lt;as.numeric ... 行中的逻辑应该在您的主 foreach 循环之后按顺序(而不是并行)执行。

  3. 嵌套%dopar% 循环的行为在操作系统之间不一致,并且在其跨内核生成进程的方式上也不清楚。为获得最佳性能和可移植性,请在最外层循环中使用单个 foreach 循环,然后在其中使用普通的 for 循环。

【讨论】:

  • 谢谢!最后,我能够创建 3 个嵌套的foreach 循环,其中两个内部循环使用%do% 装饰器,外部使用%dopar%。现在我的问题是逻辑语句if(error&lt;as.numeric ...。我不想对我的 data.frame 进行排序,尤其是在其中有 6 亿个对象的情况下。我尝试编写一个.combine 函数,如下所示:mycomb &lt;- function(x,y) if(x$error&lt;y$error) x else y 但它只适用于外部foreach 循环,它没有给我预期的结果。
  • 如果你的内部循环使用for(...){...}而不是foreach(...)%do%{...},你会更好地使用“.combine=”参数。
  • 此外,您可能希望以相同的方式并行化查找最小错误的过程。如果您的机构可以访问分布式计算,请查看在集群上自动并行化应用样式函数的 R 分布。
  • 现在似乎可以工作了。我最终使用了 3 个foreach 循环,其中外部使用%dopar%,两个内部使用%do%。至于排序,我会在data.frame产生后尝试排序,然后选择最小错误。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2018-10-21
  • 1970-01-01
  • 2018-10-28
  • 1970-01-01
  • 1970-01-01
  • 2017-10-04
  • 2017-03-03
  • 2016-09-09
相关资源
最近更新 更多