%dopar%或加速顺序随机计算的替代方法

时间:2014-11-11 22:54:39

标签: r loops foreach sequential stochastic

我已经编写了一个随机过程模拟器,但我想加快速度,因为它很慢。

模拟器的主要部分由一个for循环构成,我希望将其重写为{%{1}}%divar%。

我尝试过简化循环,但我遇到了一些问题。假设我的foreach循环看起来像这样

for

这意味着在每次迭代时我都会更新library(foreach) r=0 t<-rep(0,500) for(n in 1:500){ s<-1/2+r u<-runif(1, min = 0, max = 1) if(u<s){ t[n]<-u r<-r+0.001 }else{r<-r-0.001} } r的值,并在两个结果中的一个中填充我的向量s。我尝试了几种不同的方式将其重写为t循环,但似乎每次迭代我的值都没有得到更新,我得到一些非常奇怪的结果。我尝试过使用foreach,但它似乎无法运作!

这是我提出的一个例子。

return

如果不可能使用rr=0 tt<-foreach(i=1:500, .combine=c) %dopar% { ss<-1/2+rr uu<-runif(1, min = 0, max = 1) if(uu<=ss){ return(uu) rr<-rr+0.001 }else{ return(0) rr<-rr-0.001} } 那么我可以用其他方式重新编写循环,以便能够使用所有内核并加快速度吗?

2 个答案:

答案 0 :(得分:5)

由于你的评论,关于转向C,是鼓励并且 - 最近 - 证明这不是一项艰巨的任务(特别是对于此类操作)而且值得研究,这里是两个接受的示例函数的比较多次迭代并执行循环步骤:

ffR = function(n) 
{
   r = 0
   t = rep(0, n)
   for(i in 1:n) {
       s = 1/2 + r
       u = runif(1)
       if(u < s) {
           t[i] = u
           r = r + 0.001
       } else r = r - 0.001
   }

   return(t)
}


ffC = inline::cfunction(sig = c(R_n = "integer"), body = '
    int n = INTEGER(AS_INTEGER(R_n))[0];

    SEXP ans;
    PROTECT(ans = allocVector(REALSXP, n));

    double r = 0.0, s, u, *pans = REAL(ans);

    GetRNGstate();

    for(int i = 0; i < n; i++) {
        s = 0.5 + r;
        u = runif(0.0, 1.0);

        if(u < s) {
            pans[i] = u;
            r += 0.001;
        } else {
            pans[i] = 0.0;
            r -= 0.001;
        }
    }

    PutRNGstate();

    UNPROTECT(1);
    return(ans);
', includes = "#include <Rmath.h>")

结果比较:

set.seed(007); ffR(5)
#[1] 0.00000000 0.39774545 0.11569778 0.06974868 0.24374939
set.seed(007); ffC(5)
#[1] 0.00000000 0.39774545 0.11569778 0.06974868 0.24374939

速度比较:

microbenchmark::microbenchmark(ffR(1e5), ffC(1e5), times = 20)
#Unit: milliseconds
#       expr        min         lq     median         uq        max neval
# ffR(1e+05) 497.524808 519.692781 537.427332 668.875402 692.598785    20
# ffC(1e+05)   2.916289   3.019473   3.133967   3.445257   4.076541    20

为了完整起见:

set.seed(101); ans1 = ffR(1e5)
set.seed(101); ans2 = ffC(1e5)
all.equal(ans1, ans2)
#[1] TRUE

希望这些在某些方面都有所帮助。

答案 1 :(得分:1)

您要做的是什么,因为每次迭代都依赖于循环的前面步骤,似乎不可并行化。您正在更新变量r并期望同时运行的其他分支知道它,并且实际上等待更新发生,其中 1)不会发生。他们不会等待,他们只会在他们运行时获取r的当前值 2)如果确实如此,则与没有%dopar%

的情况相同