r - 使用 foreach 函数和 doParallel 库在 R 中嵌套 for 循环

标签 r parallel-processing parallel-foreach

我正在尝试计算矩阵中列之间的余弦相似度。我能够使用标准 for 循环让它工作,但是当我尝试让它并行运行以使代码运行得更快时,它并没有给我相同的答案。问题是我无法使用 foreach 循环方法得到相同的答案。我怀疑我没有使用正确的语法,因为我有单个 foreach 循环工作。我尝试使第二个循环成为常规 for 循环,并在 foreach 循环中使用了 %:% 参数,但该函数甚至没有运行。

请参阅下面我附加的代码。预先感谢您的帮助。

## Function that calculates cosine similarity using paralel functions.

#for calculating parallel processing
library(doParallel)

## Set up cluster on 8 cores

cl = makeCluster(8)

registerDoParallel(cl)

#create an example data
x=array(data=sample(1000*100), dim=c(1000, 100))

## Cosine similarity function using sequential for loops

cosine_seq =function (x) {

  co = array(0, c(ncol(x), ncol(x)))

  for (i in 2:ncol(x)) {
    for (j in 1:(i - 1)) {

      co[i, j] = crossprod(x[, i], x[, j])/sqrt(crossprod(x[, i]) * crossprod(x[, j]))
    }
  }

  co = co + t(co)

  diag(co) = 1

  return(as.matrix(co))

}

## Cosine similarity function using parallel for loops

cosine_par =function (x) {

  co = array(0, c(ncol(x), ncol(x)))

  foreach (i=2:ncol(x)) %dopar% {

    for (j in 1:(i - 1)) {

      co[i, j] = crossprod(x[, i], x[, j])/sqrt(crossprod(x[, i]) * crossprod(x[, j]))
    }
  }

  co = co + t(co)

  diag(co) = 1

  return(as.matrix(co))

}

## Calculate cosine similarity

tm_seq=system.time(
{

  x_cosine_seq=cosine_seq(x)

})

tm_par=system.time(
{

  x_cosine_par=cosine_par(x)

})

## Test equality of cosine similarity functions

all.equal(x_cosine_seq, x_cosine_par)

#stop cluster
stopCluster(cl)

最佳答案

嵌套循环的正确并行化使用 %:% (阅读 here )。

library(foreach)
library(doParallel)
registerDoParallel(detectCores())    
cosine_par1 <- function (x) {  
  co <- foreach(i=1:ncol(x)) %:%
    foreach (j=1:ncol(x)) %dopar% {    
      co = crossprod(x[, i], x[, j])/sqrt(crossprod(x[, i]) * crossprod(x[, j]))
    }
  matrix(unlist(co), ncol=ncol(x))
}

我建议您在 Rcpp 中编写它,而不是并行运行它,因为 foreach(i=2:n, .combine=cbind) 并不总是以正确的顺序绑定(bind)列。另外,在上面的代码中,我只删除了下三角条件,但运行时间比未并行的代码时间要慢得多。

set.seed(186)
x=array(data=sample(1000*100), dim=c(1000, 100))
cseq <- cosine_seq(x)
cpar <- cosine_par1(x)
 all.equal(cpar, cseq)
#[1] TRUE
head(cpar[,1])
#[1] 1.0000000 0.7537411 0.7420011 0.7496145 0.7551984 0.7602620
head(cseq[,1])
#[1] 1.0000000 0.7537411 0.7420011 0.7496145 0.7551984 0.7602620

附录:对于这个特定问题,cosine_seq 的(半)矢量化是可能的; cosine_veccosine_seq 快约 40-50 倍。

cosine_vec <- function(x){
  crossprod(x) / sqrt(tcrossprod(apply(x, 2, crossprod)))
}
all.equal(cosine_vec(x), cosine_seq(x))
#[1] TRUE
library(microbenchmark)
microbenchmark(cosine_vec(x), cosine_seq(x), times=20L, unit="relative")
#Unit: relative
#          expr      min       lq     mean   median       uq      max neval
# cosine_vec(x)  1.00000  1.00000  1.00000  1.00000  1.00000  1.00000    20
# cosine_seq(x) 55.81694 52.80404 50.36549 52.17623 49.56412 42.94437    20

关于r - 使用 foreach 函数和 doParallel 库在 R 中嵌套 for 循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28029445/

相关文章:

r - R中的分离直方图

r - 加载多个包含逗号或句点作为小数点的 `csv` 文件

multithreading - Julia - 读取大文件的并行性

r - 将列并行分配给 data.table

R并行: rbind parallely into separate data.帧

r - 错误的dim(data)<-dim : invalid first argument

r - ggplot2 和 Shiny 的 : how to scale the size of legend with figure size?

Python 并行执行 - threading.Lock 未按预期工作

perl - 如何并行运行 perl 脚本并捕获文件中的输出?

C# Parallel.ForEach 和 Task.WhenAll 有时返回的值比假设的要少