TAI BUI
Back to curriculum
BuildPython

Dimensionality Reduction

High-dimensional data has structure. You just have to look at it from the right angle.

TIME: ~90 minutesPREREQUISITES: Phase 1, Lessons 01 (Linear Algebra Intuition), 02 (Vectors, Matrices & Operations), 03 (Eigenvalues & Eigenvectors), 06 (Probability & Distributions)

Learning Objectives

  • Implement PCA from scratch: center data, compute the covariance matrix, eigendecompose, and project
  • Use explained variance ratio and the elbow method to choose the number of principal components
  • Compare PCA, t-SNE, and UMAP for visualizing MNIST digits in 2D and explain their tradeoffs
  • Apply kernel PCA with an RBF kernel to separate nonlinear data structures that standard PCA cannot handle

The Problem

Picture a dataset with 784 features per sample: pixel values from handwritten digits, gene expression levels, user behavior signals, whatever it is. You cannot visualize 784 dimensions, and you cannot hold that many axes in your head at once.

Most of those features are redundant, though. The real information lives on a much smaller surface. A handwritten "7" does not need 784 independent numbers to describe it. A few will do: the angle of the stroke, the length of the crossbar, how much it leans. Everything else is noise.

Dimensionality reduction is the search for that smaller surface. It takes your 784-dimensional data and compresses it down to 2, 10, or 50 dimensions while keeping the structure that actually matters.

Warm-up0/3
1. A spreadsheet row has 784 numeric columns (one per pixel of a small image). If you tried to plot that single row as a point on ordinary graph paper, how many of those 784 numbers could actually go on the page?Warm-up
A row of 784 numbers, x1 through x784, with an arrow down to a plain two-axis sheet of graph paper and a question mark where the point should go.
2. From Lesson 06 (Probability & Distributions): if a set of measurements has high variance along some direction, what does that tell you about the data?Warm-up
An arrow labeled this direction with a box reading variance high next to a question mark, asking what high variance along a direction tells you about the measurements.
3. From Lesson 03 (Eigenvalues & Eigenvectors): a matrix is applied to one of its own eigenvectors. What happens to that vector?Warm-up
A vector v drawn along a dashed line through the origin, next to a box labeled matrix A, with an arrow to a question mark asking what happens to v when A is applied, with v marked as an eigenvector of A.

The Concept

The curse of dimensionality

The curse of dimensionality is what happens to geometric intuition once you leave two or three dimensions: it quietly stops applying. Three things go wrong as dimensions grow.

Distance becomes meaningless. In high dimensions, the distance between any two random points converges to the same value. Once every point sits roughly the same distance from every other point, nearest-neighbor search has nothing left to work with.

Dimension    Avg distance ratio (max/min between random points)
2            ~5.0
10           ~1.8
100          ~1.2
1000         ~1.02

Volume concentrates in corners. A unit hypercube in d dimensions has 2^d corners, and in 100 dimensions nearly all of that volume sits in the corners, far from the center. Data points spread out to the edges, and your models end up starved for data in the interior.

You need exponentially more data. Keeping the same sample density while going from 2D to 20D would take 10^18 times more data than you started with. You will never have that much. Reducing dimensions is what brings the density back down to something workable.

PCA: find the directions that matter

Principal Component Analysis (PCA) finds the axes along which your data varies the most, then rotates your coordinate system to line up with them: the first axis captures the most variance, the second captures whatever is left over, and so on.

The algorithm:

1. Center the data        (subtract the mean from each feature)
2. Compute covariance     (how features move together)
3. Eigendecomposition     (find the principal directions)
4. Sort by eigenvalue     (biggest variance first)
5. Project               (keep top k eigenvectors, drop the rest)

Why eigendecomposition, specifically? The covariance matrix is symmetric, which means its eigenvectors are guaranteed to be orthogonal directions in feature space. The eigenvalues tell you how much variance each of those directions captures, and the eigenvector with the largest eigenvalue points along the direction of maximum variance.

