Vikash Balasubramanian
Vikash Balasubramanian

Reputation: 3233

R expand matrix dimensions using apply

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

Answers (2)

akrun
akrun

Reputation: 887971

We can create a list of matrixes

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

Thomas Guillerme
Thomas Guillerme

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

Related Questions