1

nRIには、forループ時間を繰り返す次のサンプルモジュールがあります。

function(n){
#inputs - n - number of results required
    #reserve n spaces for results
    r_num_successes <- 1:n

    #start looping n times
    for(i in 1:n){

        #set first uniform "random" deviate equal to 0.05 and number of successes to 0
        current_unif <- 0.05
        num_successes <- 0

        #start while loop that updates current_unif - it runs as long as 
        #current_unif is less than 0.95, increments num_successes each loop
        while(current_unif < 0.95){

            #set current_unif to a uniform random deviate between the
            #existing current_unif and 1
            current_unif <- runif(1,current_unif)
            num_successes <- num_successes + 1
        }

        #set the i-th element of the results vector to that final num_successes
        #generated by the while loop
        r_num_successes[i] <- num_successes
    }

            #output the mean of all the successes
    return(mean(r_num_successes))
}

n大きくなると、これはかなりゆっくりと粉砕し始めます。それを最適化する良い方法はありますか?

4

2 に答える 2

10

純粋なRを使用してこれの速度を大幅に改善するためにできることは何もありません。バイトコンパイルはわずかな改善をもたらしますが、大幅な速度向上のためにコンパイル済みコードに移動する必要があります。

更新:これがDirkのためのRcppソリューションです:)

> nCode <- '
+   int N = as<int>(n);
+   std::vector<double> rns;
+ 
+   RNGScope scope;  // Initialize Random number generator
+ 
+   for(int i=0; i<N; i++) {
+     double current_unif = 0.05;
+     double num_successes = 0;
+     while(current_unif < 0.95) {
+       current_unif = ::Rf_runif(current_unif, 1.0);
+       num_successes++;
+     }
+     rns.push_back(num_successes);
+   }
+ 
+   double mean = std::accumulate(rns.begin(), rns.end(), 0.0) / rns.size();
+   return wrap(mean);  // Return to R
+ '
>
> library(inline)
> nFunRcpp <- cxxfunction(signature(n="int"), nCode, plugin="Rcpp")
> library(compiler)
> nFunCmp <- cmpfun(nFun)
> system.time(nFun(1e5))
   user  system elapsed 
  3.100   0.000   3.098 
> system.time(nFunCmp(1e5))
   user  system elapsed 
  2.120   0.000   2.114 
> system.time(nFunRcpp(1e5))
   user  system elapsed 
  0.010   0.000   0.016 
于 2012-04-27T18:09:17.623 に答える
2

完全を期すために、@JoshuaUlrichに提案した内容は次のとおりです。

R> res <- benchmark(nFun(1e5L), nFunCmp(1e5L), nFunRcpp(1e5L), nFun2Rcpp(1e5L),
+                  columns = c("test", "replications", "elapsed", "relative"),
+                  replications=10,
+                  order="relative")
R> print(res)
               test replications elapsed  relative
4 nFun2Rcpp(100000)           10   0.117   1.00000
3  nFunRcpp(100000)           10   0.122   1.04274
2   nFunCmp(100000)           10  13.845 118.33333
1      nFun(100000)           10  23.212 198.39316
R> 

nFun2Rcppは、単に1行追加します。

rns.reserve(N);

割り当てをに変更します

rns[i] = num_successes;

これを使用.push_back()するのではなく、メモリ割り当てを少し効率的にします。

編集それは不正確であり、ランダム化されたアルゴリズムを反映していることがわかりました。それぞれにセットを追加するset.seed()と、2つのC++バージョン間で時間が同じになります。ここでは測定可能な利益はありません。

于 2012-04-27T19:14:52.580 に答える