Reputation: 3233
I am looking to expand my 2D matrix to a 3D by applying a function to each row of matrix and returning a matrix, so that i can have a 3D matrix.
The simplest example i can think of to reproduce is, say I have a 3x3 Matrix A, i want to convert each row of A into a diagonal matrix so that now i have a 3D matrix.
testmat <- matrix(c(1,2,3,4,5,6,7,8,9), nrow = 3, byrow = TRUE) #create matrix
tesmatapply <- apply(testmat, 1, function(r) matrix(c(r[1], 0, 0, 0, r[2], 0, 0, 0, r[3]), nrow = 3, byrow= TRUE))
What i want is for testmatapply to be a 3x3x3 matrix so that tesmatapply[,,1] gives me a 3x3 diagonal matrix diag(1,2,3) corresponding to first row
But apply returns a flattened vector. leading to a 9x3 matrix How can i avoid this?
EDIT:
Basically, my expected output is an array such that:
testapply[,,1]
[,1] [,2] [,3]
[1,] 1 0 0
[2,] 0 2 0
[3,] 0 0 3
testapply[,,2]
[,1] [,2] [,3]
[1,] 4 0 0
[2,] 0 5 0
[3,] 0 0 6
testapply[,,3]
[,1] [,2] [,3]
[1,] 7 0 0
[2,] 0 8 0
[3,] 0 0 9
However i am getting a 9x3 matrix:
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 0 0 0
[3,] 0 0 0
[4,] 0 0 0
[5,] 2 5 8
[6,] 0 0 0
[7,] 0 0 0
[8,] 0 0 0
[9,] 3 6 9
Upvotes: 0
Views: 509
Reputation: 887971
We can create a list
of matrix
es
lapply(split(testmat, row(testmat)), `*`, diag(3))
#$`1`
# [,1] [,2] [,3]
#[1,] 1 0 0
#[2,] 0 2 0
#[3,] 0 0 3
#$`2`
# [,1] [,2] [,3]
#[1,] 4 0 0
#[2,] 0 5 0
#[3,] 0 0 6
#$`3`
# [,1] [,2] [,3]
#[1,] 7 0 0
#[2,] 0 8 0
#[3,] 0 0 9
If we need an array
as output, another option is
a1 <- replicate(3, diag(3))
replace(a1, a1==1, t(testmat))
#, , 1
# [,1] [,2] [,3]
#[1,] 1 0 0
#[2,] 0 2 0
#[3,] 0 0 3
#, , 2
# [,1] [,2] [,3]
#[1,] 4 0 0
#[2,] 0 5 0
#[3,] 0 0 6
#, , 3
# [,1] [,2] [,3]
#[1,] 7 0 0
#[2,] 0 8 0
#[3,] 0 0 9
Upvotes: 1
Reputation: 1877
You can simply use the array
function specifying the number of dimensions (3x3x3):
## The data
testmat <- matrix(c(1,2,3,4,5,6,7,8,9), nrow = 3, byrow = TRUE) #create matrix
## The array
array(apply(testmat, 1, diag), dim = c(3,3,3))
#, , 1
#
# [,1] [,2] [,3]
#[1,] 1 0 0
#[2,] 0 2 0
#[3,] 0 0 3
#
#, , 2
#
# [,1] [,2] [,3]
#[1,] 4 0 0
#[2,] 0 5 0
#[3,] 0 0 6
#
#, , 3
#
# [,1] [,2] [,3]
#[1,] 7 0 0
#[2,] 0 8 0
#[3,] 0 0 9
[edit]
I've replace the original apply
function by diag
as righlty suggested by @Tom. Of course, you can replace diag
by any more complex function.
Upvotes: 2