Linear Algebra in R#

Here I briefly introduce the use of matrix algebra manipulations for R. Other programs are arguably better for pure linear algebra work (e.g. Matlab or Julia), but R is a very good environment for mixing modeling including running pre-packaged statistical commands and linear algebra. In my opinion stata’s linear algebra code is a lot more intuitive than R’s.

Creating vectors and matrices#

Suppose we want to define a row vector \(\mathbf{a}\) as

(51)#\[\begin{equation} \mathbf{a} = \begin{bmatrix} 1 & 2 & 3 \end{bmatrix} \end{equation}\]

we can enter this in R as

a <- cbind(1,2,3)
print(a)
     [,1] [,2] [,3]
[1,]    1    2    3

If instead, we wanted a column vector

(52)#\[\begin{equation} \mathbf{a} = \begin{bmatrix} 1 \\ 2 \\ 3 \end{bmatrix} \end{equation}\]

we use this

a <- rbind(1,2,3)
print(a)
     [,1]
[1,]    1
[2,]    2
[3,]    3

Creating Matrices and Vectors from DataFrames#

Sometimes we want to use information in R DataFrames for matrix operations. To convert part (or all) of a DataFrame to a matrix, use data.matrix(frame). Here is an example:

library(foreign)
tk.df = read.dta("http://rlhick.people.wm.edu/econ407/data/tobias_koop.dta")
tk.matrix = data.matrix(tk.df)

or if we only need a few columns and only some rows:

tk.matrix = data.matrix(tk.df[tk.df$time == 4,c("educ", "pexp", "ability")])

to construct a matrix with time period 4 data and the education, experience, and ability columns.

Referencing elements in arrays#

We can grab individual elements of this vector using slicing:

print(a[1:2])
print(a[3])
[1] 1 2
[1] 3

Note, since we are working with a column, we don’t need to refer to the row dimension, although we could:

print(a[1:2,1])
print(a[3,1])
[1] 1 2
[1] 3

Creating this matrix $\( B = \begin{bmatrix} 2&4&3\\1&5&7 \end{bmatrix} \)$ is done this way:

B <- matrix(c(2, 4, 3, 1, 5, 7), nrow = 2, byrow = TRUE)
print(B)
     [,1] [,2] [,3]
[1,]    2    4    3
[2,]    1    5    7

slicing is also possible

print(B[,2:3])
     [,1] [,2]
[1,]    4    3
[2,]    5    7

It is also to create an empty matrix (all zeros) and fill it in using slicing:

C <- matrix(0, 5, 5)
C[3:4, 5] = -999
print(C)
     [,1] [,2] [,3] [,4] [,5]
[1,]    0    0    0    0    0
[2,]    0    0    0    0    0
[3,]    0    0    0    0 -999
[4,]    0    0    0    0 -999
[5,]    0    0    0    0    0

The identity matrix#

These are created using diag, having the arguments:

  • Value to place on the diagonal

  • Number of rows

  • Number of columns (if ommitted, columns=rows)

I = diag(1,5)
print(I)
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    0    0    0    0
[2,]    0    1    0    0    0
[3,]    0    0    1    0    0
[4,]    0    0    0    1    0
[5,]    0    0    0    0    1

or, if you only supply one argument (row, column dimension):

I = diag(5)
print(I)
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    0    0    0    0
[2,]    0    1    0    0    0
[3,]    0    0    1    0    0
[4,]    0    0    0    1    0
[5,]    0    0    0    0    1

Creating a column vector of ones#

print(cbind(rep(1, 5)))
     [,1]
[1,]    1
[2,]    1
[3,]    1
[4,]    1
[5,]    1

Getting information about your matrices and vectors#

The most important information we need is the dimensions of our matrices. The function dim tells us rows and columns (for 2 dimensional objects):

dim(B)
  1. 2
  2. 3

We can extract row and column dimensions like this:

dim(B)[1]
dim(B)[2]
2
3

