Skip to article frontmatterSkip to article content
Contents
Linear Equations and Matrix Algebra
and

8. Linear Equations and Matrix Algebra

8.1Overview

Many problems in economics and finance require solving linear equations.

In this lecture we discuss linear equations and their applications.

To illustrate the importance of linear equations, we begin with a two good model of supply and demand.

The two good case is so simple that solutions can be calculated by hand.

But often we need to consider markets containing many goods.

In the multiple goods case we face large systems of linear equations, with many equations and unknowns.

To handle such systems we need two things:

  • matrix algebra (and the knowledge of how to use it) plus
  • computer code to apply matrix algebra to the problems of interest.

This lecture covers these steps.

We will use the following packages:

import numpy as np
import matplotlib.pyplot as plt

8.2A two good example

In this section we discuss a simple two good example and solve it by

  1. pencil and paper
  2. matrix algebra

The second method is more general, as we will see.

8.2.1Pencil and paper methods

Suppose that we have two related goods, such as

  • propane and ethanol, and
  • rice and wheat, etc.

To keep things simple, we label them as good 0 and good 1.

The demand for each good depends on the price of both goods:

q0d=10010p05p1q1d=50p010p1\begin{aligned} q_0^d = 100 - 10 p_0 - 5 p_1 \\ q_1^d = 50 - p_0 - 10 p_1 \end{aligned}

(We are assuming demand decreases when the price of either good goes up, but other cases are also possible.)

Let’s suppose that supply is given by

q0s=10p0+5p1q1s=5p0+10p1\begin{aligned} q_0^s = 10 p_0 + 5 p_1 \\ q_1^s = 5 p_0 + 10 p_1 \end{aligned}

Equilibrium holds when supply equals demand (q0s=q0dq_0^s = q_0^d and q1s=q1dq_1^s = q_1^d).

This yields the linear system

10010p05p1=10p0+5p150p010p1=5p0+10p1\begin{aligned} 100 - 10 p_0 - 5 p_1 = 10 p_0 + 5 p_1 \\ 50 - p_0 - 10 p_1 = 5 p_0 + 10 p_1 \end{aligned}

We can solve this with pencil and paper to get

p0=4.41andp1=1.18.p_0 = 4.41 \quad \text{and} \quad p_1 = 1.18.

Inserting these results into either (1) or (2) yields the equilibrium quantities

q0=50andq1=33.82.q_0 = 50 \quad \text{and} \quad q_1 = 33.82.

8.2.2Looking forward

Pencil and paper methods are easy in the two good case.

But what if there are many goods?

For such problems we need matrix algebra.

Before solving problems with matrix algebra, let’s first recall the basics of vectors and matrices, in both theory and computation.

8.3Vectors

A vector of length nn is just a sequence (or array, or tuple) of nn numbers, which we write as x=(x1,,xn)x = (x_1, \ldots, x_n) or x=[x1,,xn]x = \begin{bmatrix}x_1, \ldots, x_n\end{bmatrix}.

We can write these sequences either horizontally or vertically.

But when we use matrix operations, our default assumption is that vectors are column vectors.

The set of all nn-vectors is denoted by Rn\mathbb R^n.

Often vectors are represented visually as arrows from the origin to the point.

Here’s a visualization.

Source
fig, ax = plt.subplots()
# Set the axes through the origin
for spine in ['left', 'bottom']:
    ax.spines[spine].set_position('zero')
for spine in ['right', 'top']:
    ax.spines[spine].set_color('none')

ax.set(xlim=(-5, 5), ylim=(-5, 5))

vecs = ((2, 4), (-3, 3), (-4, -3.5))
for v in vecs:
    ax.annotate('', xy=v, xytext=(0, 0),
                arrowprops=dict(facecolor='blue',
                shrink=0,
                alpha=0.7,
                width=0.5))
    ax.text(1.1 * v[0], 1.1 * v[1], str(v))
plt.show()
<Figure size 640x480 with 1 Axes>

8.3.1Vector operations

Sometimes we want to modify vectors.

