1

This is a question following a previous one. In that question, it is suggested to use rollapply to calculate sum of the 1st, 2nd, 3rd entry of a vector; then 2nd, 3rd, 4th; and so on.

My question is how calculate sum of the 1st, 2nd and 3rd; then the 4th, 5th and 6th. That is, rolling without overlapping. Can this be easily done, please?

Community
  • 1
  • 1
LaTeXFan
  • 1,136
  • 4
  • 14
  • 36

4 Answers4

6

Same idea. You just need to specify the by argument. Default is 1.

x <-c(1, 5, 4, 5, 7, 8, 9, 2, 1)

zoo::rollapply(x, 3, by = 3, sum)
#[1] 10 20 12

#or another Base R option
sapply(split(x, ceiling(seq_along(x)/3)), sum)
# 1  2  3 
#10 20 12 
Sotos
  • 51,121
  • 6
  • 32
  • 66
3

Using tapply in base R:

set.seed(1)
vec <- sample(10, 20, replace = TRUE)
#[1]  3  4  6 10  3  9 10  7  7  1  3  2  7  4  8  5  8 10  4  8
unname(tapply(vec, (seq_along(vec)-1) %/% 3, sum))

# [1] 13 22 24  6 19 23 12

Alternatively,

colSums(matrix(vec[1:(ceiling(length(vec)/3)*3)], nrow = 3), na.rm = TRUE)

#[1] 13 22 24  6 19 23 12

vec[1:(ceiling(length(vec)/3)*3)] fills in the vector with NA if the length is not divisible by 3. Then, you simply ignore NAs in colSums.


Yet another one using cut and aggregate:

x <- ceiling(length(vec)/3)*3
df <- data.frame(vec=vec[1:x], col=cut(1:x, breaks = seq(0,x,3)))
aggregate(vec~col, df, sum, na.rm = TRUE)[[2]]

#[1] 13 22 24  6 19 23 12
989
  • 12,579
  • 5
  • 31
  • 53
1

you can define the window size, and do:

x <-c(1, 5, 4, 5, 7, 8, 9, 2, 1)
n <- 3
diff(c(0, cumsum(x)[slice.index(x, 1)%%n == 0]))

p.s. using the input from the answer by @Sotos

Aramis7d
  • 2,444
  • 19
  • 25
1

We can use roll_sum from RcppRoll which would be very efficient

library(RcppRoll)
roll_sum(x, n=3)[c(TRUE, FALSE, FALSE)]
#[1] 10 20 12

data

x <-c(1, 5, 4, 5, 7, 8, 9, 2, 1)
akrun
  • 874,273
  • 37
  • 540
  • 662