user2724310
user2724310

Reputation: 31

R: Sequentially apply a function to a data frame and carry over the result to the next calcuation

I am working on some dynamic problem (about belief updating using Bayes rule) and seeking a "loop-less" solution to speed up the calculation as my current solution using for loops is really slow.

Suppose I have a data frame or matrix, and for each row, I want to do the same calculation. However, the calculation for row r requires the output generated in the previous calculation on row r-1. The process can be illustrated by the following:

Suppose I have a R by n matrix, MA, and some initial variables y0:

  1. [input] MA[1,] + y0 => [output] y1
  2. [input] MA[2,] + y1 => [output] y2
  3. [input] MA[3,] + y2 => [output] y3
  4. ....

One of the simplest examples might be the calculation of n!. The value of n! = n * (n-1)!, where (n-1)! is the result from the previous calculation.

The first function I came up with is the apply family but apply functions can't be applied to the recursive (or dynamic) operations like I have right now; it simply repeats the same calculation to different inputs but doesn't carry the output forwards. Not sure if there is any other trick we can use. Can any genius come up with a loop-free solution to this particular problem?

Upvotes: 3

Views: 2453

Answers (3)

ARobertson
ARobertson

Reputation: 2897

You can store data in functions. An example for n!

df <- data.frame(r = 1:10)

parent.iteration <- function() {
  i <- 0
  n <- 1
  function() {
    i <<- i + 1
    n <<- n * i
    n
  }
}

# create closure
child.iteration <- parent.iteration()
df$result <- apply(df,1,function(x)child.iteration())

# continues where it left off
df$result2 <- apply(df,1,function(x)child.iteration())
df

More info: Closures

Upvotes: 1

lauratboyer
lauratboyer

Reputation: 334

The following should work with the apply family of functions... but these also contain loops. You might be able to speed the operation up by using mclappy()

ne <- new.env() # create a new environment
ne$ystore <- y0 # create an object to store the output value and initialize at y0

calc.rec <- function(x) ne$ystore <- MA[x, ] + ne$ystore
sapply(1:nrow(MA), calc.rec)

If this is too slow, depending on the exact type of calculations you want to do, you could use cumsum(), cumprod(), etc. to vectorize them.

Upvotes: 0

Karl Forner
Karl Forner

Reputation: 4414

This should not be faster, probably slower, but his is my attempt at avoiding for loops:

# input data
MA <- matrix(1:8, nrow=4)
y0 <- 1

# compute
l <- Reduce(function(x, y) MA[y,] + x, seq_len(nrow(MA)), init=y0, accumulate=TRUE)

# format
res2 <- data.matrix(t(as.data.frame(l[-1])))
rownames(res2) <- NULL

Upvotes: 2

Related Questions