Hello List
I have just written a little function that takes two matrices as
arguments and returns a large matrix that is composed of the two input
matrices in upper-left position and lower-right position with a padding
value everywhere else. (function definition and toy example below). I
need nonsquare matrices and rowname() and colname() inherited appropriately.
Two questions:
(1) Is there a better way to do this? (kronecker() isn't applicable here)
(2) How do I generalize it to take an arbitrary number of matrices as
inputs?
TIV
Robin
"blockdiag" <-
function (m1, m2, p.tr = 0, p.ll = 0)
{
## p.tr and p.ll are padding values
topleft <- m1
topright <- matrix(p.tr, nrow(m1), ncol(m2))
colnames(topright) <- colnames(m2)
lowleft <- matrix(p.ll, nrow(m2), ncol(m1))
lowright <- m2
rbind(cbind(topleft, topright), cbind(lowleft, lowright))
}
m1 <-
structure(c(1, 1, 3, 1, 3, 4), .Dim = as.integer(c(2, 3)), .Dimnames = list(
c("a", "b"), c("x", "y",
"z")))
m2 <-
structure(c(2, 1, 1, 0, 3, 2, 2, 2, 0), .Dim = as.integer(c(3,
3)), .Dimnames = list(c("I", "II", "III"),
c("A", "B", "C")))
R> m1
x y z
a 1 3 3
b 1 1 4
R> m2
A B C
I 2 0 2
II 1 3 2
III 1 2 0
R> blockdiag(m1,m2)
x y z A B C
a 1 3 3 0 0 0
b 1 1 4 0 0 0
I 0 0 0 2 0 2
II 0 0 0 1 3 2
III 0 0 0 1 2 0
R>
--
Robin Hankin
Uncertainty Analyst
Southampton Oceanography Centre
SO14 3ZH
tel +44(0)23-8059-7743
initialDOTsurname at soc.soton.ac.uk (edit in obvious way; spam precaution)
Dear Robin,
you could use the following function which has been submitted to
s-news some time ago:
bdiag <- function(x){
if(!is.list(x)) stop("x not a list")
n <- length(x)
if(n==0) return(NULL)
x <- lapply(x, function(y) if(length(y)) as.matrix(y) else
stop("Zero-length component in x"))
d <- array(unlist(lapply(x, dim)), c(2, n))
rr <- d[1,]
cc <- d[2,]
rsum <- sum(rr)
csum <- sum(cc)
out <- array(0, c(rsum, csum))
ind <- array(0, c(4, n))
rcum <- cumsum(rr)
ccum <- cumsum(cc)
ind[1,-1] <- rcum[-n]
ind[2,] <- rcum
ind[3,-1] <- ccum[-n]
ind[4,] <- ccum
imat <- array(1:(rsum * csum), c(rsum, csum))
iuse <- apply(ind, 2, function(y, imat) imat[(y[1]+1):y[2],
(y[3]+1):y[4]], imat=imat)
iuse <- as.vector(unlist(iuse))
out[iuse] <- unlist(x)
return(out)
}
#########################
mats <- list(matrix(1:20, 5, 4), matrix(1:12, 4, 3), matrix(1:25, 5,
5))
bdiag(mats)
Regarding the dimnames of the matrices, I think you can easily create
a function thas calls bdiag and gives the appropriate names to the
final matrix.
I hope this helps.
Best,
Dimitris
----
Dimitris Rizopoulos
Doctoral Student
Biostatistical Centre
School of Public Health
Catholic University of Leuven
Address: Kapucijnenvoer 35, Leuven, Belgium
Tel: +32/16/396887
Fax: +32/16/337015
Web: http://www.med.kuleuven.ac.be/biostat/
http://www.student.kuleuven.ac.be/~m0390867/dimitris.htm
----- Original Message -----
From: "Robin Hankin" <rksh at soc.soton.ac.uk>
To: <r-help at stat.math.ethz.ch>
Sent: Thursday, May 27, 2004 10:24 AM
Subject: [R] block diagonal matrix function
> Hello List
>
> I have just written a little function that takes two matrices as
> arguments and returns a large matrix that is composed of the two
input> matrices in upper-left position and lower-right position with a
padding> value everywhere else. (function definition and toy example below).
I> need nonsquare matrices and rowname() and colname() inherited
appropriately.>
> Two questions:
>
> (1) Is there a better way to do this? (kronecker() isn't applicable
here)>
> (2) How do I generalize it to take an arbitrary number of matrices
as> inputs?
>
>
> TIV
>
> Robin
>
>
>
> "blockdiag" <-
> function (m1, m2, p.tr = 0, p.ll = 0)
> {
> ## p.tr and p.ll are padding values
> topleft <- m1
> topright <- matrix(p.tr, nrow(m1), ncol(m2))
> colnames(topright) <- colnames(m2)
> lowleft <- matrix(p.ll, nrow(m2), ncol(m1))
> lowright <- m2
> rbind(cbind(topleft, topright), cbind(lowleft, lowright))
> }
>
> m1 <-
> structure(c(1, 1, 3, 1, 3, 4), .Dim = as.integer(c(2, 3)), .Dimnames
= list(> c("a", "b"), c("x", "y",
"z")))
>
> m2 <-
> structure(c(2, 1, 1, 0, 3, 2, 2, 2, 0), .Dim = as.integer(c(3,
> 3)), .Dimnames = list(c("I", "II", "III"),
c("A", "B", "C")))
>
> R> m1
> x y z
> a 1 3 3
> b 1 1 4
>
> R> m2
> A B C
> I 2 0 2
> II 1 3 2
> III 1 2 0
>
> R> blockdiag(m1,m2)
> x y z A B C
> a 1 3 3 0 0 0
> b 1 1 4 0 0 0
> I 0 0 0 2 0 2
> II 0 0 0 1 3 2
> III 0 0 0 1 2 0
> R>
> --
> Robin Hankin
> Uncertainty Analyst
> Southampton Oceanography Centre
> SO14 3ZH
> tel +44(0)23-8059-7743
> initialDOTsurname at soc.soton.ac.uk (edit in obvious way; spam
precaution)>
> ______________________________________________
> R-help at stat.math.ethz.ch mailing list
> https://www.stat.math.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide!
http://www.R-project.org/posting-guide.html
The zoo package can handle multiway merges of this sort. The
following example uses your two matrices m1 and m2 but any
number could have been supplied. Each matrix must be converted
to a zoo object with successive times and then NAs in the result
replaced with zeros. If the names are important you would have
to set those yourself afterwards:
R> require(zoo)
[1] TRUE
R> m1. <- zoo(m1,1:2)
R> m2. <- zoo(m2,3:5)
R> m. <- merge(m1., m2.)
R> ifelse(is.na(m.),0,m.)
m1..x m1..y m1..z m2..A m2..B m2..C
[1,] 1 3 3 0 0 0
[2,] 1 1 4 0 0 0
[3,] 0 0 0 2 0 2
[4,] 0 0 0 1 3 2
[5,] 0 0 0 1 2 0
Robin Hankin <rksh <at> soc.soton.ac.uk> writes:
:
: Hello List
:
: I have just written a little function that takes two matrices as
: arguments and returns a large matrix that is composed of the two input
: matrices in upper-left position and lower-right position with a padding
: value everywhere else. (function definition and toy example below). I
: need nonsquare matrices and rowname() and colname() inherited appropriately.
:
: Two questions:
:
: (1) Is there a better way to do this? (kronecker() isn't applicable here)
:
: (2) How do I generalize it to take an arbitrary number of matrices as
: inputs?
:
: TIV
:
: Robin
:
:
: "blockdiag" <-
: function (m1, m2, p.tr = 0, p.ll = 0)
: {
: ## p.tr and p.ll are padding values
: topleft <- m1
: topright <- matrix(p.tr, nrow(m1), ncol(m2))
: colnames(topright) <- colnames(m2)
: lowleft <- matrix(p.ll, nrow(m2), ncol(m1))
: lowright <- m2
: rbind(cbind(topleft, topright), cbind(lowleft, lowright))
: }
:
: m1 <-
: structure(c(1, 1, 3, 1, 3, 4), .Dim = as.integer(c(2, 3)), .Dimnames = list(
: c("a", "b"), c("x", "y",
"z")))
:
: m2 <-
: structure(c(2, 1, 1, 0, 3, 2, 2, 2, 0), .Dim = as.integer(c(3,
: 3)), .Dimnames = list(c("I", "II", "III"),
c("A", "B", "C")))
:
: R> m1
: x y z
: a 1 3 3
: b 1 1 4
:
: R> m2
: A B C
: I 2 0 2
: II 1 3 2
: III 1 2 0
:
: R> blockdiag(m1,m2)
: x y z A B C
: a 1 3 3 0 0 0
: b 1 1 4 0 0 0
: I 0 0 0 2 0 2
: II 0 0 0 1 3 2
: III 0 0 0 1 2 0
: R>