Imagine you have a 3-dimensional array with rows, columns, and layers:
A <- array (1:27, c(3,3,3))
and imagine you have a function that takes a matrix as input and returns a matrix as output, like t
.
How can you apply the function to each layer of the array, returning another array of the same size as the first?
I feel like I ought to be able to do it with apply
somehow, but I can't.
Bonus question (I'd be very grateful if you answered this): is it faster to do this, or to make a list of each of the layer matrices and lapply
the function to them?
--
Edit: please don't think that this question is answered - the answer below does not answer the question.
You can think the array as a table with 3 rows and each row has 4 columns. Similarly, you can declare a three-dimensional (3d) array. For example, float y[2][4][3];
A three-way array X (or three-dimensional matrix) is an array of numbers xijk subscripted by three indices. A triad is a multiplicative array, xijk = aibjck.
You have to think about which margin(s) over which you wish to extract the values.
you can transpose each of the 3rd
dimension matrices by applying over dimensions 1 and 2 (rows and columns for want of a better word)
apply(A,1:2,t)
, , 1
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 10 11 12
[3,] 19 20 21
, , 2
[,1] [,2] [,3]
[1,] 4 5 6
[2,] 13 14 15
[3,] 22 23 24
, , 3
[,1] [,2] [,3]
[1,] 7 8 9
[2,] 16 17 18
[3,] 25 26 27
You can also use plyr
and aaply
which may act more intuitively
library(plyr)
aaply(A,3,t)
, , = 1
X1 1 2 3
1 1 4 7
2 10 13 16
3 19 22 25
, , = 2
X1 1 2 3
1 2 5 8
2 11 14 17
3 20 23 26
, , = 3
X1 1 2 3
1 3 6 9
2 12 15 18
3 21 24 27
As to which is faster lapply
or apply
, I would think perhaps lapply
would win, but you would still have to do the thinking about which margins you wanted to extract the matrices from.
I usually find it far easier to think in one dimension. Everything would be more straight forward if the earth were flat!
Another possibility for the transposition is function aperm
.
A <- array (1:27, c(3,3,3))
# aperm permute the dimensions in the given order
# here we want to permute dimension 1 and 2
# so the new order is 2-1-3 instead of 1-2-3
aperm(A, c(2,1,3))
, , 1
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 4 5 6
[3,] 7 8 9
, , 2
[,1] [,2] [,3]
[1,] 10 11 12
[2,] 13 14 15
[3,] 16 17 18
, , 3
[,1] [,2] [,3]
[1,] 19 20 21
[2,] 22 23 24
[3,] 25 26 27
As far as applying a function to each layer (say you want to multiply each layer by a different value) is concerned, here's another possibility:
vec <- c(1,5,3)
lapply(seq_along(vec), function(x)A[,,x]*vec[x])
[[1]]
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
[[2]]
[,1] [,2] [,3]
[1,] 50 65 80
[2,] 55 70 85
[3,] 60 75 90
[[3]]
[,1] [,2] [,3]
[1,] 57 66 75
[2,] 60 69 78
[3,] 63 72 81
But as you see it creates a list, so it needs one more step using function simplify2array
:
simplify2array(lapply(seq_along(vec),function(x)A[,,x]*vec[x]))
, , 1
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
, , 2
[,1] [,2] [,3]
[1,] 50 65 80
[2,] 55 70 85
[3,] 60 75 90
, , 3
[,1] [,2] [,3]
[1,] 57 66 75
[2,] 60 69 78
[3,] 63 72 81
Or directly with sapply
:
sapply(seq_along(vec), function(x)A[,,x]*vec[x], simplify="array")
, , 1
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
, , 2
[,1] [,2] [,3]
[1,] 50 65 80
[2,] 55 70 85
[3,] 60 75 90
, , 3
[,1] [,2] [,3]
[1,] 57 66 75
[2,] 60 69 78
[3,] 63 72 81
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With