user2175594
user2175594

Reputation: 819

Using apply in a 'window'

Is there a way to use apply functions on 'windows' or 'ranges'? This example should serve to illustrate:

a <- 11:20

Now I want to calculate the sums of consecutive elements. i.e.

[11+12, 12+13, 13+14, ...]

The ways I can think of handling this are:

a <- 11:20
b <- NULL
for(i in 1:(length(a)-1))
{
    b <- c(b, a[i] + a[i+1])
}
# b is 23 25 27 29 31 33 35 37 39

or alternatively,

d <- sapply( 1:(length(a)-1) , function(i) a[i] + a[i+1] )
# d is 23 25 27 29 31 33 35 37 39

Is there a better way to do this? I'm hoping there's something like:

e <- windowapply( a, window=2, function(x) sum(x) )  # fictional function
# e should be 23 25 27 29 31 33 35 37 39

Upvotes: 4

Views: 864

Answers (3)

Andrea
Andrea

Reputation: 603

We can define a general moving() function:

moving <- function(f){
  g <- function(i , x, n , f, ...) f(x[(i-n+1):i], ...)
  function(x, n, ...) {
    N <- length(x)
    vapply(n:N, g, x , n , f, FUN.VALUE = numeric(1), ...)
  }  
}

Function moving() returns function that, in turn can be used to generate any moving_f() functions:

moving_sum <- moving(sum)  
moving_sum(x = 11:20, n = 2)

similarly, even passing extra arguments to moving_f()

moving_mean <- moving(mean)  
moving_mean(x = rpois(22, 6), n = 5, trim = 0.1)

Upvotes: 4

Jilber Urbina
Jilber Urbina

Reputation: 61214

Here's an anternative using rollapply from zoo package

> rollapply(a, width=2, FUN=sum )
[1] 23 25 27 29 31 33 35 37 39

zoo package also offers rollsum function

> rollsum(a, 2)
[1] 23 25 27 29 31 33 35 37 39

Upvotes: 4

Thomas
Thomas

Reputation: 44555

You can achieve your windowapply function by first creating a list of indices and then *applying over them such that they are used as extraction indices:

j <- lapply(seq_along(a), function(i) if(i<10) c(i,i+1) else i)
sapply(j, function(j) sum(a[j]))
## [1] 23 25 27 29 31 33 35 37 39

Upvotes: 0

Related Questions