The two most common operators on vectors are addition and scalar multiplication, which we now describe.

When we add two vectors, we add them element-by-element.

In general,

x+y=[x1x2xn]+[y1y2yn]:=[x1+y1x2+y2xn+yn].x + y = \begin{bmatrix} x_1 \\ x_2 \\ \vdots \\ x_n \end{bmatrix} + \begin{bmatrix} y_1 \\ y_2 \\ \vdots \\ y_n \end{bmatrix} := \begin{bmatrix} x_1 + y_1 \\ x_2 + y_2 \\ \vdots \\ x_n + y_n \end{bmatrix}.

We can visualise vector addition in R2\mathbb{R}^2 as follows.

Source
fig, ax = plt.subplots()
# Set the axes through the origin
for spine in ['left', 'bottom']:
    ax.spines[spine].set_position('zero')
for spine in ['right', 'top']:
    ax.spines[spine].set_color('none')

ax.set(xlim=(-2, 10), ylim=(-4, 4))
# ax.grid()
vecs = ((4, -2), (3, 3), (7, 1))
tags = ('(x1, x2)', '(y1, y2)', '(x1+x2, y1+y2)')
colors = ('blue', 'green', 'red')
for i, v in enumerate(vecs):
    ax.annotate('', xy=v, xytext=(0, 0),
                arrowprops=dict(color=colors[i],
                shrink=0,
                alpha=0.7,
                width=0.5,
                headwidth=8,
                headlength=15))
    ax.text(v[0] + 0.2, v[1] + 0.1, tags[i])

for i, v in enumerate(vecs):
    ax.annotate('', xy=(7, 1), xytext=v,
                arrowprops=dict(color='gray',
                shrink=0,
                alpha=0.3,
                width=0.5,
                headwidth=5,
                headlength=20))
plt.show()
<Figure size 640x480 with 1 Axes>

Scalar multiplication is an operation that multiplies a vector xx with a scalar elementwise.

More generally, it takes a number γ and a vector xx and produces

γx:=[γx1γx2γxn].\gamma x := \begin{bmatrix} \gamma x_1 \\ \gamma x_2 \\ \vdots \\ \gamma x_n \end{bmatrix}.

Scalar multiplication is illustrated in the next figure.

Source
fig, ax = plt.subplots()
# Set the axes through the origin
for spine in ['left', 'bottom']:
    ax.spines[spine].set_position('zero')
for spine in ['right', 'top']:
    ax.spines[spine].set_color('none')

ax.set(xlim=(-5, 5), ylim=(-5, 5))
x = (2, 2)
ax.annotate('', xy=x, xytext=(0, 0),
            arrowprops=dict(facecolor='blue',
            shrink=0,
            alpha=1,
            width=0.5))
ax.text(x[0] + 0.4, x[1] - 0.2, '$x$', fontsize='16')

scalars = (-2, 2)
x = np.array(x)

for s in scalars:
    v = s * x
    ax.annotate('', xy=v, xytext=(0, 0),
                arrowprops=dict(facecolor='red',
                shrink=0,
                alpha=0.5,
                width=0.5))
    ax.text(v[0] + 0.4, v[1] - 0.2, f'${s} x$', fontsize='16')
plt.show()
<Figure size 640x480 with 1 Axes>

In Python, a vector can be represented as a list or tuple, such as x = [2, 4, 6] or x = (2, 4, 6).

However, it is more common to represent vectors with NumPy arrays.

One advantage of NumPy arrays is that scalar multiplication and addition have very natural syntax.

x = np.ones(3)            # Vector of three ones
y = np.array((2, 4, 6))   # Converts tuple (2, 4, 6) into a NumPy array
x + y                     # Add (element-by-element)
array([3., 5., 7.])
4 * x                     # Scalar multiply
array([4., 4., 4.])

8.3.2Inner product and norm

The inner product of vectors x,yRnx,y \in \mathbb R^n is defined as

