0

I often find myself using the following construction in R:

a    <- c(1, rep(NA, 20))
rate <- 1.2     

for (i in 2:length(a)){
   a[i] <- a[i-1]*rate
}

which yields:
> a
 [1]  1.000000  1.200000  1.440000  1.728000  2.073600 ... 

What would be a more "R-like" way of accomplishing this, avoiding the for/while loop?

It's so easy to do this in a spreadsheet!:

enter image description here

The following related questions won't answer my question:
avoid for loop in R
How to avoid for loop in this dataset?

Community
  • 1
  • 1
Dan
  • 1,711
  • 2
  • 24
  • 39

2 Answers2

4

For your specific example the cumprod function is one simple way to do this:

a <- c(1, rep(1.2, 20) )
a <- cumprod(a)

More generally if there is not a cum function for your procedure, but you want that type of functionality then you can also use the Reduce function:

a <- c(1, rep(1.2, 20))
a <- Reduce(`*`, a, accumulate=TRUE)

But consider that while there is a certain elegance in avoiding loops in R, from a practical standpoint the loop may be the quickest overall answer (when you include both programming and running time). Loops in R have been optimized to run reasonably fast (unless you create a really poor loop, but yours is an example of the efficient way to do things) and often if you can think of the looping approach then the time saved by vectorizing may be less than the extra time to think about how to vectorize it. Unless this is going to be done many times for very long loops, time savings may be too small to matter (see fortune(98)). In the cases of very long vectors, rounding may be different between the for loop and vectorized alternatives, so that issue may be of more importance than the speed.

Learning alternatives to for are great for improving your knowledge/programming skills and can be great simplifiers for a lot of code, just don't feel that you always have to find an alternative to for.

Greg Snow
  • 48,497
  • 6
  • 83
  • 110
  • Accepted answer as it gives a specific and a general solution to the question, further expanding the discussion about usage of loops in R. It added a lot to me, a non-programmer, and made me feel "not-so-dumb" for using loops :) – Dan May 28 '14 at 16:32
3

As the power function ^ is vectorised, you can create a sequence of indices and raise your rate to it.

rate <- 1.2
a <- rate^(0:19)
Miff
  • 7,486
  • 20
  • 20
  • Very concise solution, @Miff. Thanks! I wonder how to generalize this further though. Say the replacement in my for loop instead of `a[i-1]*rate` is something more complex as `a[i-1]*df$var2[i-1]*rate`. Should I explore the apply family of functions? – Dan May 28 '14 at 15:15
  • 1
    @DanielRP Sounds like you may want to investigate the `zoo` package for operations along a vector (or time-series). Another option: Since you're looking for general solutions to `a[i] <- f(a[i-1])` you cannot use a vectorize operation directly, but you can create your `f(x)` function and apply `vectorize` to it. – Carl Witthoft May 28 '14 at 15:19