Dimensionality Reduction

UMAP

UMAP draws the same kind of neighbour-preserving 2-D maps as t-SNE, but runs faster, keeps a little more of the big picture, and can place new points onto an existing map.

Read these first

On this page 5
  1. Why it exists
  2. How it works
  3. A real example you have seen
  4. Remember this
  5. What to learn next

One lesson, three depths. Pick the one that fits you today — you can switch any time.

Beginner — No maths. Plain English.

UMAP makes neighbour-preserving 2-D maps like t-SNE, but faster — and it can seat latecomers.

Recall the wedding-seating picture from t-SNE: put every guest with their close friends, accept that the hall's overall layout is a compromise. UMAP is a second planner doing the same job with a better method. It first sketches the whole friendship network — who connects to whom, and how strongly — and then finds a hall layout respecting that network.

The network-first approach brings two practical gifts. The planner works much faster on big guest lists. And when a latecomer arrives, they can be seated at the right table without rearranging the hall — something t-SNE cannot do at all.

Why it exists

t-SNE conquered data visualisation but left three complaints. It gets slow on large datasets. It has no way to place new points onto a finished map — a deal-breaker for production systems that keep receiving data. And it scrambles the big picture badly: the arrangement of islands relative to each other is nearly meaningless.

UMAP (Uniform Manifold Approximation and Projection) was built on different mathematics. It uses networks and graph layouts rather than probability matching. It improves all three complaints: markedly faster, a transform for new points, and an island-to-island arrangement that preserves a little more truth. The pictures look similar; the workflow around them changes.

How it works

step 1: build the friendship network
        each point connects to its ~15 nearest neighbours,
        with connection strengths

step 2: lay the network out on a page
        connected points pull together,
        unconnected points push apart,
        until the layout settles

Two knobs matter. n_neighbors is how many friends count — small values favour fine local detail, large values favour the big picture. min_dist is how tightly settled points may pack — small values give dense tight islands, larger values spread them for readability.

A real example you have seen

Single-cell biology has its cell atlases: posters where each dot is one cell and colours mark cell types. Those moved almost wholesale from t-SNE to UMAP. Product teams use the same maps for customers, songs and support tickets, precisely because tomorrow's new customer can be projected onto today's map.

Remember this

  • Same neighbour-first philosophy as t-SNE; different machinery underneath.
  • Faster, and new points can be projected onto an existing map.
  • The same reading rules apply: trust islands, distrust distances and sizes.

What to learn next

Developer — Code and libraries.

Setup

bash
pip install umap-learn

Honest download note: umap-learn itself is under 1 MB, but it pulls in numba, pynndescent and llvmlite. That stack measured about 130 MB installed here (Windows, Python 3.10), most of it llvmlite; wheel downloads are smaller and vary by platform. First import compiles code and takes extra seconds; later runs are fast. Verified with umap-learn 0.5.12 and scikit-learn 1.7.2. Like t-SNE, results vary slightly across versions and platforms.

Map the digits, then seat a latecomer

umap_demo.py
from sklearn.datasets import load_digits
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import cross_val_score
import umap

digits = load_digits()
X, y = digits.data, digits.target

reducer = umap.UMAP(n_neighbors=15, min_dist=0.1, random_state=42)
emb = reducer.fit_transform(X)
print("shape:", X.shape, "->", emb.shape)

new_points = reducer.transform(X[:5])      # UMAP can place NEW points
print("first digit, embedded twice:", emb[0].round(2), new_points[0].round(2))

score = cross_val_score(KNeighborsClassifier(10), emb, y, cv=3).mean()
print(f"neighbour agreement in 2-D: {score:.3f}")
Output
shape: (1797, 64) -> (1797, 2)
first digit, embedded twice: [15.12 10.65] [15.06 10.53]
neighbour agreement in 2-D: 0.983

Runs in well under a minute on CPU, after the first-import compile.

The walkthrough

transform is the headline. The same image embedded during fit and again through transform lands at nearly the same spot (15.12, 10.65 versus 15.06, 10.53 — the projection is approximate, not exact). This is the capability t-SNE lacks: a fitted UMAP object is a reusable map, so you can embed training data once and stream new points onto it.

The agreement score edges out t-SNE's. 0.983 versus 0.977 on the same data and metric from the t-SNE lesson — both excellent, UMAP's neighbourhoods a touch purer here. Treat the difference as typical, not guaranteed.