xy=[x1x2xn][y1y2yn]=x1y1+x2y2++xnyn:=i=1nxiyi.x^\top y = \begin{bmatrix} \color{red}{x_1} & \color{blue}{x_2} & \cdots & x_n \end{bmatrix} \begin{bmatrix} \color{red}{y_1} \\ \color{blue}{y_2} \\ \vdots \\ y_n \end{bmatrix} = {\color{red}{x_1 y_1}} + {\color{blue}{x_2 y_2}} + \cdots + x_n y_n := \sum_{i=1}^n x_i y_i.

The norm of a vector xx represents its “length” (i.e., its distance from the zero vector) and is defined as

x:=xx:=(i=1nxi2)1/2.\| x \| := \sqrt{x^\top x} := \left( \sum_{i=1}^n x_i^2 \right)^{1/2}.

The expression xy\| x - y\| can be thought of as the “distance” between xx and yy.

The inner product and norm can be computed as follows

np.sum(x*y)      # Inner product of x and y
np.float64(12.0)
x @ y            # Another way to compute the inner product
np.float64(12.0)
np.sqrt(np.sum(x**2))  # Norm of x, method one
np.float64(1.7320508075688772)
np.linalg.norm(x)      # Norm of x, method two
np.float64(1.7320508075688772)

8.4Matrix operations

When we discussed linear price systems, we mentioned using matrix algebra.

Matrix algebra is similar to algebra for numbers.

Let’s review some details.

8.4.1Addition and scalar multiplication

Just as was the case for vectors, we can add, subtract and scalar multiply matrices.

Scalar multiplication and addition are generalizations of the vector case:

In general for a number γ and any matrix AA,

γA=γ[a11a1kan1ank]:=[γa11γa1kγan1γank].\gamma A = \gamma \begin{bmatrix} a_{11} & \cdots & a_{1k} \\ \vdots & \vdots & \vdots \\ a_{n1} & \cdots & a_{nk} \end{bmatrix} := \begin{bmatrix} \gamma a_{11} & \cdots & \gamma a_{1k} \\ \vdots & \vdots & \vdots \\ \gamma a_{n1} & \cdots & \gamma a_{nk} \end{bmatrix}.

In general,

A+B=[a11a1kan1ank]+[b11b1kbn1bnk]:=[a11+b11a1k+b1kan1+bn1ank+bnk].A + B = \begin{bmatrix} a_{11} & \cdots & a_{1k} \\ \vdots & \vdots & \vdots \\ a_{n1} & \cdots & a_{nk} \end{bmatrix} + \begin{bmatrix} b_{11} & \cdots & b_{1k} \\ \vdots & \vdots & \vdots \\ b_{n1} & \cdots & b_{nk} \end{bmatrix} := \begin{bmatrix} a_{11} + b_{11} & \cdots & a_{1k} + b_{1k} \\ \vdots & \vdots & \vdots \\ a_{n1} + b_{n1} & \cdots & a_{nk} + b_{nk} \end{bmatrix}.

In the latter case, the matrices must have the same shape in order for the definition to make sense.

8.4.2Matrix multiplication

We also have a convention for multiplying two matrices.

The rule for matrix multiplication generalizes the idea of inner products discussed above.

If AA and BB are two matrices, then their product ABA B is formed by taking as its i,ji,j-th element the inner product of the ii-th row of AA and the jj-th column of BB.

If AA is n×kn \times k and BB is j×mj \times m, then to multiply AA and BB we require k=jk = j, and the resulting matrix ABA B is n×mn \times m.

As an important special case, consider multiplying n×kn \times k matrix AA and k×1k \times 1 column vector xx.

According to the preceding rule, this gives us an n×1n \times 1 column vector.

