3

I have a list (of 100 members) each of whose member is a 4*2 matrix. How to convert this list into a array of dimension 400*2 with out using loop in R?

For example

A<-list()


A[[1]] 
        x         y
    85.56384 27.97745
    85.58448 28.02133
    85.60252 27.96366
    85.62318 28.00753

and so on and lastly

A[[100]]
         x         y
     85.58448 28.02133
     85.60500 28.06502
     85.62317 28.00754
     85.64372 28.05122

I want to have A<-

      x         y
    85.56384 27.97745
    85.58448 28.02133
    85.60252 27.96366
    85.62318 28.00753
         :        :
    85.58448 28.02133
    85.60500 28.06502
    85.62317 28.00754
    85.64372 28.05122

Thanks for helps.

Janak
  • 653
  • 7
  • 25
  • Add reproducing example. – Colonel Beauvel Feb 05 '15 at 08:49
  • possible duplicate of [How to convert a list to a matrix more efficiently in R?](http://stackoverflow.com/questions/13224553/how-to-convert-a-list-to-a-matrix-more-efficiently-in-r) –  Feb 05 '15 at 08:51
  • 1
    I would suggest `rbindlist` from `data.table` package or `unnest` from `tidyr` package. Take a look [here](http://stackoverflow.com/questions/28135192/converting-list-of-data-frames-to-a-data-table/), for example – David Arenburg Feb 05 '15 at 08:58
  • @Pascal Thanks for attention. Could you please suggest how to modify the answers code (given in the mentioned link ) can be used to solve my problem? It is dealing with the list of vectors and not straight forward to extend to the case of matrices of any order. – Janak Feb 05 '15 at 09:04
  • @DavidArenburg: Your suggestions are great for lists of `data.frame` objects , but they don't work so well for a list of `matrix` objects. Conversion to `data.frame` will take longer than the `rbind`. – shadow Feb 05 '15 at 09:07
  • @shadow you probably right, I didn't test it on matrices. – David Arenburg Feb 05 '15 at 09:17

3 Answers3

8

Here's a benchmark test of the different strategies that were suggested. Feel free to update if you have new ideas / strategies.

# packages
require(data.table)
require(tidyr)
require(microbenchmark)

# data
lst <- replicate(100, matrix(rnorm(16), ncol = 4), simplify = FALSE)
# benchmark test
microbenchmark(
  do.call(rbind, lst), 
  Reduce(rbind, lst), 
  apply(simplify2array(lst), 2, rbind), 
  rbindlist(lapply(lst, data.frame)), 
  unnest(lapply(lst, data.frame))
  )

And the results:

Unit: microseconds
                                 expr       min         lq        mean     median        uq       max neval  
                  do.call(rbind, lst)    43.290    47.9760    55.63858    52.8845    62.703   101.307   100  
                   Reduce(rbind, lst)   542.236   570.7985   620.99652   585.3020   610.518  1871.272   100  
 apply(simplify2array(lst), 2, rbind)   311.061   345.2010   382.22978   368.6315   388.268  1563.782   100  
   rbindlist(lapply(lst, data.frame)) 11827.884 12472.3190 13092.57937 12823.0995 13595.841 15833.736   100   
      unnest(lapply(lst, data.frame)) 12371.905 12927.9765 13514.24261 13236.1360 14008.655 16121.143   100  

Just out of curiosity, I have performed these benchmark tests for data.frame inputs as well and there the picture is very different:

# packages
require(data.table)
require(tidyr)
require(microbenchmark)
# data
lst <- replicate(100, as.data.frame(matrix(rnorm(16), ncol = 4)), simplify=FALSE)
# benchmark test
microbenchmark(
  do.call(rbind, lst), 
  Reduce(rbind, lst), 
  apply(simplify2array(lapply(lst, as.matrix)), 2, rbind), 
  rbindlist(lst), 
  unnest(lst)
)

with results:

Unit: microseconds
                                                    expr       min         lq       mean    median        uq        max neval 
                                     do.call(rbind, lst) 12406.716 12944.2660 13746.8552 13571.966 14564.056  16333.128   100    
                                      Reduce(rbind, lst) 36316.866 38450.7765 39894.9806 39299.610 40325.395 100949.158   100    
 apply(simplify2array(lapply(lst, as.matrix)), 2, rbind)  9577.717  9940.9930 10273.8674 10065.059 10291.996  12114.846   100    
                                          rbindlist(lst)   324.896   369.0770   397.7828   402.995   426.202    500.732   100  
                                             unnest(lst)   926.487   974.9095  1011.7322  1010.834  1033.596   1171.051   100 
slamballais
  • 3,161
  • 3
  • 18
  • 29
shadow
  • 21,823
  • 4
  • 63
  • 77
3

You can use Reduce:

> lst=list(matrix(1:16, ncol=4), matrix(4:23, ncol=4))
[[1]]
     [,1] [,2] [,3] [,4]
[1,]    1    5    9   13
[2,]    2    6   10   14
[3,]    3    7   11   15
[4,]    4    8   12   16

[[2]]
     [,1] [,2] [,3] [,4]
[1,]    4    9   14   19
[2,]    5   10   15   20
[3,]    6   11   16   21
[4,]    7   12   17   22
[5,]    8   13   18   23

> Reduce(rbind, lst)
      [,1] [,2] [,3] [,4]
 [1,]    1    5    9   13
 [2,]    2    6   10   14
 [3,]    3    7   11   15
 [4,]    4    8   12   16
 [5,]    4    9   14   19
 [6,]    5   10   15   20
 [7,]    6   11   16   21
 [8,]    7   12   17   22
 [9,]    8   13   18   23

As per @Roland suggestion, avoid Reduce :)

#> lst=lapply(1:100000, function(u) m+u)
#> system.time(do.call(rbind, lst))
#   user  system elapsed 
#   0.37    0.01    0.39 
#> system.time(Reduce(rbind, lst))
#   user  system elapsed 
# 704.94   38.66  743.96 
Colonel Beauvel
  • 30,423
  • 11
  • 47
  • 87
0

#Easiest solution

lst <- replicate(100, matrix(rnorm(16), ncol=4), simplify=FALSE)

mat_array <- do.call(rbind, lst) #this is the answer

ra<-simplify2array(lst) #collection of matrices in an array

dim(ra)

#[1]   4   4 100

Help function for simplify2array