EVERYTHING AIAI engineering, made visual
0/23 complete
LESSON 10 · MATHEMATICS × AI · BUILD

High-dimensional data
has a low-dimensional shape.

maximize wᵀΣw subject to ‖w‖ = 1 looks like calculus, but its answer is an eigenvector: the direction the data stretches most. Find it, project onto it, and 784 numbers become a handful without losing the pattern.

75 MIN · 8 CHAPTERSPREREQ · LESSONS 03, 06
FIG. 10 / PCA FINDS THE GRAIN, THEN FLATTENS IT
VAR(PC1) = 4.70 · VAR(PC2) = 0.53 data PC1 PC2
LESSON 10TYPE · BUILD~75 MINPREREQ · LESSONS 03, 06ORIGINAL LESSON ↗
THE 60-SECOND VERSIONThen show me why ↓
01 / WHEN DIMENSIONS GROW, DISTANCE DIES

Everything becomes equally far away.

In a d-dimensional box, pairwise distances divide by roughly the same mean and grow only √d apart: max/min falls from ~5 at d = 2 to ~1.02 at d = 1000. At the same time volume flees to the corners and the outer shell, and keeping sample density constant costs 10× more data per added dimension.

max/min → 1.02 at d = 1000 · outer shell 1 − 0.9ᵈ
02 / PCA KEEPS THE BIGGEST SPREAD

Eigenvectors of the covariance matrix.

Center the data, compute C = XᵀX/(n − 1), and eigendecompose. The eigenvectors are the perpendicular directions of the cloud, and each eigenvalue is the variance along its direction. Keep the top k and every sample becomes k coordinates instead of d.

Cw = λw · explained ratio = λₖ / Σλᵢ
03 / PCA SHIPS, t-SNE SHOWS

Compression feeds models; layouts feed eyes.

PCA is deterministic, invertible and fast: use it as preprocessing, compression and a quick look at variance. t-SNE and UMAP preserve neighborhoods only, shuffle global positions between seeds, and must never be fed to a classifier. Kernel PCA and autoencoders handle curved structure when a flat subspace is not enough.

PCA → model · t-SNE / UMAP → eyes only
MENTAL MODEL IN ONE SENTENCE

A cloud of data points is usually flat-ish: it spreads a lot in a few directions and barely at all in the rest. PCA rotates your axes so the first points along the biggest spread, then keeps the first k axes and throws the rest away — and those axes are exactly the eigenvectors from Lesson 03.

By the end you will be able to explain the curse of dimensionality with numbers, run and read the explained-variance curve, choose k from the elbow or from downstream accuracy, tell which method is for looking and which is for training, and recognize when reducing dimensions is the wrong move.

TOO MANY DIMENSIONS

In high dimensions,
everything is far away.

Four features is already hard to picture; 784 is impossible to picture and mathematically strange. Three everyday intuitions — distance, volume and density — quietly break as dimension grows.

Distances stop meaning anything. Take two random points in a d-dimensional box. As d grows, the distance between them converges to one predictable value: every pair sits at almost the same distance. If the nearest and farthest neighbours are equally far, then “closest” is a coin flip, and nearest-neighbour search, clustering and similarity ranking all degrade together.

Volume hides in the corners and the shell. A d-cube has 2ᵈ corners, and the fraction of a ball’s volume in its thin outer shell, 1 − 0.9ᵈ, climbs to 1: in high dimensions almost all the volume is at the edge, far from the center where your samples cluster. Data points spread outward, and models starve in the middle.

Density collapses exponentially. To keep the same number of samples per unit volume, going from 2-D to 20-D multiplies the data you need by 10¹⁸ — ten per new dimension. You never have enough data; reduction brings the density back to something workable.

Dimension avg distance ratio (max/min, random points) 2 ~5.0 10 ~1.8 100 ~1.2 1000 ~1.02 ← every point is 2% farther than every other

The curse of dimensionality, measured

Raise d and watch two things happen to a cloud of 90 uniform random points: the distance histogram packs into a spike around its mean, and the volume of the unit ball migrates into the thin outer shell.

d = 2, 90 points, 4005 pairs min distance = 0.0116 mean distance = 0.5241 max distance = 1.2684 max/min ratio = 109.683 sd / mean = 0.4762 outer-shell share 1 − 0.9^d = 19.00% a corner is 4 of them.

