[,1] [,2] [,3] [,4]
[1,] 4 0 2 1
[2,] 3 1 4 2
[3,] 2 0 1 3
8 Matrices and arrays
Matrices and arrays are fundamental data structures in R that enable efficient storage and manipulation of multi-dimensional data. Throughout this chapter, we explore how to create, manipulate, and perform operations on matrices and arrays.
8.1 Definition of a matrix
In mathematics, a matrix is a rectangular array of elements arranged in rows and columns. A matrix is defined by its dimensions, which specify the number of rows and columns it contains. For example:
The matrix
Then
Also
The main diagonal of a matrix refers to the collection of elements that run from the top-left corner to the bottom-right corner of the matrix. In other words, it is a sequence of elements where the row index and the column index are the same (
Example
The column vectors are:
, , ,The row vectors are:
, ,The main diagonal consisted of the numbers 4, 1, and 1.
8.2 Creating a matrix in R
In R, each data object has various attributes that describe its characteristics and structure. For example, matrices are created using the dim
(dimension) attribute, which facilitates matrix algebra operations.
Matrix
A matrix is a two-dimensional atomic vector used to represent data organized into rows and columns, where all elements are of the , such as numeric, character, or logical.
Adding a dimension attribute of 2 to an atomic vector allows it to be reshaped into a two-dimensional matrix. For example:
The dim()
is an in-built R function that either sets or returns the dimension of the matrix, array, or data frame. Here, the dim()
function sets the dimension for the X1
object.
Most often we create a matrix using the matrix()
function. In this case, we need to specify the number of rows and columns in the function.
Example: numeric matrix
[,1] [,2] [,3] [,4]
[1,] 4 0 2 1
[2,] 3 1 4 2
[3,] 2 0 1 3
The matrix is filled by columns (default column-wise), so entries can be thought of starting in the “upper left” corner and running down the columns. If we want the matrix to be filled by rows we must add the extra argument byrow = TRUE
in the matrix()
function, as follows:
X3 <- matrix(x_numeric, nrow = 3, ncol = 4, byrow = TRUE)
X3
[,1] [,2] [,3] [,4]
[1,] 4 3 2 0
[2,] 1 0 2 4
[3,] 1 1 2 3
The type
of data, the class
and the dimension
of the X3
object are:
Note that the typeof()
function returns the data type contained within an object (i.e., double), while the class()
function returns the structural type (i.e., matrix) of the object.
dim(X3)
[1] 3 4
In this example, the dim()
function takes the R object X3
as an argument and returns its dimension.
Example: logical matrix
x_logical <- c(TRUE, FALSE, FALSE, TRUE, FALSE, FALSE)
X4 <- matrix(x_logical, nrow = 2, ncol = 3)
X4
[,1] [,2] [,3]
[1,] TRUE FALSE FALSE
[2,] FALSE TRUE FALSE
The data type of the X4
object is:
typeof(X4)
[1] "logical"
Example: character matrix
[,1] [,2] [,3]
[1,] "a" "c" "e"
[2,] "b" "d" "f"
The data type of the X5
object is:
typeof(X5)
[1] "character"
8.3 Using matrix subscripts
In R, we can access rows, columns, or individual elements of a matrix using subscripts within brackets. Specifically, X[i, ]
refers to the X[ , j]
refers to X[i, j]
refers to the
# create a 2x5 numeric matrix filled by column
X <- matrix(1:10, nrow=2)
X
[,1] [,2] [,3] [,4] [,5]
[1,] 1 3 5 7 9
[2,] 2 4 6 8 10
X[2, ] # select the 2nd row
[1] 2 4 6 8 10
X[, 2] # select the 2nd column
[1] 3 4
X[1, 4] # select the element in the 1st row, 4th column
[1] 7
Furthermore, we can use numeric vectors within the brackets to select multiple rows and/or columns, as shown in the example below:
X[1, c(4, 5)] # select the elements in the 1st row, 4th and 5th column
[1] 7 9
INFO
Similar to atomic vectors, square brackets [ ] are used to select individual or multiple elements from a matrix. Since matrices have two dimensions, both the row(s) and column(s) must be specified, separated by a in the format [row(s), column(s)].
8.4 Special types of matrices
8.4.1 The square matrix
A square matrix is a matrix that has an equal number of rows and columns.
Example
In R:
[,1] [,2] [,3]
[1,] 5 1 0
[2,] 3 -1 2
[3,] 4 0 -1
The main diagonal consists of the numbers 5, -1, and -1. In R, we can extract the diagonal elements of a matrix using the diag()
function, as follows:
diag(M)
[1] 5 -1 -1
The trace of a square matrix is the sum of its main diagonal elements. In the example above, the trace is
8.4.2 The diagonal matrix
A diagonal matrix is a special type of square matrix where all the elements outside the main diagonal are zero.
Example
In R, we can create a diagonal matrix of size 3 using the diag()
function as follows:
8.4.3 The identity matrix
An identity matrix, often denoted as
Example
In R, we can create the identity matrix of size 3 by using the diag()
function:
I <- diag(3)
I
[,1] [,2] [,3]
[1,] 1 0 0
[2,] 0 1 0
[3,] 0 0 1
8.4.4 Symmetric matrix
A symmetric matrix is a square matrix that remains unchanged when we transpose it (see also section 8.5.1), which means we swap its rows and columns.
Example
[,1] [,2] [,3]
[1,] 13 -4 2
[2,] -4 11 -2
[3,] 2 -2 8
In
8.5 Basic matrix algebra
8.5.1 The transpose of a matrix
The transpose operation swaps the rows and columns of an
Example
Given the matrix
The transpose of
In R:
We define the matrix
To compute the transpose of matrix t()
function:
t(A)
[,1] [,2]
[1,] 4 0
[2,] -1 1
[3,] -5 -2
8.5.2 Matrix addition
Matrix addition is an operation performed on two matrices with the same dimensions. It involves adding the corresponding elements of the matrices (element-wise addition) to create a new matrix of the same dimension.
Example
Consider the following matrices
To add
In the resulting matrix, the element in the first row and first column is
In R:
A
[,1] [,2] [,3]
[1,] 4 -1 -5
[2,] 0 1 -2
[,1] [,2] [,3]
[1,] 3 1 -5
[2,] 0 2 -2
To perform the addition of matrices +
operator:
A + B
[,1] [,2] [,3]
[1,] 7 0 -10
[2,] 0 3 -4
8.5.3 Scalar multiplication of matrices
In scalar multiplication, each element of a matrix is multiplied by a given scalar (a constant number). For example:
Example
Consider the scalar multiplication of matrix
In the resulting matrix, the element in the first row and first column is
In R:
A
[,1] [,2] [,3]
[1,] 4 -1 -5
[2,] 0 1 -2
-3 * A
[,1] [,2] [,3]
[1,] -12 3 15
[2,] 0 -3 6
8.5.4 Hadamard product
The Hadamard product is the element-wise multiplication of two matrices,
Example
In the resulting matrix, the element in the first row and first column is
In R:
A
[,1] [,2] [,3]
[1,] 4 -1 -5
[2,] 0 1 -2
B
[,1] [,2] [,3]
[1,] 3 1 -5
[2,] 0 2 -2
The output will be a new matrix with the same dimensions as the original matrices:
A * B
[,1] [,2] [,3]
[1,] 12 -1 25
[2,] 0 2 4
8.5.5 Matrix product
Suppose
IMPORTANT
Before multiplying two matrices, we must ensure that their dimensions are compatible. The number of columns in the first matrix must equal the number of rows in the second matrix.
Example: compatible matrices
Suppose we have the following matrices
The row-by-column multiplication of these two matrices results in a new matrix:
We observe that the resulting matrix has dimensions
the element in the first row and first column of the new matrix is the result of the dot product between the first row of
and the first column of :the element in the first row and second column of the new matrix is the result of the dot product between the first row of
and the second column of :the element in the second row and first column of the new matrix is the result of the dot product between the second row of
and the first column of :the element in the second row and second column of the new matrix is the result of the dot product between the second row of
and the second column of :
Matrix multiplication can be achieved using the dot product operator %*%
.
A
[,1] [,2] [,3]
[1,] 4 -1 -5
[2,] 0 1 -2
[,1] [,2]
[1,] -5 5
[2,] 2 1
[3,] -2 0
A %*% C
[,1] [,2]
[1,] -12 19
[2,] 6 1
Example: multiplication after transposition
Consider the matrices
and
These matrices are not compatible for multiplication because the number of columns in
Now, the
In R:
t(A)
[,1] [,2]
[1,] 4 0
[2,] -1 1
[3,] -5 -2
B
[,1] [,2] [,3]
[1,] 3 1 -5
[2,] 0 2 -2
[,1] [,2] [,3]
[1,] 12 4 -20
[2,] -3 1 3
[3,] -15 -9 29
However, it is more efficient and faster using the crossprod()
function:
crossprod(A, B)
[,1] [,2] [,3]
[1,] 12 4 -20
[2,] -3 1 3
[3,] -15 -9 29
8.5.6 The inverse of a matrix
Given a square matrix
Example
Let’s consider a 3x3 matrix
In R, we can use the generic built-in solve()
function to find the inverse of the matrix
# create the matrix E
E <- matrix( c(1, 2, 1, -1, 0, 1, 1, 1, 2), nrow = 3)
# the solve() function takes a matrix as input and returns the matrix's inverse
E_inv <- solve(E)
E_inv
[,1] [,2] [,3]
[1,] -0.25 0.75 -0.25
[2,] -0.75 0.25 0.25
[3,] 0.50 -0.50 0.50
Therefore, we can verify that if we multiply the matrix
E %*% E_inv
[,1] [,2] [,3]
[1,] 1 0 0
[2,] 0 1 0
[3,] 0 0 1
8.6 Arrays
8.6.1 Creating an array
An array is similar to matrix but can have more than two dimensions. Conceptually, it can be thought of as a stack of matrices, where each matrix has a specific number of rows and columns. These layers are stacked on top of each other, forming the multidimensional structure of the array.
Let’s create an example of an array using the array()
function from base R:
, , 1
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
, , 2
[,1] [,2] [,3]
[1,] 7 9 11
[2,] 8 10 12
, , 3
[,1] [,2] [,3]
[1,] 13 15 17
[2,] 14 16 18
, , 4
[,1] [,2] [,3]
[1,] 19 21 23
[2,] 20 22 24
This example demonstrates how arrays extend matrices by providing greater flexibility in data representation. Each layer is a 2x3
matrix, and four such layers are stacked to form the array. Like matrices, arrays contain elements of a single data type (e.g., numeric). We can check the array’s type
, class
and the dimensions
as follows:
The output confirms a 3-dimensional array of integers with dimensions 2, 3, and 4.
8.6.2 Indexing in an array
To access a specific matrix within the array, for example, the 3rd matrix, we type:
# access the 3rd matrix of the array
my_array[, , 3]
[,1] [,2] [,3]
[1,] 13 15 17
[2,] 14 16 18
To access the 2nd row of the 3rd matrix:
# access the 2nd row of the 3rd matrix of the array.
my_array[2, , 3]
[1] 14 16 18
To access the element in the 1st row and 3rd column of the 3rd matrix:
# access the element in the 1st row and 3rd column of the 3rd matrix
my_array[1, 3, 3]
[1] 17
8.7 Operations with arrays
Arrays in R support element-wise arithmetic operations, such as addition, subtraction, multiplication, and division, allowing users to perform computations on corresponding elements across arrays.
8.7.1 Addition of arrays
Let’s consider the addition of two arrays, arr1
and arr2
, each with dimensions 2×3×2:
, , 1
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
, , 2
[,1] [,2] [,3]
[1,] 7 9 11
[2,] 8 10 12
, , 1
[,1] [,2] [,3]
[1,] 13 15 17
[2,] 14 16 18
, , 2
[,1] [,2] [,3]
[1,] 19 21 23
[2,] 20 22 24
# Element-wise addition of two arrays
array_addition <- arr1 + arr2
array_addition
, , 1
[,1] [,2] [,3]
[1,] 14 18 22
[2,] 16 20 24
, , 2
[,1] [,2] [,3]
[1,] 26 30 34
[2,] 28 32 36
In R, the addition operation for arrays is performed element-wise, where corresponding elements at the same indices in arr1
and arr2
are summed to produce the elements in array_addition
.
8.7.2 Multiplication of arrays
Similarly, we can perform element-wise multiplication between two arrays:
# Element-wise multiplication of two arrays
array_multiplication <- arr1 * arr2
array_multiplication
, , 1
[,1] [,2] [,3]
[1,] 13 45 85
[2,] 28 64 108
, , 2
[,1] [,2] [,3]
[1,] 133 189 253
[2,] 160 220 288