Skip to main content
© 2026 ePowerAI. All rights reserved.
CoursesContact
eAI
CoursesContact
Week 8: Least Squares and QR
Linear Algebra
01Week 1: Vectors and Linear Combinations
02Week 2: Linear Transformations and Matrices
03Week 3: Elimination and LU Factorization
04Week 4: Determinants
05Week 5: Vector Spaces, Independence, and Basis
06Week 6: The Four Fundamental Subspaces
07Week 7: Orthogonality and Projections
08Week 8: Least Squares and QR
09Week 9: Eigenvalues and Eigenvectors
10Week 10: Diagonalization and Markov Matrices
11Week 11: Differential Equations
12Week 12: Symmetric and Positive Definite Matrices
13Week 13: The SVD and Complex Matrices
14Week 14: The Fourier Matrix, FFT, and PCA
Week 08· Linear Algebra20 min read

Week 8: Least Squares and QR

✦Learning Outcomes
  • Set up and solve the least-squares normal equations for an overdetermined system
  • Apply Gram-Schmidt orthogonalization to a set of vectors
  • Factor a matrix as A=QRA = QRA=QR
  • Explain why QR improves the numerical solution of least-squares problems
◆Prerequisites

Background knowledge assumed:

  • Projections onto a subspace

Recommended: Review Week 7: Orthogonality and Projections before starting.

Least Squares Fitting#

Week 7 showed that when bbb does not lie in the column space C(A)C(A)C(A), the equation Ax=bAx = bAx=b has no exact solution. The closest you can get is the orthogonal projection of bbb onto C(A)C(A)C(A): find x^\hat{x}x^ so that

p=Ax^p = A\hat{x}p=Ax^

minimizes the residual length ∥b−Ax∥\|b - Ax\|∥b−Ax∥ over all xxx. That is the least-squares problem

min⁡x∥b−Ax∥2.\min_x \|b - Ax\|^2.xmin​∥b−Ax∥2.

The geometry is the same as last week: the residual e=b−Ax^e = b - A\hat{x}e=b−Ax^ must be orthogonal to every column of AAA, which forces the normal equations

A⊤A x^=A⊤b.A^\top A\, \hat{x} = A^\top b.A⊤Ax^=A⊤b.

When AAA is m×nm \times nm×n with m>nm > nm>n and full column rank nnn, the Gram matrix A⊤AA^\top AA⊤A is n×nn \times nn×n, symmetric, and invertible, so a unique least-squares solution exists:

x^=(A⊤A)−1A⊤b.\hat{x} = (A^\top A)^{-1} A^\top b.x^=(A⊤A)−1A⊤b.

The fitted values are p=Ax^p = A\hat{x}p=Ax^; the residual e=b−pe = b - pe=b−p lives in the left null space N(A⊤)N(A^\top)N(A⊤).

When this shows up. Overdetermined systems are the everyday case: more measurements than parameters. Fitting a line through noisy sensor readings, estimating robot pose from many landmarks, regressing a policy on a batch of trajectories — all are least squares.

Worked example: fit a line. Suppose we want y=c+dty = c + d ty=c+dt for three data points

(t,y):(0,1),(1,2),(2,2).(t, y):\quad (0, 1),\quad (1, 2),\quad (2, 2).(t,y):(0,1),(1,2),(2,2).

Stack the model as Ax=bA x = bAx=b with x=(d,c)⊤x = (d, c)^\topx=(d,c)⊤ (slope first, then intercept):

A=(011121),b=(122).A = \begin{pmatrix} 0 & 1 \\ 1 & 1 \\ 2 & 1 \end{pmatrix}, \qquad b = \begin{pmatrix} 1 \\ 2 \\ 2 \end{pmatrix}.A=​012​111​​,b=​122​​.

The first column is the ttt-values; the second is the constant column of ones. No exact line hits all three points (check: the slopes between consecutive pairs differ). Form the normal equations:

