AuthorJing Wu2018-06-11

Introduction

Many papers in statistics and quantitative finance make heavy use of linear algebra, so you need to have a working knowledge of it in order to read and apply them to your trading.

Vectors

A vector can be thought of as an arrow pointing from the origin to a specific point. Any vector or point can be represented by its coordinates i.e. an array of numbers, such as for a 2-dimensional vector, or for a 3-dimensional one. We usually write a vector as a column:

The scalar product of two vectors and in 2-dimensional space is defined as:

This definition can be easily generalized to n dimensional space. Clearly, we cannot take the scalar product of two vectors with different dimensions.

Matrices

If we have a few vectors with the same dimension, then we can put them side-by-side to form a matrix. For example, the vectors

can be combined to produce a matrix:

m is a 3 × 3 matrix. We typically describe the dimensions of a matrix as where m = number of rows and n = number of columns.

A square matrix is one with as many rows as columns.

Notation: refers to a specific value in row and column of a matrix . For example, is the number in the second row and third column of .

Python Implementation

In Python, the NumPy package deals with linear algebra. The array we learned in the NumPy chapter can be deemed as a vector:

import numpy as np
a = np.array([1,2,3])
b = np.array([2,2,2])
c = np.array([3,1,1])
matrix = np.column_stack((a,b,c))
print(matrix)
print(type(matrix))
[out]:
[[1 2 3]
 [2 2 1]
 [3 2 1]]
[out]: <class 'numpy.ndarray'>

It is worth noticing that we used column_stack() here to ensure that the vectors are vertical and placed side-by-side to form a matrix. Without the column_stack() function, the vectors will be made horizontal and stacked on top of one another:

matrix2 = np.array([a,b,c])
print(matrix2)
[out]:
[[1 2 3]
 [2 2 2]
 [3 1 1]]

Matrix Multiplication

How are two matrices multiplied? Suppose . Each entry of matrix is the scalar product of row from matrix with column from matrix . This is best illustrated with an example:

In NumPy, we can multiply matrices with the dot() function:

A = np.array([[2,3],[4,2],[2,2]])
B = np.array([[4,2],[4,6]])
x = np.dot(A,B)
print x
[out]:
[[20 22]
 [24 20]
 [16 16]]

Since matrix multiplication is defined in terms of scalar products, the matrix product exists only if has as many columns as has rows. It's useful to remember this shorthand: (m × n) × (n × p) = (m × p) which means that an (m × n) matrix multiplied by an (n × p) matrix yields an (m × p) matrix.

Reversing the order of multiplication results in an error since B does not have as many columns as A has rows:

x = np.dot(B,A)

A natrual consequence of this fact is that matrix multiplication is not commutative. In other words, in general.

Inverse

An identity matrix is a square matrix with ones on the main diagonal and zeros elsewhere. Here is an identity matrix:

Multiplying any matrix by an identity matrix (of the correct shape) is like multiplying a number by 1. Concretely, if is an matrix, then:

is the inverse matrix of a square matrix if:

Some caveats:

  • A rectangular matrix will not have an inverse, but it may have a pseudoinverse (not covered in this tutorial).
  • A square matrix may not have an inverse i.e. it may be "singular".
  • If a square matrix has an inverse, then its inverse is unique.

Inverse matrices are computed using the Gauss-Jordan method. In NumPy, we use the linalg.inv() function to do it:

print(matrix)
print('\n-------------------------\n')
print(np.linalg.inv(matrix))
[out]:
[[1 2 3]
 [2 2 1]
 [3 2 1]]

-------------------------

[[ 0.   -1.    1.  ]
 [-0.25  2.   -1.25]
 [ 0.5  -1.    0.5 ]]

Now let's check if the multiplication is :

inverse = np.linalg.inv(matrix)
print(np.dot(matrix, inverse))
print('\n-------------------------\n')
print(np.dot(inverse,matrix))
[out]:
[[  1.00000000e+00  -6.66133815e-16   6.66133815e-16]
 [  0.00000000e+00   1.00000000e+00   1.11022302e-16]
 [  0.00000000e+00  -2.22044605e-16   1.00000000e+00]]

-------------------------

[[  1.00000000e+00  -4.44089210e-16  -2.22044605e-16]
 [  6.66133815e-16   1.00000000e+00   0.00000000e+00]
 [  0.00000000e+00   0.00000000e+00   1.00000000e+00]]

Not surprisingly, we ended up with an identity matrix. We can form a non-invertible matrix by making one of its rows a multiple of another:

singular = np.array([[1,2,3],[1,2,3],[3,3,3]])
inv = np.linalg.inv(singular)   
[out]: numpy.linalg.linalg.LinAlgError: Singular matrix

Linear Equations

A common problem in linear algebra is solving linear equations. Consider the following linear equations:

If we let:

Then the linear equations above can be written as

If A is invertible, then we can multiply on both sides of the equation to obtain the solution:

As long as exists, we can compute it to solve the linear equations:

A = np.array([[2,1,-1],[-3,-1,2],[-2,1,2]])
b = np.array([[8],[-11],[-3]])
inv_A = np.linalg.inv(A)
print np.dot(inv_A, b)
[out]:
[[ 2.]
 [ 3.]
 [-1.]]

The solution is x = 2, y = 3, z = −1. However, computing the inverse matrix is not recommended, since it is numerically unstable i.e. small rounding errors can dramatically affect the result.

Instead, NumPy solves linear equations by LU decomposition:

print np.linalg.solve(A, b)
[out]:
[[ 2.]
 [ 3.]
 [-1.]]

Of course, we get the same solution. We can check the correctness of the solution by substituting x, y and z into the linear equations.

Summary

In this chapter we have introduced vectors, matrices, inverse matrices and linear equations. Some applications in finance include: finding arbitrage opportunities by solving linear equations, computing portfolio variance, etc. In the next chapter, we will introduce modern portfolio theory and CAPM.



Previous: Multiple Linear Regression Next: Modern Portfolio Theory