# example 1
<- matrix(1:6, nrow = 2, ncol = 3)
m1 m1
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
Stat 133
matrix()
cbind()
and rbind()
mat[row,col]
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
<- matrix(1:6, nrow = 2, ncol = 3)
m1 m1
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
# example 2
<- matrix(1:6, nrow = 3, ncol = 2)
m2 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)
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
<- matrix(1:6, nrow = 2, ncol = 3, byrow = TRUE)
m3 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
matrix()
exampleHow 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
<- c("Harry", "Ron", "Hermione",
hp "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
<- c("Harry", "Potter", "Ron", "Weasley",
hp "Hermione", "Granger")
# matrix filled up by rows
matrix(hp, nrow = 3, byrow = TRUE)
[,1] [,2]
[1,] "Harry" "Potter"
[2,] "Ron" "Weasley"
[3,] "Hermione" "Granger"
Matrices have:
length()
: number of cells
typeof()
: data type (recall that matrices are atomic)
dim()
: dimensions; number of rows and columns
nrow()
: number of rowsncol()
: number of columnsWe 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)
<- matrix(runif(12), nrow = 3, ncol = 4)
A 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)
<- matrix(runif(12), nrow = 3, ncol = 4)
B 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)
<- matrix(runif(12), nrow = 3, ncol = 4)
C 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"
Recycling rules also apply to matrices, for example:
<- letters[1:4]
x <- matrix(x, nrow = 4, ncol = 3)
X 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
<- matrix("", nrow = 4, ncol = 3)
mat_chr
<- matrix(0, nrow = 4, ncol = 3)
mat_num
<- matrix(NA, nrow = 4, ncol = 3) mat_lgl
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:
<- c(2, 4, 6)
a <- c(1, 3, 5) b
# 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
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
1,3] m1[
[1] 5
# 2nd column of matrix m2
2] m2[ ,
[1] 4 5 6
# 1st row of matrix m3
1, ] m3[
[1] 1 2 3
Keep in mind that you can also specify a single indexing vector inside brackets, without any commas:
# 2nd element
2] m1[
[1] 2
And you can also specify double brackets:
# 2nd element
2]] m1[[
[1] 2
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.
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) |
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 |