The generated points above also drive the distance histogram: the same seed gives the same cloud, so raising d extends the same data instead of rolling new dice.

Derivation: why distances concentrate (with numbers)

Take two random points whose d coordinates are each uniform on [0, 1]. Their squared distance is a sum of d independent terms (xᵢ − yᵢ)², each with the same mean and variance. For uniforms, that single term has mean μ = 1/6 and variance σ² = 7/180:

E[(x − y)²] = 2 · Var(uniform) = 2 · 1/12 = 1/6 ≈ 0.1667 mean of squared distance = d · μ grows like d standard deviation = √d · σ grows like √d relative spread = (√d σ)/(d μ) = (σ/μ)/√d shrinks like 1/√d σ/μ = √(7/180) / (1/6) = √1.4 ≈ 1.1832 d = 2 → 1.1832/√2 = 0.8367 d = 10 → 1.1832/√10 = 0.3742 d = 100 → 1.1832/√100 = 0.1183 d = 1000 → 1.1832/√1000 = 0.0374 ← distances bunch up

The mean grows faster than the spread, so the histogram of distances becomes a narrower and narrower spike relative to its position — the lab draws exactly that. A similar calculation explains the shell: the volume of a d-ball of radius r is proportional to rᵈ, so the share inside radius 0.9 is 0.9ᵈ and the share in the outer shell is 1 − 0.9ᵈ. Numeric check: 1 − 0.9² = 0.19 (19% of a disk is in the outer shell), while 1 − 0.9¹⁰⁰ = 0.99997 — essentially all of it.

Quick check

You index 100-dimensional embeddings and find that the closest and farthest of almost any point's neighbours are nearly the same distance away. What is the most accurate conclusion?

THE DATA IS FLAT-ISH

784 numbers,
a handful of ideas.

Real high-dimensional data is almost never spread evenly through every direction. It lives on a much smaller surface, and most of the extra coordinates are redundancy or noise.

A handwritten “7” is a 28 × 28 grid of pixel values — 784 numbers. But it does not take 784 independent choices to draw a seven. It takes a few: the angle of the stroke, the length of the crossbar, how much the digit leans, how thick the pen is. Everything else about those pixels is a consequence. The information lives on a low-dimensional manifold: a small surface folded inside the big space.

Finding that surface buys three things. Compression: store or transmit fewer numbers. Speed: models train on shorter vectors. Clarity: two or three directions can be plotted, and plots are how humans spot structure. It also acts as a gentle denoiser, because directions that carry almost no variance are often exactly where the measurement noise lives.

The catch is the word “almost”. Reduction always throws something away. The whole craft is choosing a surface that keeps what matters for your task and drops what does not.

Compress a picture to a few components

Eighteen 6 × 6 patterns built from a small vocabulary of smooth shapes, squeezed to k components. Blue tiles are the components themselves — the shapes the data is made of.

k = 3 of 36 possible directions variance kept = 97.2% MSE over all 18 patterns = 0.00055 top eigenvalues λ1 = 0.3358 λ2 = 0.2898 λ3 = 0.0956 λ4 = 0.0122 λ5 = 0.0014 λ6 = 0.0012 k = 0 shows the dataset mean, not black.

This is why PCA is compression: the components are a basis, and each pattern is stored as k numbers plus the shared basis. Lose the tail of the eigenvalue list and the blurry parts of the picture go first.

Worked check: the compression budget

Suppose you have 5,000 digit images at 784 pixels each, and 50 principal components capture the digit shapes. What does storing the compressed version actually cost?

raw: 5,000 × 784 = 3,920,000 numbers PCA: the shared basis 784 × 50 = 39,200 numbers one code per image 5,000 × 50 = 250,000 numbers total = 289,200 numbers 289,200 / 3,920,000 = 0.0738 → about 7.4% of the raw storage. per image: 784 values → 50 values + a basis the whole dataset shares.

Two honest footnotes. The 50 codes are not automatically smaller than the raw pixels in a byte-for-byte sense — a float is a float — so the saving is real only when k is small relative to d and the decoder is shared. And if 50 components capture 95% of the variance, the missing 5% is still in the file: reconstruction is a trade, not a magic trick.

