Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perform an operation on a vector using the previous value after an initial value

Tags:

r

In Excel, it's easy to perform a calculation on a previous cell by referencing that earlier cell. For example, starting from an initial value of 100 (step = 0), each next step would be 0.9 * previous + 9 simply by dragging the formula bar down from the first cell (step = 1). The next 10 steps would look like:

      step     value
 [1,]    0 100.00000
 [2,]    1  99.00000
 [3,]    2  98.10000
 [4,]    3  97.29000
 [5,]    4  96.56100
 [6,]    5  95.90490
 [7,]    6  95.31441
 [8,]    7  94.78297
 [9,]    8  94.30467
[10,]    9  93.87420
[11,]   10  93.48678

I've looked around the web and StackOverflow, and the best I could come up with is a for loop (below). Are there more efficient ways to do this? Is it possible to avoid a for loop? It seems like most functions in R (such as cumsum, diff, apply, etc) work on existing vectors instead of calculating new values on the fly from previous ones.

#for loop.  This works
value <- 100   #Initial value
for(i in 2:11) {
  current <- 0.9 * value[i-1] + 9
  value <- append(value, current)
}
cbind(step = 0:10, value)  #Prints the example output shown above
like image 919
oshun Avatar asked Feb 29 '16 07:02

oshun


2 Answers

It seems like you're looking for a way to do recursive calculations in R. Base R has two ways of doing this which differ by the form of the function used to do the recursion. Both methods could be used for your example.

Reduce can be used with recursion equations of the form v[i+1] = function(v[i], x[i]) where v is the calculated vector and x an input vector; i.e. where the i+1 output depends only the i-th values of the calculated and input vectors and the calculation performed by function(v, x) may be nonlinear. For you case, this would be

    value <- 100
    nout <- 10
# v[i+1]  =  function(v[i], x[i])
    v <- Reduce(function(v, x) .9*v  + 9, x=numeric(nout),  init=value, accumulate=TRUE)
    cbind(step = 0:nout, v)

filter is used with recursion equations of the form y[i+1] = x[i] + filter[1]*y[i-1] + ... + filter[p]*y[i-p] where y is the calculated vector and x an input vector; i.e. where the output can depend linearly upon lagged values of the calculated vector as well as the i-th value of the input vector. For your case, this would be:

    value <- 100
     nout <- 10
# y[i+1] = x[i] + filter[1]*y[i-1] + ... + filter[p]*y[i-p]
        y <- c(value, stats::filter(x=rep(9, nout), filter=.9, method="recursive", sides=1, init=value))
     cbind(step = 0:nout, y)

For both functions, the length of the output is given by the length of the input vector x.
Both of these approaches give your result.

like image 59
WaltS Avatar answered Sep 30 '22 14:09

WaltS


Use our knowledge about the geometric series.

i <- 0:10
0.9 ^ i * 100 + 9 * (0.9 ^ i - 1) / (0.9 - 1)
#[1] 100.00000  99.00000  98.10000  97.29000  96.56100  95.90490  95.31441  94.78297  94.30467  93.87420  93.48678
like image 37
Roland Avatar answered Sep 30 '22 14:09

Roland