Matrix algebra

Scalar addition/subtraction

Scalar addition and subtraction on a matrix works identically to addition or subtraction on a vector. We simply use the standard addition (+) and subtraction (-) operators.

a <- matrix(1:6, nrow = 2)
a
##      [,1] [,2] [,3]
## [1,]    1    3    5
## [2,]    2    4    6
a + 1
##      [,1] [,2] [,3]
## [1,]    2    4    6
## [2,]    3    5    7
a - 2
##      [,1] [,2] [,3]
## [1,]   -1    1    3
## [2,]    0    2    4

Scalar multiplication/division

Scalar multiplication and division also work with the standard operators (* and /).

a * 2
##      [,1] [,2] [,3]
## [1,]    2    6   10
## [2,]    4    8   12
a/2
##      [,1] [,2] [,3]
## [1,]  0.5  1.5  2.5
## [2,]  1.0  2.0  3.0

Matrix comparators, logicals, and assignment

As with a vector, it is possible to apply comparators to an entire matrix:

a > 2
##       [,1] [,2] [,3]
## [1,] FALSE TRUE TRUE
## [2,] FALSE TRUE TRUE

We can then use the resulting logical matrix as an index:

a[a > 2]
## [1] 3 4 5 6

But the result is a vector, not a matrix. If we use the same statement to assign, however, the result is a matrix:

a[a > 2] <- 99
a
##      [,1] [,2] [,3]
## [1,]    1   99   99
## [2,]    2   99   99

Matrix Multiplication

In statistics, an important operation is matrix multiplication. Unlike scalar multiplication, this procedure involves the multiplication of two matrices by one another.

Let's start by defining a function to demonstrate how matrix multiplication works:

mmdemo <- function(A, B) {
    m <- nrow(A)
    n <- ncol(B)
    C <- matrix(NA, nrow = m, ncol = n)
    for (i in 1:m) {
        for (j in 1:n) {
            C[i, j] <- paste("(", A[i, ], "*", B[, j], ")", sep = "", collapse = "+")
        }
    }
    print(C, quote = FALSE)
}

Now let's generate two matrices, multiply them and see how it worked:

amat <- matrix(1:4, ncol = 2)
bmat <- matrix(1:6, nrow = 2)
amat
##      [,1] [,2]
## [1,]    1    3
## [2,]    2    4
bmat
##      [,1] [,2] [,3]
## [1,]    1    3    5
## [2,]    2    4    6
amat %*% bmat
##      [,1] [,2] [,3]
## [1,]    7   15   23
## [2,]   10   22   34
mmdemo(amat, bmat)
##      [,1]        [,2]        [,3]       
## [1,] (1*1)+(3*2) (1*3)+(3*4) (1*5)+(3*6)
## [2,] (2*1)+(4*2) (2*3)+(4*4) (2*5)+(4*6)

Let's try it on a different set of matrices:

amat <- matrix(1:16, ncol = 4)
bmat <- matrix(1:32, nrow = 4)
amat
##      [,1] [,2] [,3] [,4]
## [1,]    1    5    9   13
## [2,]    2    6   10   14
## [3,]    3    7   11   15
## [4,]    4    8   12   16
bmat
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
## [1,]    1    5    9   13   17   21   25   29
## [2,]    2    6   10   14   18   22   26   30
## [3,]    3    7   11   15   19   23   27   31
## [4,]    4    8   12   16   20   24   28   32
amat %*% bmat
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
## [1,]   90  202  314  426  538  650  762  874
## [2,]  100  228  356  484  612  740  868  996
## [3,]  110  254  398  542  686  830  974 1118
## [4,]  120  280  440  600  760  920 1080 1240
mmdemo(amat, bmat)
##      [,1]                      [,2]                     
## [1,] (1*1)+(5*2)+(9*3)+(13*4)  (1*5)+(5*6)+(9*7)+(13*8) 
## [2,] (2*1)+(6*2)+(10*3)+(14*4) (2*5)+(6*6)+(10*7)+(14*8)
## [3,] (3*1)+(7*2)+(11*3)+(15*4) (3*5)+(7*6)+(11*7)+(15*8)
## [4,] (4*1)+(8*2)+(12*3)+(16*4) (4*5)+(8*6)+(12*7)+(16*8)
##      [,3]                         [,4]                         
## [1,] (1*9)+(5*10)+(9*11)+(13*12)  (1*13)+(5*14)+(9*15)+(13*16) 
## [2,] (2*9)+(6*10)+(10*11)+(14*12) (2*13)+(6*14)+(10*15)+(14*16)
## [3,] (3*9)+(7*10)+(11*11)+(15*12) (3*13)+(7*14)+(11*15)+(15*16)
## [4,] (4*9)+(8*10)+(12*11)+(16*12) (4*13)+(8*14)+(12*15)+(16*16)
##      [,5]                          [,6]                         
## [1,] (1*17)+(5*18)+(9*19)+(13*20)  (1*21)+(5*22)+(9*23)+(13*24) 
## [2,] (2*17)+(6*18)+(10*19)+(14*20) (2*21)+(6*22)+(10*23)+(14*24)
## [3,] (3*17)+(7*18)+(11*19)+(15*20) (3*21)+(7*22)+(11*23)+(15*24)
## [4,] (4*17)+(8*18)+(12*19)+(16*20) (4*21)+(8*22)+(12*23)+(16*24)
##      [,7]                          [,8]                         
## [1,] (1*25)+(5*26)+(9*27)+(13*28)  (1*29)+(5*30)+(9*31)+(13*32) 
## [2,] (2*25)+(6*26)+(10*27)+(14*28) (2*29)+(6*30)+(10*31)+(14*32)
## [3,] (3*25)+(7*26)+(11*27)+(15*28) (3*29)+(7*30)+(11*31)+(15*32)
## [4,] (4*25)+(8*26)+(12*27)+(16*28) (4*29)+(8*30)+(12*31)+(16*32)

Note: matrix multiplication is noncommutative, so the order of matrices matters in a statement!

Cross-product

Another important operation is the crossproduct. See also: OLS in matrix form.

Row/column means and sums

Sometimes we want to calculate a sum or mean for each row or column of a matrix. R provides built-in functions for each of these operations:

cmat <- matrix(1:20, nrow = 5)
cmat
##      [,1] [,2] [,3] [,4]
## [1,]    1    6   11   16
## [2,]    2    7   12   17
## [3,]    3    8   13   18
## [4,]    4    9   14   19
## [5,]    5   10   15   20
rowSums(cmat)
## [1] 34 38 42 46 50
colSums(cmat)
## [1] 15 40 65 90
rowMeans(cmat)
## [1]  8.5  9.5 10.5 11.5 12.5
colMeans(cmat)
## [1]  3  8 13 18

These functions can be helpful for aggregating multiple variables and performing the sum or mean with these functions is much faster than manually adding (or taking the mean) of columns using + and / operators.