Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I am not sure how to translate your loop into vectorized operations. However, there are two fairly easy options for large performance improvements. The first is to simply put your loop into an <code>R</code> function, and use the <code>compiler</code> package to precompile it. The second slightly more complicated option is to translate your <code>R</code> loop into a <code>c++</code> loop and use the <code>Rcpp</code> package to link it to an <code>R</code> function. Then you call an <code>R</code> function that passes it to <code>c++</code> code which is fast. I show both these options and timings. I do want to gratefully acknowledge the help of Alexandre Bujard from the Rcpp listserv, who helped me with a pointer issue I did not understand.</p> <p>First, here is your <code>R</code> loop as a function, <code>foo.r</code>.</p> <pre><code>## Your R loop as a function foo.r &lt;- function(d) { ans &lt;- d running_total &lt;- 100 count &lt;- 1 max &lt;- 100 toggle &lt;- FALSE processing &lt;- FALSE for(i in d){ if(i != 0 ){ processing &lt;- TRUE if(toggle == TRUE){ ans[count] &lt;- 0 } else { running_total = running_total + i; if (running_total &gt; max) { max &lt;- running_total } else if (0.98*max &gt; running_total) { toggle &lt;- TRUE } } } if(i == 0 &amp;&amp; processing == TRUE) { running_total &lt;- 100 max &lt;- 100 toggle &lt;- FALSE } count &lt;- count + 1 } return(ans) } </code></pre> <p>Now we can load the <code>compiler</code> package and compile the function and call it <code>foo.rcomp</code>.</p> <pre><code>## load compiler package and compile your R loop require(compiler) foo.rcomp &lt;- cmpfun(foo.r) </code></pre> <p>That is all it takes for the compilation route. It is all <code>R</code> and obviously very easy. Now for the <code>c++</code> approach, we use the <code>Rcpp</code> package as well as the <code>inline</code> package which allows us to "inline" the <code>c++</code> code. That is, we do not have to make a source file and compile it, we just include it in the <code>R</code> code and the compilation is handled for us.</p> <pre><code>## load Rcpp package and inline for ease of linking require(Rcpp) require(inline) ## Rcpp version src &lt;- ' const NumericVector xx(x); int n = xx.size(); NumericVector res = clone(xx); int toggle = 0; int processing = 0; int tot = 100; int max = 100; typedef NumericVector::iterator vec_iterator; vec_iterator ixx = xx.begin(); vec_iterator ires = res.begin(); for (int i = 0; i &lt; n; i++) { if (ixx[i] != 0) { processing = 1; if (toggle == 1) { ires[i] = 0; } else { tot += ixx[i]; if (tot &gt; max) { max = tot; } else if (.98 * max &gt; tot) { toggle = 1; } } } if (ixx[i] == 0 &amp;&amp; processing == 1) { tot = 100; max = 100; toggle = 0; } } return res; ' foo.rcpp &lt;- cxxfunction(signature(x = "numeric"), src, plugin = "Rcpp") </code></pre> <p>Now we can test that we get the expected results:</p> <pre><code>## demonstrate equivalence d &lt;- c(0,0,0,1,3,4,5,-1,2,3,-5,8,0,0,-2,-3,3,5,0,0,0,-1,-1,-1,-1) all.equal(foo.r(d), foo.rcpp(d)) </code></pre> <p>Finally, create a much larger version of <code>d</code> by repeating it 10e4 times. Then we can run the three different functions, pure <code>R</code> code, compiled <code>R</code> code, and <code>R</code> function linked to <code>c++</code> code.</p> <pre><code>## make larger vector to test performance dbig &lt;- rep(d, 10^5) system.time(res.r &lt;- foo.r(dbig)) system.time(res.rcomp &lt;- foo.rcomp(dbig)) system.time(res.rcpp &lt;- foo.rcpp(dbig)) </code></pre> <p>Which on my system, gives:</p> <pre><code>&gt; system.time(res.r &lt;- foo.r(dbig)) user system elapsed 12.55 0.02 12.61 &gt; system.time(res.rcomp &lt;- foo.rcomp(dbig)) user system elapsed 2.17 0.01 2.19 &gt; system.time(res.rcpp &lt;- foo.rcpp(dbig)) user system elapsed 0.01 0.00 0.02 </code></pre> <p>The compiled <code>R</code> code takes about 1/6 the time the uncompiled <code>R</code> code taking only 2 seconds to operate on the vector of 2.5 million. The <code>c++</code> code is orders of magnitude faster even then the compiled <code>R</code> code requiring just .02 seconds to complete. Aside from the initial setup, the syntax for the basic loop is nearly identical in <code>R</code> and <code>c++</code> so you do not even lose clarity. I suspect that even if parts or all of your loop could be vectorized in <code>R</code>, you would be sore pressed to beat the performance of the <code>R</code> function linked to <code>c++</code>. Lastly, just for proof:</p> <pre><code>&gt; all.equal(res.r, res.rcomp) [1] TRUE &gt; all.equal(res.r, res.rcpp) [1] TRUE </code></pre> <p>The different functions return the same results.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload