22

Does R have a base function to bind matrices in a block-diagonal shape?

The following does the job, but I'd like to know if there is a standard way:

a <- matrix(1:6, 2, 3)
b <- matrix(7:10, 2, 2)

rbind(cbind(a, matrix(0, nrow=nrow(a), ncol=ncol(b))),
      cbind(matrix(0, nrow=nrow(b), ncol=ncol(a)), b))

#     [,1] [,2] [,3] [,4] [,5]
#[1,]    1    3    5    0    0
#[2,]    2    4    6    0    0
#[3,]    0    0    0    7    9
#[4,]    0    0    0    8   10
Ferdinand.kraft
  • 12,579
  • 10
  • 47
  • 69
  • For fixed block-diagonal matrices see https://stackoverflow.com/questions/47955114/build-a-block-diagonal-matrix-from-a-known-matrix – JStrahl Sep 18 '18 at 12:41

2 Answers2

32

adiag from a package magic does what you want:

library(magic)
adiag(a,b)
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    3    5    0    0
[2,]    2    4    6    0    0
[3,]    0    0    0    7    9
[4,]    0    0    0    8   10

Alternatively, you could use a package Matrix and function bdiag

library(Matrix)
bdiag(a,b)
4 x 5 sparse Matrix of class "dgCMatrix"

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

that returns a sparse matrix and which might be more efficient. Use as.matrix(bdiag(a,b)) to get a regular one.

MichaelChirico
  • 33,841
  • 14
  • 113
  • 198
Julius Vainora
  • 47,421
  • 9
  • 90
  • 102
  • 2
    Adding for `adiag` that if your matrices are stored in a list (e.g. `lst<-list(a,b)`), you'll need to use `Reduce(adiag,lst)` since it doesn't seem to know how to parse the list natively – MichaelChirico Aug 05 '15 at 22:02
0
foo = function(...){
    d = list(...)
    nrows = sum(sapply(d, NROW))
    ncols = sum(sapply(d, NCOL))
    ans = matrix(0, nrows, ncols)
    i1 = 1
    j1 = 1        
    for (m in d){
        i2 = i1 + NROW(m) - 1
        j2 = j1 + NCOL(m) - 1
        ans[i1:i2, j1:j2] = m
        i1 = i2 + 1
        j1 = j2 + 1
    }
    return(ans)
}

foo(a, b)
#      [,1] [,2] [,3] [,4] [,5]
# [1,]    1    3    5    0    0
# [2,]    2    4    6    0    0
# [3,]    0    0    0    7    9
# [4,]    0    0    0    8   10
d.b
  • 32,245
  • 6
  • 36
  • 77