PCA: THE BIGGEST SPREAD

Rotate the axes
to the data’s grain.

Principal Component Analysis finds the directions along which the cloud actually stretches, ranks them by how much variance they hold, and lets you keep the top few. The eigenvectors of Lesson 03 are those directions.

The recipe is five steps, and every one has a plain-English job:

  1. Center the data. Subtract each feature’s mean so the cloud sits at the origin. Without this, PCA points at the mean instead of at the spread.
  2. Compute the covariance matrix. C = XᵀX / (n − 1) records how each feature varies and how pairs of features move together.
  3. Eigendecompose it. The eigenvectors of C are the principal directions; because C is symmetric, they come out perpendicular. The eigenvalues measure variance.
  4. Sort by eigenvalue. Biggest first: PC1 is the direction of greatest spread, PC2 the greatest spread perpendicular to PC1, and so on.
  5. Project. Keep the top k directions and replace every sample with its k coordinates along them. That is the compression.

Find the spread, then flatten it

Drag the cloud into a shape, then project it onto PC1. The axes are the eigenvectors of the covariance matrix, drawn at one standard deviation; the pink dots are the compressed data.

C = [[4.02, 2.04], [2.04, 1.60]] PC1 = [0.869, 0.495] λ₁ = 5.182 PC2 = [-0.495, 0.869] λ₂ = 0.435 explained = 92.3% + 7.7% = 100% projection error per point = 0.427

When the cloud is almost a line, λ₂ ≈ 0 and the projection loses almost nothing. When the cloud is round, λ₁ ≈ λ₂ and losing PC2 throws away half the spread — no rotation can fix that.

Covariance in, eigenvectors out

Edit the symmetric covariance matrix and a sample point; the console runs the whole PCA derivation: trace, determinant, eigenvalues, eigenvectors, explained variance and the projection arithmetic.

C = [[5.000, 4.000], [4.000, 5.000]] trace = C₁₁ + C₂₂ = 10.000 det = C₁₁·C₂₂ − C₁₂² = 9.000 λ = trace/2 ± √((C₁₁−C₂₂)²/4 + C₁₂²) λ₁ = 9.000 λ₂ = 1.000 PC1 = [0.707, 0.707] explains 90.0% of total variance PC2 = [-0.707, 0.707] explains 10.0% wᵀCw checks (variance along a unit direction): w = [1, 0] → 5.000 w = [0, 1] → 5.000 w = PC1 → 9.000 ← the maximum sample x = [2.000, 1.000] z₁ = x · PC1 = 2.121 rebuilt with k = 1: [1.500, 1.500] residual² = 0.500 (‖x‖² = 5.000) fraction of this point's squared length dropped = 10.0%
Derivation: why the principal directions are eigenvectors
  1. Variance along a direction. Let w be a unit vector (length 1). Projecting every centered sample x onto w gives the score z = x·w. The variance of those scores is zᵀz/(n − 1) = (Xw)ᵀ(Xw)/(n − 1) = wᵀCw. One small product gives the spread in any direction you like.
  2. Maximize it under a constraint. We want the w that maximizes wᵀCw subject to wᵀw = 1. At the optimum the gradient of the objective (2Cw) is parallel to the gradient of the constraint (2w), so 2Cw = λ·2w, which is Cw = λw: w must be an eigenvector of C.
  3. Which eigenvector? Plug the eigenvector back in: variance = wᵀCw = wᵀ(λw) = λ·wᵀw = λ. The variance along an eigenvector equals its eigenvalue, so the largest eigenvalue gives the direction of largest spread. The trace equals the sum of the eigenvalues, so the total variance is Σλᵢ.
  4. Explained variance. Component k explains the fraction λₖ/Σλᵢ. Dropping components k+1…d loses exactly the sum of the dropped eigenvalues — which is the reconstruction error in squared units.