Mermaid diagram

  • Before PCA: Data cloud is spread diagonally across both x and y axes
  • After PCA: Coordinate system is rotated so PC1 aligns with the direction of maximum variance (elongated spread) and PC2 aligns with the direction of minimum variance (narrow spread)
  • Dimensionality reduction: Dropping PC2 projects the data onto PC1, losing very little information

Explained variance ratio

Each principal component captures some fraction of the total variance. The explained variance ratio is just that fraction, spelled out per component.

Component    Eigenvalue    Explained ratio    Cumulative
PC1          4.73          0.473              0.473
PC2          2.51          0.251              0.724
PC3          1.12          0.112              0.836
PC4          0.89          0.089              0.925
...

Once cumulative explained variance crosses 0.95, that handful of components already accounts for 95% of the information. Whatever is left over is mostly noise.

Choosing the number of components

Three ways to pick it:

  1. Threshold. Keep whatever number of components explains 90-95% of the variance.
  2. Elbow method. Plot explained variance per component and look for where it drops off sharply.
  3. Downstream performance. Use PCA as a preprocessing step, sweep k, and measure your model's accuracy directly. The best k is wherever accuracy plateaus.

t-SNE: preserve neighborhoods

t-SNE (t-Distributed Stochastic Neighbor Embedding) is built for one job: visualization. It maps high-dimensional data down to 2D or 3D while preserving which points sit near each other.

Here is the idea: in the original space, compute a probability distribution over pairs of points based on how close they are. Near points get high probability, far points get low probability. Then search for a 2D arrangement that reproduces roughly the same distribution. Points that were neighbors in 784 dimensions end up neighbors in 2D too.

A few things worth knowing about it:

  • It is non-linear, so it can unfold complex manifolds that PCA cannot.
  • It is stochastic. Run it twice and you will get two different layouts.
  • The perplexity parameter controls how many neighbors it considers (typical range: 5-50).
  • Distances between clusters in the output are not meaningful. Only the clusters themselves are.
  • It is slow on large datasets, O(n^2) by default.

UMAP: faster, better global structure

UMAP (Uniform Manifold Approximation and Projection) does roughly what t-SNE does, but with two advantages:

  • It is faster, because it works from approximate nearest-neighbor graphs instead of computing every pairwise distance.
  • It preserves more meaningful global structure. The relative positions of clusters in the output tend to actually mean something, unlike in t-SNE.

Under the hood, UMAP builds a weighted graph over the high-dimensional data (its "fuzzy topological representation") and then searches for a low-dimensional layout that preserves that graph as closely as possible.

Two parameters worth knowing:

  • n_neighbors: how many neighbors define local structure (similar to perplexity). Push it higher to preserve more global structure.
  • min_dist: how tightly points can pack together in the output. Lower values produce denser clusters.

When to use which

MethodUse casePreservesSpeed
PCAPreprocessing before trainingGlobal varianceFast (exact), works on millions of samples
PCAQuick exploratory visualizationLinear structureFast
t-SNEPublication-quality 2D plotsLocal neighborhoodsSlow (< 10k samples ideal)
UMAP2D visualization at scaleLocal + some global structureMedium (handles millions)
PCAFeature reduction for modelsVariance-ranked featuresFast
t-SNE / UMAPUnderstanding cluster structureCluster separationMedium to slow

Rule of thumb: reach for PCA when you are preprocessing or compressing data, and reach for t-SNE or UMAP when you need to actually see the structure in 2D.

Kernel PCA

Kernel PCA runs PCA inside a high-dimensional feature space induced by a kernel function, without ever explicitly computing coordinates in that space. This is the kernel trick, the same idea behind SVMs.

It exists because standard PCA only finds linear subspaces: it rotates your coordinate system and drops axes, full stop. That falls apart the moment your data sits on a nonlinear manifold. A circle in 2D cannot be separated by any line, and standard PCA has no way around that.