A⊤A=(012111)(011121)=(5333),A⊤b=(65).A^\top A = \begin{pmatrix} 0 & 1 & 2 \\ 1 & 1 & 1 \end{pmatrix} \begin{pmatrix} 0 & 1 \\ 1 & 1 \\ 2 & 1 \end{pmatrix} = \begin{pmatrix} 5 & 3 \\ 3 & 3 \end{pmatrix}, \qquad A^\top b = \begin{pmatrix} 6 \\ 5 \end{pmatrix}.A⊤A=(01​11​21​)​012​111​​=(53​33​),A⊤b=(65​).

Solve A⊤A x^=A⊤bA^\top A\, \hat{x} = A^\top bA⊤Ax^=A⊤b:

(5333)(d^c^)=(65).\begin{pmatrix} 5 & 3 \\ 3 & 3 \end{pmatrix} \begin{pmatrix} \hat{d} \\ \hat{c} \end{pmatrix} = \begin{pmatrix} 6 \\ 5 \end{pmatrix}.(53​33​)(d^c^​)=(65​).

Subtract the second row from the first after scaling: from 3d^+3c^=53\hat{d} + 3\hat{c} = 53d^+3c^=5 we get d^+c^=5/3\hat{d} + \hat{c} = 5/3d^+c^=5/3. From 5d^+3c^=65\hat{d} + 3\hat{c} = 65d^+3c^=6, eliminate c^\hat{c}c^ to find d^=1/2\hat{d} = 1/2d^=1/2, then c^=5/3−1/2=7/6\hat{c} = 5/3 - 1/2 = 7/6c^=5/3−1/2=7/6. So

x^=(1/27/6)⟹y^(t)=12t+76.\hat{x} = \begin{pmatrix} 1/2 \\ 7/6 \end{pmatrix} \quad\Longrightarrow\quad \hat{y}(t) = \frac{1}{2}t + \frac{7}{6}.x^=(1/27/6​)⟹y^​(t)=21​t+67​.

The fitted values are Ax^=(7/6,  5/3,  13/6)⊤A\hat{x} = (7/6,\; 5/3,\; 13/6)^\topAx^=(7/6,5/3,13/6)⊤, and the residual b−Ax^=(−1/6,  1/3,  −1/6)⊤b - A\hat{x} = (-1/6,\; 1/3,\; -1/6)^\topb−Ax^=(−1/6,1/3,−1/6)⊤ is orthogonal to both columns of AAA (dot products zero). Among all lines, this one minimizes the sum of squared vertical errors.

Connection to Week 7. The normal equations are exactly the subspace-projection equations A⊤(b−Ax^)=0A^\top(b - A\hat{x}) = 0A⊤(b−Ax^)=0. Least squares is projection of bbb onto C(A)C(A)C(A), rephrased as “best fit in the 2-norm.”


Gram-Schmidt Orthogonalization#

Projections become cleanest when the basis is orthonormal: vectors q1,…,qnq_1, \ldots, q_nq1​,…,qn​ with

qi⊤qj=δijq_i^\top q_j = \delta_{ij}qi⊤​qj​=δij​

(unit length, pairwise orthogonal). The projection of bbb onto span⁡{q1,…,qn}\operatorname{span}\{q_1, \ldots, q_n\}span{q1​,…,qn​} collapses to a sum of line projections:

p=(q1⊤b) q1+⋯+(qn⊤b) qn,p = (q_1^\top b)\, q_1 + \cdots + (q_n^\top b)\, q_n,p=(q1⊤​b)q1​+⋯+(qn⊤​b)qn​,

with no matrix inverse. Gram-Schmidt turns any independent set a1,…,ana_1, \ldots, a_na1​,…,an​ into such an orthonormal set.

