Slash
Slash

Reputation: 509

How to convert 2D data frame to 3D matrix, preserving row and column order

I would like to convert a 2D data frame into a 3D matrix, while preserving row and column order.

I have some data like so:

dat<-  data.frame(obs = rep(1:3,2),
  LET=c('A','A','A','B','B','B'),
            x1=c('a','b','c','d','e','f'),
            x2=c('g','h','i','j','k','l')) 
  obs LET x1 x2
1   1   A  a  g
2   2   A  b  h
3   3   A  c  i
4   1   B  d  j
5   2   B  e  k
6   3   B  f  l

And I'd like to create a 3D matrix, where the output looks like this:

, , 1

     [,1] [,2] [,3] [,4]
[1,] "1"  "A"  "a"  "g" 
[2,] "1"  "B"  "d"  "j" 

, , 2

     [,1] [,2] [,3] [,4]
[1,] "2"  "A"  "b"  "h" 
[2,] "2"  "B"  "e"  "k" 

, , 3

     [,1] [,2] [,3] [,4]
[1,] "3"  "A"  "c"  "i" 
[2,] "3"  "B"  "f"  "l" 

Where each "layer" is a different obs of two LETs and their x values. When I do dim(dat) <- c(2,4,3) the order isn't preserved the way I'd like it to be, I'm not sure how to shape it in order to get the right format.

Upvotes: 3

Views: 212

Answers (1)

akrun
akrun

Reputation: 887223

One option is split the data into a list, create an array of specified dimensions and assign the values of the list to it

lst1 <- split(dat, dat$obs)
ar1 <- array(dim = c(dim(lst1[[1]]), length(lst1)))
for(i in seq_along(lst1)) ar1[,,i] <- as.matrix(lst1[[i]])
ar1
#, , 1

#     [,1] [,2] [,3] [,4]
#[1,] "1"  "A"  "a"  "g" 
#[2,] "1"  "B"  "d"  "j" 

#, , 2

#     [,1] [,2] [,3] [,4]
#[1,] "2"  "A"  "b"  "h" 
#[2,] "2"  "B"  "e"  "k" 

#, , 3

#     [,1] [,2] [,3] [,4]
#[1,] "3"  "A"  "c"  "i" 
#[2,] "3"  "B"  "f"  "l" 

Or convert to character class for all the columns, do the split, unlist the list and create the array

dat[] <- lapply(dat, as.character)
lst1 <- split(dat, dat$obs)
array(unlist(lst1), c(dim(lst1[[1]]), length(lst1)))

Upvotes: 2

Related Questions