7

I am trying to calculate cumulative product for subsets of xts object. Here is an example of what I want and a question whether this can be done faster/more elegant using period.apply or some other c++ based fast function?

# install.packages("qmao", repos="http://R-Forge.R-project.org")
require(qmao) # for do.call.rbind()

# I need something like cumprod over xts but by endpoints (subsets of xts)
test <- xts(rep(0.01, length(as.Date(13514:13523, origin="1970-01-01"))), as.Date(13514:13523, origin="1970-01-01"))
ep <- c(0, 5, NROW(test))
# This does not do the trick
period.prod(test, INDEX=ep)
# So, try the obvious, but it does not do the trick
period.apply(test, INDEX=ep, FUN=function(x) cumprod(1 + x))

# Well, write your own
# Hm, there is no split.xts that takes ep (endpoints) as parameter...
# OK, split it manually
test.list <- list(length(ep) - 1)
k <- 1:(length(ep) - 1)
test.list <- lapply(k, function(x) test[(ep[x] + 1):ep[x + 1], ])
# This is what I want...
do.call.rbind(lapply(test.list, function(x) cumprod(1 + x)))
# Is there a better/faster way to do this?
Samo
  • 2,065
  • 20
  • 41

1 Answers1

5

period.apply and friends won't work because they only return one observation per period. You want something more like ave:

dep <- diff(ep)
out.ave <- ave(test+1, rep(ep, c(0,dep)), FUN=cumprod)
Joshua Ulrich
  • 173,410
  • 32
  • 338
  • 418
  • This is very elegant, and I'll give it a +1 when I have more votes, but I benchmarked it with a 100000 row xts, and it's 9 times slower that @Samo's solution. – GSee Oct 31 '12 at 23:35
  • @GSee: while it's still slower, my solution compares more favorably as the number of endpoints increases. – Joshua Ulrich Nov 01 '12 at 00:15
  • @JoshuaUlrich Thanks. Every day I learn about one or two new functions - life expectancy seems optimistic... :) One question: any chance to add this functionality to xts (I mean change period.apply or add new function that does this)? Well, and another question: split.xts - would it be possible to add a parameter to set endpoints (on which to split xts)? – Samo Nov 01 '12 at 09:29
  • @Samo: As it says in `?split.xts`, dispatch is passed to `split.zoo` if `f` is not "character". That means you can almost do what you want, but you have to convert your endpoints into a vector the same length as `test`. For example: `split(test, rep(ep,c(0,diff(ep))))`. – Joshua Ulrich Nov 01 '12 at 17:23