Manipulating Matrices

Accessing Matrix Elements

As with vectors, we can access and assign values within a matrix using the square brackets operator, [], but with one key difference. Matrices require two indices, one to define the row selection and one to define the column selection.

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

Select the first two rows and the first three columns of m1, then print the selected elements as a matrix.

m1[1:2, 1:3]
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8

Select the first and third rows and the second and third columns of m1, then save the selection as a new matrix called m2

(m2 <- m1[c(1, 3), 2:3])
     [,1] [,2]
[1,]    4    7
[2,]    6    9
Practice

Consider the following matrix.

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

Predict what m1[, 2] will return.

m1[, 2]
[1] 4 5 6

Leaving the row index blank (m1[, 2]) tells R to select all rows. By specifying 2 for the column index, we’re telling R to select the second column. So, we extract all three elements from the second column.

Notice that R returns a plain vector here, not a one-column matrix. By default, R “drops” a dimension when a selection only has one column (or one row). We’ll come back to this idea when we discuss subsetting data frames in the Lists & Data Frames module.

Modifying Matrix Elements

Editing the value of matrix elements works the same way that it did for vectors. We, use the [] operator to select the values we want to overwrite, and then we assign new values for the selected elements using the ordinary assignment operator, <-.

(m3 <- matrix(1, 3, 3))
     [,1] [,2] [,3]
[1,]    1    1    1
[2,]    1    1    1
[3,]    1    1    1

Replace the element in the first row and second column of m3 with 33.

m3[1, 2] <- 33
m3
     [,1] [,2] [,3]
[1,]    1   33    1
[2,]    1    1    1
[3,]    1    1    1

Replace all elements in the range covered by the second and third rows and the first and third columns with 44.

m3[2:3, c(1, 3)] <- 44
m3
     [,1] [,2] [,3]
[1,]    1   33    1
[2,]   44    1   44
[3,]   44    1   44
Practice

Consider the following matrix.

(a <- matrix(1:4, 2, 2))
     [,1] [,2]
[1,]    1    3
[2,]    2    4

Predict what the following code will print.

a[1, 1] <- "b"
a
a[1, 1] <- "b"
a
     [,1] [,2]
[1,] "b"  "3" 
[2,] "2"  "4" 

You should notice two changes to the matrix a.

  1. The data in the upper-left corner cell has been overwritten with "b".
  2. All other values in the matrix have been converted to character strings.

As with vectors, matrices can only store one type of data. When we try to replace the numeric value in a[1, 1] with the length-one character vector "b", R needs to do something to resolve the type discrepancy. Since there’s no unambiguous way to convert "b" to a number, R converts all of a to a character matrix.

Recycling

Matrices usually obey R’s recycling rules (the same rules you already learned for vectors). 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.

(m1 <- matrix(1:9, 3, 3))
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9
(m2 <- matrix(sample(-5:5, 9, TRUE), 3, 3))
     [,1] [,2] [,3]
[1,]    5   -1    3
[2,]   -2   -2    5
[3,]    1   -3    0
(v1 <- 1:3)
[1] 1 2 3
(v2 <- 1:2)
[1] 1 2

As with vectors, R won’t issue a warning if the length of the vector evenly divides the number of elements in the matrix.

# 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

When the vector’s length is not a multiple of the number of elements in the matrix, recycling triggers a warning.

# 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

We can also leverage recycling when generating new matrices. For example, the following code demonstrates a common use-case where we create an empty matrix to fill later. We populated a \(2 \times 2\) matrix by recycling the missing data code, NA, four times.

matrix(NA, 2, 2)
     [,1] [,2]
[1,]   NA   NA
[2,]   NA   NA

When populating a matrix with by recycle multi-element vectors, we need to be mindful of the order in which the matrix cells are filled.

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:2, 4, 4, byrow = TRUE)
     [,1] [,2] [,3] [,4]
[1,]    1    2    1    2
[2,]    1    2    1    2
[3,]    1    2    1    2
[4,]    1    2    1    2
Practice
  • Predict what the following expression will print.
  • Will this code produce an error or a warning? If so, why?
matrix(2:3, 3, 4)
     [,1] [,2] [,3] [,4]
[1,]    2    3    2    3
[2,]    3    2    3    2
[3,]    2    3    2    3
matrix(2:3, 3, 4)
     [,1] [,2] [,3] [,4]
[1,]    2    3    2    3
[2,]    3    2    3    2
[3,]    2    3    2    3
  • The code produces a \(3 \times 4\) matrix filled (in column-major order) with the values 2 and 3.
  • The code runs without any errors or warnings because the matrix contains 12 cells, the input vector has two elements, and 2 evenly divides 12.

We can also use recycling when we want to overwrite multiple matrix elements with the same replacement value.

m2[1:2, 3] <- -99
m2
     [,1] [,2] [,3]
[1,]    5   -1  -99
[2,]   -2   -2  -99
[3,]    1   -3    0
m2[3, 1:2] <- c(88, 99)
m2
     [,1] [,2] [,3]
[1,]    5   -1  -99
[2,]   -2   -2  -99
[3,]   88   99    0

Exceptions

Recycling isn’t a universal shortcut, though. Sometimes, R won’t accommodate our sloppiness. 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
# 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

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
# Fails: Replace 4 elements with length-3 vector (3 does not divide 4 evenly)
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 (8 is bigger than the selection)
m1[1:2, 2:3] <- 1:8
Error in m1[1:2, 2:3] <- 1:8: number of items to replace is not a multiple of replacement length
Knowledge Check
  • What’s the difference between m1[1, ] and m1[, 1]?
  • Assume m1 is a \(3 \times 4\) matrix, v1 is a length-two vector, and v2 is a length-five vector. Why does m1 + v1 recycle silently, while m1 + v2 recycles with a warning? What’s the underlying rule?
Ready to Continue?

You’re ready progress if you can:

  • Explain what makes a matrix “just a vector with a dim attribute.”
  • Create a matrix with matrix(), and predict whether it fills by row or by column.
  • Apply arithmetic to matrices and predict when recycling will happen silently vs. with a warning.
  • Select and modify matrix elements using row and column indices.

Take the Knowledge Quiz to evaluate your learning.

Back to top