0

Not a duplicate of rollapply for two-dimensional arrays (R), but rather an elaboration upon it - what I actually want to do is slightly more complicated than described in that question. I hoped that any answer to that question would easily extend to a solution for my actual problem, but that unfortunately proved not to be the case.

For simple vectors we have

> a <- c(1:4)
> a
[1] 1 2 3 4
> rollapply(a, 2, mean)
[1] 1.5 2.5 3.5

which is as it should be. While rollapply itself is limited to one-dimensional vectors, several very helpful answers such as this one by akrun allowed me to extend this to two-dimensional arrays in a multitude of ways.

Unfortunately, I am now stuck again, because I do not see how any of the answers generalize to higher dimensions than two (*). Taking an array b

> b <- array(rep(c(1:4),each=6), c(2,3,4))
> b
, , 1

     [,1] [,2] [,3]
[1,]    1    1    1
[2,]    1    1    1

, , 2

     [,1] [,2] [,3]
[1,]    2    2    2
[2,]    2    2    2

, , 3

     [,1] [,2] [,3]
[1,]    3    3    3
[2,]    3    3    3

, , 4

     [,1] [,2] [,3]
[1,]    4    4    4
[2,]    4    4    4

there should be some way to take means over a window-size of 2 to yield

, , 1

     [,1] [,2] [,3]
[1,]  1.5  1.5  1.5
[2,]  1.5  1.5  1.5

, , 2

     [,1] [,2] [,3]
[1,]  2.5  2.5  2.5
[2,]  2.5  2.5  2.5

, , 3

     [,1] [,2] [,3]
[1,]  3.5  3.5  3.5
[2,]  3.5  3.5  3.5

but I do not see how (obviously in real cases the sub-arrays would not consist of just repeating the same integer throughout the array, but would contain actual data).

Ideally, I would also like to be able to assign different weights to the various sub-arrays in the window for the purposes of the averaging, but I assume that would just be a matter of defining a custom function to apply.

(*) Perhaps there is an obvious way, but it's late where I am and I'm not finding it.

Drubbels
  • 327
  • 2
  • 4
  • 11
  • 2
    Do you need `apply(b, c(1,2), FUN = function(x) rollapply(x, 2, FUN = mean))` – akrun May 12 '21 at 22:10
  • 1
    I was confused that this doesn't seem to do what I'm asking for - but it does seem to work when combined with `aperm`! – Drubbels May 12 '21 at 22:19
  • 1
    Thanks again. As a plus, this whole escapade has lead to me *finally* discovering `aperm`. I knew that R had to have some equivalent of NumPy's `swapaxes`, but hadn't been able to find it yet. – Drubbels May 12 '21 at 22:21

2 Answers2

1

I couldn't get zoo::rollapply to work (as an external call, unlike its use internally in one of the comments), but one can mimic much of its behavior by controlling the input vector externally (seq_len(dim(b)[3])[-1]) and the "window" ([-1] externally, and i-1:0 internally). From there, it's just a mean of one dim of an array:

sapply(seq_len(dim(b)[3])[-1],
       function(i) apply(b[,,i-1:0,drop=FALSE], 1:2, mean),
       simplify="array")
# , , 1
#      [,1] [,2] [,3]
# [1,]  1.5  1.5  1.5
# [2,]  1.5  1.5  1.5
# , , 2
#      [,1] [,2] [,3]
# [1,]  2.5  2.5  2.5
# [2,]  2.5  2.5  2.5
# , , 3
#      [,1] [,2] [,3]
# [1,]  3.5  3.5  3.5
# [2,]  3.5  3.5  3.5
r2evans
  • 141,215
  • 6
  • 77
  • 149
1

The problem with apply is that it can do an implicit transpose of dimensions but aaply in the plyr package is similar but without the implicit transpose.

library(plyr)
library(zoo)

aaply(b, 1:2, rollmean, 2)

giving:

   X2
X1    1   2   3
  1 1.5 1.5 1.5
  2 1.5 1.5 1.5

, ,  = 2

   X2
X1    1   2   3
  1 2.5 2.5 2.5
  2 2.5 2.5 2.5

, ,  = 3

   X2
X1    1   2   3
  1 3.5 3.5 3.5
  2 3.5 3.5 3.5
G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341