Christopher DuBois
Christopher DuBois

Reputation: 43420

How do I make a matrix from a list of vectors in R?

Goal: from a list of vectors of equal length, create a matrix where each vector becomes a row.

Example:

> a <- list()
> for (i in 1:10) a[[i]] <- c(i,1:5)
> a
[[1]]
[1] 1 1 2 3 4 5

[[2]]
[1] 2 1 2 3 4 5

[[3]]
[1] 3 1 2 3 4 5

[[4]]
[1] 4 1 2 3 4 5

[[5]]
[1] 5 1 2 3 4 5

[[6]]
[1] 6 1 2 3 4 5

[[7]]
[1] 7 1 2 3 4 5

[[8]]
[1] 8 1 2 3 4 5

[[9]]
[1] 9 1 2 3 4 5

[[10]]
[1] 10  1  2  3  4  5

I want:

      [,1] [,2] [,3] [,4] [,5] [,6]
 [1,]    1    1    2    3    4    5
 [2,]    2    1    2    3    4    5
 [3,]    3    1    2    3    4    5
 [4,]    4    1    2    3    4    5
 [5,]    5    1    2    3    4    5
 [6,]    6    1    2    3    4    5
 [7,]    7    1    2    3    4    5
 [8,]    8    1    2    3    4    5
 [9,]    9    1    2    3    4    5
[10,]   10    1    2    3    4    5 

Upvotes: 120

Views: 122170

Answers (7)

jan-glx
jan-glx

Reputation: 9486

data.table::transpose(a) can be a useful tool here if you your list elements have unequal size or you actually wanted a data.frame instead.

It efficiently turns a length-n list of length-up-to-p vectors into a length-p list of length-n vectors, padding the missing elements with a value of your choice.

# For list of vectors of unequal size if you want to pad instead of recycle
a <- sapply(1:6, function(i) c(i, seq_len(i)))
a
#> [[1]]
#> [1] 1 1
#> 
#> [[2]]
#> [1] 2 1 2
#> 
#> [[3]]
#> [1] 3 1 2 3
#> 
#> [[4]]
#> [1] 4 1 2 3 4
#> 
#> [[5]]
#> [1] 5 1 2 3 4 5
#> 
#> [[6]]
#> [1] 6 1 2 3 4 5 6

matrix(unlist(data.table::transpose(a)), nrow=length(a))
#>      [,1] [,2] [,3] [,4] [,5] [,6] [,7]
#> [1,]    1    1   NA   NA   NA   NA   NA
#> [2,]    2    1    2   NA   NA   NA   NA
#> [3,]    3    1    2    3   NA   NA   NA
#> [4,]    4    1    2    3    4   NA   NA
#> [5,]    5    1    2    3    4    5   NA
#> [6,]    6    1    2    3    4    5    6
#
## neat if you want a data.frame instead
data.table::setDF(data.table::as.data.table(data.table::transpose(a)))[]
#>   V1 V2 V3 V4 V5 V6 V7
#> 1  1  1 NA NA NA NA NA
#> 2  2  1  2 NA NA NA NA
#> 3  3  1  2  3 NA NA NA
#> 4  4  1  2  3  4 NA NA
#> 5  5  1  2  3  4  5 NA
#> 6  6  1  2  3  4  5  6

