Make a list of matrices where each matrix is one row of dataframe

184 Views Asked by At

I would like to make a list of 2x2 matrices, where each row of a dataframe becomes a 2x2 matrix. I will be working with a huge dataset (toy example for convenience) so I am trying to figure out how to do this without for loops. I have been trying to do this using a homemade function and apply() but I get an error message.

dat<-data.frame(x1=c(2,3,4),
               x2=c(1,2,3),
               x3=c(5,76,7),
               x4=c(4,6,0))

make_matrix<-function(df){
  with(dat, matrix(c(x1,x2,x3, x4),byrow=T,nrow=2, ncol=2))
  }

apply(dat, 1, FUN=make_matrix)
  
Error in eval(substitute(expr), data, enclos = parent.frame()) : 
  numeric 'envir' arg not of length one 

2

There are 2 best solutions below

0
On BEST ANSWER

We could use asplit

lapply(asplit(dat, 1), matrix, 2, 2, byrow = TRUE)

-output

#[[1]]
#     [,1] [,2]
#[1,]    2    1
#[2,]    5    4

#[[2]]
#     [,1] [,2]
#[1,]    3    2
#[2,]   76    6

#[[3]]
#     [,1] [,2]
#[1,]    4    3
#[2,]    7    0

The OP's function argument and the body is not matching i.e. it takes an argument 'df' and inside the function uses dat. But, that is not the only issue. When we loop over the row, it is a vector of values and with will not work on those. As we need a list, the matrix can be wrapped in a list

make_matrix <- function(x) list(matrix(x, byrow = TRUE, ncol = 2, nrow = 2))

should work

do.call(c, apply(dat, 1, make_matrix))
#[[1]]
#     [,1] [,2]
#[1,]    2    1
#[2,]    5    4

#[[2]]
#     [,1] [,2]
#[1,]    3    2
#[2,]   76    6

#[[3]]
#     [,1] [,2]
#[1,]    4    3
#[2,]    7    0
0
On

Here is another option using array

mat <- array(c(t(dat)), c(2, 2, 3))
mat[] <- apply(mat, 3, t)

which gives

> mat
, , 1

     [,1] [,2]
[1,]    2    1
[2,]    5    4

, , 2

     [,1] [,2]
[1,]    3    2
[2,]   76    6

, , 3

     [,1] [,2]
[1,]    4    3
[2,]    7    0

If you want to have result in the form of list, you can try

Map(t, asplit(array(c(t(dat)), c(2, 2, 3)), 3))

which gives

[[1]]
     [,1] [,2]
[1,]    2    1
[2,]    5    4

[[2]]
     [,1] [,2]
[1,]    3    2
[2,]   76    6

[[3]]
     [,1] [,2]
[1,]    4    3
[2,]    7    0