The algorithm:

  1. Compute the kernel matrix K where K_ij = k(x_i, x_j)
  2. Center the kernel matrix in feature space
  3. Eigendecompose the centered kernel matrix
  4. The top eigenvectors (scaled by 1/sqrt(eigenvalue)) are the projections

Common kernel functions:

KernelFormulaGood for
RBF (Gaussian)exp(-gamma * ||x - y||^2)Most nonlinear data, smooth manifolds
Polynomial(x . y + c)^dPolynomial relationships
Sigmoidtanh(alpha * x . y + c)Neural network-like mappings

When to use kernel PCA vs standard PCA:

CriterionStandard PCAKernel PCA
Data structureLinear subspaceNonlinear manifold
SpeedO(min(n^2 d, d^2 n))O(n^2 d + n^3)
InterpretabilityComponents are linear combinations of featuresComponents lack direct feature interpretation
ScalabilityWorks on millions of samplesKernel matrix is n x n, memory-limited
ReconstructionDirect inverse transformRequires pre-image approximation

Take the classic example: two concentric rings of points in 2D, one inside the other. Standard PCA projects both onto the same line, which is useless for classification. Kernel PCA with an RBF kernel sends the inner and outer rings to different regions instead, which makes them linearly separable.

Reconstruction Error

Reconstruction error tells you what you lost when you compressed, say, 784 dimensions down to 50. You measure it in three steps:

  1. Project data to k dimensions: X_reduced = X @ W_k
  2. Reconstruct: X_hat = X_reduced @ W_k^T
  3. Compute MSE: mean((X - X_hat)^2)

For PCA, reconstruction error has a clean relationship to explained variance:

Reconstruction error = sum of eigenvalues NOT included
Total variance = sum of ALL eigenvalues
Fraction lost = (sum of dropped eigenvalues) / (sum of all eigenvalues)

The explained variance ratio for each component is:

explained_ratio_k = eigenvalue_k / sum(all eigenvalues)

Plotting cumulative explained variance against number of components gives you the "elbow" curve. The right number of components is where:

  • The curve flattens out (diminishing returns)
  • Cumulative variance crosses your threshold (usually 0.90 or 0.95)
  • Downstream task performance plateaus

Reconstruction error is not just for choosing k. It doubles as an anomaly detector: samples with high reconstruction error do not fit the subspace the model learned, which marks them as outliers. That is the basis of PCA-based anomaly detection in a lot of production systems.