Worked example 1 — the lesson's C = [[2, 1], [1, 2]] trace = 4, det = 2·2 − 1·1 = 3 λ = (4 ± √(4² − 4·3))/2 = (4 ± 2)/2 → 3 and 1 PC1 = [1, 1]/√2 = [0.707, 0.707] explains 3/(3+1) = 75% PC2 = [1, −1]/√2 explains 25% keep PC1: z = 0.707·x₁ + 0.707·x₂, and 25% of the spread is gone. Worked example 2 — a second matrix, C = [[5, 4], [4, 5]] trace = 10, det = 25 − 16 = 9 λ = (10 ± √(10² − 4·9))/2 = (10 ± 8)/2 → 9 and 1 explained: 9/10 = 90% and 1/10 = 10% PC1 = [0.707, 0.707], PC2 = [0.707, −0.707] numeric check that PC1 really is the max: w = [1, 0] → wᵀCw = 5 w = [0.6, 0.8] → 5(0.36) + 8(0.48) + 5(0.64) = 8.84 < 9 w = PC1 → 9 exactly. Any unit w gives at most 9. project the point x = [2, 1]: z = 0.707·2 + 0.707·1 = 2.121 rebuild: z·PC1 = [1.500, 1.500] residual: x − x̂ = [0.500, −0.500], squared length = 0.5 dropped fraction for this point: 0.5 / ‖x‖² = 0.5/5 = 10% ✓

The last line is the whole promise in one number: for this point and this covariance, keeping the single best direction loses exactly the 10% that PC2 accounted for — and no other direction could lose less.

PCA in practice: SVD on the data instead of eigendecomposition

Forming the covariance matrix squares every number, and squaring is also what happens to numerical error: the condition number of XᵀX is the square of X’s. Libraries therefore compute PCA from the singular value decomposition of the centered data directly: X = UΣVᵀ. The columns of V are exactly the principal directions, the squared singular values divided by (n − 1) are the covariance eigenvalues, and the scores are UΣ.

C = XᵀX/(n − 1) and X = UΣVᵀ give XᵀX = VΣ²Vᵀ so λᵢ = σᵢ²/(n − 1) and PCᵢ = column i of V. numeric check on the four centered points from before: X = [[−1.5, −1.5], [−0.5, 0.5], [0.5, −0.5], [1.5, 1.5]] σ₁² = (n − 1)·λ₁ = 3·3 = 9 → σ₁ = 3 σ₂² = (n − 1)·λ₂ = 3·(1/3) = 1 → σ₂ = 1 explained ratio = σ₁²/(σ₁² + σ₂²) = 9/10 = 90% ✓ the n − 1 cancels, so SVD can report ratios without ever choosing a variance denominator.
PCA through SVDpython
import numpy as np

Xc = X - X.mean(axis=0)                # center first, always
U, s, Vt = np.linalg.svd(Xc, full_matrices=False)
components = Vt[:k]                    # k x d principal directions
Z = Xc @ components.T                  # n x k scores
explained = s[:k]**2 / (s**2).sum()    # ratios, no (n-1) needed

# sklearn does this for you:
# from sklearn.decomposition import PCA
# pca = PCA(n_components=k).fit(X)
Eigendecomposition is the derivation; SVD is the production implementation. Use eigh on the covariance only when d is small and you want the covariance itself.
Quick check

A 2-D covariance matrix has eigenvalues 6 and 2 along perpendicular directions. Which statement is correct?

HOW MANY COMPONENTS

Keep enough to explain
90-ish percent.

PCA hands you a ranked list of directions. Choosing k turns that list into a decision — and there are three honest ways to make it.

Each principal component captures a fraction of the total variance: explained ratio for component k = λₖ / Σλᵢ. Sum the top-k ratios and you know how much of the original spread k coordinates preserve. The rest is exactly what reconstruction error measures: run the data down to k components and back up, and the mean squared difference from the original is the share of eigenvalues you dropped.

Three strategies, in increasing order of honesty about your actual task:

  1. Threshold. Keep enough components to explain 90–95% of the variance. Fast, arbitrary, and a good default.
  2. Elbow. Plot the explained variance per component. A sharp drop-off marks the boundary between structure and noise — the flat tail is usually redundancy.
  3. Downstream performance. Sweep k, train the real model, and stop where accuracy plateaus. The best k is the smallest one that stops helping.
ComponentEigenvalueExplained ratioCumulative
PC14.730.4730.473
PC22.510.2510.724
PC31.120.1120.836
PC40.890.0890.925
PC5–PC100.75 total0.075 total1.000

