7.2 Matrix Indexing

Matrices are incredibly useful in data analysis, but the primary reason we are talking about them now is to get you used to working in two dimensions. Let’s practice sub-setting with matrices.

We use the sub-setting operator [ to pick out parts of a matrix. For example, in order to get the element in the second row and third column of numbersMat, ask for:

numbersMat[2,3]
## [1] 14

The row and column numbers are called indices.

If we want the entire second row, then we could ask for:

numbersMat[2,1:4]
##  A  B  C  D 
##  2  8 14 20

The result is a one-dimensional vector consisting of the elements in the second row of numbersMat. It inherits as its names the column names of numbersMat.

Actually, if you want the entire row you don’t have to specify which columns you want. Just leave the spot after the comma empty, like this:

numbersMat[2, ]
##  A  B  C  D 
##  2  8 14 20

What if you want some items on the second row, but only the items in columns 1, 2 and 4? Then frame your request in terms of a vector of column-indices:

numbersMat[2, c(1, 2, 4)]
##  A  B  D 
##  2  8 20

You can specify a vector of row-indices along with a vector of column-indices, if you like:

numbersMat[1:2, 1:3]
##   A B  C
## a 1 7 13
## b 2 8 14

If the vector has row or column names then you may use them in place of indices to make a selection:

numbersMat[, c("B", "D")]
##    B  D
## a  7 19
## b  8 20
## c  9 21
## d 10 22
## e 11 23
## f 12 24

You can use sub-setting to change the values of the elements of a matrix

numbersMat[2,3] <- 0
numbersMat
##   A  B  C  D
## a 1  7 13 19
## b 2  8  0 20
## c 3  9 15 21
## d 4 10 16 22
## e 5 11 17 23
## f 6 12 18 24

You can assign a value to an entire row:

numbersMat[2,] <- 0
numbersMat
##   A  B  C  D
## a 1  7 13 19
## b 0  0  0  0
## c 3  9 15 21
## d 4 10 16 22
## e 5 11 17 23
## f 6 12 18 24

In the code above, the 0 was “recycled” into each of the four elements of the second row

You can assign the elements of a vector to corresponding selected elements of a matrix:

numbersMat[2,] <- c(100, 200, 300, 400)
numbersMat
##     A   B   C   D
## a   1   7  13  19
## b 100 200 300 400
## c   3   9  15  21
## d   4  10  16  22
## e   5  11  17  23
## f   6  12  18  24

7.2.1 To Drop or Not?

Note that when we ask for a single row of numbersMat we got a regular one-dimensional vector:

numbersMat[3, ]
##  A  B  C  D 
##  3  9 15 21

The same things happens if we ask for a single column:

numbersMat[ , 2]
##   a   b   c   d   e   f 
##   7 200   9  10  11  12

We get the second column of numbersMat, but as a regular vector. It’s not a “column” anymore. (Note that it inherits the row names from numbersMat.)

When a subset of a matrix comes from only one row or column, R takes the opportunity to “drop” the class of the subset from “matrix” to “vector.” If you would like the subset to stay a vector, set the drop parameter, which by default is TRUE, to FALSE. Thus the second column of numbersMat, kept as a matrix with six rows and one column, is found as follows:

numbersMat[ , 2, drop = FALSE]
##     B
## a   7
## b 200
## c   9
## d  10
## e  11
## f  12

In most applications people want the simpler vector structure, so they usually leave drop at its default value.

7.2.2 Practice Exercises

In these exercises we’ll work with the following matrix:

numbers <- 1:40
practiceMatrix <- matrix(numbers, nrow = 4)
rownames(practiceMatrix) <- letters[1:4]
colnames(practiceMatrix) <- LETTERS[1:10]
practiceMatrix
##   A B  C  D  E  F  G  H  I  J
## a 1 5  9 13 17 21 25 29 33 37
## b 2 6 10 14 18 22 26 30 34 38
## c 3 7 11 15 19 23 27 31 35 39
## d 4 8 12 16 20 24 28 32 36 40
  1. Write two different one-line commands to get this matrix:

    ##   B  C  D  E
    ## a 5  9 13 17
    ## c 7 11 15 19
  2. Write a one-line command to get this matrix:

    ##   A  C  E  G  I
    ## a 1  9 17 25 33
    ## b 2 10 18 26 34
    ## c 3 11 19 27 35
    ## d 4 12 20 28 36
  3. Write a one-line command to get this vector:

    ## a b c d 
    ## 1 2 3 4
  4. Write a one-line command to get this vector:

    ##  A  B  C  D  E  F  G  H  I  J 
    ##  2  6 10 14 18 22 26 30 34 38
  5. Write a one-line command to get this matrix:

    ##   A
    ## a 1
    ## b 2
    ## c 3
    ## d 4
  6. Write a convenient one-line command to get this matrix:

    ##   A B  C  D  E  F  G  H  I
    ## a 1 5  9 13 17 21 25 29 33
    ## b 2 6 10 14 18 22 26 30 34
    ## c 3 7 11 15 19 23 27 31 35
    ## d 4 8 12 16 20 24 28 32 36
  7. Write a convenient one-line command to get this matrix:

    ##   A  C  D  E  F  G  H  I
    ## a 1  9 13 17 21 25 29 33
    ## b 2 10 14 18 22 26 30 34
    ## c 3 11 15 19 23 27 31 35
    ## d 4 12 16 20 24 28 32 36
  8. Write a function called myRowSums() that will find the sums of the rows of any given matrix. The function should use a for-loop (see the Chapter on Flow Control). The function should take a single parameter called mat, the matrix whose rows the user wishes to sum. It should work like this:

    myMatrix <- matrix(1:24, ncol = 6)
    myRowSums(mat = myMatrix)
    ## [1] 66 72 78 84

7.2.3 Solutions to Practice Exercises

  1. Here are two ways:

    practiceMatrix[c(1,3), 2:5]
    practiceMatrix[c("a","c"), 2:5]
  2. Here’s one way:

    practiceMatrix[ , seq(1, 9, by = 2)]
  3. Here’s one way:

    practiceMatrix[ , 1]
  4. Here’s one way:

    practiceMatrix[2, ]
  5. Here’s one way:

    practiceMatrix[ , 1, drop = FALSE]
  6. Here’s one way:

    practiceMatrix[ , -10]
  7. Here’s one way:

    practiceMatrix[ , -c(2, 10)]
  8. Here is one way to write the function:

    myRowSums <- function(mat) {
      n <- nrow(mat)
      sums <- numeric(n)
      for (i in 1:n) {
        sums[i] <- sum(mat[i, ])
      }
      sums
    }