A Guide to Matrix Operations in R

In this tutorial we will discuss about matrices and common operations with them.

In R, a matrix is a collection of elements of the same data type (numeric, character, or logical) arranged into a fixed number of rows and columns.

When talking about operations on matrices, you can treat either the elements of the matrix or the whole matrix as the value you operate on. That difference is pretty clear when you compare, for example, transposing a matrix and adding a single number (or scalar) to a matrix.

The first useful function I want to show you is dim(). dim() tells us about the dimensions of a matrix. The dimensions of a matrix are simply the number of rows and columns. Other useful functions are nrow() for getting number of rows in matrix and ncol() for getting number of columns.

I will create simple 3×3 matrix:

              x <- matrix(1:9, nrow = 3, ncol = 3)

x

     [,1] [,2] [,3]

[1,]    1    4    7

[2,]    2    5    8

[3,]    3    6    9

We can get dimensions of a matrix (number of columns and number of rows) with dim() function:

              dim(x)

[1] 3 3  

nrow() and ncol():

              ncol(x)

[1] 3

nrow(x)

[1] 3

We can do mathematical operations on matrices both between matrices (if they have same dimensions) and between matrices and single numbers.

Adding a number to elements of  matrix:

A <- matrix(1:9, nrow = 3, ncol = 3)

A

     [,1] [,2] [,3]

[1,]    1    4    7

[2,]    2    5    8

[3,]    3    6    9

A + 1

     [,1] [,2] [,3]

[1,]    2    5    8

[2,]    3    6    9

[3,]    4    7   10

Each element of a matrix gets increased for 1.

We can also do mathemathical operations between matrices.

Multiplying between matrices:

A <- matrix(1:9, nrow = 3, ncol = 3)

A

     [,1] [,2] [,3]

[1,]    1    4    7

[2,]    2    5    8

[3,]    3    6    9

 B <- matrix(1:9, nrow = 3, ncol = 3)

 B

     [,1] [,2] [,3]

[1,]    1    4    7

[2,]    2    5    8

[3,]    3    6    9

 A*B

     [,1] [,2] [,3]

[1,]    1   16   49

[2,]    4   25   64

[3,]    9   36   81

Each element of matrix A gets multiplied by element from same index in matrix B.

To get elements of a matrix, we must specify row and column of the element we want with square brackets. We can retrieve single elements or whole submatrices.

Select number 5:

              elements[2,2]

[1] 5

Select rows 1&2 and columns 2& 3:

              elements[c(1,2),c(2,3)]

                   [,1] [,2]

[1,]    4    7

[2,]    5    8

Inside of squared brackets we specify rows and columns of elements we want. If we don’t specify them, we will retrieve all of the columns and rows. For example, I will take 1 and second row and all columns:

              elements[c(1,2), ]

                [,1] [,2] [,3]

[1,]    1    4    7

[2,]    2    5    8

I will take all rows and second column:

              elements[, 2]

[1] 4 5 6

If I leave both row and column, I will get whole matrix:

              elements[ , ]

                [,1] [,2] [,3]

[1,]    1    4    7

[2,]    2    5    8

[3,]    3    6    9


Select all rows and all columns except the second:

              elements[ , -2]

               [,1] [,2]

[1,]    1    7

[2,]    2    8

[3,]    3    9

What we should note is that when we specify only one row or column, we will get a vector:

              elements[ , 2]

[1] 4 5 6

 This can be stoped by using the argument drop = FALSE when indexing. I will select all rows and second column:

              elements[ , 2, drop= FALSE]

                      [,1]

[1,]    4

[2,]    5

[3,]    6

It is possible to index a matrix with a single vector. While indexing in such a way, it acts like a vector formed by stacking columns of the matrix one after another. The result is returned as a vector:

> elements <- c(9,8,7,6,5,4,3,2,1)

> dim(elements)<- c(3,3)

> elements

     [,1] [,2] [,3]

[1,]    9    6    3

[2,]    8    5    2

[3,]    7    4    1

> elements[1:4]

[1] 9 8 7 6

> elements[c(1,2,3,4)]

[1] 9 8 7 6

Two logical vectors can be used to index a matrix. In such situation, rows and columns where the value is TRUE is returned. These indexing vectors are recycled if necessary and can be mixed with integer vectors:

              elements

     [,1] [,2] [,3]

[1,]    9    6    3

[2,]    8    5    2

[3,]    7    4    1

elements[c(TRUE,FALSE,TRUE),c(TRUE,TRUE,FALSE)]

     [,1] [,2]

[1,]    9    6

[2,]    7    4

The indexing logical vector is also recycled and thus alternating elements are selected. This property is utilized for filtering of matrix elements:

              elements[elements>5]

[1] 9 8 7 6

              elements[elements%%2 == 0]

[1] 8 6 4 2

We can combine assignment operator with the above learned methods for accessing elements of a matrix to modify it:

              elements <- c(1,2,3,4,5,6,7,8,9)

dim(elements)<- c(3,3)

elements

     [,1] [,2] [,3]

[1,]    1    4    7

[2,]    2    5    8

[3,]    3    6    9

              elements[2,2] <- 10

elements

     [,1] [,2] [,3]

[1,]    1    4    7

[2,]    2   10    8

[3,]    3    6    9

Modify elements less than 5:

              elements[elements<5] <- 0

elements

     [,1] [,2] [,3]

[1,]    0    0    7

[2,]    0   10    8

[3,]    0    6    9

A common operation with matrix is to transpose it. This means arranging rows to columns and columns to rows. This can be done with the function t()

              elements <- c(1,2,3,4,5,6,7,8,9)

dim(elements)<- c(3,3)

elements

     [,1] [,2] [,3]

[1,]    1    4    7

[2,]    2    5    8

[3,]    3    6    9

t(elements)

     [,1] [,2] [,3]

[1,]    1    2    3

[2,]    4    5    6

[3,]    7    8    9

So, the t() function converts rows to columns and vice versa, like rotating the matrix.

Lets check example when we have 2 rows and 3 columns:

elements <- c(1,2,3,4,5,6)

elements <- matrix(elements, ncol = 3)

elements

     [,1] [,2] [,3]

[1,]    1    3    5

[2,]    2    4    6

Now when we transpose it:

t(elements)

     [,1] [,2]

[1,]    1    2

[2,]    3    4

[3,]    5    6

We get two columns and three rows. Earlier it was oposite.

Lets check what happens when you have one row or one column:

elements <- c(1,2,3,4,5,6)

elements <- matrix(elements, ncol = 1)

elements

     [,1]

[1,]    1

[2,]    2

[3,]    3

[4,]    4

[5,]    5

[6,]    6

t(elements)

     [,1] [,2] [,3] [,4] [,5] [,6]

[1,]    1    2    3    4    5    6

Transposing a matrix with t() function always swaps places of columns and rows and that is all.

In summary, we have studied in detail about R matrices. Moreover, we learned about the uses of matrices and operations which we perform on other matrices functions.

R makes it easy to work with data in matrices by providing native matrix functions. Even functions such as sqrt, which work with single values, work with matrices as well. When you are writing R code, feel free to take some data and interact with it, writing expressions to see what they do. R was made with this kind of experimentation in mind. Unexpected results present an opportunity to learn.