1

How can I pass the width argument of the zoo:rollapply function to the FUN function called within rollapply?

I put the values and widths as columns of a same data.frame:

library(zoo)
a = data.frame(v = 1:10, w = c(2,1,3,5,2,7,3,2,1,3))
#     v w
# 1   1 2
# 2   2 1
# 3   3 3
# 4   4 5
# 5   5 2
# 6   6 7
# 7   7 3
# 8   8 2
# 9   9 1
# 10 10 3

I can do:

rollapply(a$v, a$w, function(x) sum(x), partial=T)

Which gives:

[1] 3 2 9 20 11 42 21 17 9 19

Now I would like to use, for each rolling window of a$v, the corresponding value of a$w in the computation. For example:

rollapply(a$v, a$w, function(x) sum(x) + a$w[1], partial=T)

But instead of having a$w[1] as a constant value (here, it simply adds 2 to the values above), I would like to use the value in a$w corresponding each time to the a$w (i.e., in the same row of a).

Hence the desired output would be:

[1] 5 3 12 25 13 49 24 19 10 22

ztl
  • 2,512
  • 1
  • 26
  • 40

1 Answers1

2

1) The width need not be in the function. It can be added on afterwards:

rollapply(a$v, a$w, sum, partial = TRUE) + a$w
## [1]  5  3 12 25 13 49 24 19 10 22

Specify align= if you want different alignment.

2) This approach is a bit ugly but another way is to maintain an external index.

i <- 0
rollapply(a$v, a$w, function(x) sum(x) + a$w[i <<- i+1], partial = TRUE)
## [1]  5  3 12 25 13 49 24 19 10 22

2a) This can be cleaned up a bit at the expense of extra code using object oriented ideas to maintain state. Here we define a proto object p having an internal counter and an incr method which increments and returns it each time incr is invoked on the object.

library(proto)
p <- proto(counter = 0, incr = function(.) .$counter <- .$counter + 1)
rollapply(a$v, a$w, function(x) sum(x) + a$w[p$incr()], partial = TRUE)
## [1]  5  3 12 25 13 49 24 19 10 22

3) The example in the question used center alignment but if you actually need right or left alignment then it can be done by iterating over a rather than just over a$v. Here it is for right alignment.

Sum <- function(x) {
  x <- matrix(x,,2)
  v <- x[, 1]
  w <- tail(x[, 2], 1)
  sum(v) + w
}
rollapplyr(a, a$w, Sum, partial = TRUE, by.column = FALSE)
## [1]  3  3  9 15 11 28 21 17 10 30

# double check
rollapplyr(a$v, a$w, sum, partial = TRUE) + a$w
## [1]  3  3  9 15 11 28 21 17 10 30
G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341
  • Thanks - my example was badly chosen as too simple. I really need the `width` parameter inside the function, as the value of something inside it depends on it (I'll edit my question later on) – ztl Feb 08 '20 at 20:23
  • Have added (2) and (3). – G. Grothendieck Feb 08 '20 at 23:04
  • Thanks! Interesting suggestions - `2a` brings new stuff to me, thanks! Re-thinking about it... actually, there could be a simple solution using `length(x)` inside the function with appropriate management of the borders/`partial` aspects...? – ztl Feb 10 '20 at 09:36
  • Not in general if you are using center alignment. Consider `rollapply(1:5, 3, toString, partial = TRUE)` On the first iteration "1, 2" is returned and on the last iteration "4, 5" is returned but if all you have as input is 1:2 or 4:5 you don't know if the first number is the index or the second is. In fact it is the first number for "1, 2" but it is the second for "4, 5". – G. Grothendieck Feb 10 '20 at 12:18