Reputation: 31
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
:
[input] MA[1,] + y0 => [output] y1
[input] MA[2,] + y1 => [output] y2
[input] MA[3,] + y2 => [output] y3
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
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
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
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