R 加速循环中指数随机变量的重复生成

R 加速循环中指数随机变量的重复生成,r,performance,random,rcpp,R,Performance,Random,Rcpp,我正在实现一个算法,作为其中的一部分,我需要生成指数随机变量。不幸的是,我不能真正避免循环,因为每个生成的随机变量都依赖于前一个,所以我认为矢量化是不可能的。我对这一代人做了一些计算,但瓶颈(目前)是这一代人。此时,我假设N将很大(N>=1000000) 下面是一些示例代码: N <- 1e7 #Preallocate x <- rep(0, times=N) #Set a starting seed x[1] <- runif(1) for(i in 2:N) {

我正在实现一个算法,作为其中的一部分,我需要生成指数随机变量。不幸的是,我不能真正避免循环,因为每个生成的随机变量都依赖于前一个,所以我认为矢量化是不可能的。我对这一代人做了一些计算,但瓶颈(目前)是这一代人。此时,我假设N将很大(N>=1000000)

下面是一些示例代码:

N <- 1e7
#Preallocate
x <- rep(0, times=N)

#Set a starting seed
x[1] <- runif(1)

for(i in 2:N) {
    #Do some calculations
    x[i] <- x[i-1] + rexp(1, x[i-1])  #Bottleneck
    #Do some more calculations
}
N我们可以利用如果X~Exp(λ)那么kX~Exp(λ/k)的事实来加速代码。通过这种方式,我们可以预先使用
rate=1
进行所有随机绘制,然后在循环中进行划分,以适当地缩放它们

draws = rexp(N, rate = 1)
x <- rep(0, times = N)
x[1] <- runif(1)
for(i in 2:N) {
    #Do some calculations
    x[i] <- x[i-1] + draws[i] / x[i-1] 
    #Do some more calculations
}

强力Rcpp解决方案:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector genExp(int N) {

  NumericVector res(N);
  double prev;

  res[0] = unif_rand();
  for (int i = 1; i < N; i++) {
    prev = res[i-1];
    res[i] = prev + exp_rand() / prev;
  }

  return res;
}
使用
N=1e7

Unit: milliseconds
          expr      min       lq      mean    median        uq       max neval
 draw_up_front 1698.730 1708.739 1737.8633 1716.1345 1752.3276 1923.3940    20
          rcpp  297.142  319.794  338.6755  327.6626  364.6308  398.1554    20

陛下有趣。我将尝试一下,看看它是如何进行的。谢谢你的回复。如果你没有把所有的函数都放在基准测试中,那就是作弊。谢谢。我用这个答案来帮助加速我的代码,但是真正的进步是由于上面格雷戈的答案,所以我接受了这个答案。
Unit: milliseconds
             expr        min         lq       mean     median         uq        max neval
    draw_up_front  167.17031  168.57345  170.62292  170.18072  171.73782  175.46868    20
 draw_one_at_time 1415.01898 1465.57139 1510.81220 1502.15753 1550.07829 1623.70831    20
             rcpp   28.25466   29.33682   33.52528   29.89636   30.74908   94.38009    20
Unit: milliseconds
          expr      min       lq      mean    median        uq       max neval
 draw_up_front 1698.730 1708.739 1737.8633 1716.1345 1752.3276 1923.3940    20
          rcpp  297.142  319.794  338.6755  327.6626  364.6308  398.1554    20