Check: The Concept0/34
1. What is the curse of dimensionality?Define
Four squares of growing size labeled 2D, 10D, 100D and 1000D side by side with a question mark above them, with a note that distances, volume and data needed all change as dimensions climb, with no specific effect drawn.
2. What does PCA do to a dataset?Define
A diagonally leaning cloud of points plotted on its original x and y axes only, with no rotated axes drawn, and a question mark asking what PCA does to a dataset shaped like this.
Illustrative data cloud.
3. What is a principal component?Define
A cloud of points with three candidate direction arrows labeled A, B and C drawn from the origin, none of them marked as correct, asking which one is a principal component.
Illustrative data cloud and candidate directions.
4. What is the explained variance ratio of a principal component?Define
Four bars labeled lambda 1 through lambda 4 at different heights, with a note that their total is the sum of all four, and a question mark asking what one component's eigenvalue is divided by to get its ratio.
5. What does a covariance matrix hold?Define
A 2 by 2 bracketed grid holding cov of x1 x1, cov of x1 x2, cov of x2 x1 and cov of x2 x2, for two generic features x1 and x2, asking what the matrix holds and what shape it has.
6. What is t-SNE?Define
Three labeled points, A, B and C, clustered together in one panel, with an arrow marked t-SNE to a second panel where the same three points are still clustered together but at different coordinates.
7. What is UMAP?Define
Five points, A through E, connected by lines into a neighbor graph, with an arrow labeled UMAP into a dashed placeholder box marked 2D layout, asking what kind of method starts from a graph like this.
8. What does the perplexity parameter control in t-SNE?Define
A horizontal slider labeled fewer neighbors on the left and more neighbors on the right, with a marker partway along it labeled current setting and no range of typical values written anywhere.
9. What is a manifold in the context of dimensionality reduction?Define
A single curved, looping line drawn inside a flat rectangular plane, with no other structure, asking what this kind of lower-dimensional surface sitting inside a higher-dimensional space is called.
10. What is kernel PCA?Define
Two concentric rings of points in an original space, with an arrow labeled kernel into a dashed box marked implicit feature space where coordinates are never computed, and a question mark inside it, asking what this kind of PCA is called.
11. What is reconstruction error in PCA?Define
A flow of four boxes, X original, project to k dimensions, reconstruct, and compare to X, the last one subtitled with a question mark, asking what single number the comparison step produces.
12. Which formula is the RBF (Gaussian) kernel used in kernel PCA?Define
Two points labeled x and y with a dashed line between them, next to K of x, y equals question mark, asking which formula is the RBF kernel.
13. Why does PCA use eigendecomposition of the covariance matrix to find its principal directions?Explain
A symmetric 2 by 2 matrix with entries a, c, c and b, the two c entries highlighted as equal to each other, with a question asking why PCA eigendecomposes a matrix shaped like this.
14. In the PCA algorithm, why are the eigenvectors sorted by eigenvalue before keeping the top k?Explain
Four bars labeled lambda b, lambda a, lambda d and lambda c at mismatched heights in that scrambled order, with an arrow down to a note that reads sort by eigenvalue descending then keep top k, and a question mark.
15. How does the elbow method choose the number of PCA components?Explain
A bar chart of explained variance for five components, PC1 through PC5, dropping in height from left to right with no cutoff line marked, asking how a chart like this is used to pick the number of components.
Illustrative shape, not tied to a specific dataset.
16. PCA on 784-dimensional MNIST data with k=50 components captures 95% of the variance. What does that tell you?Explain
A box labeled 784 dimensions, original MNIST pixels, with an arrow to a box labeled k equals 50 components, 95% of variance kept, and an arrow to a question mark, asking what this tells you.
17. Keeping the same sample density while going from 2D to 20D would take about 10^18 times more data. What does that imply for high-dimensional datasets?Explain
A box labeled 2D, normal sample density, with an arrow to a box labeled 20D, about 10 to the 18th more data needed, and a question mark below, asking what this implies for a real high-dimensional dataset.
18. Why can standard PCA not separate two concentric rings of points?Explain
Two concentric rings of points, a smaller blue ring inside a larger green ring, with an arrow labeled standard PCA leading to a question mark, asking why standard PCA cannot separate the two rings.
19. Why should you not use t-SNE as preprocessing before training a classifier?Explain
A flow of four boxes, high-dimensional data, t-SNE, 2D coordinates, and train classifier, with a question mark beneath, asking why this pipeline is a bad idea.
20. What two advantages does UMAP offer over t-SNE?Explain
A table with columns method, distance computation and global structure; the t-SNE row reads every pairwise distance and not meaningful, while both UMAP cells are left as question marks, asking what goes in them.
21. When would you choose kernel PCA over standard PCA?Explain
Two concentric rings of points above two unmarked candidate boxes, standard PCA and kernel PCA, each with a question mark, asking which one fits a dataset shaped like this.
22. Why does kernel PCA struggle on millions of samples when standard PCA does not?Explain
A box labeled n samples, millions of rows, with an arrow to a box labeled kernel matrix, n by n entries, and a question mark, asking how the cost grows as n grows.
23. How is the reconstruction error of a PCA model related to its eigenvalues?Explain
Six eigenvalue bars, l1 through l6, decreasing in height, with the first two underlined kept and the rest underlined dropped, and a question mark asking which combination of them equals the reconstruction error.
24. The eigenvalues are 4.73, 2.51, 1.12, 0.89 (cumulative ratios 0.473, 0.724, 0.836, 0.925). What is the smallest number of components that reaches a 90% variance threshold?Apply
A table of four components, PC1 through PC4, with eigenvalues 4.73, 2.51, 1.12 and 0.89 and cumulative ratios 0.473, 0.724, 0.836 and 0.925, with a question mark asking for the smallest number of components reaching 90%.
25. Using the same table, where the total variance is 10, what fraction of the variance is lost if you keep only PC1 and PC2?Apply
The same eigenvalue table with a status column marking PC1 and PC2 kept and PC3 and PC4 dropped, and a question mark asking what fraction of the total variance is lost.
26. Nearest-neighbor search works well with 10 engineered features, but with 500 features it returns results that look almost random. What is the most likely explanation?Analyze
Two boxes, 10 engineered features where nearest-neighbor search works well, and 500 features where the results look almost random, with a question mark between them asking for the most likely explanation.
27. You run t-SNE twice with different seeds. In one layout clusters A and B touch, and in the other they are far apart. What is the right reading?Analyze
Two panels of the same two clusters from the same data, run with different random seeds: in one panel the clusters nearly touch, and in the other they sit far apart.
28. A linear classifier trained on a single PCA component of two concentric rings performs near chance. What is the right diagnosis?Analyze
Two concentric rings of points, with a note that a classifier trained on a single PCA component reaches about 50% accuracy, near chance, and a question mark asking for the right diagnosis.
29. A teammate wants to say which original pixels drive kernel PCA component 1 and to rebuild images with an inverse transform. Which statement is right?Analyze
Two boxes side by side: standard PCA, whose components are direct linear combinations of features with an exact inverse transform, and kernel PCA, with both its component interpretation and its reconstruction left as question marks.
30. Two customer segments overlap in a t-SNE plot, and a colleague concludes they are basically the same. What is the best check?Analyze
A t-SNE plot of two heavily overlapping point clusters, a colleague's quoted conclusion that the two segments are basically the same, and a question mark asking for the best way to check that conclusion.
31. You must shrink 784-feature data for 3 million samples before training a classifier, and you want to justify the number of components. Which design fits?Design
A box labeled 3,000,000 samples, 784 features, above a table of three candidates, PCA with a swept k, t-SNE to 2D, and kernel PCA, with a question mark in the fits column for each.
32. You need a 2D plot of 2 million samples where the relative positions of clusters should carry meaning. Which method fits best?Design
A box labeled 2,000,000 samples, need a 2D plot, above a table of three candidates, t-SNE, UMAP and standard PCA with 2 components, with a question mark in the fits column for each, and a note that cluster positions need to carry real meaning.
33. A production system must flag unusual sensor readings, and you have plenty of normal readings. How can PCA help?Design
A cloud of normal sensor readings lying along a dashed learned subspace line, with one new reading marked far from the line, and a question mark asking whether it should be flagged based on its reconstruction error.
34. You have 3,000 samples on a ring-shaped manifold and need compact features for a linear model. Which design fits, and why?Design
Two concentric rings labeled 3,000 samples, ring-shaped manifold, above a table of three candidates, standard PCA with 1 component, kernel PCA with an RBF kernel, and t-SNE to 2D, each with a question mark in the fits column, and a note that the features feed a linear model.

