t-SNE
t-SNE maps high-dimensional data to two or three dimensions while keeping similar points close, revealing clusters. Learn how it works and how to read its plots.
Overview
t-SNE, short for t-distributed stochastic neighbor embedding, is a method for drawing high-dimensional data on a two- or three-dimensional map. It places each point so that items that are close neighbours in the original space also end up close on the map. When the data contain groups, such as different handwritten digits, cell types or document topics, those groups usually appear as visible clusters.
t-SNE is a tool for looking, not for modelling. It is excellent at showing local neighbourhoods, but the map distorts other things on purpose. The size of a cluster, the distance between two clusters and the empty space around them generally do not carry reliable meaning. Reading a t-SNE plot well means knowing what it preserves and what it does not.
An everyday picture is seating guests at a large party. You make sure close friends sit at the same table, and acquaintances sit near each other. But which table is next to which, and how far apart the tables are, says little about how the groups relate. t-SNE arranges data points the same way.
What it is
| Part | What it means |
|---|---|
| High-dimensional similarities | For each point, a probability that each other point is its neighbour, using a Gaussian |
| Perplexity | Roughly the effective number of neighbours each point considers |
| Low-dimensional similarities | The same idea on the map, using a heavy-tailed Student-t distribution |
| KL divergence | The cost that measures mismatch between the two sets of similarities |
| Gradient descent | The optimiser that moves map points to reduce the cost |
| Early exaggeration | A first phase that pulls clusters tightly together so they can separate |
| Barnes-Hut approximation | A speed-up that groups distant points to cut computation |
The method is non-linear and non-parametric. It does not learn a formula that maps any new point; it optimises the positions of the given points directly. Adding new data normally means running it again.
Where it came from
Geoffrey Hinton and Sam Roweis introduced stochastic neighbor embedding (SNE) in 2002. It matched neighbour probabilities between the original space and the map, but it was hard to optimise and tended to crush points together in the centre of the map, a difficulty known as the crowding problem.
In 2008 Laurens van der Maaten and Geoffrey Hinton published "Visualizing Data using t-SNE" in the Journal of Machine Learning Research. Their variant used a symmetric cost that was easier to optimise and a Student-t distribution in the map, whose heavy tails let moderately distant points sit further apart and relieve crowding. They showed clearer maps than earlier methods such as Sammon mapping, Isomap and locally linear embedding on many datasets.
The original method scaled poorly, with cost growing with the square of the number of points. In 2014 van der Maaten published a tree-based Barnes-Hut approximation that runs in roughly N log N time, which made maps of hundreds of thousands of points practical. Further accelerations followed. t-SNE became a standard tool in single-cell biology and for inspecting embeddings from neural networks. UMAP, introduced in 2018, is now a common alternative.
How it works
Step 1: measure neighbourhoods in the original space
For each point, centre a Gaussian on it and convert distances to every other point into probabilities: near points get high probability, far points almost zero. The width of each Gaussian is set so that the distribution has the chosen perplexity. Dense regions get narrow Gaussians, sparse regions get wide ones.
Step 2: make the similarities symmetric
The probabilities for point A seeing B and B seeing A are averaged, giving one joint similarity per pair.
Step 3: place points on the map
Start with an initial layout, randomly or from PCA. PCA initialisation tends to keep more of the global arrangement and makes results more repeatable.
Step 4: measure neighbourhoods on the map
Compute similarities between map points using a Student-t distribution with one degree of freedom. Its heavy tails mean that points only moderately far apart can be placed well apart without a large penalty.
Step 5: minimise the mismatch
Measure the Kullback-Leibler divergence between the two sets of similarities and move map points by gradient descent to reduce it. The cost punishes placing true neighbours far apart much more than placing non-neighbours close, which is why local structure is preserved best.
Step 6: early exaggeration, then refinement
In the first iterations, original similarities are multiplied by a factor, 12 by default in scikit-learn, so clusters form tightly and move apart. Then the factor is removed and the map is refined.
from sklearn.manifold import TSNE
emb2d = TSNE(n_components=2, perplexity=30, init="pca",
learning_rate="auto", random_state=0).fit_transform(X)
Key concepts and terms
| Term | Meaning |
|---|---|
| Embedding | The low-dimensional coordinates produced for each point |
| Perplexity | A smooth measure of how many neighbours each point attends to |
| Crowding problem | The difficulty of fitting many moderately distant points into few dimensions |
| Student-t distribution | A heavy-tailed distribution used for map similarities |
| KL divergence | An asymmetric measure of difference between probability distributions |
| Early exaggeration | Temporarily inflating similarities to separate clusters |
| Barnes-Hut | A tree approximation that speeds up force calculations |
| Learning rate | Step size of the optimiser; scikit-learn sets it automatically by default |
| Random state | The seed that controls initialisation and repeatability |
| Global structure | Relationships between clusters, which t-SNE preserves weakly |
A worked example
This scenario is illustrative. A product team has 20,000 customer support tickets, each turned into a 768-dimensional embedding by a text model. They want to see what kinds of issues exist before building a classifier.
They first reduce the embeddings to 50 dimensions with PCA, which removes noise and speeds up the next step. They then run t-SNE with perplexity 30 and PCA initialisation. The map shows about a dozen clear islands. Sampling tickets from each island reveals themes: password resets, refund requests, delivery delays, app crashes on one phone model, and so on.
To check the result is not an artefact, the team reruns with perplexity 10 and 50 and with three different seeds. The main islands appear every time, although their positions and sizes shift. A small island that appears only at perplexity 10 turns out to be a set of near-duplicate tickets. The team uses the stable islands as starting labels for clustering and later trains a classifier on them.
Strengths and limitations
Strengths:
- Very good at revealing local cluster structure.
- Handles complex, non-linear relationships.
- Works on any data with a meaningful distance, including embeddings.
- Produces maps that are intuitive to explore.
- Widely implemented and well studied.
Limitations:
- Distances between clusters and cluster sizes are not reliable.
- Results depend on perplexity, initialisation and random seed.
- Slow on very large datasets compared with UMAP or PCA.
- No standard way to place new points on an existing map.
- Not suitable as general-purpose features for downstream models.
How it compares with alternatives
| Method | Linear | Speed | Global structure | New points |
|---|---|---|---|---|
| t-SNE | No | Medium | Weak | Not natively |
| UMAP | No | Fast | Better | Yes |
| PCA | Yes | Very fast | Good | Yes |
| Autoencoders | No | Training needed | Depends | Yes |
| Multidimensional scaling | Classical form is linear | Slow on large data | Tries to keep all distances | Limited |
Practical guidance and best practices
- Reduce very high-dimensional data to around 50 dimensions with PCA first.
- Try several perplexity values, for example 5, 30 and 50, and trust only structure that persists.
- Use PCA initialisation for more stable and repeatable layouts.
- Fix the random seed when you need to reproduce a figure.
- Colour points by known labels or metadata to interpret clusters.
- Sample and read actual examples from each cluster before naming it.
- Use UMAP or PCA when you need to embed new points consistently.
Common mistakes
- Interpreting the distance between clusters as a measure of how different they are.
- Reading cluster size as group size or spread.
- Drawing conclusions from a single run with one perplexity.
- Using t-SNE coordinates as input features for a predictive model.
- Seeing clusters in random noise, which t-SNE can produce at low perplexity.
Frequently asked questions
What perplexity should I use?
The scikit-learn documentation suggests values between 5 and 50, and the default is 30. Larger datasets usually tolerate larger values. Run a few settings and focus on structure that appears in all of them.
Why does my plot look different every time?
The optimisation starts from a random or partly random layout and the cost has many local minima. Different seeds give different arrangements. Fix the seed for reproducible figures and use PCA initialisation for more stable layouts.
Can I use t-SNE for clustering?
You can use it to see whether clusters might exist, but clustering directly on t-SNE coordinates is risky because the map distorts densities and distances. Cluster in the original or PCA space and use t-SNE to visualise the result.
Is UMAP better than t-SNE?
UMAP is usually faster, keeps more global structure and can transform new points, so it is often the default today. t-SNE still gives excellent local detail and is well understood. Both need care in interpretation.
How many points can t-SNE handle?
With the Barnes-Hut approximation, tens or hundreds of thousands of points are practical on ordinary hardware, though it can take minutes. For millions of points, faster implementations or UMAP are more convenient.
Glossary
- Dimensionality reduction: representing data with fewer coordinates.
- Neighbourhood: the set of points closest to a given point.
- Perplexity: the effective number of neighbours considered.
- KL divergence: the cost t-SNE minimises.
- Heavy tail: a distribution that gives more probability to far values than a Gaussian.
- Initialisation: the starting layout of the map.
- Barnes-Hut approximation: a tree method that speeds up the calculation.
- Artefact: a pattern created by the method rather than the data.
Summary
t-SNE draws high-dimensional data on a small map by matching neighbour probabilities, using a Gaussian in the original space and a heavy-tailed Student-t distribution on the map. Introduced by van der Maaten and Hinton in 2008 and accelerated with Barnes-Hut in 2014, it is a powerful way to see local clusters in embeddings and complex datasets. It does not preserve distances between clusters or their sizes, and its output depends on settings and seeds. Reduce with PCA first, try several perplexities, read real examples, and use it to explore rather than to model.
Related
It belongs to ML foundations in my stack, under Machine learning. Others in the same group: