2

I have a function that creates a 2-D array from a vector. I'd like to apply this function to each row of a matrix, to get a 3-D array in which the rows correspond to rows of the input matrix, and dimensions 2 and 3 correspond to dimensions 1 and 2 of the function output.

Note that speed is important here, so I'd like to vectorize as much as possible.

The following code does what I want, but the reshaping at the end is confusing. I feel like there must be a more straightforward way?


# Vectorized apply a function across rows of a matrix to yield a 3-D array

# Create 2x4 matrix
mat <- matrix(1:8, ncol = 4)

# Function to create 1 x 4 x 3 array from vector
rep.fun <- function(x) {
  array(rep(x, times = 3), dim = c(1, length(x), 3))
}

# Use apply to apply the function; then reshape the resulting array in a confusing way

array(t(apply(mat, MARGIN = 1, FUN = rep.fun)), dim = c(2, 4, 3))

#> , , 1
#> 
#>      [,1] [,2] [,3] [,4]
#> [1,]    1    3    5    7
#> [2,]    2    4    6    8
#> 
#> , , 2
#> 
#>      [,1] [,2] [,3] [,4]
#> [1,]    1    3    5    7
#> [2,]    2    4    6    8
#> 
#> , , 3
#> 
#>      [,1] [,2] [,3] [,4]
#> [1,]    1    3    5    7
#> [2,]    2    4    6    8

This questions seems to be asking more or less the same thing, but remains unanswered.

Drew Steen
  • 16,045
  • 12
  • 62
  • 90
  • `aperm(apply(matrix(1:8, ncol = 4), 1:2, rep, 3), c(2, 3, 1))`? In this particular case, you can just use recycling: `array(matrix(1:8, ncol = 4), c(2, 4, 3))` – alistaire Mar 08 '18 at 17:53

1 Answers1

2

Your approach is perfectly fine, but the following one might look more intuitive. First we apply your function to each row of the matrix and get a list:

arrs <- sapply(1:nrow(mat), function(i) rep.fun(mat[i, ]), simplify = FALSE)

and then we bind these results along the first dimension:

library(abind)
abind(arrs, along = 1)
Julius Vainora
  • 47,421
  • 9
  • 90
  • 102