1

I am following the thread 2d matrix to 3d stacked array in r and have a clarification on the aperm function.

1) I get the first part of the solution, but did not understand the c(2,1,3) used in the function. Could you kindly clarify that?

2) Also I am trying a slight variation of the example in that thread.

My case is as follows: For a similar matrix in example:

      set.seed(1)
      mat <- matrix(sample(100, 12 * 5, TRUE), ncol = 5)


    [,1] [,2] [,3] [,4] [,5]
 [1,]   27   69   27   80   74
 [2,]   38   39   39   11   70
 [3,]   58   77    2   73   48
 [4,]   91   50   39   42   87
 [5,]   21   72   87   83   44
 [6,]   90  100   35   65   25
 [7,]   95   39   49   79    8
 [8,]   67   78   60   56   10
 [9,]   63   94   50   53   32
[10,]    7   22   19   79   52
[11,]   21   66   83    3   67
[12,]   18   13   67   48   41

I am trying to rearrange such that I have a 3 (row) X 5 (col) x 11 (third dim) array. So, essentially the rows would overlap and show something like:

,,1
    27   69   27   80   74
    38   39   39   11   70
    58   77    2   73   48

,,2
   38   39   39   11   70
   58   77    2   73   48
   91   50   39   42   87

,,3
  58   77    2   73   48
  91   50   39   42   87
  21   72   87   83   44
and so on until we hit ,,11

Would someone have any experience with this? Thanks!

FlyingPickle
  • 1,047
  • 1
  • 9
  • 19

1 Answers1

1

Just stumbled over this question. Though the answer comes a little late, here are two options for you.

First, you need to extend mat in such a way that it's rows overlap. We can use this vector for row indexing.

#[1] 1  2  3  2  3  4  3  4  5  4  5  6  5  6  7  6  7  8  7  8  9  8  9 10  9 10 11 10 11 12

I used rollapply from the zoo package to create it as follows:

library(zoo)
row_nums <- c(t(rollapply(1:nrow(mat), width = 3, FUN = rep, 1)))

mat <- mat[row_nums, ]
dim(mat)
#[1] 30  5

Now use the matsplitter function that @Mr.Flick provided in this answer (please consider to upvote his answer) to get the desired output:

matsplitter(mat, 3, 5)
#, , 1
#
#     [,1] [,2] [,3] [,4] [,5]
#[1,]   27   69   27   80   74
#[2,]   38   39   39   11   70
#[3,]   58   77    2   73   48
#
#, , 2
#
#     [,1] [,2] [,3] [,4] [,5]
#[1,]   38   39   39   11   70
#[2,]   58   77    2   73   48
#[3,]   91   50   39   42   87
#
#, , 3
#
#     [,1] [,2] [,3] [,4] [,5]
#[1,]   58   77    2   73   48
#[2,]   91   50   39   42   87
#[3,]   21   72   87   83   44
#
#, , 4
# ...

Note that you will end up with an array of dimension 3 x 5 x 10, not 11.

matsplitter <- function(M, r, c) {
  rg <- (row(M) - 1) %/% r + 1
  cg <- (col(M) - 1) %/% c + 1
  rci <- (rg - 1) * max(cg) + cg
  N <- prod(dim(M)) / r / c
  cv <- unlist(lapply(1:N, function(x)
    M[rci == x]))
  dim(cv) <- c(r, c, N)
  cv
}

Here is a solution using aperm as in the linked answer (assuming that mat was extended as above and is of dimension 30 x 5).

aperm(`dim<-`(t(mat), list(5, 3, 10)), c(2, 1, 3))
  • t(mat): transposes mat (new dimension: 5 x 30)
  • `dim<-`(t(mat), list(5, 3, 10)): changes the dimension of t(mat) from 5 X 30 to 5 x 3 x 10
  • aperm(..., c(2, 1, 3)) permutes the dimensions of the array `dim<-`(t(mat), list(5, 3, 10)) from 5 x 3 x 10 to 3 x 5 x 10, i.e. the second dimension becomes the first, the first dimension becomes the second and the third dimension stays the same.
markus
  • 25,843
  • 5
  • 39
  • 58