Build It

Step 1: PCA from scratch

python
import numpy as np
 
class PCA:
    def __init__(self, n_components):
        self.n_components = n_components
        self.components = None
        self.mean = None
        self.eigenvalues = None
        self.explained_variance_ratio_ = None
 
    def fit(self, X):
        self.mean = np.mean(X, axis=0)
        X_centered = X - self.mean
 
        cov_matrix = np.cov(X_centered, rowvar=False)
 
        eigenvalues, eigenvectors = np.linalg.eigh(cov_matrix)
 
        sorted_idx = np.argsort(eigenvalues)[::-1]
        eigenvalues = eigenvalues[sorted_idx]
        eigenvectors = eigenvectors[:, sorted_idx]
 
        self.components = eigenvectors[:, :self.n_components].T
        self.eigenvalues = eigenvalues[:self.n_components]
        total_var = np.sum(eigenvalues)
        self.explained_variance_ratio_ = self.eigenvalues / total_var
 
        return self
 
    def transform(self, X):
        X_centered = X - self.mean
        return X_centered @ self.components.T
 
    def fit_transform(self, X):
        self.fit(X)
        return self.transform(X)

Step 2: Test on synthetic data

python
np.random.seed(42)
n_samples = 500
 
t = np.random.uniform(0, 2 * np.pi, n_samples)
x1 = 3 * np.cos(t) + np.random.normal(0, 0.2, n_samples)
x2 = 3 * np.sin(t) + np.random.normal(0, 0.2, n_samples)
x3 = 0.5 * x1 + 0.3 * x2 + np.random.normal(0, 0.1, n_samples)
 
