[R] pairwise difference operator

Gabor Grothendieck ggrothendieck at myway.com
Sat Jul 31 04:24:33 CEST 2004


Adaikalavan Ramasamy <ramasamy <at> cancer.org.uk> writes:

: 
: There was a BioConductor thread today where the poster wanted to find
: pairwise difference between columns of a matrix. I suggested the slow
: solution below, hoping that someone might suggest a faster and/or more
: elegant solution, but no other response.
: 
: I tried unsuccessfully with the apply() family. Searching the mailing
: list was not very fruitful either. The closest I got to was a cryptic
: chunk of code in pairwise.table().
: 
: Since I do use something similar myself occasionally, I am hoping
: someone from the R-help list can suggest alternatives or past threads.
: Thank you.
: 
: ### Code ###
: pairwise.difference <- function(m){
:   npairs  <- choose( ncol(m), 2 )
:   results <- matrix( NA, nc=npairs, nr=nrow(m) )
:   cnames  <- rep(NA, npairs)
:   if(is.null(colnames(m))) colnames(m) <- paste("col", 1:ncol(m), sep="")
: 
:   k <- 1
:   for(i in 1:ncol(m)){
:     for(j in 1:ncol(m)){
:       if(j <= i) next;
:       results[ ,k] <- m[ ,i] - m[ ,j]
:       cnames[k]    <- paste(colnames(m)[ c(i, j) ], collapse=".vs.")
:       k <- k + 1
:     }
:   }
: 
:   colnames(results) <- cnames
:   rownames(results) <- rownames(m)
:   return(results)
: }
: 
: ### Example using a matrix with 5 gene/row and 4 columns ###
: mat <- matrix( sample(1:20), nc=4 )
: colnames(mat) <- LETTERS[1:4]; rownames(mat) <- paste( "g", 1:5, sep="") 
: mat
:     A  B  C  D
: g1 10 16  3 15
: g2 18  5 12 19
: g3  7  4  8 13
: g4 14  2  6 11
: g5 17  1 20  9
: 
: pairwise.difference(mat)
:    A.vs.B A.vs.C A.vs.D B.vs.C B.vs.D C.vs.D
: g1     -6      7     -5     13      1    -12
: g2     13      6     -1     -7    -14     -7
: g3      3     -1     -6     -4     -9     -5
: g4     12      8      3     -4     -9     -5
: g5     16     -3      8    -19     -8     11



1. Note that  mat[,j] - mat  subtracts each column of mat from the j-th column 
   so we just cbind 3 matrices:

      cbind( mat[,1]-mat[2:4], mat[,2]-mat[,3:4], mat[,3]-mat[,4,drop=F] )

2. For a general matrix a single sapply can do it like this:

      f <- function(i, mat) mat[, i-1] - mat[, i:ncol(mat), drop = FALSE]
      do.call("cbind", sapply(2:ncol(mat), f, mat))

3. To add nice column names just enhance f.  The statements "z <- ..."
   and "do.call ..." are the same as before:

      f <- function(i, mat) {
         z <- mat[, i-1] - mat[, i:ncol(mat), drop = FALSE]
         colnames(z) <- paste(colnames(mat)[i-1], colnames(z), sep = "-")
         z
      }
      do.call("cbind", sapply(2:ncol(mat), f, mat))




More information about the R-help mailing list