The Condition Number
One number for how much a matrix amplifies errors: the ratio of its biggest stretch to its smallest. Large means fragile answers.
Why Does This Exist?
Two systems can both be solvable yet differ wildly in trustworthiness. Nudge the inputs by a rounding error and one system's answer barely moves while the other's swings. The condition number
measures that fragility: a relative wobble of in can exit amplified up to in . A matrix with is mildly touchy; one with turns double precision into noise.
This number explains half of numerical linear algebra's behaviour: why the normal equations ( squares the condition number) lose to QR, why feature standardisation speeds up solvers, and why the Hessian's eigenvalue spread in Jacobian and Hessian sets the learning-rate dilemma. Sizes come from norms; systems from linear systems and least squares.
The one idea you need first
Singular values are a matrix's independent stretch factors, largest to smallest . Along the top singular vector inputs grow the most; along the bottom they shrink the most. The condition number is the ratio between those extremes: how uneven the stretching is.
Think of It Like This
A photocopier with uneven zoom
A photocopier enlarges horizontally by 10 and vertically by 1. Feed it a circle and a long thin ellipse comes out. Now smudge the input by a millimetre vertically: the output smudge is a millimetre. Smudge it horizontally: the output smudge is a centimetre.
Worse, run it backwards (solve the system): a millimetre of output smudge could have come from a tenth of a millimetre of input, or from a full millimetre, and the machine cannot tell you which. The zoom ratio 10 is the condition number: the factor by which uncertainty can grow when you invert. A copier with zoom 1 in both directions (orthogonal matrix, ) never amplifies anything.
How It Actually Works
The error bound that matters: for with perturbed ,
Relative input error times bounds relative output error. Two consequences: forming squares (a problem becomes , borderline unsolvable in single precision), and preconditioning means finding such that has a smaller before iterating.
Worked example
Take : stretches 1 and 10, so . Solve with , giving . Now perturb by (a 1% relative wobble, since ):
Here the wobble landed on the tame axis. Aim it at the fragile axis instead, : and the relative error hits from a 1% input. Same , direction-dependent damage, worst case exactly -fold. That direction dependence is why the bound uses .
Code
The point is the check: compute and confirm the determinant can look innocent while conditioning screams.
import numpy as np
A = np.array([[1.0, 0.0], [0.0, 10.0]])print(float(np.linalg.cond(A))) # -> 10.0B = np.array([[1e6, 0.0], [0.0, 1e-6]])print(float(np.linalg.det(B))) # -> 1.0print(float(np.linalg.cond(B))) # -> 1e+12has determinant 1, the picture of health, and a condition number of a trillion. Determinants measure volume; conditioning measures unevenness. Never read one for the other.
Watch Out For
Trusting a determinant of one
As the code shows, coexists with : volume preserved, directions mangled. Determinants near zero do flag singularity, but moderate determinants say nothing about conditioning. Ask for (or an estimate) whenever a solve must be trusted, not the determinant.
Training on unscaled features and blaming the optimiser
Features in units of millions beside features in thousandths build a design matrix with enormous , and gradient descent crawls along the valley floor exactly as the Hessian's spread predicts. Standardise first: zero mean, unit variance. It is the cheapest preconditioner in machine learning, and skipping it disguises a conditioning problem as a tuning problem.
The Quick Version
- : relative input error can grow -fold in the answer.
- The diag(1, 10) example scores 10: a 1% wobble can exit near 7% along the fragile axis.
- Normal equations square ; prefer QR or SVD on ill-conditioned problems.
- Determinant 1 does not mean healthy: the / diagonal has .
- Standardise features first: it is preconditioning you get for free.