Matrix Operations

Size

The length() function works with matrices, but the results may not be that interesting. When applied to matrices, length() returns the number of cells in the matrix.

(m1 <- matrix(1:9, 3, 3))
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9
length(m1)
[1] 9

To get the dimensions of the matrix, we use dim().

dim(m1)
[1] 3 3

Arithmetic

As with vectors, default arithmetic with R matrices works element-wise. R performs the requested operation on each pair of corresponding entries in the two matrices.

(m2 <- matrix(sample(-5:5, 9, TRUE), 3, 3))
     [,1] [,2] [,3]
[1,]    4    5    4
[2,]   -1    3   -4
[3,]    1   -2   -4
m1 + m2
     [,1] [,2] [,3]
[1,]    5    9   11
[2,]    1    8    4
[3,]    4    4    5
m2 - m1
     [,1] [,2] [,3]
[1,]    3    1   -3
[2,]   -3   -2  -12
[3,]   -2   -8  -13
m1 / m2
      [,1]      [,2]  [,3]
[1,]  0.25  0.800000  1.75
[2,] -2.00  1.666667 -2.00
[3,]  3.00 -3.000000 -2.25
m1 * m2
     [,1] [,2] [,3]
[1,]    4   20   28
[2,]   -2   15  -32
[3,]    3  -12  -36

Matrix Algebra

If you’re familiar with matrix algebra and/or have some affinity for programming languages that overload their operators, the matrix arithmetic described above may seem very strange. Rather than overloading the standard operators, R defines special functions for matrix algebraic operations. For example:

  • %*%: Multiplication
  • t(): Transposition
  • solve(): Inversion
# Multiply m1 and m2 using true matrix multiplication
m1 %*% m2
     [,1] [,2] [,3]
[1,]    7    3  -40
[2,]   11    9  -44
[3,]   15   15  -48
# Transpose m1
t(m1)
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6
[3,]    7    8    9
# Invert m2
solve(m2)
            [,1]        [,2]        [,3]
[1,] 0.161290323 -0.09677419  0.25806452
[2,] 0.064516129  0.16129032 -0.09677419
[3,] 0.008064516 -0.10483871 -0.13709677

Recycling

Matrices usually obey R’s recycling rules. If you attempt to perform arithmetic between a matrix and a vector that has fewer elements than the matrix, R will try to make the lengths match by recycling the elements from the vector.

v1 <- 1:3
v2 <- 1:2

# Recycling the elements of 'v1' without a warning
m1 + v1
     [,1] [,2] [,3]
[1,]    2    5    8
[2,]    4    7   10
[3,]    6    9   12
m1 * v1
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    4   10   16
[3,]    9   18   27
# Recycling the elements of 'v2' with a warning
m1 + v2
Warning in m1 + v2: longer object length is not a multiple of shorter object
length
     [,1] [,2] [,3]
[1,]    2    6    8
[2,]    4    6   10
[3,]    4    8   10
m1 * v2
Warning in m1 * v2: longer object length is not a multiple of shorter object
length
     [,1] [,2] [,3]
[1,]    1    8    7
[2,]    4    5   16
[3,]    3   12    9
# Use recycling to fill a new matrix
matrix(42, 2, 2)
     [,1] [,2]
[1,]   42   42
[2,]   42   42
matrix(1:4, 4, 4)
     [,1] [,2] [,3] [,4]
[1,]    1    1    1    1
[2,]    2    2    2    2
[3,]    3    3    3    3
[4,]    4    4    4    4
matrix(1:3, 4, 4)
Warning in matrix(1:3, 4, 4): data length [3] is not a sub-multiple or multiple
of the number of rows [4]
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    1
[2,]    2    3    1    2
[3,]    3    1    2    3
[4,]    1    2    3    1
# Use recycling to match replacement values to all selected elements
m2[1:2, 3] <- -99
m2
     [,1] [,2] [,3]
[1,]    4    5  -99
[2,]   -1    3  -99
[3,]    1   -2   -4
m2[3, 1:2] <- c(88, 99)
m2
     [,1] [,2] [,3]
[1,]    4    5  -99
[2,]   -1    3  -99
[3,]   88   99   -4

Sometimes, R won’t apply recycling to accommodate our sloppiness, though. For example, we can’t do any arithmetic with matrices that have different dimensions.

(m3 <- matrix(c(1, 3), 2, 1))
     [,1]
[1,]    1
[2,]    3
m1 + m3
Error in m1 + m3: non-conformable arrays
m1 * m3
Error in m1 * m3: non-conformable arrays

We also can’t do arithmetic between a matrix and vector that contains more elements than the matrix.

v3 <- 1:18
m1 + v3
Error: dims [product 9] do not match the length of object [18]
m1 * v3
Error: dims [product 9] do not match the length of object [18]

When it comes to overwriting matrix elements, R is especially picky about what size of vector it will use to overwrite a selection of matrix elements.

  • OK
    • Replacement length = Selection length
    • Replacement length cleanly divides selection length
  • Not OK
    • Replacement length > Selection length
      • Still true when replacement length is a multiple of selection length
    • Replacement length does not cleanly divide the selection length
# Works: Replace 4 elements with length-4 vector
m1[1:2, 2:3] <- 1:4
m1
     [,1] [,2] [,3]
[1,]    1    1    3
[2,]    2    2    4
[3,]    3    6    9
# Works: Replace 4 elements with length-2 vector
m1[1:2, 2:3] <- 1:2
m1
     [,1] [,2] [,3]
[1,]    1    1    1
[2,]    2    2    2
[3,]    3    6    9
# Works: Replace 4 elements with length-1 vector
m1[1:2, 2:3] <- 42
m1
     [,1] [,2] [,3]
[1,]    1   42   42
[2,]    2   42   42
[3,]    3    6    9
# Fails: Replace 4 elements with length-3 vector
m1[1:2, 2:3] <- 1:3
Error in m1[1:2, 2:3] <- 1:3: number of items to replace is not a multiple of replacement length
# Fails: Replace 4 elements with length-8 vector
m1[1:2, 2:3] <- 1:3
Error in m1[1:2, 2:3] <- 1:3: number of items to replace is not a multiple of replacement length
Practice
  1. Create a 5x3 numeric matrix called ‘myMat’ wherein each column is equal to the vector 1:5.
  2. Multiply each entry in ‘myMat’ by pi (i.e., the mathematical constant).

HINT: The built-in R object pi contains the value of pi.

(myMat <- matrix(1:5, 5, 3))
     [,1] [,2] [,3]
[1,]    1    1    1
[2,]    2    2    2
[3,]    3    3    3
[4,]    4    4    4
[5,]    5    5    5
myMat * pi
          [,1]      [,2]      [,3]
[1,]  3.141593  3.141593  3.141593
[2,]  6.283185  6.283185  6.283185
[3,]  9.424778  9.424778  9.424778
[4,] 12.566371 12.566371 12.566371
[5,] 15.707963 15.707963 15.707963
Back to top