24 Nov 2011

A Function for Adding up Matrices with Different Dimensions

I couldn't find a function that can handle matrices with different dimensions and thus coded one myself.  It can sum up matrices and also copes with matrices with different dimensions.


# File: combmat.R
# Purpose: add up matrices with different dimensions
# Input: a list of 2-dimensional matrices
# Output: a combined matrix
# Author: Kay Cichini
# Date: Nov. 23th 2011
 
combmat <- function(m_l = list(NA)){
  n_m <- length(m_l)                               # no. of matrices used
  rownames_l <- lapply(m_l, rownames)              # list of rownames
  colnames_l <- lapply(m_l, colnames)              # list of colnames
  rownames_new <- unique(unlist(rownames_l))       # new, general rownames
  colnames_new <- unique(unlist(colnames_l))       # new, general colnames
 
  dimnames_new = list(rownames_new, colnames_new)
  m_new <- matrix(nrow = length(rownames_new),
                 ncol = length(colnames_new),
                 data = 0,
                 dimnames = dimnames_new)
 
  m_interm_arr <-                                  # array of intermediate 
  array(m_new, dim = c(length(rownames_new),       # matrices with same no. of 
                       length(colnames_new), n_m), # dimensions as elements in  
        dimnames = dimnames_new)                   # list of input matrices
 
  # take i-th element in list of imput matrices and add
  # its values according to the appropiate row and col indexes
  # in i-th dimension (i-th matrix) within array:
  for (i in 1:n_m) {
    m_interm_arr[,,i][rownames_l[[i]], colnames_l[[i]]] <- m_l[[i]]
  }
  return(apply(m_interm_arr, c(1,2), sum))
}
 
# Example:
print(m1 <- matrix(sample(1:40), 4, 10, dimnames = list(1:4,1:10)))
print(m2 <- matrix(sample(1:40), 10, 4, dimnames = list(1:10,1:4)))
 
combmat(m_l = list(m1, m2))

It is very likely that someone else may come to a more effective approach - I'd be happy to here about improvements or if there is a package/function doing the same...

2 comments :

  1. Hi Kay,

    I like your solution, but how about the following (using your m1 and m2 matrices)?

    library(reshape2)
    m_comb <- do.call(rbind, lapply(list(m1, m2), melt))
    acast(m_comb, m_comb$Var1~m_comb$Var2, sum)


    However, if colname classes are mixed, this re-sorts columns alphabetically, with numbers stored as character... although mixedorder in gtools could be used to sort a bit more sensibly:
    library(gtools)
    m_sum[, mixedorder(colnames(m_sum))]

    Cheers,
    John

    ReplyDelete
  2. Hi John,

    Many thanks for your input. Actually, I was searching for something like this! In the end, my post my serve as an example for yielding equal results with build-in functions and by hand..

    Best regards,
    Kay

    ReplyDelete