X_synthetic = np.column_stack([x1, x2, x3])
 
pca = PCA(n_components=2)
X_reduced = pca.fit_transform(X_synthetic)
 
print(f"Original shape: {X_synthetic.shape}")
print(f"Reduced shape:  {X_reduced.shape}")
print(f"Explained variance ratios: {pca.explained_variance_ratio_}")
print(f"Total variance captured: {sum(pca.explained_variance_ratio_):.4f}")

Step 3: MNIST digits in 2D

python
from sklearn.datasets import fetch_openml
 
mnist = fetch_openml("mnist_784", version=1, as_frame=False, parser="auto")
X_mnist = mnist.data[:5000].astype(float)
y_mnist = mnist.target[:5000].astype(int)
 
pca_mnist = PCA(n_components=50)
X_pca50 = pca_mnist.fit_transform(X_mnist)
print(f"50 components capture {sum(pca_mnist.explained_variance_ratio_):.2%} of variance")
 
pca_2d = PCA(n_components=2)
X_pca2d = pca_2d.fit_transform(X_mnist)
print(f"2 components capture {sum(pca_2d.explained_variance_ratio_):.2%} of variance")

Step 4: Compare with sklearn

python
from sklearn.decomposition import PCA as SklearnPCA
from sklearn.manifold import TSNE
 
sklearn_pca = SklearnPCA(n_components=2)
X_sklearn_pca = sklearn_pca.fit_transform(X_mnist)
 
print(f"\nOur PCA explained variance:     {pca_2d.explained_variance_ratio_}")
print(f"Sklearn PCA explained variance: {sklearn_pca.explained_variance_ratio_}")
 
diff = np.abs(np.abs(X_pca2d) - np.abs(X_sklearn_pca))
print(f"Max absolute difference: {diff.max():.10f}")
 
tsne = TSNE(n_components=2, perplexity=30, random_state=42)
X_tsne = tsne.fit_transform(X_mnist)
print(f"\nt-SNE output shape: {X_tsne.shape}")

Step 5: UMAP comparison

python
try:
    from umap import UMAP
 
    reducer = UMAP(n_components=2, n_neighbors=15, min_dist=0.1, random_state=42)
    X_umap = reducer.fit_transform(X_mnist)
    print(f"UMAP output shape: {X_umap.shape}")
except ImportError:
    print("Install umap-learn: pip install umap-learn")

Step 6: Kernel PCA on nonlinear data

Two concentric rings can't be separated by any straight line, so standard PCA is stuck: it can only rotate and project, never bend space. Kernel PCA with an RBF kernel can, because the kernel implicitly lifts the data into a space where the rings pull apart.

python
def kernel_pca(X, n_components, kernel="rbf", gamma=1.0):
    n = X.shape[0]
    if kernel == "rbf":
        sq_dists = np.sum(X ** 2, axis=1).reshape(-1, 1) + np.sum(X ** 2, axis=1).reshape(1, -1) - 2 * X @ X.T
        K = np.exp(-gamma * sq_dists)
    else:
        K = X @ X.T
 
    one_n = np.ones((n, n)) / n
    K_centered = K - one_n @ K - K @ one_n + one_n @ K @ one_n
 
    eigenvalues, eigenvectors = np.linalg.eigh(K_centered)
    sorted_idx = np.argsort(eigenvalues)[::-1]
    eigenvalues, eigenvectors = eigenvalues[sorted_idx], eigenvectors[:, sorted_idx]
 
    top_vals = eigenvalues[:n_components]
    top_vecs = eigenvectors[:, :n_components]
    for i in range(n_components):
        if top_vals[i] > 1e-10:
            top_vecs[:, i] = top_vecs[:, i] / np.sqrt(top_vals[i])
    return top_vecs * top_vals[:n_components]
 
 