The elbow, and what k throws away

The bars are the eigenvalues of a synthetic 10-feature dataset; the dashed line is cumulative explained variance. Slide k and watch one sample’s 10 numbers rebuilt from its first k coordinates.

top eigenvalues λ1..5 = 4.85, 2.71, 1.29, 0.83, 0.28 keep k = 2 variance kept = 72.8% variance dropped = 27.2% reconstruction MSE per entry = 0.28111 k = 2 captures 72.8% of this dataset; the lesson table's first two components capture 72.4%.

The MSE counts squared error per coordinate, so it is tiny next to the raw eigenvalues: the total squared error equals (n − 1) × the dropped eigenvalues, spread over n × d entries.

Derivation: reconstruction error is the dropped eigenvalues

The total variance of the dataset is the trace of the covariance matrix, which equals Σλᵢ. Keeping k components preserves Σᵏλᵢ of it; the reconstruction error — the average squared distance between each original point and its rebuilt version — is the rest:

total squared error over the dataset = (n − 1) · Σ(dropped λ) mean squared error per entry = (n − 1) · Σ(dropped λ) / (n · d) numeric check with the table above (total variance = 10.00): keep k = 2 → kept 7.24, dropped 2.76 → 72.4% kept, 27.6% lost keep k = 4 → kept 9.25, dropped 0.75 → 92.5% kept, 7.5% lost for n = 101 samples and d = 10 features, keep k = 2: total squared error = 100 × 2.76 = 276 MSE per entry = 276 / (101 × 10) = 0.273 and the dropped axis in the last five eigenvalues is mostly noise.

Because the relationship is exact — not approximate — reconstruction error and explained variance are two readings of the same number. That is also why reconstruction error doubles as an anomaly score: a point the kept subspace cannot rebuild is a point that does not fit the pattern the rest of the data learned.

Quick check

A classifier's validation accuracy is 0.91 with k = 30 components and 0.911 with k = 300. Which k would you ship, and why?

WHEN STRAIGHT LINES FAIL

Some structure only unfolds
when you bend the space.

PCA finds flat subspaces. Circles, spirals and Swiss rolls are not flat — so the toolbox grows three more tools: kernel PCA for curved structure, and t-SNE and UMAP for looking at it.

Two concentric rings of points cannot be separated by any line. Project them onto the best straight direction and both rings collapse onto the same span of numbers. Kernel PCA first maps the data into a higher-dimensional space — where the rings become a flat, separable problem — and runs PCA there, without ever computing the coordinates. The kernel trick is the shortcut: a kernel function k(x, y) returns dot products between mapped points directly. The most common is the RBF (Gaussian) kernel, exp(−γ‖x − y‖²).

t-SNE and UMAP take a different bargain. Instead of preserving variance, they preserve who is near whom: t-SNE turns pairwise distances into neighbor probabilities and searches for a 2-D layout with the same probabilities; UMAP builds a weighted neighbor graph and lays it out. Both produce gorgeous cluster pictures. Both distort global distances — t-SNE severely, UMAP less so — and both are stochastic.

STANDARD PCA1-D projectionmixedKERNEL PCA (RBF)lifted valueouterinner

A teaching picture, not a literal rendering: kernel PCA does not draw points on a line, it finds their principal directions in a lifted feature space.

Three clusters, different maps

Forty-five points in 6-D arranged in three groups, laid out by a small t-SNE-style optimizer: neighbor affinities in 6-D, attraction and repulsion in 2-D. Change the seed and watch the global arrangement move while the neighbors stay together.

run seed = 4 perplexity = 15 the three groups are genuinely far apart in 6-D. their 2-D distances are whatever the optimizer settled on. low perplexity → many tight clumps high perplexity → clusters bleed together new seed → clusters move to new places This is why t-SNE plots are for looking, not for measuring.

A teaching implementation: exact O(n²) affinities and gradient, no early exaggeration, no Barnes-Hut. Real t-SNE adds those for speed and stability — and still carries the same warning about global distances.

Worked check: the RBF kernel on the two rings

The RBF kernel measures closeness in the lifted space. With x − y the distance between two points:

k(x, y) = exp(−γ‖x − y‖²) γ = 0.5, distance 2 → exp(−0.5 · 4) = e⁻² ≈ 0.135 γ = 0.1, distance 2 → exp(−0.1 · 4) = e⁻⁰·⁴ ≈ 0.670 concentric rings, inner radius 1, outer radius 3, γ = 0.5: k(point, center) for an inner point = e^(−0.5·1) = 0.607 k(point, center) for an outer point = e^(−0.5·9) = 0.011 separation ≈ 0.6 versus 0.01 — the rings become linearly separable in the lifted coordinate, which no straight line in 2-D could do. cost: the kernel matrix is n × n. n = 10,000 → 10⁸ entries → 10⁸ · 8 bytes ≈ 800 MB (float64) that memory wall is why kernel PCA stops around tens of thousands of samples while plain PCA handles millions.

γ is the bandwidth knob: large γ makes each point care only about its immediate neighbours (risking overfit), small γ makes everything look similar (losing structure). It plays the same role perplexity does in t-SNE.

MethodUse it forPreservesSpeed
PCAPreprocessing, compression, quick plotsGlobal variance, linear structureFast, exact, millions of samples
Kernel PCACurved structure before a modelVariance in a lifted spaceSlow — n × n kernel matrix
t-SNEPublication-quality 2-D cluster plotsLocal neighborhoods onlySlow (under ~10k samples)
UMAP2-D plots at scaleLocal plus some global structureMedium (handles millions)
Quick check

You want to feed 2-D coordinates into a fraud classifier to make it faster. A colleague suggests running t-SNE and using its output. What is wrong with the plan?

AUTOENCODERS: PCA THAT BENDS

A network can learn
the same trick, nonlinearly.

PCA compresses by rotating and dropping axes. An autoencoder compresses by squeezing data through a narrow layer and learning to rebuild it — a generalization of PCA whose surface can curve.

An autoencoder is two networks in a row. The encoder maps a 784-pixel image down to a small code, say 32 numbers. The decoder maps that code back to 784 pixels. Training minimizes reconstruction error — mean squared difference between input and output — so the only way to do well is to keep whatever information the decoder needs. The narrow layer in the middle is the bottleneck, and its 32 activations are the compressed representation.

784input pixels128encoder32bottleneck code128decoder784reconstructionloss = mean squared difference between input and reconstruction
Derivation: a linear autoencoder lands on PCA, then nonlinearity buys more

Strip out the nonlinearities and the autoencoder is a matrix product: code z = W₁x, reconstruction x̂ = W₂z. Minimizing mean squared error over all data has a known optimum: the column space of W₂ (and the row space of W₁) spans exactly the top-k principal subspace. So PCA is the linear special case — same answer, found by gradient descent instead of an eigendecomposition.

a single dense layer 784 → 784: weights 784 × 784 + 784 biases = 615,440 parameters an hourglass 784 → 32 → 784: encoder 784 × 32 + 32 = 25,120 decoder 32 × 784 + 784 = 25,872 total = 50,992 parameters 50,992 / 615,440 ≈ 0.083 → about 8% of the parameters, for a representation 24.5× smaller (784/32). The bottleneck is doing the compression; the depth is doing the fitting.

Now add a nonlinearity between encoder and decoder and the optimal surface can bend. A linear method cannot represent a circle with one coordinate; a nonlinear autoencoder can — it learns a curved manifold just as kernel PCA finds one, but as a trained network rather than a fixed kernel. The cost is what PCA never had: a training loop, a learning rate, and no guarantee of a global optimum.

WHEN NOT TO REDUCE

Sometimes the extra
dimensions are the signal.

PCA is powerful, unsupervised and blind to your labels. There are real situations where running it is the wrong first move — and one where it throws away exactly the direction you needed.

Run PCA because the data is redundant, not because it is high-dimensional. If a model is already fast enough, if features are individually meaningful, or if a regularizer can handle the redundant directions, reduction adds a preprocessing pipeline without buying anything. The checklist before reaching for PCA or t-SNE:

  • Is the signal in a low-variance direction? PCA keeps spread, not usefulness. A feature that barely varies can be the one that separates the classes.
  • Do you need to explain the model? Principal components are mixtures of every original feature. “PC3 is up 0.3” tells a clinician or auditor nothing.
  • Is the data already small? With 20 features and 5,000 samples, the dimensionality is not what is hurting you.
  • Is the method for looking or for training? t-SNE and UMAP coordinates are not features. Never feed them to a classifier.
  • Can you afford it? Kernel PCA stores an n × n matrix; at 10,000 samples that is hundreds of megabytes before any computation.
  • Have you standardized? Without it, the feature with the largest units wins PC1 by accident, and every component after it is distorted.