Linear Algebra Operations#

Scalar Addition#

a = 1
b = 1
print(a + b)
[1] 2

Matrix Addition#

a = rbind(2, 5, 8)
b = rbind(6, 4, 3)
print(b + a)
     [,1]
[1,]    8
[2,]    9
[3,]   11

Note, conformability matters:

a = rbind(2, 5)
b = rbind(6, 4, 3)
print(b + a)
Error in b + a: non-conformable arrays
Traceback:

1. print(b + a)

Matrix Multiplication#

Matrix multiplication uses the %*% operator:

dim(B)
dim(b)
print(B%*%b)
  1. 2
  2. 3
  1. 3
  2. 1
     [,1]
[1,]   37
[2,]   47

Again, comformability (and order) matters:

print(b%*%B)
Error in b %*% B: non-conformable arguments
Traceback:

1. print(b %*% B)

Matrix Transpose#

The transpose operator is t():

print(B)
print(t(B))
     [,1] [,2] [,3]
[1,]    2    4    3
[2,]    1    5    7
     [,1] [,2]
[1,]    2    1
[2,]    4    5
[3,]    3    7

Matrix Inversion#

A <- matrix(c(2, 4, 3, 4, 9, 1,	 1, 5, 7), nrow = 3, byrow = TRUE)
A_inv = solve(A)
print(A_inv)
           [,1]       [,2]        [,3]
[1,]  1.4146341 -0.3170732 -0.56097561
[2,] -0.6585366  0.2682927  0.24390244
[3,]  0.2682927 -0.1463415  0.04878049

and the matrix A_inv satisfies the properties of an inverse:

print(A_inv%*%A)
              [,1]         [,2]          [,3]
[1,]  1.000000e+00 4.440892e-16 -8.881784e-16
[2,] -1.942890e-16 1.000000e+00  4.163336e-16
[3,]  6.245005e-17 1.457168e-16  1.000000e+00

Scalar Operations#

Scalar Addition and Subtraction

print(a)
print(a - 5)
     [,1]
[1,]    2
[2,]    5
     [,1]
[1,]   -3
[2,]    0

Scalar Multiplication and Addition

print(a/5)
print(a*5)
     [,1]
[1,]  0.4
[2,]  1.0
     [,1]
[1,]   10
[2,]   25

Elementwise Operations#

Sometimes we want to combine arrays by performing arithmetic on the corresponding elements. For example, supposing that

(53)#\[\begin{equation} \mathbf{a} = \begin{bmatrix} 1 \\ 2 \end{bmatrix} \nonumber \end{equation}\]

and

(54)#\[\begin{equation} \mathbf{b} = \begin{bmatrix} 3 \\ 4 \end{bmatrix} \nonumber \end{equation}\]

we might want to calculate

(55)#\[\begin{equation} a\_divide\_b=\begin{bmatrix} 1/3 \\ 2/4 \end{bmatrix} \end{equation}\]

by default R performs these operations using basic arithmetic operators so long as the arrays are of the same dimensions. Note in the first example below, \(\mathbf{b}\) and \(\mathbf{a}\) are not conformable.

print(dim(a))
print(dim(b))
print(a/b)
[1] 2 1
[1] 3 1
Error in a/b: non-conformable arrays
Traceback:

1. print(a/b)

However, if we redefine \(\mathbf{b}\) for having conformable dimensions, element-wise division exists

b=c(6,4)
print(a/b)
          [,1]
[1,] 0.3333333
[2,] 1.2500000

Some other useful commands in R#

Sometimes we want to extract diagonal elements of a matrix or set off diagonal elements of a matrix to zero. In R, we use the diag command for these cases:

To grab the diagonal elements as a vector:

print(diag(B))
[1] 2 5

and to set off diagonal elements of \(\mathbf{B}\) to zero, apply diag twice:

print(diag(diag(B)))
     [,1] [,2]
[1,]    2    0
[2,]    0    5