Ax=[a11a12a1kai1ai2aikan1an2ank]n×k[x1x2xk]k×1:=[a11x1+a22x2++a1kxkai1x1+ai2x2++aikxkan1x1+an2x2++ankxk]n×1A x = {\begin{bmatrix} a_{11} & a_{12} & \cdots & a_{1k} \\ \vdots & \vdots & & \vdots \\ \color{red}{a_{i1}} & \color{red}{a_{i2}} & \color{red}{\cdots} & \color{red}{a_{i}k} \\ \vdots & \vdots & & \vdots \\ a_{n1} & a_{n2} & \cdots & a_{nk} \end{bmatrix}}_{n \times k} {\begin{bmatrix} \color{red}{x_{1}} \\ \color{red}{x_{2}} \\ \color{red}{\vdots} \\ \color{red}{\vdots} \\ \color{red}{x_{k}} \end{bmatrix}}_{k \times 1} := {\begin{bmatrix} a_{11} x_1 + a_{22} x_2 + \cdots + a_{1k} x_k \\ \vdots \\ \color{red}{a_{i1} x_1 + a_{i2} x_2 + \cdots + a_{ik} x_k} \\ \vdots \\ a_{n1} x_1 + a_{n2} x_2 + \cdots + a_{nk} x_k \end{bmatrix}}_{n \times 1}

Here is a simple illustration of multiplication of two matrices.

AB=[a11a12a21a22][b11b12b21b22]:=[a11b11+a12b21a11b12+a12b22a21b11+a22b21a21b12+a22b22]AB = \begin{bmatrix} a_{11} & a_{12} \\ \color{red}{a_{21}} & \color{red}{a_{22}} \\ \end{bmatrix} \begin{bmatrix} b_{11} & \color{red}{b_{12}} \\ b_{21} & \color{red}{b_{22}} \\ \end{bmatrix} := \begin{bmatrix} a_{11}b_{11} + a_{12}b_{21} & a_{11}b_{12} + a_{12}b_{22} \\ a_{21}b_{11} + a_{22}b_{21} & \color{red}{a_{21}b_{12} + a_{22}b_{22}} \end{bmatrix}

There are many tutorials to help you further visualize this operation, such as

One important special case is the identity matrix, which has ones on the principal diagonal and zero elsewhere:

I=[1001]I = \begin{bmatrix} 1 & \cdots & 0 \\ \vdots & \ddots & \vdots \\ 0 & \cdots & 1 \end{bmatrix}

It is a useful exercise to check the following:

  • if AA is n×kn \times k and II is the k×kk \times k identity matrix, then AI=AAI = A, and
  • if II is the n×nn \times n identity matrix, then IA=AIA = A.

8.4.3Matrices in NumPy

NumPy arrays are also used as matrices, and have fast, efficient functions and methods for all the standard matrix operations.

You can create them manually from tuples of tuples (or lists of lists) as follows

A = ((1, 2),
     (3, 4))

type(A)
tuple
A = np.array(A)

type(A)
numpy.ndarray
A.shape
(2, 2)

The shape attribute is a tuple giving the number of rows and columns --- see here for more discussion.

To get the transpose of A, use A.transpose() or, more simply, A.T.

There are many convenient functions for creating common matrices (matrices of zeros, ones, etc.) --- see here.

Since operations are performed elementwise by default, scalar multiplication and addition have very natural syntax.

A = np.identity(3)    # 3 x 3 identity matrix
B = np.ones((3, 3))   # 3 x 3 matrix of ones
2 * A
array([[2., 0., 0.], [0., 2., 0.], [0., 0., 2.]])
A + B
array([[2., 1., 1.], [1., 2., 1.], [1., 1., 2.]])

To multiply matrices we use the @ symbol.

8.4.4Two good model in matrix form

We can now revisit the two good model and solve (3) numerically via matrix algebra.

This involves some extra steps but the method is widely applicable --- as we will see when we include more goods.

First we rewrite (1) as

qd=Dp+hwhereqd=[q0dq1d]D=[105110]andh=[10050]. q^d = D p + h \quad \text{where} \quad q^d = \begin{bmatrix} q_0^d \\ q_1^d \end{bmatrix} \quad D = \begin{bmatrix} -10 & - 5 \\ - 1 & - 10 \end{bmatrix} \quad \text{and} \quad h = \begin{bmatrix} 100 \\ 50 \end{bmatrix}.

Recall that pR2p \in \mathbb{R}^{2} is the price of two goods.

(Please check that qd=Dp+hq^d = D p + h represents the same equations as (1).)

