我已经编写了一个随机过程模拟器,但我想加快速度,因为它很慢。
模拟器的主要部分由一个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}
}
那么我可以用其他方式重新编写循环,以便能够使用所有内核并加快速度吗?
答案 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%