1
votes

Suppose I have the following zoo object:

x.orig <- read.zoo(data.frame(date=seq(as.Date('2020-01-01'), as.Date('2020-01-10'), 1), v=c(1,2,3,100,4,5,1000,8,8,10)))
2020-01-01 2020-01-02 2020-01-03 2020-01-04 2020-01-05 2020-01-06 2020-01-07 2020-01-08 2020-01-09 2020-01-10 
         1          2          3        100          4          5       1000          8          8         10 

I would like to compute a rolling sum of width=seq_along(x.orig) as follows:

2020-01-01 1
2020-01-02 1 + 2                                   #2020-01-01 + 2020-01-02
2020-01-03 1 + (1 + 2) + 3                         #2020-01-01 + 2020-01-02 + 2020-01-03
2010-01-04 1 + (1 + 2) + (1 + (1 + 2) + 3) + 100   #2020-01-01 + 2020-01-02 + 2020-01-03 + 2020-01-04
...

I would imagine the way to do this would be to result-feed x in some way so that x is updated after each rollapply loop so that the next rollapply iteration picks up the modified value in its window but am just not sure how to write it...

3
it may ve easier and faters chass with the base R. cumsum(cumsum(x))Santiago I. Hurtado
In reality I have a rolling window of a week so that is why cumsum wouldn't work but yes, I think it has to be sort-of like cumsumDenis
maybe create a function(x){cumsum(cumsum(x))} and then roll it by one weekSantiago I. Hurtado

3 Answers

2
votes

I don't think this is very common so probably there won't be a function for this, however you can hack your own fast function with Rcpp, here's an example:

library(data.table)
library(Rcpp)

DT <- data.table(date=seq(as.Date('2020-01-01'), as.Date('2020-01-10'), 1),
                 v=c(1,2,3,100,4,5,1000,8,8,10))
DT[, week := 1:.N %/% 7] # create a week column (you can adapt this to your needs)

# Add your logic to a cpp function
cppFunction("
    IntegerVector roll_cumsum(IntegerVector x) {
        int n = x.size();
        int cumsum = 0;
        IntegerVector y = clone(x);
        for (int i = 0; i < n; ++i) {
            y[i] += cumsum;
            cumsum += y[i];
        }
        return y;
    }
")

DT[, result := roll_cumsum(v), by = week][]
1
votes

A simple loop will do it:

v <- x.orig
for(i in seq_along(v)) v[i] <- sum(head(v, i))

which results in this zoo object:

> v
2020-01-01 2020-01-02 2020-01-03 2020-01-04 2020-01-05 2020-01-06 2020-01-07 
         1          3          7        111        126        253       1501 
2020-01-08 2020-01-09 2020-01-10 
      2010       4020       8042 

rollapply

If you wanted to wrap this within a rollapplyr of width 3, say:

accum <- function(x) { for(i in seq_along(x)) x[i] <- sum(head(x, i)); tail(x, 1) }
rollapplyr(x.orig, 3, accum)
0
votes

Here's my attempt at this. Ideally I wanted to modify x.orig after every iteration but couldn't get that to work so made another variable called latest. I doubt this is the best way to do it though:

library(zoo)

latest <- x.orig
rollapplyr(x.orig, width = seq_along(x.orig), function(x) {
   #browser()
   x <- latest[index(x)]
   v <- sum(x)
   if (!is.na(v))
     latest[last(index(x))] <<- v
   latest[last(index(x))]
})

2020-01-01 2020-01-02 2020-01-03 2020-01-04 2020-01-05 2020-01-06 2020-01-07 2020-01-08 2020-01-09 2020-01-10 
         1          3          7        111        126        253       1501       2010       4020       8042