THE DATA: WIDE IN X, SEPARATED IN YPC1 (99.9% of variance)PROJECTIONSonto PC1:both classes land in the same rangeonto y (0.08%):the quiet direction is the useful one
Worked check: PCA keeps 99.9% of the variance and 0% of the classes

Suppose the x coordinate is uniform on [−3, 3] in both classes, and the only difference is a small shift in y: class A sits at y = +0.05, class B at y = −0.05.

Var(x) = (6)²/12 = 3.0000 Var(y): y is +0.05 or −0.05, so E[y²] = 0.0025 and Var(y) = 0.0025 C ≈ [[3.0000, 0], [0, 0.0025]] (x and y uncorrelated) PC1 = [1, 0], λ₁ = 3.0000 → 3.0000/3.0025 = 99.92% of variance PC2 = [0, 1], λ₂ = 0.0025 → 0.08% mean of class A on PC1 = 0 mean of class B on PC1 = 0 difference in class means on PC1 = 0.000 ← PCA's best direction difference in class means on PC2 = 0.100 ← the signal Conclusion: keeping the top component keeps 99.9% of the spread and throws away 100% of the class separation.

This is not a pathology of the numbers; it is a property of unsupervised methods. If the labels exist, use them: linear discriminant analysis, partial least squares or a supervised feature selection step can rank directions by how much they separate classes. PCA has no idea the labels exist.

CHECK YOURSELF

Five questions.
Then the terms worth keeping.

Answer before you look. The PCA question and the t-SNE question are the two that come up most in real debugging sessions.

0 / 5 answered · 0 correct

01What is the “curse of dimensionality”?

02What does PCA find?

03After running PCA on 784-dimensional MNIST data with k = 50 components, you find 95% of the variance is captured. What does this tell you?

04Why should you NOT use t-SNE as preprocessing before training a classifier?

05When would you choose kernel PCA over standard PCA?

Key terms, demystified

Click a card to swap the lazy description for what it actually means.

Exercises from the lesson

