1

ゼロの数が多い大きな行列を必要とするプロジェクトに取り組んでいます。残念ながら、これらの行列の一部は 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)

ラムダはすべて非常に小さいため、5 番目の要素ごとに約 0 と異なるだけであるため、結果をスパース行列に格納することが賢明です。

残念ながら、反復回数を 1e6 から少なくとも 1e7 に増やす必要が生じたため、foreachループによって生成される行列が大きすぎて 8 GB の RAM に格納できなくなりました。ここでやりたいことは、タスクをそれぞれ 1e6 回の反復を含むステップに分割し、これらを 1 つのスパース マトリックスに結合することです。

私は今、アイデアとして次のことを考えています。

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)

正常に動作しますが、ラムダを何らかの値に修正する必要がありました。私のアプリケーションでは、ラムダ ベクトルの i 番目の要素に平均が等しいポアソン分布から得られる i 番目の行の値が必要です。これは明らかにforeachループでうまく機能しましたが、適用ループで機能させる方法をまだ見つけていません。

私の質問は次のとおりです。

  1. 適用関数に、それが操作している行を「認識」させ、対応する引数を関数に渡すことは可能ですか?
  2. 標準マトリックスを作成し、次のステップでそれをスパース マトリックスに変換する必要なく、foreach およびスパース マトリックスを操作する方法はありますか?
  3. 上記のいずれにも当てはまらない場合、タスクを R のスレーブ プロセスに手動で割り当てる方法はありますか?まばらなベクトルであり、最後のステップでこれらを結合するだけです。
4

1 に答える 1

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 のベクトルに適用することです。

于 2014-06-03T15:20:15.670 に答える