【问题标题】:foreach and non-parallel change of iterators迭代器的 foreach 和非并行更改
【发布时间】:2013-08-06 12:45:37
【问题描述】:

我需要使用两个相同大小的迭代变量(例如 1:n)执行 foreach,但函数会更改它们平行写作here

我们称 a 和 b 为迭代变量,因为它们是在多次执行期间不断变化的变量。请注意,我们是在并行迭代它们,也就是说,它们都在同时发生变化。

我需要让 foreach 独立更改它们,这样我就有一个长度为 n^2 的列表,而不是 n

示例:

X = foreach(i=1:n, j=1:n) %do% (sum(M[i,]*M[j,]))

最后我得到一个长度为 n 的向量,它只是矩阵 X 的对角线,而不是完整矩阵。

附:我试图通过 for 循环来实现这一点,但计算时间太长,无法让代码处于未优化状态。

【问题讨论】:

标签: r foreach parallel-processing iteration


【解决方案1】:

要嵌套foreach 循环,请使用嵌套运算符“%:%”:

library(foreach)
n <- 4
M <- matrix(rnorm(n*n), n)
X <- foreach(i=1:n, .combine='cbind') %:%
       foreach(j=1:n, .combine='c') %do% {
         sum(M[i,]*M[j,])
       }

为避免重复计算,您可以让ji 迭代到n,并使用.final 函数用NA 填充结果向量:

pad <- function(x) c(rep(NA, n - length(x)), x)
Y <- foreach(i=1:n, .combine='cbind') %:%
       foreach(j=i:n, .combine='c', .final=pad) %do% {
         sum(M[i,]*M[j,])
       }

但这些解决方案仅具有学术意义。为了简单和速度,我怀疑tcrossprod 是迄今为止最好的解决方案:

Z <- tcrossprod(M)

对于 4000 X 4000 矩阵,这在我的 Linux 机器上执行不到 8 秒。

【讨论】:

  • +1 令人惊讶的是,有时想出明显的解决方案是多么困难。但是,combn 解决方案可以用于其他功能。
  • @Roland 同意。看到你的例子,我会记住combn
【解决方案2】:

foreach 的效率并不比for 高。查找@BenBarnes 评论的%:% 运算符以使用它。并行化可能会有所帮助,但作用不大。

尝试以下方法而不是显式循环:

M <- matrix(1:8,4)

prodsums <- combn(seq_len(nrow(M)), 2, FUN=function(ind) {
  res <- sum(M[ind[1],]*M[ind[2],])
  names(res) <- paste(ind, collapse="*")
  res
}, simplify=F)

unlist(prodsums)
#1*2 1*3 1*4 2*3 2*4 3*4 
# 32  38  44  48  56  68 

resmat <- matrix(ncol=nrow(M),nrow=nrow(M))
resmat[lower.tri(resmat)] <- unlist(prodsums)
#       [,1] [,2] [,3] [,4]
# [1,]   NA   NA   NA   NA
# [2,]   32   NA   NA   NA
# [3,]   38   48   NA   NA
# [4,]   44   56   68   NA

resmat[upper.tri(resmat)] <- t(resmat)[upper.tri(resmat)]

diag(resmat) <- rowSums(M^2)
#     [,1] [,2] [,3] [,4]
#[1,]   26   32   38   44
#[2,]   32   40   48   56
#[3,]   38   48   58   68
#[4,]   44   56   68   80

【讨论】:

  • 非常感谢,计算时间减少了 50 倍!最后一个问题 - 如何在您的示例中填充 resmat 的上三角,使其与下三角对称?
  • @Seva 查看我的编辑。尽管如果您的矩阵很大,使用稀疏矩阵可能会更好,因为这是冗余信息。顺便说一句,如果你省略names(res) &lt;- paste(ind, collapse="*"),它可能会快一点。
猜你喜欢
  • 2015-08-27
  • 2010-11-07
  • 1970-01-01
  • 2014-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多