Search code examples
rmatrixerror-handlingapplydo.call

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


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 


Solution

  • 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