title: lapply vs for loop - Performance R
body: <p>It is often said that one should prefer <code>lapply</code> over <code>for</code> loops.
  There are some exception as for example Hadley Wickham points out in his Advance R book.</p>
  
  <p>(<a href="http://adv-r.had.co.nz/Functionals.html" rel="noreferrer">http://adv-r.had.co.nz/Functionals.html</a>) (Modifying in place, Recursion etc).
  The following is one of this case.</p>
  
  <p>Just for sake of learning, I tried to rewrite a perceptron algorithm in a functional form in order to benchmark 
  relative performance.
  source (<a href="https://rpubs.com/FaiHas/197581" rel="noreferrer">https://rpubs.com/FaiHas/197581</a>).</p>
  
  <p>Here is the code.</p>
  
  <pre><code># prepare input
  data(iris)
  irissubdf &lt;- iris[1:100, c(1, 3, 5)]
  names(irissubdf) &lt;- c("sepal", "petal", "species")
  head(irissubdf)
  irissubdf$y &lt;- 1
  irissubdf[irissubdf[, 3] == "setosa", 4] &lt;- -1
  x &lt;- irissubdf[, c(1, 2)]
  y &lt;- irissubdf[, 4]
  
  # perceptron function with for
  perceptron &lt;- function(x, y, eta, niter) {
  
    # initialize weight vector
    weight &lt;- rep(0, dim(x)[2] + 1)
    errors &lt;- rep(0, niter)
  
  
    # loop over number of epochs niter
    for (jj in 1:niter) {
  
      # loop through training data set
      for (ii in 1:length(y)) {
  
        # Predict binary label using Heaviside activation
        # function
        z &lt;- sum(weight[2:length(weight)] * as.numeric(x[ii, 
          ])) + weight[1]
        if (z &lt; 0) {
          ypred &lt;- -1
        } else {
          ypred &lt;- 1
        }
  
        # Change weight - the formula doesn't do anything
        # if the predicted value is correct
        weightdiff &lt;- eta * (y[ii] - ypred) * c(1, 
          as.numeric(x[ii, ]))
        weight &lt;- weight + weightdiff
  
        # Update error function
        if ((y[ii] - ypred) != 0) {
          errors[jj] &lt;- errors[jj] + 1
        }
  
      }
    }
  
    # weight to decide between the two species
  
    return(errors)
  }
  
  err &lt;- perceptron(x, y, 1, 10)
  
  ### my rewriting in functional form auxiliary
  ### function
  faux &lt;- function(x, weight, y, eta) {
    err &lt;- 0
    z &lt;- sum(weight[2:length(weight)] * as.numeric(x)) + 
      weight[1]
    if (z &lt; 0) {
      ypred &lt;- -1
    } else {
      ypred &lt;- 1
    }
  
    # Change weight - the formula doesn't do anything
    # if the predicted value is correct
    weightdiff &lt;- eta * (y - ypred) * c(1, as.numeric(x))
    weight &lt;&lt;- weight + weightdiff
  
    # Update error function
    if ((y - ypred) != 0) {
      err &lt;- 1
    }
    err
  }
  
  weight &lt;- rep(0, 3)
  weightdiff &lt;- rep(0, 3)
  
  f &lt;- function() {
    t &lt;- replicate(10, sum(unlist(lapply(seq_along(irissubdf$y), 
      function(i) {
        faux(irissubdf[i, 1:2], weight, irissubdf$y[i], 
          1)
      }))))
    weight &lt;&lt;- rep(0, 3)
    t
  }
  </code></pre>
  
  <p>I did not expected any consistent improvement due to the aforementioned
  issues. But nevertheless I was really surprised when I saw the sharp worsening 
  using <code>lapply</code> and <code>replicate</code>.</p>
  
  <p>I obtained this results using <code>microbenchmark</code> function from <code>microbenchmark</code> library</p>
  
  <p>What could possibly be the reasons?
  Could it be some memory leak?</p>
  
  <pre><code>                                                      expr       min         lq       mean     median         uq
                                                          f() 48670.878 50600.7200 52767.6871 51746.2530 53541.2440
    perceptron(as.matrix(irissubdf[1:2]), irissubdf$y, 1, 10)  4184.131  4437.2990  4686.7506  4532.6655  4751.4795
   perceptronC(as.matrix(irissubdf[1:2]), irissubdf$y, 1, 10)    95.793   104.2045   123.7735   116.6065   140.5545
          max neval
   109715.673   100
     6513.684   100
      264.858   100
  </code></pre>
  
  <p>The first function is the <code>lapply</code>/<code>replicate</code> function</p>
  
  <p>The second is the function with <code>for</code> loops </p>
  
  <p>The third is the same function in <code>C++</code> using <code>Rcpp</code></p>
  
  <p>Here According to Roland the profiling of the function.
  I am not sure I can interpret it in the right way.
  It looks like to me most of the time is spent in subsetting
  <a href="https://i.stack.imgur.com/N2Nez.png" rel="noreferrer">Function profiling</a></p>