Algorithm. Start with independent vectors a1,…,an∈Rma_1, \ldots, a_n \in \mathbb{R}^ma1​,…,an​∈Rm.

  1. v1=a1v_1 = a_1v1​=a1​, then q1=v1/∥v1∥q_1 = v_1 / \|v_1\|q1​=v1​/∥v1​∥.
  2. For j=2,…,nj = 2, \ldots, nj=2,…,n:
    • Subtract projections onto the previous qiq_iqi​'s: vj=aj−∑i=1j−1(qi⊤aj) qi.v_j = a_j - \sum_{i=1}^{j-1} (q_i^\top a_j)\, q_i.vj​=aj​−i=1∑j−1​(qi⊤​aj​)qi​.
    • Normalize: qj=vj/∥vj∥q_j = v_j / \|v_j\|qj​=vj​/∥vj​∥.

Each vjv_jvj​ is the component of aja_jaj​ orthogonal to span⁡{q1,…,qj−1}=span⁡{a1,…,aj−1}\operatorname{span}\{q_1, \ldots, q_{j-1}\} = \operatorname{span}\{a_1, \ldots, a_{j-1}\}span{q1​,…,qj−1​}=span{a1​,…,aj−1​}. Independence of the aia_iai​'s guarantees vj≠0v_j \neq 0vj​=0, so normalization is always defined.

Worked example: two vectors in R3\mathbb{R}^3R3. Take

a1=(110),a2=(101).a_1 = \begin{pmatrix} 1 \\ 1 \\ 0 \end{pmatrix}, \qquad a_2 = \begin{pmatrix} 1 \\ 0 \\ 1 \end{pmatrix}.a1​=​110​​,a2​=​101​​.

First vector: ∥a1∥=2\|a_1\| = \sqrt{2}∥a1​∥=2​, so

q1=12(110)=(1/21/20).q_1 = \frac{1}{\sqrt{2}}\begin{pmatrix} 1 \\ 1 \\ 0 \end{pmatrix} = \begin{pmatrix} 1/\sqrt{2} \\ 1/\sqrt{2} \\ 0 \end{pmatrix}.q1​=2​1​​110​​=​1/2​1/2​0​​.

Second vector: the coefficient of q1q_1q1​ is

q1⊤a2=12(1+0+0)=12.q_1^\top a_2 = \frac{1}{\sqrt{2}}(1 + 0 + 0) = \frac{1}{\sqrt{2}}.q1⊤​a2​=2​1​(1+0+0)=2​1​.

Then

v2=a2−12 q1=(101)−12(1/21/20)=(101)−(1/21/20)=(1/2−1/21).v_2 = a_2 - \frac{1}{\sqrt{2}}\, q_1 = \begin{pmatrix} 1 \\ 0 \\ 1 \end{pmatrix} - \frac{1}{\sqrt{2}}\begin{pmatrix} 1/\sqrt{2} \\ 1/\sqrt{2} \\ 0 \end{pmatrix} = \begin{pmatrix} 1 \\ 0 \\ 1 \end{pmatrix} - \begin{pmatrix} 1/2 \\ 1/2 \\ 0 \end{pmatrix} = \begin{pmatrix} 1/2 \\ -1/2 \\ 1 \end{pmatrix}.v2​=a2​−2​1​q1​=​101​​−2​1​​1/2​1/2​0​​=​101​​−​1/21/20​​=​1/2−1/21​​.

Norm: ∥v2∥=(1/2)2+(−1/2)2+12=3/2=6/2\|v_2\| = \sqrt{(1/2)^2 + (-1/2)^2 + 1^2} = \sqrt{3/2} = \sqrt{6}/2∥v2​∥=(1/2)2+(−1/2)2+12​=3/2​=6​/2. So

q2=v2∥v2∥=16(1−12)(equivalently 2/3 v2).q_2 = \frac{v_2}{\|v_2\|} = \frac{1}{\sqrt{6}}\begin{pmatrix} 1 \\ -1 \\ 2 \end{pmatrix} \quad\text{(equivalently } \sqrt{2/3}\, v_2\text{)}.q2​=∥v2​∥v2​​=6​1​​1−12​​(equivalently 2/3​v2​).