Four problems, including a hand-computed PCA from scratch. Try first; a worked answer is one click away.

  1. Add inverse_transform to the PCA class: X_hat = Z @ components + mean. Reconstruct MNIST digits with 10, 50 and 200 components and print the mean squared reconstruction error. How does it relate to the dropped eigenvalues?
    Show one worked answer

    inverse_transform(Z) = Z @ components + mean undoes transform because components has orthonormal rows. The total squared reconstruction error over the dataset equals (n − 1) × (sum of eigenvalues not kept), so the MSE per entry is (n − 1)·Σ_dropped / (n·d). Concretely: with n = 5000, d = 784 and dropped eigenvalues summing to 0.31, total squared error = 4999 × 0.31 = 1549.7, and per-element MSE = 1549.7 / 3,920,000 ≈ 0.000395. Which components you drop matters more than how many: at 10 components the dropped sum is large; by 200 it is a rounding error, and the per-pixel error is dominated by genuine noise the subspace never captured.

  2. Run t-SNE on the same data with perplexity 5, 30 and 100. Describe how the output changes, and explain why perplexity affects cluster tightness.
    Show one worked answer

    Perplexity is the effective number of neighbors each point uses. At 5, each point listens only to its closest handful: the picture fragments into many tiny tight clumps, and large-scale relationships wash out. At 30, local clusters themselves become clear. At 100, neighborhoods are large enough that clusters bleed into one another into a smoother, less separated map — small clusters can dissolve. The tightness changes because perplexity sets the width σᵢ of each point's Gaussian affinity in high-dimensional space; a narrow Gaussian makes almost everything a near-zero neighbor, so the optimizer is pushed to fold close friends tightly together. Standard advice is to try several values and distrust conclusions that only appear at one setting.

  3. Generate a dataset with 50 features where only 5 are informative (sklearn.datasets.make_classification with n_informative=5, n_redundant=0, n_repeated=0). Apply PCA and check whether the cumulative explained-variance curve identifies the true dimension.
    Show one worked answer

    The curve climbs steeply for the first 5 components and then flattens: those 5 directions capture the class structure, and the remaining 45 are pure noise with roughly equal, tiny eigenvalues. Numeric sanity check: if the 5 informative eigenvalues are around 3.0 each and each of the 45 noise directions contributes about 1.0, the informative share is 15/(15 + 45) = 25% spread over 5 components, so the elbow sits near 25% cumulative — not 90–95%. That is the point: a flat tail of eigenvalue-1 directions is the signature of pure noise, and a 95% threshold would keep far more components than the data's true dimension. The elbow often identifies the dimension better than a fixed threshold.

  4. PCA by hand: four centered points are (−1.5, −1.5), (−0.5, 0.5), (0.5, −0.5), (1.5, 1.5). Compute the covariance matrix, its eigenvalues and eigenvectors, the explained-variance ratios, and the total squared reconstruction error from keeping only PC1.
    Show one worked answer

    C = XᵀX/(n − 1) with n − 1 = 3. Σx² = 2.25 + 0.25 + 0.25 + 2.25 = 5, Σy² = 5, Σxy = 2.25 − 0.25 − 0.25 + 2.25 = 4, so C = [[5/3, 4/3], [4/3, 5/3]]. This is 1/3 × [[5, 4], [4, 5]], whose eigenvalues are (5 ± 4)/3 = 3 and 1/3. Eigenvectors: [1, 1]/√2 for eigenvalue 3, and [1, −1]/√2 for 1/3. Explained ratios: 3/(10/3) = 90% and (1/3)/(10/3) = 10%. Projecting with PC1 = [0.707, 0.707]: the first point gives z = (−1.5 − 1.5)/√2 = −2.121 and rebuilds exactly to (−1.5, −1.5); the second gives z = 0 and rebuilds to (0, 0), leaving residual (−0.5, 0.5) with squared length 0.5. By symmetry point three loses 0.5 and points one and four lose nothing. Total squared error = 0 + 0.5 + 0.5 + 0 = 1.000, which equals (n − 1) × λ₂ = 3 × (1/3) = 1.000 ✓.

Terms this lesson borrows from later lessons (or outside)

You do not need to master these here. Each one gets a proper treatment in its own lesson; the one-line meaning is enough to keep reading. Orange dotted underlines in the prose point back to this list.

  • featureOne input column: a single measured property of each example (age, pixel value, word count). (Lessons 01–02)
  • positive semi-definiteA symmetric matrix whose eigenvalues are all ≥ 0, so wᵀMw is never negative for any w. Covariance matrices are always like this, which is why their eigenvalues are variances. (Lesson 03)
  • Lagrange multiplierA technique for maximizing a function under a constraint: at the optimum the gradient of the objective is parallel to the gradient of the constraint. (Lesson 04; returns in Lesson 18)
  • clusteringGrouping data points so that points in a group are closer to each other than to points in other groups. (outside these lessons)
  • nearest neighbourThe stored point closest to a query under some distance; k-nearest-neighbours classifiers vote among the k closest. (outside these lessons)
  • anomaly detectionFlagging data points that do not fit the pattern of the rest — often with reconstruction error as the score. (outside these lessons)
  • SVDSingular value decomposition: any matrix A becomes UΣVᵀ, and PCA can be computed from it directly without forming the covariance matrix. (Lesson 11)
  • latent spaceThe learned low-dimensional coordinate system inside a model, where compressed codes live. (outside these lessons; returns with autoencoders and diffusion)
KEEP GOING

A picture is a start.
Practice is the rest.

This lesson is a port of an open course. Everything here traces back to it — and the next step is running the code yourself.

Lesson text adapted from AI Engineering from Scratch (Phase 01, Lesson 10) and the Math Foundations Notebook reference build. Interactive figures, the animated projection hero, the hand-computed PCA example, the when-not-to-reduce counterexample and the curse, PCA, scree, compression, t-SNE and eigen labs are original to this page. Every lab runs in your browser.