title: R - Fast way to calculate rolling mean with varying width
body: <p>I have a dataframe that contains bank assets for several dates (times). Each bank has a unique ID:</p>
  
  <pre><code># Sample Data
  time &lt;- c(51, 52, 53, 55, 56, 51, 52, 51, 52, 53)
  id &lt;- c(1234, 1234, 1234, 1234, 1234, 2345, 2345, 3456, 3456, 3456)
  name &lt;- c("BANK A", "BANK A", "BANK A", "BANK A", "BANK A", "BANK B", "BANK B", "BANK C", 
            "BANK C", "BANK C")
  assets &lt;- c(5000, 6000, 4000, 7000, 8000, 10000, 12000, 30000, 35000, 40000)
  df &lt;- data.frame(time, id, name, assets)
  
  &gt; df
     time   id   name assets
  1    51 1234 BANK A   5000
  2    52 1234 BANK A   6000
  3    53 1234 BANK A   4000
  4    55 1234 BANK A   7000
  5    56 1234 BANK A   8000
  6    51 2345 BANK B  10000
  7    52 2345 BANK B  12000
  8    51 3456 BANK C  30000
  9    52 3456 BANK C  35000
  10   53 3456 BANK C  40000
  </code></pre>
  
  <p>For each bank I want to calculate the rolling mean of the assets, varying the width according to the number of consecutive time values. So the rolling mean shall include all availabe consecutive previous values of a bank's asssets. If there is no previous value availabe for one bank it shall equal  assets. Therefor I add a column that counts the number of consecutive time-values and than use <code>rollapplyr</code>from the zoo package, which gives me the desired result, but with a large data set it is far too slow:</p>
  
  <pre><code># Calculate number of consecutive times
  require(dplyr)
  df &lt;- df %&gt;%
    mutate(number.time = 1) %&gt;% # insert column for number.time, start value = 1
    group_by(id) %&gt;%
    arrange(time) # correct order for moving average
  
  for(i in 2:nrow(df)) # Start loop in second row, end in last row of df
    df$number.time[i] &lt;- 
      ifelse(df$time[i] == df$time[i-1]+1,    # Is time consecutive?
             df$number.time[i - 1] + 1,       # If yes: add 1 to previous number.time
             1)                               # If no: set number.time = 1
  # Moving Average
  require(zoo)
  df %&gt;%
    mutate(mov.average = rollapplyr(data = assets,
                                    width = number.time, # use number.time for width
                                    FUN = mean, 
                                    fill = NA,
                                    na.rm = TRUE))
  Source: local data frame [10 x 6]
  Groups: id [3]
  
      time    id   name assets number.time mov.average
     (dbl) (dbl) (fctr)  (dbl)       (dbl)       (dbl)
  1     51  1234 BANK A   5000           1        5000
  2     52  1234 BANK A   6000           2        5500
  3     53  1234 BANK A   4000           3        5000
  4     55  1234 BANK A   7000           1        7000
  5     56  1234 BANK A   8000           2        7500
  6     51  2345 BANK B  10000           1       10000
  7     52  2345 BANK B  12000           2       11000
  8     51  3456 BANK C  30000           1       30000
  9     52  3456 BANK C  35000           2       32500
  10    53  3456 BANK C  40000           3       35000
  </code></pre>
  
  <p>How could I get this output using a faster function? I'm aware of <code>rollmean</code> from zoo as well as <code>SMA</code> from TTR and <code>ma</code>from forecast but these do not allow for varying width. My question may also be related to <a href="https://stackoverflow.com/questions/20134823/r-faster-way-to-calculate-rolling-statistics-over-a-variable-interval">this question</a> and this <a href="http://www.r-bloggers.com/wapply-a-faster-but-less-functional-rollapply-for-vector-setups/" rel="nofollow noreferrer">rblog</a>, but I'm not familiar with C++ nor do I know a lot about function writing, so I do not really understand those posts.</p>
  
  <p><strong>EDIT 1:</strong> Note that in my code above it isn't the <code>for</code>-loop but the rollapplyr that takes a lot of time.</p>
  
  <p><strong>EDIT 2:</strong> The rolling mean shall include not more than the last 4 values. This is, as many consecutive values as there are according to the time-variable, but no more than the last 4 values. Sorry for the inexact question! :/ My wording was based on the assumption to use the "number.time"-column where it would have been easy to limit all values to maximum = 4.</p>