Check: q1⊤q2=(1/12)(1−1+0)=0q_1^\top q_2 = (1/\sqrt{12})(1 - 1 + 0) = 0q1⊤​q2​=(1/12​)(1−1+0)=0, and both have unit length. The pair {q1,q2}\{q_1, q_2\}{q1​,q2​} is an orthonormal basis for span⁡{a1,a2}\operatorname{span}\{a_1, a_2\}span{a1​,a2​}.

Failure mode. If the input vectors are linearly dependent, some vjv_jvj​ is zero and you cannot normalize — Gram-Schmidt is ill-defined (or you drop that vector and reduce rank). Orthogonal or already unit-length independent vectors are fine; the algorithm simply skips the “subtract” step when coefficients are zero.

Exercise · Fill in the blank

Apply the first step of Gram-Schmidt to a1 = (1, 1, 0): normalize it to get q1. What is the first (x) component of q1, rounded to 3 decimals?


The QR Factorization#

Pack the independent columns of AAA as a1,…,ana_1, \ldots, a_na1​,…,an​ and the Gram-Schmidt outputs as q1,…,qnq_1, \ldots, q_nq1​,…,qn​. By construction, each aja_jaj​ is a linear combination of q1,…,qjq_1, \ldots, q_jq1​,…,qj​ only (earlier qiq_iqi​'s appear with coefficient qi⊤ajq_i^\top a_jqi⊤​aj​; later ones do not appear). In matrix form that is the QROrthogonal-Upper (matrix factorization) factorization

A=QR,A = QR,A=QR,

where

  • QQQ is m×nm \times nm×n with orthonormal columns (Q⊤Q=InQ^\top Q = I_nQ⊤Q=In​),
  • RRR is n×nn \times nn×n upper triangular.

Explicitly, the entries of RRR are the Gram-Schmidt coefficients:

Rij={qi⊤aji<j,∥vj∥i=j,0i>j.R_{ij} = \begin{cases} q_i^\top a_j & i < j, \\ \|v_j\| & i = j, \\ 0 & i > j. \end{cases}Rij​=⎩⎨⎧​qi⊤​aj​∥vj​∥0​i<j,i=j,i>j.​

Column jjj of A=QRA = QRA=QR reads aj=r1jq1+⋯+rjjqja_j = r_{1j} q_1 + \cdots + r_{jj} q_jaj​=r1j​q1​+⋯+rjj​qj​, which is exactly the reverse of the Gram-Schmidt subtractions.

Example continued. With a1,a2a_1, a_2a1​,a2​ from above,

Q=(1/21/61/2−1/602/6),R=(21/206/2).Q = \begin{pmatrix} 1/\sqrt{2} & 1/\sqrt{6} \\ 1/\sqrt{2} & -1/\sqrt{6} \\ 0 & 2/\sqrt{6} \end{pmatrix}, \qquad R = \begin{pmatrix} \sqrt{2} & 1/\sqrt{2} \\ 0 & \sqrt{6}/2 \end{pmatrix}.Q=​1/2​1/2​0​1/6​−1/6​2/6​​​,R=(2​0​1/2​6​/2​).

Check R11=∥a1∥=2R_{11} = \|a_1\| = \sqrt{2}R11​=∥a1​∥=2​, R12=q1⊤a2=1/2R_{12} = q_1^\top a_2 = 1/\sqrt{2}R12​=q1⊤​a2​=1/2​, R22=∥v2∥=6/2R_{22} = \|v_2\| = \sqrt{6}/2R22​=∥v2​∥=6​/2, and R21=0R_{21} = 0R21​=0. Multiplying QRQRQR recovers A=[a1  a2]A = [a_1\; a_2]A=[a1​a2​].

Full vs thin QR. When AAA is m×nm \times nm×n with m≥nm \geq nm≥n and full column rank, the form above is the thin (or reduced) QR: QQQ is m×nm \times nm×n, RRR is n×nn \times nn×n. A full QR extends QQQ to an m×mm \times mm×m orthogonal matrix by adding an orthonormal basis for the left null space; the extra rows of RRR are zero. For least squares the thin form is enough.

Why care. QRQRQR is a stable way to encode “orthonormal basis for the column space” plus “change-of-basis coefficients.” Week 13 reuses orthonormal columns in the SVD construction; Gram-Schmidt is the constructive prototype for that idea.


Least Squares via QR#

Substitute A=QRA = QRA=QR into the normal equations A⊤A x^=A⊤bA^\top A\, \hat{x} = A^\top bA⊤Ax^=A⊤b:

(QR)⊤(QR) x^=(QR)⊤b⟹R⊤Q⊤Q R x^=R⊤Q⊤b.(QR)^\top (QR)\, \hat{x} = (QR)^\top b \quad\Longrightarrow\quad R^\top Q^\top Q\, R\, \hat{x} = R^\top Q^\top b.(QR)⊤(QR)x^=(QR)⊤b⟹R⊤Q⊤QRx^=R⊤Q⊤b.

Since Q⊤Q=IQ^\top Q = IQ⊤Q=I and RRR is invertible (upper triangular with positive diagonal entries from full column rank), multiply both sides by (R⊤)−1(R^\top)^{-1}(R⊤)−1:

R x^=Q⊤b.R\, \hat{x} = Q^\top b.Rx^=Q⊤b.

That is a triangular system. Solve it by back-substitution — no need to form A⊤AA^\top AA⊤A or invert it.

Why this is better numerically. Forming A⊤AA^\top AA⊤A squares the condition number: κ(A⊤A)=κ(A)2\kappa(A^\top A) = \kappa(A)^2κ(A⊤A)=κ(A)2. If AAA is already moderately ill-conditioned, A⊤AA^\top AA⊤A can lose all accurate digits before you solve. Working with Rx^=Q⊤bR\hat{x} = Q^\top bRx^=Q⊤b keeps the condition number of order κ(A)\kappa(A)κ(A), not κ(A)2\kappa(A)^2κ(A)2. Library routines (numpy.linalg.lstsq, np.linalg.qr followed by a triangular solve) use QR or related orthogonal factorizations for this reason.

Algorithm summary.

  1. Compute thin QR: A=QRA = QRA=QR.
  2. Form the projected right-hand side c=Q⊤bc = Q^\top bc=Q⊤b.
  3. Solve Rx^=cR\hat{x} = cRx^=c by back-substitution.
  4. Fitted values: p=Ax^=Q(Q⊤b)p = A\hat{x} = Q(Q^\top b)p=Ax^=Q(Q⊤b); residual e=b−pe = b - pe=b−p is orthogonal to C(A)C(A)C(A).

For the line-fit design matrix from the first section, the same x^\hat{x}x^ appears whether you solve normal equations or use QR; the QR path is the one you should prefer on real data.


Knowledge check#

Question 1 of 3

In A = QR, what property do the columns of Q have?

Orthonormal
Diagonal
Upper triangular
Symmetric

Browser lab#

Fit a noisy line with least squares, solved via QR.

python · runs in browser
import numpy as np
import matplotlib.pyplot as plt

rng = np.random.default_rng(0)
x = np.linspace(0, 10, 20)
y_true = 2.0 * x + 1.0
y = y_true + rng.normal(scale=2.0, size=x.shape)

A = np.column_stack([x, np.ones_like(x)])
Q, R = np.linalg.qr(A)
x_hat = np.linalg.solve(R, Q.T @ y)

print("slope, intercept =", x_hat)

fig, ax = plt.subplots(figsize=(6, 4))
ax.scatter(x, y, color="tab:blue", label="data")
ax.plot(x, A @ x_hat, color="tab:orange", label="least-squares fit")
ax.legend()
ax.set_title("Least squares line fit via QR")
plt.show()
← Previous
Week 7: Orthogonality and Projections
Next →
Week 9: Eigenvalues and Eigenvectors
On this page
  • Least Squares Fitting
  • Gram-Schmidt Orthogonalization
  • The QR Factorization
  • Least Squares via QR
  • Knowledge check
  • Browser lab