We rewrite (2) as

qs=Cpwhereqs=[q0sq1s]andC=[105510]. q^s = C p \quad \text{where} \quad q^s = \begin{bmatrix} q_0^s \\ q_1^s \end{bmatrix} \quad \text{and} \quad C = \begin{bmatrix} 10 & 5 \\ 5 & 10 \end{bmatrix}.

Now equality of supply and demand can be expressed as qs=qdq^s = q^d, or

Cp=Dp+h.C p = D p + h.

We can rearrange the terms to get

(CD)p=h.(C - D) p = h.

If all of the terms were numbers, we could solve for prices as p=h/(CD)p = h / (C-D).

Matrix algebra allows us to do something similar: we can solve for equilibrium prices using the inverse of CDC - D:

p=(CD)1h. p = (C - D)^{-1} h.

Before we implement the solution let us consider a more general setting.

8.4.5More goods

It is natural to think about demand systems with more goods.

For example, even within energy commodities there are many different goods, including crude oil, gasoline, coal, natural gas, ethanol, and uranium.

The prices of these goods are related, so it makes sense to study them together.

Pencil and paper methods become very time consuming with large systems.

But fortunately the matrix methods described above are essentially unchanged.

In general, we can write the demand equation as qd=Dp+hq^d = Dp + h, where

  • qdq^d is an n×1n \times 1 vector of demand quantities for nn different goods.
  • DD is an n×nn \times n “coefficient” matrix.
  • hh is an n×1n \times 1 vector of constant values.

Similarly, we can write the supply equation as qs=Cp+eq^s = Cp + e, where

  • qsq^s is an n×1n \times 1 vector of supply quantities for the same goods.
  • CC is an n×nn \times n “coefficient” matrix.
  • ee is an n×1n \times 1 vector of constant values.

To find an equilibrium, we solve Dp+h=Cp+eDp + h = Cp + e, or

(DC)p=eh. (D- C)p = e - h.

Then the price vector of the n different goods is

p=(DC)1(eh).p = (D- C)^{-1}(e - h).

8.4.6General linear systems

A more general version of the problem described above looks as follows.

a11x1+a12x2++a1nxn=b1an1x1+an2x2++annxn=bn\begin{matrix} a_{11} x_1 & + & a_{12} x_2 & + & \cdots & + & a_{1n} x_n & = & b_1 \\ \vdots & & \vdots & & & & \vdots & & \vdots \\ a_{n1} x_1 & + & a_{n2} x_2 & + & \cdots & + & a_{nn} x_n & = & b_n \end{matrix}

The objective here is to solve for the “unknowns” x1,,xnx_1, \ldots, x_n.

We take as given the coefficients a11,,anna_{11}, \ldots, a_{nn} and constants b1,,bnb_1, \ldots, b_n.

Notice that we are treating a setting where the number of unknowns equals the number of equations.

This is the case where we are most likely to find a well-defined solution.

(The other cases are referred to as overdetermined and underdetermined systems of equations --- we defer discussion of these cases until later lectures.)

In matrix form, the system (27) becomes

Ax=bwhereA=[a11a1nan1ann]andb=[b1bn]. A x = b \quad \text{where} \quad A = \begin{bmatrix} a_{11} & \cdots & a_{1n} \\ \vdots & \vdots & \vdots \\ a_{n1} & \cdots & a_{nn} \end{bmatrix} \quad \text{and} \quad b = \begin{bmatrix} b_1 \\ \vdots \\ b_n \end{bmatrix}.

When considering problems such as (28), we need to ask at least some of the following questions

  • Does a solution actually exist?
  • If a solution exists, how should we compute it?

8.5Solving systems of equations

Recall again the system of equations (27), which we write here again as

Ax=b. A x = b.

The problem we face is to find a vector xRnx \in \mathbb R^n that solves (30), taking bb and AA as given.

We may not always find a unique vector xx that solves (30).

We illustrate two such cases below.

8.5.1No solution

Consider the system of equations given by,

x+3y=32x+6y=8.\begin{aligned} x + 3y &= 3 \\ 2x + 6y &= -8. \end{aligned}

