📈 Machine Learning · Lecture 30 of 47

t-SNE and UMAP: Visualising High-Dimensional Data

Non-linear embeddings reveal cluster structure that PCA hides. We explain how t-SNE and UMAP work, what their hyperparameters do, and — critically — how not to misread their plots.

You have trained a model that embeds 50,000 documents into 768-dimensional vectors. Are there natural groups? Are two classes confused? PCA to two dimensions often shows a shapeless cloud, because the structure lies on a curved, non-linear manifold. t-SNE and UMAP are non-linear methods designed to reveal such structure in 2-D plots. They are indispensable tools — and among the most frequently misinterpreted.

t-SNE: matching neighbour probabilities#

t-distributed Stochastic Neighbour Embedding (van der Maaten & Hinton, 2008) works in three steps.

1. High-dimensional similarities. For each point $i$, define a Gaussian-based probability that $i$ would pick $j$ as its neighbour:

$$ p_{j \mid i} = \frac{\exp(-\|\mathbf{x}_i - \mathbf{x}_j\|^2/2\sigma_i^2)}{\sum_{k \ne i}\exp(-\|\mathbf{x}_i - \mathbf{x}_k\|^2/2\sigma_i^2)} $$

The bandwidth $\sigma_i$ is chosen per point so that the distribution's perplexity matches a user-set value — roughly, the effective number of neighbours. Symmetrise: $p_{ij} = (p_{j \mid i} + p_{i \mid j})/2n$.

2. Low-dimensional similarities use a heavy-tailed Student-t distribution with one degree of freedom:

$$ q_{ij} = \frac{(1 + \|\mathbf{y}_i - \mathbf{y}_j\|^2)^{-1}}{\sum_{k \ne l}(1 + \|\mathbf{y}_k - \mathbf{y}_l\|^2)^{-1}} $$

3. Optimise the 2-D positions $\mathbf{y}_i$ by gradient descent to minimise

$$ D_{\text{KL}}(P\,\|\,Q) = \sum_{i \ne j}p_{ij}\ln\frac{p_{ij}}{q_{ij}} $$

Why the heavy tail? In high dimensions, many points can be moderately far from a given point, but in 2-D there is not enough room — the crowding problem. The Student-t lets moderately distant points be placed much farther apart in 2-D, producing well-separated clusters.

UMAP: fuzzy topology#

Uniform Manifold Approximation and Projection (McInnes, Healy & Melville, 2018) builds a weighted k-nearest-neighbour graph in high dimensions (grounded in fuzzy simplicial sets from topology), then optimises a low-dimensional layout whose graph matches it using a cross-entropy objective with attractive forces along edges and repulsive forces via negative sampling.

Compared with t-SNE, UMAP typically:

  • runs much faster and scales to millions of points;
  • preserves more global structure (relative positions of clusters are somewhat more meaningful, though still not reliable);
  • can transform new points into an existing embedding;
  • works as a general-purpose reduction for clustering (e.g. UMAP → HDBSCAN on text embeddings).

Hyperparameters#

MethodParameterEffect
t-SNEperplexity (5–50)Neighbourhood size; low → many tiny clusters, high → broader structure
t-SNElearning rate, iterationsToo few iterations → unconverged "ball"
UMAPn_neighbors (5–200)Local vs global balance
UMAPmin_dist (0–0.99)How tightly points pack within clusters
python
import numpy as np
from sklearn.datasets import load_digits
from sklearn.manifold import TSNE
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
# pip install umap-learn
import umap

X, y = load_digits(return_X_y=True)
X50 = PCA(n_components=30, random_state=0).fit_transform(X)   # common pre-step for speed/denoising

emb = {
    "PCA": PCA(n_components=2).fit_transform(X),
    "t-SNE (perplexity 30)": TSNE(perplexity=30, init="pca", random_state=0).fit_transform(X50),
    "UMAP (n_neighbors 15)": umap.UMAP(n_neighbors=15, min_dist=0.1, random_state=0).fit_transform(X50),
}
fig, axes = plt.subplots(1, 3, figsize=(16, 5))
for ax, (name, Z) in zip(axes, emb.items()):
    ax.scatter(Z[:, 0], Z[:, 1], c=y, cmap="tab10", s=5); ax.set_title(name)
plt.tight_layout(); plt.show()

PCA shows overlapping digit groups; t-SNE and UMAP show ten crisp clusters.

How NOT to read these plots#

Wattenberg, Viégas and Johnson's interactive article "How to Use t-SNE Effectively" demonstrates these pitfalls vividly; every student should explore it.

Good practice#

  • Standardise features; for very high-dimensional data, reduce to 30–50 dimensions with PCA first.
  • Try multiple perplexities / neighbour counts and seeds; trust only structure that persists.
  • Colour points by known labels, metadata and model predictions to generate hypotheses — then test those hypotheses with proper methods.
  • Report hyperparameters with every plot.

Uses in ML practice#

  • Inspecting learned embeddings (words, sentences, images).
  • Diagnosing classifier confusion — misclassified points often lie between clusters.
  • Detecting label noise and data-quality problems (points of one class inside another's cluster).
  • Exploring single-cell biology data, where UMAP plots are standard.
JA
Written by

Janin A Apurba

B.Sc. in CSE, AUST · Advanced ICT Officer, CNRS-UNHCR. Teaching AI, ML and Deep Learning to the next generation of engineers and researchers.

Keep learning

Related lectures

📈 Machine Learning

Encoding Categorical Variables: One-Hot, Ordinal, Target and Beyond

Models need numbers, but many features are categories. We compare one-hot, ordinal, frequency, target and hashing encoders, handle high cardinality and unseen categories, and avoid target-encoding leakage.

Beginner⏱ 5 min#084
📈 Machine Learning

Recommender Systems II: Matrix Factorisation and Latent Factors

Matrix factorisation represents users and items as vectors in a shared latent space. We derive the regularised objective, train it with SGD and ALS, add biases and implicit feedback, and connect it to modern embedding models.

Advanced⏱ 5 min#091
📈 Machine Learning

Principal Component Analysis (PCA): Theory and Practice

PCA finds the orthogonal directions of maximum variance. We derive it two ways — maximum variance and minimum reconstruction error — compute it via SVD, choose the number of components, and discuss its limits.

Intermediate⏱ 5 min#078