t-SNE : Guide complet — Visualisation de Données en Haute Dimension
Résumé — t-SNE (t-Distributed Stochastic Neighbor Embedding) est un algorithme de réduction de dimension non linéaire développé par Laurens van der Maaten et Geoffrey Hinton en 2008. Contrairement au PCA qui préserve la variance globale, t-SNE préserve les voisinages locaux : les points proches en haute dimension restent proches en 2D/3D, tandis que les points éloignés sont repoussés. C’est l’outil de référence pour visualiser des clusters et des structures complexes dans des données haute dimension (images, textes, génomique).
Principe mathématique
1. Similarités en haute dimension
t-SNE commence par calculer, pour chaque paire de points (x_i, x_j), une probabilité conditionnelle qui mesure la similarité entre eux :
$$p_{j|i} = \frac{\exp(-||x_i – x_j||^2 / (2\sigma_i^2))}{\sum_{k \neq i} \exp(-||x_i – x_k||^2 / (2\sigma_i^2))}$$
où σ_i est un paramètre de bande passante qui dépend de la densité locale autour de x_i. Dans les zones denses, σ_i est petit ; dans les zones clairsemées, il est grand.
La valeur de σ_i est calibrée pour que la perplexité (une mesure de la taille effective du voisinage) soit constante :
$$\text{Perplexité}(P_i) = 2^{H(P_i)}$$
où H(P_i) = -Σj p{j|i} · log₂(p_{j|i}) est l’entropie de Shannon de la distribution autour du point i.
Les probabilités conditionnelles sont ensuite symétrisées :
$$p_{ij} = \frac{p_{j|i} + p_{i|j}}{2n}$$
2. Similarités en basse dimension (2D/3D)
Dans l’espace de projection (y_i, y_j), t-SNE utilise une distribution t de Student à un degré de liberté (distribution de Cauchy) :
$$q_{ij} = \frac{(1 + ||y_i – y_j||^2)^{-1}}{\sum_{k \neq l} (1 + ||y_k – y_l||^2)^{-1}}$$
Le choix de la t de Student est crucial : ses queues lourdes font que la décroissance de q_ij est beaucoup plus lente que celle de p_ij. Conséquence : les points qui sont éloignés en haute dimension sont encore plus éloignés en projection, ce qui révèle la structure globale.
3. Minimisation de la divergence KL
L’objectif de t-SNE est de rendre la distribution Q (basse dimension) aussi proche que possible de la distribution P (haute dimension), en minimisant la divergence de Kullback-Leibler :
$$\text{KL}(P || Q) = \sum_{i \neq j} p_{ij} \cdot \log\left(\frac{p_{ij}}{q_{ij}}\right)$$
Le gradient par rapport à chaque point y_i est :
$$\frac{\partial \text{KL}}{\partial y_i} = 4 \sum_{j \neq i} (p_{ij} – q_{ij}) \cdot (y_i – y_j) \cdot (1 + ||y_i – y_j||^2)^{-1}$$
Ce gradient contient deux forces :
– Attraction quand p_ij > q_ij : les points proches en haute dimension sont rapprochés.
– Répulsion quand q_ij > p_ij : les points éloignés sont repoussés.
4. Early Exaggeration
Pendant les premières itérations, t-SNE multiplie les p_ij par un facteur (typiquement 4-12). Cela renforce l’attraction entre voisins proches et permet aux clusters de se former plus rapidement avant que la répulsion ne s’installe.
Intuition
Imaginez que vous avez des milliers de photographies de visages et que vous voulez les ranger sur un mur de deux mètres sur un. Chaque photo a des milliers de pixels (haute dimension), mais vous ne disposez que d’un plan 2D.
Le PCA placerait les photos de gauche à droite selon l’éclairage général. Les visages clairs d’un côté, les sombres de l’autre. C’est global mais pas très utile.
t-SNE, lui, dit : « Les visages qui se ressemblent doivent être côte à côte, et les visages très différents doivent être aux extrémités opposées du mur. » Résultat : vous voyez des groupes se former — les sourires ensemble, les visages de face ensemble, les profils ensemble — sans qu’on lui ait dit ce qu’est un sourire.
L’analogie des aimants et des ressorts : t-SNE imagine que chaque point de haute dimension est relié à tous les autres par des ressorts. Plus deux points sont proches en haute dimension, plus le ressort est fort. En projection 2D, les points bougent jusqu’à l’équilibre : les voisins restent collés, les éloignés sont repoussés. La t de Student agit comme un ressort qui ne s’arrête jamais de pousser — même très loin.
Implémentation Python
Exemple 1 : t-SNE basique avec scikit-learn
import numpy as np
import matplotlib.pyplot as plt
from sklearn.manifold import TSNE
from sklearn.datasets import load_digits
# Données : 64 pixels par chiffre manuscrit
digits = load_digits()
X = digits.data # (1797, 64)
y = digits.target # 10 classes (0-9)
# t-SNE en 2D
tsne = TSNE(n_components=2, perplexity=30, random_state=42, n_iter=1000)
X_embedded = tsne.fit_transform(X)
print(f"Shape originale : {X.shape}")
print(f"Shape projetée : {X_embedded.shape}")
# Visualisation
fig, ax = plt.subplots(figsize=(10, 8))
scatter = ax.scatter(X_embedded[:, 0], X_embedded[:, 1], c=y,
cmap='tab10', alpha=0.8, s=50, edgecolors='black', linewidth=0.5)
plt.colorbar(scatter, ticks=range(10), label='Chiffre')
ax.set_title(f't-SNE : Chiffres manuscrits (perplexity=30)')
ax.set_xlabel('t-SNE 1')
ax.set_ylabel('t-SNE 2')
plt.tight_layout()
plt.savefig('tsne_digits.png', dpi=150)
Exemple 2 : Impact de la perplexité
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
perplexities = [5, 15, 30, 50]
for ax, perp in zip(axes.ravel(), perplexities):
tsne_p = TSNE(n_components=2, perplexity=perp, random_state=42, n_iter=1000)
embedded_p = tsne_p.fit_transform(X)
sc = ax.scatter(embedded_p[:, 0], embedded_p[:, 1], c=y,
cmap='tab10', alpha=0.8, s=30)
ax.set_title(f'Perplexité = {perp}')
ax.set_xticks([])
ax.set_yticks([])
plt.suptitle('Impact de la perplexité sur la visualisation t-SNE')
plt.tight_layout()
plt.savefig('tsne_perplexity.png', dpi=150)
# Observations :
print("Perplexité faible (5) : petits clusters locaux, fragmentation")
print("Perplexité moy. (30) : bon équilibre, groupes cohérents")
print("Perplexité élev. (50) : clusters globaux, perte des détails fins")
Exemple 3 : Comparaison avec PCA et UMAP
from sklearn.decomposition import PCA
# PCA en 2D
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)
# Comparaison visuelle
fig, axes = plt.subplots(1, 2, figsize=(14, 6))
axes[0].scatter(X_pca[:, 0], X_pca[:, 1], c=y, cmap='tab10', alpha=0.7, s=40)
axes[0].set_title(f'PCA — Variance expliquée: {pca.explained_variance_ratio_.sum()*100:.1f}%')
axes[0].set_xlabel('PC1')
axes[0].set_ylabel('PC2')
axes[1].scatter(X_embedded[:, 0], X_embedded[:, 1], c=y, cmap='tab10', alpha=0.7, s=40)
axes[1].set_title('t-SNE — Stochastic Neighbor Embedding')
axes[1].set_xlabel('t-SNE 1')
axes[1].set_ylabel('t-SNE 2')
plt.suptitle('PCA vs t-SNE sur les chiffres manuscrits')
plt.tight_layout()
plt.savefig('pca_vs_tsne.png', dpi=150)
Exemple 4 : t-SNE 3D
from mpl_toolkits.mplot3d import Axes3D
tsne_3d = TSNE(n_components=3, perplexity=30, random_state=42, n_iter=1000)
X_3d = tsne_3d.fit_transform(X)
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
sc = ax.scatter(X_3d[:, 0], X_3d[:, 1], X_3d[:, 2], c=y,
cmap='tab10', alpha=0.7, s=30)
plt.colorbar(sc, ticks=range(10))
ax.set_title('t-SNE 3D : Chiffres manuscrits')
plt.tight_layout()
plt.savefig('tsne_3d.png', dpi=150)
Hyperparamètres
| Hyperparamètre | Valeur typique | Description |
|---|---|---|
n_components |
2 ou 3 | Dimension de l’espace de projection. 2 pour visualisation, 3 pour immersion |
perplexity |
5-50 (30 par défaut) | Taille effective du voisinage. Plus élevé = vue plus globale. Généralement 5-50 pour datasets < 10 000 points |
learning_rate |
10-1000 (200 par défaut) | Pas d’optimisation. Si les points s’effondrent, l’augmenter. Si instable, le réduire |
early_exaggeration |
4-12 (12 par défaut) | Multiplicateur des p_ij pendant les premières itérations. Renforce la séparation des clusters |
n_iter |
250-5000 (1000 par défaut) | Nombre d’itérations. 250 pour explorer, 1000+ pour affiner |
init |
‘random’ ou ‘pca’ | Initialisation. ‘pca’ donne souvent de meilleurs résultats et converge plus vite |
method |
‘barnes_hut’ ou ‘exact’ | ‘barnes_hut’ pour les gros datasets (O(n·log(n))), ‘exact’ pour précision maximale |
Avantages de t-SNE
- Préservation des structures non linéaires : Contrairement au PCA qui ne capture que la variance linéaire, t-SNE révèle des structures complexes (clusters, boucles, branches) que les méthodes linéaires ratent.
- Résultats visuellement excellents : Les visualisations t-SNE sont souvent impressionnantes : les clusters se séparent nettement, les sous-groupes émergent naturellement. C’est l’outil préféré pour l’exploration visuelle de données.
- Pas d’hypothèse sur la forme des données : t-SNE ne suppose ni linéarité ni distribution gaussienne. Il fonctionne sur toute donnée où une distance est définie.
- Révèle la topologie locale : t-SNE excelle à préserver les voisinages proches, ce qui est exactement ce qu’on veut voir dans une visualisation de clusters.
Limites de t-SNE
- Ne préserve pas les distances globales : La distance entre deux clusters sur une visualisation t-SNE n’a pas de sens intrinsèque. On ne peut pas dire « ce cluster est plus éloigné que celui-là » de manière quantitative.
- Résultats non déterministes : Chaque exécution (avec une graine différente) peut donner des visualisations radicalement différentes, même si les clusters locaux restent cohérents.
- Coût computationnel élevé : Barnes-Hut est en O(n·log(n)) mais reste lent sur des millions de points. L’algorithme exact est en O(n²) et impraticable au-delà de 10 000 points.
- Pas de mécanisme de projection inverse : Contrairement au PCA où on peut transformer un nouveau point sans recalculer toute la décomposition, t-SNE n’offre pas de fonction de projection pour des données non vues. Chaque exécution repart de zéro.
- Sensibilité aux hyperparamètres : La perplexité et le learning rate doivent être ajustés pour chaque dataset. Un mauvais choix peut donner une visualisation trompeuse (tout regroupé, ou tout éparpillé).
4 cas d’usage concrets
1. Visualisation d’embeddings de mots (NLP)
En traitement du langage naturel, t-SNE est utilisé pour visualiser les embeddings Word2Vec ou GloVe : chaque mot est un point en 300 dimensions, et t-SNE les projette en 2D. On découvre alors que les mots sémantiquement proches (roi/reine, homme/femme, Paris/France) se regroupent naturellement en clusters.
2. Exploration de clusters de clients
Les données clients (comportement d’achat, données démographiques, engagement) sont souvent en 50-200 dimensions après feature engineering. t-SNE projette ces données en 2D pour révéler visuellement des segments naturels de clients, validant ou infirmant les résultats d’un K-Means.
3. Analyse de données génomiques
En génomique, les données d’expression génique ont typiquement 20 000 features (un par gène). t-SNE révèle des sous-types cellulaires et des clusters de patients qui correspondent à des profils moléculaires distincts, utilisés en oncologie pour la classification de tumeurs.
4. Visualisation de l’espace latent des autoencodeurs
Quand un autoencodeur est entraîné sur des images, son espace latent ( bottleneck ) est un espace compressed où chaque dimension encode une caractéristique abstraite. t-SNE projette cet espace en 2D pour vérifier que les images similaires sont effectivement proches dans la représentation apprise.
Conclusion
t-SNE est l’outil incontournable pour voir ce qui se passe dans des données haute dimension. Sa capacité à révéler des structures non linéaires et des clusters invisibles au PCA en fait un standard dans la boîte à outils de tout data scientist.
Mais attention : t-SNE est un outil d’exploration, pas de modélisation. Ses visualisations sont magnifiques mais interprétables avec précaution. Les distances entre clusters n’ont pas de sens absolu, et les résultats dépendent des hyperparamètres utilisés.
Pour les très gros datasets, UMAP est une alternative plus rapide et plus structurée globalement. Mais pour la qualité pure de visualisation, t-SNE reste la référence.
Voir aussi
- Découvrez ‘Factor Shuffle’ en Python : Guide Complet pour Réorganiser vos Collections Efficacement
- Découverte des Voisins Lexicographiques en Python : Guide Complet pour Développeurs