It can be verified manually that this system has no possible solution.

To illustrate why this situation arises let’s plot the two lines.

fig, ax = plt.subplots()
x = np.linspace(-10, 10)
plt.plot(x, (3-x)/3, label=f'$x + 3y = 3$')
plt.plot(x, (-8-2*x)/6, label=f'$2x + 6y = -8$')
plt.legend()
plt.show()
<Figure size 640x480 with 1 Axes>

Clearly, these are parallel lines and hence we will never find a point xR2x \in \mathbb{R}^2 such that these lines intersect.

Thus, this system has no possible solution.

We can rewrite this system in matrix form as

Ax=bwhereA=[1326]andb=[38]. A x = b \quad \text{where} \quad A = \begin{bmatrix} 1 & 3 \\ 2 & 6 \end{bmatrix} \quad \text{and} \quad b = \begin{bmatrix} 3 \\ -8 \end{bmatrix}.

It can be noted that the 2nd2^{nd} row of matrix A=(2,6)A = (2, 6) is just a scalar multiple of the 1st1^{st} row of matrix A=(1,3)A = (1, 3).

The rows of matrix AA in this case are called linearly dependent.

8.5.2Many solutions

Now consider,

x2y=42x+4y=8.\begin{aligned} x - 2y &= -4 \\ -2x + 4y &= 8. \end{aligned}

Any vector v=(x,y)v = (x,y) such that x=2y4x = 2y - 4 will solve the above system.

Since we can find infinite such vectors this system has infinitely many solutions.

This is because the rows of the corresponding matrix

A=[1224]. A = \begin{bmatrix} 1 & -2 \\ -2 & 4 \end{bmatrix}.

are linearly dependent --- can you see why?

We now impose conditions on AA in (30) that rule out these problems.

8.5.3Nonsingular matrices

To every square matrix we can assign a unique number called the determinant.

For 2×22 \times 2 matrices, the determinant is given by,

[abcd]=adbc.\begin{bmatrix} \color{red}{a} & \color{blue}{b} \\ \color{blue}{c} & \color{red}{d} \end{bmatrix} = {\color{red}{ad}} - {\color{blue}{bc}}.

If the determinant of AA is not zero, then we say that AA is nonsingular.

A square matrix AA is nonsingular if and only if the rows and columns of AA are linearly independent.

A more detailed explanation of matrix inverse can be found here.

You can check yourself that the in (32) and (34) with linearly dependent rows are singular matrices.

This gives us a useful one-number summary of whether or not a square matrix can be inverted.

In particular, a square matrix AA has a nonzero determinant, if and only if it possesses an inverse matrix A1A^{-1}, with the property that AA1=A1A=IA A^{-1} = A^{-1} A = I.

As a consequence, if we pre-multiply both sides of Ax=bAx = b by A1A^{-1}, we get

x=A1b. x = A^{-1} b.

This is the solution to Ax=bAx = b --- the solution we are looking for.

8.5.4Linear equations with NumPy

In the two good example we obtained the matrix equation,

p=(CD)1h.p = (C-D)^{-1} h.

where CC, DD and hh are given by (20) and (21).

This equation is analogous to (36) with A=(CD)1A = (C-D)^{-1}, b=hb = h, and x=px = p.

We can now solve for equilibrium prices with NumPy’s linalg submodule.

All of these routines are Python front ends to time-tested and highly optimized FORTRAN code.

C = ((10, 5),      # Matrix C
     (5, 10))

Now we change this to a NumPy array.

C = np.array(C)
D = ((-10, -5),     # Matrix D
     (-1, -10))
D = np.array(D)
h = np.array((100, 50))   # Vector h
h.shape = 2,1             # Transforming h to a column vector
from numpy.linalg import det, inv
A = C - D
# Check that A is nonsingular (non-zero determinant), and hence invertible
det(A)
np.float64(340.0000000000001)
A_inv = inv(A)  # compute the inverse
A_inv
array([[ 0.05882353, -0.02941176], [-0.01764706, 0.05882353]])
p = A_inv @ h  # equilibrium prices
p
array([[4.41176471], [1.17647059]])
q = C @ p  # equilibrium quantities
q
array([[50. ], [33.82352941]])