# Two concentric rings -- no straight line separates them
np.random.seed(42)
n_per_ring = 200
theta_inner = np.random.uniform(0, 2 * np.pi, n_per_ring)
r_inner = 1.0 + np.random.normal(0, 0.1, n_per_ring)
inner = np.column_stack([r_inner * np.cos(theta_inner), r_inner * np.sin(theta_inner)])
 
theta_outer = np.random.uniform(0, 2 * np.pi, n_per_ring)
r_outer = 3.0 + np.random.normal(0, 0.1, n_per_ring)
outer = np.column_stack([r_outer * np.cos(theta_outer), r_outer * np.sin(theta_outer)])
 
X_circles = np.vstack([inner, outer])
labels = np.array([0] * n_per_ring + [1] * n_per_ring)
 
# Standard PCA: both rings land in the same range, no separation
pca_linear = PCA(n_components=1)
X_linear = pca_linear.fit_transform(X_circles)
print(f"Linear PCA -- inner ring range: [{X_linear[labels==0].min():.2f}, {X_linear[labels==0].max():.2f}]")
print(f"Linear PCA -- outer ring range: [{X_linear[labels==1].min():.2f}, {X_linear[labels==1].max():.2f}]")
 
# Kernel PCA with an RBF kernel: the rings pull apart
X_kpca = kernel_pca(X_circles, n_components=2, kernel="rbf", gamma=0.5)
inner_mean = X_kpca[labels == 0, 0].mean()
outer_mean = X_kpca[labels == 1, 0].mean()
print(f"Kernel PCA -- inner ring PC1 mean: {inner_mean:.4f}")
print(f"Kernel PCA -- outer ring PC1 mean: {outer_mean:.4f}")
print(f"Separation on PC1: {abs(outer_mean - inner_mean):.4f}")

Run both and compare: the linear PCA ranges for the two rings overlap almost completely, so a classifier trained on that single component can't tell them apart. The kernel PCA means land far apart on PC1 instead. Same data, same goal, but only one of the two projections actually separates the classes.

Check: Build It0/5
1. In Step 2 the PCA class is fit on X_synthetic with 500 samples and 3 features, using n_components=2. What do the two shape lines print?Apply
A box labeled X_synthetic, shape 500 by 3, with an arrow marked PCA with n_components equals 2, into a box labeled X_reduced, shape open parenthesis question mark comma question mark.
2. Inside fit(), the eigenvalues are [1.0, 5.0, 3.0]. What does sorted_idx = np.argsort(eigenvalues)[::-1] contain?Apply
The eigenvalues list, 1.0, 5.0, 3.0, with the line sorted_idx equals np.argsort of eigenvalues reversed, and the result left as a question mark.
3. In the Build It kernel PCA step, standard PCA with 1 component is run on two concentric rings before trying the kernel version. What do the printed ranges show?Apply
Two concentric rings of points with an arrow labeled PCA 1 component leading to a question mark, asking whether the inner and outer ring ranges on the single component overlap.
4. In Step 6, each of the two rings has 200 points and kernel_pca is called with n_components=2. What is the shape of the returned array?Apply
Two concentric rings of 200 points each, with a note that kernel_pca is called on X_circles with n_components equals 2, and the returned array's shape left as a question mark.
5. Step 5 runs UMAP with n_neighbors=15 and min_dist=0.1. Which change would give denser, tighter clusters in the output?Apply
A horizontal line labeled min_dist with a marker at the current setting of 0.1, and a question mark asking which direction along the line gives denser clusters, with neither end labeled.

