User:Timothee Flutre/Notebook/Postdoc/2012/02/17

From OpenWetWare
Jump to navigationJump to search
Project name Main project page
Previous entry      Next entry

How to subtract a vector from a matrix in R

In R, matrix algebra is very fast, so it's better to use it. But it's not always clear how to subtract a vector from each row of a matrix, or from each column, especially when the matrix is square. (When the matrix is square, R will always successfully return you an answer but it may not correspond to what you ask! While if the matrix is not square, R will run successfully or not, depending on the length of the vector).

  • Key fact: internally, R records a matrix as a long vector corresponding to the concatenation of the columns (vectorization in maths).
  • Before anything else, let's define our dummy data. Here is my matrix:
m <- matrix(1:4, nrow=2, ncol=2, byrow=TRUE)
m
     [,1] [,2]
[1,]    1    2
[2,]    3    4

And here is my vector:

v <- c(1, 5)
v
[1] 1 5
  • We can easily check that R records a matrix as a concatenation of its columns:
m[1]
[1] 1
m[2]
[1] 3
m[3]
[1] 2
m[4]
[1] 4
  • First, I want to subtract v from each column of m. Here is what I want to obtain:
     [,1] [,2]
[1,]    0    1
[2,]   -2   -1

The following simple command gives me what I want:

m - v
     [,1] [,2]
[1,]    0    1
[2,]   -2   -1

We could also have done it with apply:

apply(m, 2, "-", v)
     [,1] [,2]
[1,]    0    1
[2,]   -2   -1

Or with sweep:

sweep(m, 1, v, "-")
     [,1] [,2]
[1,]    0    1
[2,]   -2   -1

Note that the parameter MARGIN in "apply" should be put to 2 to operate on the columns, while in "sweep" it should be put to 1...

  • Second, I want to subtract v from each row of m. Here is what I want to obtain:
     [,1] [,2]
[1,]    0   -3
[2,]    2   -1

Of course, m - v won't work here. But again, as we know how R handle matrices internally, we can use the transpose function:

t(t(m)-v)
     [,1] [,2]
[1,]    0   -3
[2,]    2   -1

We could also have use "apply" (with MARGIN=1). But wait, "transpose" is also required here!

t(apply(m, 1, "-", v))
     [,1] [,2]
[1,]    0   -3
[2,]    2   -1

And for "sweep"? Well, it understands properly that we want to operate on rows (MARGIN=2), so it returns the results row by row...

sweep(m, 2, v, "-")
     [,1] [,2]
[1,]    0   -3
[2,]    2   -1