Notice that we get the same solutions as the pencil and paper case.

We can also solve for pp using solve(A, h) as follows.

from numpy.linalg import solve
p = solve(A, h)  # equilibrium prices
p
array([[4.41176471], [1.17647059]])
q = C @ p  # equilibrium quantities
q
array([[50. ], [33.82352941]])

Observe how we can solve for x=A1yx = A^{-1} y by either via inv(A) @ y, or using solve(A, y).

The latter method uses a different algorithm that is numerically more stable and hence should be the default option.

8.6Exercises

Solution to Exercise 1

The generated system would be:

35p05p15p2=1005p0+25p110p2=755p05p1+15p2=55\begin{aligned} 35p_0 - 5p_1 - 5p_2 = 100 \\ -5p_0 + 25p_1 - 10p_2 = 75 \\ -5p_0 - 5p_1 + 15p_2 = 55 \end{aligned}

In matrix form we will write this as:

Ap=bwhereA=[3555525105515],p=[p0p1p2]andb=[1007555]Ap = b \quad \text{where} \quad A = \begin{bmatrix} 35 & -5 & -5 \\ -5 & 25 & -10 \\ -5 & -5 & 15 \end{bmatrix} , \quad p = \begin{bmatrix} p_0 \\ p_1 \\ p_2 \end{bmatrix} \quad \text{and} \quad b = \begin{bmatrix} 100 \\ 75 \\ 55 \end{bmatrix}
import numpy as np
from numpy.linalg import det

A = np.array([[35, -5, -5],  # matrix A
              [-5, 25, -10],
              [-5, -5, 15]])

b = np.array((100, 75, 55))  # column vector b
b.shape = (3, 1)

det(A)  # check if A is nonsingular
np.float64(9999.99999999999)
# Using inverse
from numpy.linalg import det

A_inv = inv(A)

p = A_inv @ b
p
array([[4.9625], [7.0625], [7.675 ]])
# Using numpy.linalg.solve
from numpy.linalg import solve
p = solve(A, b)
p
array([[4.9625], [7.0625], [7.675 ]])

The solution is given by:

p0=4.6925,  p1=7.0625    and    p2=7.675p_0 = 4.6925, \; p_1 = 7.0625 \;\; \text{and} \;\; p_2 = 7.675
Solution to Exercise 2
import numpy as np
from numpy.linalg import inv
# Using matrix algebra
A = np.array([[1, -9],  # matrix A
              [1, -7],
              [1, -3]])

A_T = np.transpose(A)  # transpose of matrix A

b = np.array((1, 3, 8))  # column vector b
b.shape = (3, 1)

x = inv(A_T @ A) @ A_T @ b
x
array([[11.46428571], [ 1.17857143]])
# Using numpy.linalg.lstsq
x, res, _, _ = np.linalg.lstsq(A, b, rcond=None)
Source
print(f"x\u0302 = {x}")
print(f"\u2016Ax\u0302 - b\u2016\u00B2 = {res[0]}")
x̂ = [[11.46428571]
 [ 1.17857143]]
‖Ax̂ - b‖² = 0.07142857142857066

Here is a visualization of how the least squares method approximates the equation of a line connecting a set of points.

We can also describe this as “fitting” a line between a set of points.

fig, ax = plt.subplots()
p = np.array((1, 3, 8))
q = np.array((9, 7, 3))

a, b = x

ax.plot(q, p, 'o', label='observations', markersize=5)
ax.plot(q, a - b*q, 'r', label='Fitted line')
plt.xlabel('quantity demanded')
plt.ylabel('price')
plt.legend()
plt.show()
<Figure size 640x480 with 1 Axes>

8.6.1Further reading

The documentation of the numpy.linalg submodule can be found here.

More advanced topics in linear algebra can be found here.

CC-BY-SA-4.0

Creative Commons License – This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International.