Use It

Here is PCA as a preprocessing step before a classifier:

python
from sklearn.decomposition import PCA as SklearnPCA
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
 
X_train, X_test, y_train, y_test = train_test_split(
    X_mnist, y_mnist, test_size=0.2, random_state=42
)
 
results = {}
for k in [10, 30, 50, 100, 200]:
    pca_k = SklearnPCA(n_components=k)
    X_tr = pca_k.fit_transform(X_train)
    X_te = pca_k.transform(X_test)
 
    clf = LogisticRegression(max_iter=1000, random_state=42)
    clf.fit(X_tr, y_train)
    acc = accuracy_score(y_test, clf.predict(X_te))
    var_captured = sum(pca_k.explained_variance_ratio_)
    results[k] = (acc, var_captured)
    print(f"k={k:>3d}  accuracy={acc:.4f}  variance={var_captured:.4f}")

Performance plateaus well before you reach 784 dimensions, and that plateau is your operating point: the k where more components stop buying you anything.

Check: Use It0/1
1. X_mnist holds 5000 rows and train_test_split uses test_size=0.2. For k=50 in the Use It loop, what is the shape of X_tr?Apply
A box X_mnist with 5000 rows, an arrow marked 80 20 split into a box X_train with the row count left as a question mark, then an arrow marked PCA k equals 50 into a box X_tr with its shape left as two question marks.

Ship It

This lesson produces:

  • outputs/skill-dimensionality-reduction.md, a skill for choosing the right dimensionality reduction technique for a given task
Author's Note

The mistake I see most often with these tools is treating a t-SNE or UMAP plot as ground truth. It is a compressed cartoon, and a good one can still lie to you about how far apart two clusters really are. I once watched a teammate conclude two customer segments were basically the same because their t-SNE clusters overlapped. They were not: a plain PCA scatter on the same data showed a wide gap along PC1 alone. If a plot like this is heading into a slide deck, check it against the explained variance ratio or a linear PCA projection first. The visualization that impresses people most in the room is often the one you should trust least for an actual decision.

Exercises

  1. Add inverse_transform to the PCA class, then reconstruct MNIST digits from 10, 50, and 200 components. Print the reconstruction error (mean squared difference from the original) for each.

  2. Run t-SNE on the same MNIST subset with perplexity values of 5, 30, and 100. Describe how the output changes, and explain why perplexity affects cluster tightness.

  3. Take a dataset with 50 features where only 5 are informative (generate one with sklearn.datasets.make_classification), apply PCA, and check whether the explained variance curve correctly identifies the data as effectively 5-dimensional.

Key Terms

TermWhat people sayWhat it actually means
Curse of dimensionality"Too many features"Distances, volumes, and data density all behave counterintuitively as dimensions grow. Models need exponentially more data to compensate.
PCA"Reduce dimensions"Rotate your coordinate system so the axes align with the directions of maximum variance, then drop the low-variance axes.
Principal component"An important direction"An eigenvector of the covariance matrix. The direction in feature space along which the data varies most.
Explained variance ratio"How much info this component has"The fraction of total variance captured by one principal component. Sum the top k ratios to see how much k components preserve.
Covariance matrix"How features correlate"A symmetric matrix where entry (i,j) measures how feature i and feature j move together. Diagonal entries are individual variances.
t-SNE"That cluster plot"A nonlinear method that maps high-dimensional data to 2D by preserving pairwise neighborhood probabilities. Good for visualization, not for preprocessing.
UMAP"Faster t-SNE"A nonlinear method based on topological data analysis. Preserves both local and some global structure. Scales better than t-SNE.
Perplexity"A t-SNE knob"Controls the effective number of neighbors each point considers. Low perplexity focuses on very local structure. High perplexity captures broader patterns.
Manifold"The surface the data lives on"A lower-dimensional surface embedded in a higher-dimensional space. A sheet of paper crumpled in 3D is a 2D manifold.

Further Reading