It is almost as fast as the matrix(unlist( ), byrow=TRUE) solution and much faster than the t(sapply( approach that also works for unequal lengths.

a <- sapply(1:6, function(i) c(i, seq_len(i)))
a
bench::mark(
  matrix(unlist(data.table::transpose(a)), nrow=length(a)),
  t(sapply(a, '[', 1:max(sapply(a, length))))
)
#> # A tibble: 2 × 6
#>   expression                                                      min   median
#>   <bch:expr>                                                 <bch:tm> <bch:tm>
#> 1 matrix(unlist(data.table::transpose(a)), nrow = length(a))   6.87µs   8.68µs
#> 2 t(sapply(a, "[", 1:max(sapply(a, length))))                 33.29µs  42.14µs
#> # ℹ 3 more variables: `itr/sec` <dbl>, mem_alloc <bch:byt>, `gc/sec` <dbl>



# small list, equal sizes
a <- sapply(1:6, function(i) c(i, seq_len(5)), simplify = FALSE)
a
#> [[1]]
#> [1] 1 1 2 3 4 5
#> 
#> [[2]]
#> [1] 2 1 2 3 4 5
#> 
#> [[3]]
#> [1] 3 1 2 3 4 5
#> 
#> [[4]]
#> [1] 4 1 2 3 4 5
#> 
#> [[5]]
#> [1] 5 1 2 3 4 5
#> 
#> [[6]]
#> [1] 6 1 2 3 4 5

bench::mark(
  matrix(unlist(data.table::transpose(a)), nrow=length(a)),
  t(sapply(a, '[', 1:max(sapply(a, length)))),
  do.call(rbind, a),
  matrix(unlist(a), byrow=TRUE, nrow=length(a) )
)
#> # A tibble: 4 × 6
#>   expression                                                      min   median
#>   <bch:expr>                                                 <bch:tm> <bch:tm>
#> 1 matrix(unlist(data.table::transpose(a)), nrow = length(a))   7.03µs   9.06µs
#> 2 t(sapply(a, "[", 1:max(sapply(a, length))))                 32.99µs  36.18µs
#> 3 do.call(rbind, a)                                            2.92µs   3.47µs
#> 4 matrix(unlist(a), byrow = TRUE, nrow = length(a))            2.77µs   3.07µs
#> # ℹ 3 more variables: `itr/sec` <dbl>, mem_alloc <bch:byt>, `gc/sec` <dbl>


# large list, equal sizes
a <- sapply(seq_len(100000), function(i) c(i, seq_len(5)), simplify = FALSE)

bench::mark(
  matrix(unlist(data.table::transpose(a)), nrow=length(a)),
  t(sapply(a, '[', 1:max(sapply(a, length)))),
  do.call(rbind, a),
  matrix(unlist(a), byrow=TRUE, nrow=length(a) )
)
#> Warning: Some expressions had a GC in every iteration; so filtering is disabled.
#> # A tibble: 4 × 6
#>   expression                                                      min   median
#>   <bch:expr>                                                 <bch:tm> <bch:tm>
#> 1 matrix(unlist(data.table::transpose(a)), nrow = length(a))  11.62ms  12.54ms
#> 2 t(sapply(a, "[", 1:max(sapply(a, length))))                 94.56ms 101.09ms
#> 3 do.call(rbind, a)                                           59.02ms  70.49ms
#> 4 matrix(unlist(a), byrow = TRUE, nrow = length(a))            7.02ms   7.82ms
#> # ℹ 3 more variables: `itr/sec` <dbl>, mem_alloc <bch:byt>, `gc/sec` <dbl>

Upvotes: -1

Kalin
Kalin

Reputation: 1761

simplify2array is a base function that is fairly intuitive. However, since R's default is to fill in data by columns first, you will need to transpose the output. (sapply uses simplify2array, as documented in help(sapply).)

> t(simplify2array(a))
      [,1] [,2] [,3] [,4] [,5] [,6]
 [1,]    1    1    2    3    4    5
 [2,]    2    1    2    3    4    5
 [3,]    3    1    2    3    4    5
 [4,]    4    1    2    3    4    5
 [5,]    5    1    2    3    4    5
 [6,]    6    1    2    3    4    5
 [7,]    7    1    2    3    4    5
 [8,]    8    1    2    3    4    5
 [9,]    9    1    2    3    4    5
[10,]   10    1    2    3    4    5

Upvotes: 21

Kalin
Kalin

Reputation: 1761

The built-in matrix function has the nice option to enter data byrow. Combine that with an unlist on your source list will give you a matrix. We also need to specify the number of rows so it can break up the unlisted data. That is:

> matrix(unlist(a), byrow=TRUE, nrow=length(a) )
      [,1] [,2] [,3] [,4] [,5] [,6]
 [1,]    1    1    2    3    4    5
 [2,]    2    1    2    3    4    5
 [3,]    3    1    2    3    4    5
 [4,]    4    1    2    3    4    5
 [5,]    5    1    2    3    4    5
 [6,]    6    1    2    3    4    5
 [7,]    7    1    2    3    4    5
 [8,]    8    1    2    3    4    5
 [9,]    9    1    2    3    4    5
[10,]   10    1    2    3    4    5

Upvotes: 18

Arihant
Arihant

Reputation: 589

t(sapply(a, '[', 1:max(sapply(a, length))))

where 'a' is a list. Would work for unequal row size

Upvotes: 8

learnr
learnr

Reputation: 6649

> library(plyr)
> as.matrix(ldply(a))
      V1 V2 V3 V4 V5 V6
 [1,]  1  1  2  3  4  5
 [2,]  2  1  2  3  4  5
 [3,]  3  1  2  3  4  5
 [4,]  4  1  2  3  4  5
 [5,]  5  1  2  3  4  5
 [6,]  6  1  2  3  4  5
 [7,]  7  1  2  3  4  5
 [8,]  8  1  2  3  4  5
 [9,]  9  1  2  3  4  5
[10,] 10  1  2  3  4  5

Upvotes: 3

Paolo
Paolo

Reputation: 2815

Not straightforward, but it works:

> t(sapply(a, unlist))
      [,1] [,2] [,3] [,4] [,5] [,6]
 [1,]    1    1    2    3    4    5
 [2,]    2    1    2    3    4    5
 [3,]    3    1    2    3    4    5
 [4,]    4    1    2    3    4    5
 [5,]    5    1    2    3    4    5
 [6,]    6    1    2    3    4    5
 [7,]    7    1    2    3    4    5
 [8,]    8    1    2    3    4    5
 [9,]    9    1    2    3    4    5
[10,]   10    1    2    3    4    5

Upvotes: 12

Christopher DuBois
Christopher DuBois

Reputation: 43420

One option is to use do.call():

 > do.call(rbind, a)
      [,1] [,2] [,3] [,4] [,5] [,6]
 [1,]    1    1    2    3    4    5
 [2,]    2    1    2    3    4    5
 [3,]    3    1    2    3    4    5
 [4,]    4    1    2    3    4    5
 [5,]    5    1    2    3    4    5
 [6,]    6    1    2    3    4    5
 [7,]    7    1    2    3    4    5
 [8,]    8    1    2    3    4    5
 [9,]    9    1    2    3    4    5
[10,]   10    1    2    3    4    5

Upvotes: 142

Related Questions