Practice: Matrices

Stat 133

Author

Gaston Sanchez

Learning Objectives
  • Create Matrices with matrix()
  • Create Matrices with cbind() and rbind()
  • Subset (subscript) matrices with brackets mat[row,col]

1 Matrices and matrix()

An R matrix provides a rectangular data object: to handle data in a two-dimensional array.

The function matrix() is the primary function to create matrices in R. matrix() takes—ideally—a vector x as input, and returns a matrix arranging the elements in x according to the specified number of rows nrow and columns ncol. For example:

# example 1
m1 <- matrix(1:6, nrow = 2, ncol = 3)
m1
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
# example 2
m2 <- matrix(1:6, nrow = 3, ncol = 2)
m2
     [,1] [,2]
[1,]    1    4
[2,]    2    5
[3,]    3    6

A few important aspects about R matrices:

  • R internally stores matrices as vectors.

  • Which means that matrices are also atomic (i.e. all the elements in a matrix must be of the same data type).

  • Matrices in R are stored column-major (i.e. by columns).

  • This is like Fortran, Matlab, and Julia, but not like C or Python (e.g. numpy)

1.1 Argument byrow

The matrix() function comes with the byrow argument that allows you to arrange values by-row instead of by-column; here’s an example:

# example 2
m3 <- matrix(1:6, nrow = 2, ncol = 3, byrow = TRUE)
m3
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6

Keep in mind that m3 is still stored column-major. You can confirm this by asking R to vectorize m3

as.vector(m3)
[1] 1 4 2 5 3 6

1.2 Another matrix() example

How do you create the following matrix?

     [,1]       [,2]     
[1,] "Harry"    "Potter" 
[2,] "Ron"      "Weasley"
[3,] "Hermione" "Granger"

Here’s one way to create the preceding matrix:

# vector of names
hp <- c("Harry", "Ron", "Hermione",
        "Potter", "Weasley", "Granger")

# matrix filled up by rows
matrix(hp, nrow = 3)
     [,1]       [,2]     
[1,] "Harry"    "Potter" 
[2,] "Ron"      "Weasley"
[3,] "Hermione" "Granger"

Here’s another way to create the same matrix:

# vector of names
hp <- c("Harry", "Potter", "Ron", "Weasley", 
        "Hermione", "Granger")

# matrix filled up by rows
matrix(hp, nrow = 3, byrow = TRUE)
     [,1]       [,2]     
[1,] "Harry"    "Potter" 
[2,] "Ron"      "Weasley"
[3,] "Hermione" "Granger"

1.3 Dimensions and Names

Matrices have:

  • length(): number of cells

  • typeof(): data type (recall that matrices are atomic)

  • dim(): dimensions; number of rows and columns

    • nrow(): number of rows
    • ncol(): number of columns

We also have functions that let you set/get the names for either the rows or the columns (or both) of a matrix:

  • rownames()

  • colnames()

  • dimnames()

# rownames
set.seed(123)
A <- matrix(runif(12), nrow = 3, ncol = 4)
rownames(A) <- paste0("row", 1:nrow(A))
A
          [,1]      [,2]      [,3]      [,4]
row1 0.2875775 0.8830174 0.5281055 0.4566147
row2 0.7883051 0.9404673 0.8924190 0.9568333
row3 0.4089769 0.0455565 0.5514350 0.4533342
rownames(A)
[1] "row1" "row2" "row3"
set.seed(123)
B <- matrix(runif(12), nrow = 3, ncol = 4)
colnames(B) <- paste0("col", 1:ncol(B))
B
          col1      col2      col3      col4
[1,] 0.2875775 0.8830174 0.5281055 0.4566147
[2,] 0.7883051 0.9404673 0.8924190 0.9568333
[3,] 0.4089769 0.0455565 0.5514350 0.4533342
colnames(B)
[1] "col1" "col2" "col3" "col4"
set.seed(123)
C <- matrix(runif(12), nrow = 3, ncol = 4)
rownames(C) <- paste0("row", 1:nrow(C))
colnames(C) <- paste0("col", 1:ncol(C))
C
          col1      col2      col3      col4
row1 0.2875775 0.8830174 0.5281055 0.4566147
row2 0.7883051 0.9404673 0.8924190 0.9568333
row3 0.4089769 0.0455565 0.5514350 0.4533342
dimnames(C)
[[1]]
[1] "row1" "row2" "row3"

[[2]]
[1] "col1" "col2" "col3" "col4"

1.4 Recycling in matrices

Recycling rules also apply to matrices, for example:

x <- letters[1:4]
X <- matrix(x, nrow = 4, ncol = 3)
X
     [,1] [,2] [,3]
[1,] "a"  "a"  "a" 
[2,] "b"  "b"  "b" 
[3,] "c"  "c"  "c" 
[4,] "d"  "d"  "d" 

Here are more recycling examples:

# "empty" matrices
mat_chr <- matrix("", nrow = 4, ncol = 3)

mat_num <- matrix(0, nrow = 4, ncol = 3)

mat_lgl <- matrix(NA, nrow = 4, ncol = 3)

1.5 Row and Column binding

Another way to form matrices is by joining or binding either vectors or matrices by rows—with rbind()—or by columns—with cbind(). For example:

a <- c(2, 4, 6)
b <- c(1, 3, 5)
# column bind
cbind(a, b)
     a b
[1,] 2 1
[2,] 4 3
[3,] 6 5
cbind(m3, b)
Warning in cbind(m3, b): number of rows of result is not a multiple of vector
length (arg 2)
           b
[1,] 1 2 3 1
[2,] 4 5 6 3
# row bind
rbind(b, a)
  [,1] [,2] [,3]
b    1    3    5
a    2    4    6
rbind(m2, a)
Warning in rbind(m2, a): number of columns of result is not a multiple of
vector length (arg 2)
  [,1] [,2]
     1    4
     2    5
     3    6
a    2    4

2 Subsetting Matrices

To do subsetting (i.e. subscripting, indexing) on a matrix, you use bracket notation, passing two indexing vectors separated by a comma: the first one for indexing rows, the second one for indexing columns.

# cell in row 1, column 3 of matrix m1
m1[1,3]
[1] 5
# 2nd column of matrix m2
m2[ ,2]
[1] 4 5 6
# 1st row of matrix m3
m3[1, ]
[1] 1 2 3

Keep in mind that you can also specify a single indexing vector inside brackets, without any commas:

# 2nd element
m1[2]
[1] 2

And you can also specify double brackets:

# 2nd element
m1[[2]]
[1] 2
Warning

Keep in mind that the two preceding subsetting examples are not commonly used among R users. While they are perfectly valid commands, we prefer to explicitly denote the comma , while subsetting matrices.


3 Some Matrix Algebra Operators and Functions

In case you are curious about what kind of common matrix operators and linear algebra functions are available in R:

Operator Description Example
+ addition A + B
- subtraction A - B
* elementwise product A * B
%*% matrix product A %*% B
t() transpose t(A)
det() determinant det(A)
diag() extract diagonal diag(A)
solve() inverse solve(A)
Note

Make sure the dimensions of matrices are conformable when using an operator or some calculation on them.

Function Description
upper.tri() upper triangular part of a matrix
lower.tri() upper triangular part of a matrix
eigen() eigenvalue decomp.
svd() singular value decomp.
lu() Triangular decomposition
qr() QR decomposition
chol() Cholesky decomposition