1

I have data frame in R that looks like this :

a b
8 -16
19 -26
30 -36
41 -46
52 -56

I want to slide it or rollapply it with width 3 in both columns and calculate the the sum of the two minimum.

BUT.!!!!

I want progressively go tho width 3 starting with width (3+1)/2 = 2 and then go to width 3.

In my example must start with the first 2 rows:

a b
8 -16
19 -26

result must be the sum of the minimums of columns a and b 8+(-26)=-18 next

a b
8 -16
19 -26
30 -36

result must be the sum of the minimums of columns a and b 8+(-36)=-28

next

a b
19 -26
30 -36
41 -46

19-46 = -27

next

a b
30 -36
41 -46
52 -56

30-56 = -26

and last

a b
41 -46
52 -56

41-56=-15.

The width must be 2,3,3,3,2.

In general if this data frame had 100 rows with window 13 it will start from top to bottom with window (or width) (13+1)/2 = 7, then it will continue to 8,9,10,12,13,13,...,13,12,11,10,9,8,7.

How can I do this in R ?

library(tidyverse)

a = c(800,1900,3000,4100,5200)
b = c(-1600,-2600,-3600,-4600,-5600)

w = tibble(a,b)


Homer Jay Simpson
  • 1,043
  • 6
  • 19
  • In the dummy example, can you explain why the width is 2 for first and last – akrun Oct 20 '22 at 17:40
  • it is (width+1)/2.In the example is 3.So it will be (3+1)/2=2.For the general case it will be (width+1)/2 and progressively by 1 go to width and at the end will stop to (width+1)/2 – Homer Jay Simpson Oct 20 '22 at 17:43
  • I think your first sum is -18 as `8 + -26# [1] -18` and not `-16` – akrun Oct 20 '22 at 17:53

2 Answers2

3

We may use rollapply from zoo with partial = TRUE to loop over the sequence of rows, subset the data based on the index, get the min from columns (sapply(..., min)) and get the sum of those

library(zoo)
wd <- 3
rollapply(seq_len(nrow(df1)), FUN = function(i) sum(sapply(df1[i,],
            min)), width = wd, partial = TRUE)
[1] -18 -28 -27 -26 -15

data

df1 <- structure(list(a = c(8L, 19L, 30L, 41L, 52L), b = c(-16L, -26L, 
-36L, -46L, -56L)), class = "data.frame", row.names = c(NA, -5L
))
akrun
  • 874,273
  • 37
  • 540
  • 662
  • 2
    or maybe `rowSums(rollapply(df1, 3, min, partial = TRUE))` – G. Grothendieck Oct 20 '22 at 18:03
  • @G.Grothendieck @akrun if i had a simple vector instead of a data frame say :`a = c(800,1900,3000,4100,5200)` how this rolling-sliding procedure can be done ? – Homer Jay Simpson Oct 21 '22 at 08:54
  • 1
    @HomerJaySimpson it can be directly applied asin data.frame i.e. `rollapply(v1, 3, min, partial = TRUE)#1] 800 800 1900 3000 4100`. Here, there is no need to sum as only a single vector – akrun Oct 21 '22 at 14:36
2

in Base R you could do:

fn <- function(x, window){
  na <- rep(NA, ceiling((window-1)/2))
  apply(embed(c(na, x, na), window),1, min, na.rm = TRUE)
}

rowSums(sapply(df,fn, 3))

[1] -18 -28 -27 -26 -15
Onyambu
  • 67,392
  • 3
  • 24
  • 53