Adding together matrices of two different dimensions with column/row matching

45 views Asked by At

I have matrices of varying dimensions such as:

a <- read.table(text = "
   Si N1 N2 A1 A2 A3 A4 A5 Z1 Z2 Z3 Z5 IN M S
Si  1  0  0  0  0  1  0  0  0  0  0  0  0 0 0
N1  0  1  0  1  1  1  1  1  0  0  0  0  0 0 0
N2  0  0  1  0  1  0  0  0  0  0  0  0  0 0 0
A1  0  1  0  0  0  0  0  0  0  1  0  0  0 0 0
A2  0  1  1  0  0  0  0  0  0  0  1  1  0 1 0
A3  1  1  0  0  0  0  0  0  1  0  0  0  0 0 0
A4  0  1  0  0  0  0  1  0  0  0  0  0  0 0 0
A5  0  1  0  0  0  0  0  0  0  0  0  0  1 0 0
Z1  0  0  0  0  0  1  0  0  1  0  0  0  0 0 0
Z2  0  0  0  1  0  0  0  0  0  0  0  0  0 0 1
Z3  0  0  0  0  1  0  0  0  0  0  1  0  0 0 0
Z5  0  0  0  0  1  0  0  0  0  0  0  1  0 0 0
IN  0  0  0  0  0  0  0  1  0  0  0  0  1 0 0
M   0  0  0  0  1  0  0  0  0  0  0  0  0 1 0
S   0  0  0  0  0  0  0  0  0  1  0  0  0 0 1
", header = TRUE)

and:

b <- read.table(text = "
   Si N1 N2 A1 A2 A3 A4 A5 Z1 Z2 Z3 Z5 D IN M O P
Si  1  0  0  0  0  1  0  0  0  0  0  0 0  0 0 0 0
N1  0  1  0  1  1  1  1  1  0  0  0  0 0  0 0 0 0
N2  0  0  1  0  1  0  0  0  0  0  0  0 0  0 0 0 0
A1  0  1  0  0  0  0  0  0  0  1  0  0 0  0 1 0 1
A2  0  1  1  0  0  0  0  0  0  0  1  0 1  0 0 0 0
A3  1  0  0  0  0  0  0  0  1  0  0  0 0  0 0 0 0
A4  0  1  0  0  0  0  1  0  0  0  0  0 0  0 0 1 0
A5  0  1  0  0  0  0  0  1  0  0  0  0 0  1 0 0 0
Z1  0  0  0  0  0  1  0  0  1  1  0  0 0  0 0 0 0
Z2  0  0  0  1  0  0  0  0  0  1  0  0 0  0 0 0 0
Z3  0  0  0  0  1  0  0  0  0  1  1  0 1  0 0 0 0
Z5  0  0  0  0  0  0  0  0  0  0  0  1 0  1 0 0 0
D   0  0  0  0  1  0  0  0  0  0  0  0 1  0 0 0 0
IN  0  0  0  0  0  0  0  1  0  0  0  1 0  0 0 0 0
M   0  0  0  1  0  0  0  0  0  0  0  0 0  0 1 0 1
O   0  0  0  0  0  0  1  0  0  0  0  0 0  0 0 1 0
P   0  0  0  1  0  0  0  0  0  0  0  0 0  0 1 0 0
", header = TRUE)

and I'm trying to add them so that variables missing from either are included in the result.

I've found a helpful previous post: How to aggregate matrices which have different dimensions? [R] and have tried the codes, but the problem remains that my variable names change and that some are missing.

This code was the closest:

sum_mat = function(a, b){
  temp = matrix(data = 0, nrow = max(nrow(a), nrow(b)), ncol = max(ncol(a), ncol(b)))
  temp_a = temp
  temp_a[1:nrow(a), 1:ncol(a)] = a
  temp_b = temp
  temp_b[1:nrow(b), 1:ncol(b)] = b
  temp_a + temp_b
}

c = sum_mat(a, b)

c

but the resulting matrix is 17X17 and should be 18 X 18 because the 'S' variable from a is missing from b and needs to be included to look like this:

c <- read.table(text = "
   Si N1 N2 A1 A2 A3 A4 A5 Z1 Z2 Z3 Z5 D IN M O P S
Si  2  0  0  0  0  2  0  0  0  0  0  0 0  0 0 0 0 0
N1  0  2  0  2  2  2  2  2  0  0  0  0 0  0 0 0 0 0
N2  0  0  2  0  2  0  0  0  0  0  0  0 0  0 0 0 0 0
A1  0  2  0  0  0  0  0  0  0  2  0  0 0  0 1 0 1 0
A2  0  2  2  0  0  0  0  0  0  0  2  2 1  0 1 0 0 0
A3  2  1  0  0  0  0  0  0  2  0  0  0 0  0 0 0 0 0
A4  0  2  0  0  0  0  2  0  0  0  0  0 0  0 0 1 0 0
A5  0  2  0  0  0  0  0  1  0  0  0  0 0  2 0 0 0 0
Z1  0  0  0  0  0  2  0  0  2  1  0  0 0  0 0 0 0 0
Z2  0  0  0  2  0  0  0  0  0  1  0  0 0  0 0 0 0 1
Z3  0  0  0  0  2  0  0  0  0  1  2  0 1  0 0 0 0 0
Z5  0  0  0  0  2  0  0  0  0  0  0  2 0  1 0 0 0 0
D   0  0  0  0  1  0  0  0  0  0  0  0 1  0 0 0 0 0
IN  0  0  0  0  0  0  0  2  0  0  0  1 0  1 0 0 0 0
M   0  0  0  1  1  0  0  0  0  0  0  0 0  0 1 0 1 0
O   0  0  0  0  0  0  1  0  0  0  0  0 0  0 0 1 0 0
P   0  0  0  1  0  0  0  0  0  0  0  0 0  0 1 0 0 0
S   0  0  0  0  0  0  0  0  0  1  0  0 0  0 0 0 0 1
", header = TRUE)
2

There are 2 answers

0
jblood94 On BEST ANSWER

If the row names match the column names:

matadd <- function(a, b) {
  nms <- unique(c(colnames(b), colnames(a)))
  ia <- match(colnames(a), nms, nomatch = 0L)
  ib <- match(colnames(b), nms, nomatch = 0L)
  m <- matrix(vector(typeof(a), 1), length(nms), length(nms), 0, list(nms, nms))
  m[ia, ia] <- a
  m[ib, ib] <- m[ib, ib] + b
  m
}

matadd(as.matrix(a), as.matrix(b))
#>    Si N1 N2 A1 A2 A3 A4 A5 Z1 Z2 Z3 Z5 D IN M O P S
#> Si  2  0  0  0  0  2  0  0  0  0  0  0 0  0 0 0 0 0
#> N1  0  2  0  2  2  2  2  2  0  0  0  0 0  0 0 0 0 0
#> N2  0  0  2  0  2  0  0  0  0  0  0  0 0  0 0 0 0 0
#> A1  0  2  0  0  0  0  0  0  0  2  0  0 0  0 1 0 1 0
#> A2  0  2  2  0  0  0  0  0  0  0  2  1 1  0 1 0 0 0
#> A3  2  1  0  0  0  0  0  0  2  0  0  0 0  0 0 0 0 0
#> A4  0  2  0  0  0  0  2  0  0  0  0  0 0  0 0 1 0 0
#> A5  0  2  0  0  0  0  0  1  0  0  0  0 0  2 0 0 0 0
#> Z1  0  0  0  0  0  2  0  0  2  1  0  0 0  0 0 0 0 0
#> Z2  0  0  0  2  0  0  0  0  0  1  0  0 0  0 0 0 0 1
#> Z3  0  0  0  0  2  0  0  0  0  1  2  0 1  0 0 0 0 0
#> Z5  0  0  0  0  1  0  0  0  0  0  0  2 0  1 0 0 0 0
#> D   0  0  0  0  1  0  0  0  0  0  0  0 1  0 0 0 0 0
#> IN  0  0  0  0  0  0  0  2  0  0  0  1 0  1 0 0 0 0
#> M   0  0  0  1  1  0  0  0  0  0  0  0 0  0 2 0 1 0
#> O   0  0  0  0  0  0  1  0  0  0  0  0 0  0 0 1 0 0
#> P   0  0  0  1  0  0  0  0  0  0  0  0 0  0 1 0 0 0
#> S   0  0  0  0  0  0  0  0  0  1  0  0 0  0 0 0 0 1
0
ThomasIsCoding On

You can try xtabs along with as.data.frame.table like below

xtabs(
   Freq ~ .,
   do.call(
      rbind,
      lapply(
         list(a, b),
         \(x) as.data.frame.table(as.matrix(x))
      )
   )
)

which gives

    Var2
Var1 Si N1 N2 A1 A2 A3 A4 A5 Z1 Z2 Z3 Z5 IN M S D O P
  Si  2  0  0  0  0  2  0  0  0  0  0  0  0 0 0 0 0 0
  N1  0  2  0  2  2  2  2  2  0  0  0  0  0 0 0 0 0 0
  N2  0  0  2  0  2  0  0  0  0  0  0  0  0 0 0 0 0 0
  A1  0  2  0  0  0  0  0  0  0  2  0  0  0 1 0 0 0 1
  A2  0  2  2  0  0  0  0  0  0  0  2  1  0 1 0 1 0 0
  A3  2  1  0  0  0  0  0  0  2  0  0  0  0 0 0 0 0 0
  A4  0  2  0  0  0  0  2  0  0  0  0  0  0 0 0 0 1 0
  A5  0  2  0  0  0  0  0  1  0  0  0  0  2 0 0 0 0 0
  Z1  0  0  0  0  0  2  0  0  2  1  0  0  0 0 0 0 0 0
  Z2  0  0  0  2  0  0  0  0  0  1  0  0  0 0 1 0 0 0
  Z3  0  0  0  0  2  0  0  0  0  1  2  0  0 0 0 1 0 0
  Z5  0  0  0  0  1  0  0  0  0  0  0  2  1 0 0 0 0 0
  IN  0  0  0  0  0  0  0  2  0  0  0  1  1 0 0 0 0 0
  M   0  0  0  1  1  0  0  0  0  0  0  0  0 2 0 0 0 1
  S   0  0  0  0  0  0  0  0  0  1  0  0  0 0 1 0 0 0
  D   0  0  0  0  1  0  0  0  0  0  0  0  0 0 0 1 0 0
  O   0  0  0  0  0  0  1  0  0  0  0  0  0 0 0 0 1 0
  P   0  0  0  1  0  0  0  0  0  0  0  0  0 1 0 0 0 0