使用R中的多个核和稀疏矩阵

时间:2014-06-03 09:23:17

标签: r parallel-processing snow parallel-foreach

我正在开发一个需要大量矩阵的大型矩阵的项目。不幸的是,由于这些矩阵中的一些可能具有超过1e10个元素,因此使用"标准"由于RAM限制,R矩阵不是一种选择。此外,我需要处理多个核心,因为计算可能需要很长时间,而且真的不应该。

到目前为止,我一直在使用foreach包,然后将结果(标准矩阵中的结果)转换为稀疏矩阵。我不能帮助,但认为必须有一个更聪明的方法。

以下是我迄今为止所做的最简单的例子:

cl <- makeSOCKcluster(8)
registerDoSNOW(cl)

Mat <- foreach(j=1:length(lambda), .combine='cbind') %dopar% { 
  replicate(iter, rpois(n=1, lambda[j]))
}
Mat <- Matrix(Mat, sparse=TRUE)
stopCluster(cl)

lambda都非常小,因此只有每5个元素左右不同,因此将结果存储在稀疏矩阵中是明智的。

不幸的是,现在有必要将迭代次数从1e6增加到至少1e7,这样foreach循环产生的矩阵太大而无法存储在8GB的RAM上。我现在想要做的是将任务分成每个都有1e6次迭代的步骤,并将它们组合成一个稀疏的矩阵。

我现在有以下想法:

library(Matrix)
library(snow)

cl <- makeSOCKcluster(8)

iter <- 1e6

steps <- 1e5
numsteps <- iter / steps

draws <- function(x, lambda, steps){
  replicate(n=steps, rpois(n=1, lambda=lambda))
}

for(i in 1:numsteps){
  Mat <- Matrix(0, nrow=steps, ncol=96, sparse=TRUE)

  Mat <- Matrix(
    parApply(cl=cl, X=Mat, MARGIN=2, FUN=draws, lambda=0.2, steps=steps)
    , sparse = TRUE)

  if(!exists("fullmat")) fullmat <- Mat else fullmat <- rBind(fullmat, Mat)

  rm(Mat)   
}

stopCluster(cl)

它运行正常,但我必须将lambda修复为某个值。对于我的应用程序,我需要第i行中的值来自泊松分布,其均值等于lambda向量的第i个元素。这在foreach循环中显然工作正常。但是我还没有找到一种方法使它在apply循环中工作。

我的问题是:

  1. 是否可以使用应用功能&#34;知道&#34;在哪一行上运行并将相应的参数传递给函数?
  2. 有没有办法处理foreach和稀疏矩阵而无需创建标准矩阵并在下一步将其转换为稀疏矩阵?
  3. 如果没有上述内容,是否有办法让我手动将任务分配给R的从属进程 - 也就是说,我是否可以专门告诉进程在第1列上工作,另一个在第2列上工作,依此类推,每个都创建一个稀疏向量,并且只在最后一步中组合它们。

1 个答案:

答案 0 :(得分:1)

我能够找到解决问题的方法。

就我而言,我能够为每个列定义一个唯一的ID,并可以通过它来寻址参数。以下代码应说明我的意思:

library(snow)
library(Matrix)

iter <- 1e6
steps <- 1e5

# define a unique id
SZid <- seq(from=1, to=10, by=1)

# in order to have reproducible code, generate random parameters
SZlambda <- replicate(runif(n=1, min=0, max=.5))
SZmu <- replicate(runif(n=1, min=10, max=15))
SZsigma <- replicate(runif(n=1, min=1, max=3))

cl <- makeSOCKcluster(8)
clusterExport(cl, list=c("SZlambda", "SZmu", "SZsigma"))

numsteps <- iter / steps

MCSZ <- function(SZid, steps){ # Monte Carlo Simulation 
  lambda <- SZlambda[SZid]; mu <- SZmu[SZid]; sigma <- SZsigma[SZid];

  replicate(steps, sum(rlnorm(meanlog=mu, sdlog=sigma, 
                              n = rpois(n=1, lambda))
                       ))
}

for (i in 1:numsteps){
  Mat <- Matrix(
    parSapply(cl, X=SZid, FUN=MCSZ, steps=steps), sparse=TRUE)

  if(!exists("LossSZ")) LossSZ <- Mat else LossSZ <- rBind(LossSZ, Mat)
  rm(Mat)
}

stopCluster(cl)

诀窍是将函数应用于矩阵之上,而不是应用于与参数索引对齐的唯一ID的向量。