Chapter 6 Matrices
A matrix is a table of data organized into rows and columns. \[\begin{equation} \mathbf{A} = \begin{bmatrix} a_{11} & a_{12} & \ldots & a_{1p} \\ a_{21} & a_{22} & \ldots & a_{2p} \\ \vdots & \vdots & \ddots & \vdots \\ a_{n1} & a_{12} & \ldots & a_{np} \end{bmatrix} \nonumber \end{equation}\]
The matrix \(\mathbf{A}\) has \(n\) rows and \(p\) columns.
The matrix element \(a_{ij}\) represents the number in the \(i^{th}\) row and \(j^{th}\) column.
R allows the elements of a matrix to be any type.
As with vectors, the elements of a matrix in R must all have the same type.
6.1 Creating matrices in R
The most common way to create a matrix is with the matrix function.
The form of the matrix function is
- x is a vector that you want to convert into a matrix.
nrow
is the number of rows you want the matrix to have.ncol
is the number of columns you want the matrix to have.x
could be a single number (a vector of length one) in which case the returned matrix will have all the same entries.
- If we wanted to create a matrix named
A
with 2 rows and 3 columns that contains only zeros, we could use the following code
## [,1] [,2] [,3]
## [1,] 0 0 0
## [2,] 0 0 0
To convert a vector into a matrix
Convert the vector (1, 2, 3, 4, 5, 6) into a matrix with 2 rows and 3 columns
## [,1] [,2] [,3]
## [1,] 1 3 5
## [2,] 2 4 6
- Notice that matrix function fills in the matrix entries by columns (i.e, it fills in the numbers from
x
in the first column, then moves to the second, etc.)- This is referred to as filling in the entries “by column”
## [,1] [,2] [,3]
## [1,] 1 3 5
## [2,] 2 4 6
- You can instead fill in the matrix entries by rows by using the keyword argument
byrow = TRUE
## [,1] [,2] [,3]
## [1,] 1 2 3
## [2,] 4 5 6
- It is often useful to create a matrix which has all the same columns (or rows):
## [,1] [,2] [,3]
## [1,] 1 1 1
## [2,] 2 2 2
## [,1] [,2] [,3]
## [1,] 1 3 2
## [2,] 2 1 3
## [,1] [,2] [,3]
## [1,] 1 2 3
## [2,] 1 2 3
6.2 Accessing different features of a matrix
6.2.1 Accessing elements of a matrix
To access the \((i,j)\) element of a matrix
A
, use the syntaxA[i,j]
As an example of this, let’s create a \(2 \times 3\) matrix
A
and look at the \((2,1)\) element ofA
:
## [,1] [,2] [,3]
## [1,] 1 2 3
## [2,] 4 5 6
## [1] 4
You can access different subsets of a matrix by using vectors of indeces rather than single numbers in the indexing bracket.
For example, if you want to look at elements \((2, 1)\) and \((2,2)\) of
A
, you can use the following syntax:
## [1] 4 5
- Similarly, if you want to access all elements of
A
in either the first two rows or first two columns ofA
, you can use the following syntax:
## [,1] [,2]
## [1,] 1 2
## [2,] 4 5
- To access the entire kth column of
A
, use the syntaxA[,k]
.- To access the entire kth row of
A
, use the syntaxA[k,]
- To access the entire kth row of
## [1] 2 5
- Using nrow() or ncol() let you see the number of rows or columns of a matrix.
## [1] 2
## [1] 3
- dim will return both the number of rows and columns.
## [1] 2 3
While using the
A[i,j]
syntax is a more typical way of accessing specific elements of a matrix, you can also access the elements of a matrix as you would with a vector.For a matrix, the indexing increases by column
- For example, if
A
has 3 rows: A[1]=A[1,1]
,A[2]=A[2,1]
,A[3]=A[3,1]
,A[4]=A[1,2]
, …
- For example, if
For example if we access the “4th” and “5th” elements of a \(2 x 3\) matrix
## [,1] [,2] [,3]
## [1,] 1 2 3
## [2,] 4 5 6
## [1] 5 3
- I don’t really use this way of accessing matrix elements much though,
in some cases, it is more convenient (e.g.,
A[ which(A > 3) ]
)
- You can also access elements of a matrix like a vector using logical subsetting
## [1] 2 4 6
## [1] 4 5 6
6.2.2 Diagonals of Matrices
The diagonals of a matrix are the elements of the matrix where the row index equals the column index.
In a diagonal matrix, all non-diagonal elements must be zero.
To create a diagonal matrix in R, use the
diag
function.- You must provide the vector of diagonal elements as the input to
diag
- You must provide the vector of diagonal elements as the input to
## [,1] [,2] [,3] [,4]
## [1,] 1 0 0 0
## [2,] 0 2 0 0
## [3,] 0 0 3 0
## [4,] 0 0 0 4
- If you use
diag(A)
where the input argumentA
is a matrix, this will return the diagonal elements ofA
.
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
## [1] 1 5 9
Working with off-diagonal elements.
The function
upper.tri(A)
returns a logical matrix of the same dimension asA
withTRUE
values on the “upper diagonal” part of the matrix.- Thus, you can use
upper.tri
to update the upper diagonal parts of a matrix.
- Thus, you can use
## [,1] [,2] [,3]
## [1,] 1 0 0
## [2,] 2 5 0
## [3,] 3 6 9
- Similarly,
lower.tri(A)
allows you to look at the subset of entries on the “lower diagonal” part of a matrix.
## [,1] [,2] [,3]
## [1,] 10 0 0
## [2,] 11 13 0
## [3,] 12 14 15
6.2.3 Naming rows or columns
- You can give a name to each row with the rownames function.
- The collection of row names of a matrix should be a vector.
## [,1] [,2] [,3]
## a 1 3 5
## b 2 4 6
- You can actually access rows of a matrix by name:
## [1] 1 3 5
## [1] 1 3 5
- Similarly, you can access columns of a matrix by name:
## c1 c2 c3
## a 1 3 5
## b 2 4 6
## c2 c3
## 4 6
## c2 c3
## 4 6
6.2.4 Combining rows or columns
- You can “join” matrices in “vertical” or “horizontal” ways
by using the functions
cbind
(column bind)rbind
(row bind)
## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] 1 3 5 1 9 25
## [2,] 2 4 6 4 16 36
## [,1] [,2] [,3]
## [1,] 1 3 5
## [2,] 2 4 6
## [3,] 1 9 25
## [4,] 4 16 36
6.3 Applying functions to matrices
You can directly use matrices as input arguments with many of the widely-used built-in R functions.
Functions like sum or mean will take the sum (or average) of all the elements of a matrix:
## [1] 21
## [1] 3.5
## [1] 1.870829
- You can take the transpose of a matrix
A
usingt(A)
.- You can convert a matrix
A
into a vector usingas.vector(A)
or simplyc(A)
.
- You can convert a matrix
## [,1] [,2] [,3]
## [1,] 1 3 5
## [2,] 2 4 6
## [,1] [,2]
## [1,] 1 2
## [2,] 3 4
## [3,] 5 6
## [1] 1 2 3 4 5 6
## [1] 1 3 5 2 4 6
6.3.1 Mathematical operations with matrices
- Using
+,-,*,/
with two matrices performs element-wise addition, subtraction, multiplication, and division.
## [,1] [,2] [,3]
## [1,] 2 4 6
## [2,] 8 10 12
## [,1] [,2] [,3]
## [1,] 0 0 0
## [2,] 0 0 0
## [,1] [,2] [,3]
## [1,] 1 4 9
## [2,] 16 25 36
Note that
A*B
does not perform true matrix multiplication of matricesA
andB
.Matrix multiplication is done with
%*%
## [,1] [,2]
## [1,] 14 32
## [2,] 32 77
## [,1] [,2] [,3]
## [1,] 17 22 27
## [2,] 22 29 36
## [3,] 27 36 45
6.4 Matrix Functionals
6.4.1 Functions applied to each row/column
- We can take the sum or mean of each row/column of a matrix by using either
rowSums
,rowMeans
,colSums
, orcolMeans
.
## [,1] [,2] [,3]
## [1,] 1 3 5
## [2,] 2 4 6
## [1] 9 12
## [1] 3 7 11
## [1] 3 4
- While
rowSums
works perfectly fine, let’s try writing our own rowSums() function:
myRowSums <-function(x){
ret <- rep(NA,nrow(x)) ## make an empty vector
for(i in 1:nrow(x)) {
ret[i] <-sum(x[i,]) ## take the sum of i-th row
}
return (ret)
}
rowSums(A)
## [1] 9 12
## [1] 9 12
The implementation by the function
myRowSums
works fine.However, it is a bit cumbersome to write such a function whenever we want to compute column-wise/row-wise summary statistics.
It would be nice if there were a quick & general way to do the following:
- For each row or column of a matrix …
- Evaluate a function using the row/column vector as input
- Return the collection of results as a numeric vector.
6.4.2 apply(): dimension-wise aggregation
## [1] 9 12
## [1] 9 12
## [1] 3 7 11
## [1] 3 7 11
First parameter of apply: the input matrix.
Second parameter of apply: the dimension over which to aggregate
- 1:rows, 2:columns
Third parameter of apply: function to evaluate for each row/column
## [,1] [,2] [,3]
## [1,] 1 3 5
## [2,] 2 4 6
## [1] 9 12
## [1] 3 7 11
- Examples of using apply:
## [1] 1.5 3.5 5.5
## [1] 1.5 3.5 5.5
## [1] 2 4 6
6.4.3 Using apply with your own function
Suppose that instead of simply taking the row-wise or column-wise means we want to do the following:
For each row/column:
- Calculate the squared sum of each row/column.
- Return the vector of squared sums.
How can we do this using apply()?
A big advantage of the apply function is the flexibility it gives you.
You can use your own functions to compute row-wise/column-wise summary measures for certain measures that may not be implemented in base R.
## define a function named sqsum
sqsum <- function(x) {
return( sum(x*x) ) ## very simple implementation
}
apply(A, 1, sqsum) ## run sqsum() funciton
## [1] 35 56
You can actually write the function definition inside of the apply function.
This can be convenient when using straightforward functions that can be written on a single line:
## [1] 35 56
- Or, we can write the above apply statement in an even simpler form:
## You can omit return() and {} especially
## for simple function definitions
apply(A, 1, function(x) sum(x*x) ) ## Even simpler!
## [1] 35 56
- apply() can also return a matrix
## [,1] [,2]
## [1,] 1 2
## [2,] 5 6
## [,1] [,2] [,3]
## [1,] 1 3 5
## [2,] 2 4 6
6.5 Exercises
- Write a function that has two input arguments A and B
- A and B are both matrices with the same dimension (same number of rows and columns).
- The function returns a matrix D.
- The
[i,j]
element of D should equalA[i,j]
ifA[i,j] < B[i,j]
and equalB[i,j]
ifA[i,j] >= B[i,j]
. - You can use either a nested for loop or logical indexing.
- Suppose we define the matrix
X
as
What will be the value of apply(X, 2, sum)[2]
?
- Write a function called
PairwiseMedianDiffs
that has two numeric matricesA
andB
as the input arguments. These two input matrices are assumed to have the same dimensions. This function should return a \(p \times p\) matrix (where \(p\) is the number of columns inA
). The[i,j]
element of the returned matrix should equal the median of the \(i^{th}\) column ofA
minus the median of the \(j^{th}\) column ofB
.