random_state=42 costs speed. UMAP parallelises across cores, but a fixed seed forces single-threaded runs (the library warns about exactly this). Seed while developing; drop the seed for big production fits and accept run-to-run wiggle.

Knob effects, briefly. Raising n_neighbors (say to 50) smooths the map toward big-picture structure; lowering it (to 5) fragments into fine detail. min_dist is cosmetic spacing: 0.0 packs islands into dense cores, 0.5 fluffs them out. Neither has a correct value — explore.

Common mistakes

Reading the map like geography. Every t-SNE caveat survives: island sizes, island gaps and axis directions remain unmeasurable. UMAP preserves somewhat more global arrangement, which tempts more over-reading — resist it. The honest-reading lesson applies in full.

Using 2-D UMAP output as model features. For visualisation, 2 components; for feeding a downstream clustering or classifier, if you must use UMAP at all, use more components (10 to 50) and validate that results beat PCA at the same size. Often it will not.

Assuming determinism. Even with a seed, different library versions, thread counts or hardware can shift layouts. Never diff two maps pixel-by-pixel across environments; compare the conclusions (which points cluster together).

Forgetting that transform drifts. The projection of genuinely novel data (unlike training data, as above) is a best-effort placement. If the world changes — new classes appear — refit the map rather than trusting old coordinates forever.

Try it yourself

Fit UMAP on only digits 0 to 8, then transform the held-out 9s. Plot where the 9s land and check whether they pile onto an existing island (which one?) or float between islands — a small preview of how embeddings behave under distribution shift.

What to learn next

Researcher — Mathematics and papers.

Construction

McInnes, Healy and Melville (2018), UMAP: Uniform Manifold Approximation and Projection for dimension reduction, arXiv:1802.03426. The exposition is category-theoretic (fuzzy simplicial sets glued from local metric spaces), but the computation reduces to three concrete steps:

  1. k-NN graph via NN-descent (approximate, O(n^1.14) empirically), k = n_neighbors.
  2. Fuzzy weights: edge weight w(i, j) = exp(-(d(i, j) - rho_i) / sigma_i), with rho_i the distance to i's nearest neighbour (ensuring local connectivity) and sigma_i calibrated so weights sum to log2(k) — the analogue of t-SNE's per-point bandwidth. Symmetrise by probabilistic union: w = w1 + w2 - w1 w2.
  3. Layout: minimise the fuzzy cross-entropy sum over pairs of [ w log(w/v) + (1 - w) log((1 - w)/(1 - v)) ], where v(i, j) = (1 + a ||z_i - z_j||^{2b})^{-1}, optimised by SGD with negative sampling of the repulsive term (a, b are fitted from min_dist).

Against t-SNE: the attractive term is similar in spirit; the repulsive term comes from the (1 - w) cross-entropy rather than the normalisation of Q, which removes the global normalisation, enables per-edge sampling (hence speed and scalability), and yields somewhat more stable inter-cluster arrangement. transform works because the learned layout defines an induced map: new points are optimised against the fixed embedding of their approximate neighbours.

The comparisons literature

Claims of UMAP's superior global structure deserve caution. Kobak and Linderman (2021, Nature Biotechnology, Initialization is critical...) show much of the observed difference between t-SNE and UMAP on benchmark datasets traces to initialisation: t-SNE initialised with PCA (rather than the old random default) closes most of the gap. Becht et al. (2019, Nature Biotechnology) reported UMAP's advantages for single-cell data (speed, reproducibility, global structure); the follow-up literature refined this to "comparable pictures, different defaults, UMAP faster at scale". Independent benchmarks consistently confirm the speed and the transform capability as the durable advantages.

Descendants and variants

Parametric UMAP (Sainburg et al., 2021) replaces the direct layout with a neural network mapping inputs to embeddings — differentiable, minibatch-trainable, composable with autoencoders. densMAP (Narayan et al., 2021) adds a local-density-preservation term, addressing the size-of-islands lie directly. HDBSCAN-on-UMAP is a popular clustering pipeline, with the standing caveat that UMAP manufactures density contrasts, so cluster boundaries inherit its distortions (see the honest-reading lesson). For metrics beyond Euclidean, UMAP accepts arbitrary distance functions, including precomputed sparse graphs — one reason it colonised domains from genomics to text embeddings.

What to learn next