Gaussian Mixture Models (GMM) : Guide Complet — Principes, Exemples et Implémentation Python

Gaussian Mixture Models (GMM) : Guide Complet — Principes, Exemples et Implémentation Python

Gaussian Mixture Models (GMM) : Guide complet — Principes, Exemples et Implémentation Python

Résumé

Les Gaussian Mixture Models (GMM), ou modèles de mélange gaussien, constituent l’une des méthodes de clustering probabiliste les plus puissantes et les plus élégantes en apprentissage non supervisé. Contrairement au K-Means qui assigne chaque point de données à un seul cluster de manière rigide, le GMM permet une appartenance partielle : un point peut appartenir à plusieurs clusters simultanément, avec des probabilités associées. Cette approche dite soft clustering ouvre la voie à une modélisation beaucoup plus nuancée et réaliste de la structure sous-jacente des données.

Ce guide complet couvre le fonctionnement théorique des GMM, l’algorithme EM (espérance-maximisation) qui les optimise, les critères BIC et AIC pour choisir le nombre de composantes, et fournit une implémentation Python complète avec scikit-learn, incluant la visualisation des ellipses de covariance.


Principe mathématique

La distribution de mélange

Le principe fondamental des Gaussian Mixture Models repose sur une idée à la fois simple et puissante : supposer que nos données sont générées par un mélange de plusieurs distributions gaussiennes (normales) multivariées.

Mathématiquement, la densité de probabilité d’un point x s’écrit comme une somme pondérée de K gaussiennes :

p(x) = Σ_{k=1}^{K} π_k · N(x | μ_k, Σ_k)

où :

  • K est le nombre de composantes gaussiennes (clusters).
  • π_k est le poids (proportion) de la k-ième composante, avec Σ π_k = 1 et π_k ≥ 0. Ces poids représentent la probabilité a priori qu’un point appartienne au cluster k.
  • μ_k est le vecteur moyenne de la k-ième gaussienne, qui détermine son centre dans l’espace des données.
  • Σ_k est la matrice de covariance de la k-ième composante, qui contrôle sa forme, son orientation et son étalement.
  • N(x | μ_k, Σ_k) est la densité de la loi normale multivariée évaluée au point x :
N(x | μ, Σ) = (1 / ((2π)^{d/2} · |Σ|^{1/2})) · exp(-1/2 · (x - μ)^T · Σ^{-1} · (x - μ))

où d est la dimension de l’espace des données et |Σ| désigne le déterminant de la matrice de covariance.

La log-vraisemblance

Pour estimer les paramètres du modèle (π_k, μ_k, Σ_k pour chaque cluster k), on maximise la log-vraisemblance des données observées :

ln L = Σ_{i=1}^{N} ln(Σ_{k=1}^{K} π_k · N(x_i | μ_k, Σ_k))

Le problème est que cette fonction n’admet pas de solution analytique directe : la somme à l’intérieur du logarithme rend la dérivée non linéaire et impossible à résoudre en une seule étape. C’est précisément cette difficulté qui motive l’utilisation de l’algorithme EM.

L’algorithme EM (Espérance-Maximisation)

L’algorithme EM est un procédé itératif qui contourne l’absence de solution analytique en alternant deux étapes complémentaires :

Étape E (Espérance) : calcul des responsabilités

À chaque itération, on calcule la responsabilité γ_ik de la composante k pour le point i. C’est la probabilité a posteriori que le point x_i ait été généré par la gaussienne k, compte tenu des paramètres actuels :

γ_{ik} = (π_k · N(x_i | μ_k, Σ_k)) / (Σ_{j=1}^{K} π_j · N(x_i | μ_j, Σ_j))

La responsabilité γ_ik est un nombre compris entre 0 et 1. Pour un point donné i, la somme des responsabilités sur toutes les composantes vaut exactement 1 : Σ_k γ_ik = 1. C’est ce qui confère au GMM son caractère soft : chaque point contribue à tous les clusters proportionnellement à sa responsabilité.

Étape M (Maximisation) : mise à jour des paramètres

Ensuite, on met à jour les paramètres du modèle en utilisant les responsabilités calculées à l’étape E :

  • Nouveau poids :
π_k = (1/N) · Σ_{i=1}^{N} γ_{ik}

Le poids devient la proportion moyenne de la responsabilité du cluster k sur tous les points.

  • Nouvelle moyenne :
μ_k = (Σ_{i=1}^{N} γ_{ik} · x_i) / (Σ_{i=1}^{N} γ_{ik})

La moyenne est une moyenne pondérée des points, où chaque point est pondéré par sa responsabilité pour le cluster k.

  • Nouvelle covariance :
Σ_k = (Σ_{i=1}^{N} γ_{ik} · (x_i - μ_k) · (x_i - μ_k)^T) / (Σ_{i=1}^{N} γ_{ik})

La covariance est estimée comme une covariance pondérée, tenant compte du degré d’appartenance de chaque point.

Ces deux étapes se répètent jusqu’à convergence — c’est-à-dire lorsque l’augmentation de la log-vraisemblance entre deux itérations devient inférieure à un seuil de tolérance prédéfini.

Pourquoi ça marche

Chaque itération de l’algorithme EM garantit une augmentation (ou au minimum une non-décroissance) de la log-vraisemblance. On converge donc vers un maximum local de la fonction de vraisemblance. Notez bien : maximum local, pas global. C’est pourquoi il est recommandé de lancer l’algorithme plusieurs fois avec des initialisations différentes et de retenir la meilleure solution.


Intuition : K-Means vs GMM

Pour bien comprendre la puissance des GMM, comparons-les au K-Means, l’algorithme de clustering le plus connu.

K-Means fonctionne par assignation dure (hard clustering) : chaque point appartient à un seul cluster — celui dont le centroïde est le plus proche. La frontière entre deux clusters est une droite (en 2D) ou un hyperplan (en dimension supérieure). C’est une approche tout ou rien : soit un point est dans le cluster A, soit il est dans le cluster B.

GMM, quant à lui, fonctionne par assignation souple (soft clustering) : chaque point se voit attribuer une probabilité d’appartenance à chaque cluster. Par exemple, le GMM peut dire : « ce point appartient à 60 % au cluster A, 30 % au cluster B, et 10 % au cluster C ». C’est du clustering flou probabiliste.

Imaginez un nuage de points en deux dimensions avec deux groupes qui se chevauchent partiellement. Le K-Means tracerait une ligne droite entre les deux groupes et couperait brutalement. Le GMM, en revanche, reconnaîtrait que les points situés dans la zone de chevauchement ont une probabilité d’appartenance incertaine — ce qui est bien plus honnête et informatif.

Trois avantages conceptuels majeurs du GMM sur le K-Means

  1. Formes elliptiques : Le K-Means suppose implicitement que chaque cluster est sphérique (basé sur la distance euclidienne). Le GMM, grâce à sa matrice de covariance, peut modéliser des clusters allongés, orientés, elliptiques, bien mieux adaptés à la réalité des données.
  2. Mélange de tailles : Le K-Means tend à produire des clusters de taille similaire. Le GMM peut capturer des clusters de tailles très différentes grâce aux poids π_k.
  3. Incertitude quantifiée : Le GMM donne une mesure de confiance pour chaque assignation. Les points proches des frontières ont des responsabilités équilibrées, ce qui signale des cas ambigus. Le K-Means, lui, attribue toujours un cluster avec une certitude de 100 %, même quand c’est faux.

Implémentation Python

Exemple de base avec scikit-learn

Commençons par une implémentation simple avec des données synthétiques générées par make_blobs :

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from sklearn.mixture import GaussianMixture
from sklearn.cluster import KMeans

# Générer des données synthétiques
X, y_true = make_blobs(n_samples=500, centers=4,
                        cluster_std=1.0, random_state=42)

# Ajuster un GMM avec 4 composantes
gmm = GaussianMixture(n_components=4, random_state=42)
gmm.fit(X)

# Prédire les labels et les probabilités
labels = gmm.predict(X)
probas = gmm.predict_proba(X)

print(f"Labels uniques : {np.unique(labels)}")
print(f"Log-vraisemblance : {gmm.score(X):.4f}")
print(f"Nombre d'itérations : {gmm.n_iter_}")

# Afficher les probabilités pour les 5 premiers points
print("\nProbabilités d'appartenance (5 premiers points) :")
print(probas[:5])

Ce code produit pour chaque point un vecteur de probabilités : au lieu de dire « ce point est dans le cluster 2 », le GMM dit « ce point a 85 % de chances d’être dans le cluster 2, 10 % dans le cluster 1, etc. ».

Choisir le nombre de clusters avec le critère BIC

Comme pour le K-Means, le nombre de composantes K est un hyperparamètre. Le GMM offre deux critères d’information très pratiques pour le sélectionner automatiquement : le BIC (Bayesian Information Criterion) et l’AIC (Akaike Information Criterion).

# Chercher le nombre optimal de composantes
bic_scores = []
aic_scores = []
K_range = range(1, 10)

for k in K_range:
    gmm = GaussianMixture(n_components=k, random_state=42)
    gmm.fit(X)
    bic_scores.append(gmm.bic(X))
    aic_scores.append(gmm.aic(X))

# Le meilleur K minimise le BIC
best_k = K_range[np.argmin(bic_scores)]
print(f"Nombre optimal de clusters (BIC) : {best_k}")

# Visualisation des critères
plt.figure(figsize=(10, 4))

plt.subplot(1, 2, 1)
plt.plot(K_range, bic_scores, 'bo-', linewidth=2, markersize=8)
plt.axvline(best_k, color='r', linestyle='--', label=f'Optimal K={best_k}')
plt.xlabel('Nombre de composantes K')
plt.ylabel('BIC')
plt.title('Critère BIC vs Nombre de clusters')
plt.legend()
plt.grid(True, alpha=0.3)

plt.subplot(1, 2, 2)
plt.plot(K_range, aic_scores, 'go-', linewidth=2, markersize=8)
plt.xlabel('Nombre de composantes K')
plt.ylabel('AIC')
plt.title("Critère AIC vs Nombre de clusters")
plt.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

Le BIC pénalise plus fortement la complexité du modèle que l’AIC. Il tend donc à choisir des modèles plus parcimonieux (moins de composantes). En pratique, le BIC est généralement préféré pour les problèmes de clustering.

Comparaison GMM vs K-Means

# Comparaison visuelle GMM vs K-Means
kmeans = KMeans(n_components=4, random_state=42, n_init=10)
kmeans_labels = kmeans.fit_predict(X)
gmm_labels = gmm.predict(X)

fig, axes = plt.subplots(1, 2, figsize=(12, 5))

# K-Means
axes[0].scatter(X[:, 0], X[:, 1], c=kmeans_labels,
                cmap='viridis', s=20, alpha=0.7)
axes[0].set_title('K-Means (hard clustering)')
axes[0].set_aspect('equal')

# GMM
axes[1].scatter(X[:, 0], X[:, 1], c=gmm_labels,
                cmap='viridis', s=20, alpha=0.7)
axes[1].set_title('GMM (soft clustering)')
axes[1].set_aspect('equal')

plt.tight_layout()
plt.show()

Visualisation des ellipses de covariance

L’un des avantages les plus visuels du GMM est la capacité de dessiner les ellipses de covariance qui représentent la forme et l’orientation de chaque cluster gaussien :

def plot_gmm_ellipses(gmm, X, ax=None):
    """Trace les ellipses de covariance d'un GMM."""
    if ax is None:
        ax = plt.gca()

    labels = gmm.predict(X)
    ax.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis',
               s=15, alpha=0.6, label='Données')

    for k in range(gmm.n_components):
        # Récupérer moyenne et covariance
        mu = gmm.means_[k]
        cov = gmm.covariances_[k]

        # Valeurs propres et vecteurs propres pour l'ellipse
        eigenvalues, eigenvectors = np.linalg.eigh(cov)

        # Angle de l'ellipse
        angle = np.degrees(np.arctan2(eigenvectors[1, 0], eigenvectors[0, 0]))

        # Taille : 2 écarts-types (couvre ~95,4 % de la masse)
        width, height = 2 * np.sqrt(eigenvalues)

        ellipse = plt.matplotlib.patches.Ellipse(
            mu, width, height, angle=angle,
            edgecolor='red', facecolor='none',
            linewidth=2, alpha=0.8
        )
        ax.add_patch(ellipse)
        ax.scatter(*mu, c='red', marker='x', s=100, linewidths=3)

    ax.set_title('GMM avec ellipses de covariance')
    ax.set_aspect('equal')

fig, ax = plt.subplots(figsize=(8, 6))
plot_gmm_ellipses(gmm, X, ax)
plt.show()

Ces ellipses révèlent visuellement la forme réelle de chaque cluster — sphérique, allongée, orientée — là où le K-Means ne verrait que des cercles uniformes.

Échantillonnage à partir du modèle ajusté

Un avantage unique du GMM est qu’il s’agit d’un modèle génératif : une fois ajusté, on peut générer de nouvelles données qui suivent la même distribution :

# Générer de nouvelles données à partir du GMM ajusté
X_generated, y_generated = gmm.sample(n_samples=300)

plt.figure(figsize=(8, 6))
plt.scatter(X[:, 0], X[:, 1], c='gray', alpha=0.3, s=10,
            label='Données originales')
plt.scatter(X_generated[:, 0], X_generated[:, 1], c=y_generated,
            cmap='viridis', alpha=0.6, s=20, label='Données générées')
plt.title('GMM comme modèle génératif')
plt.legend()
plt.show()

Hyperparamètres de GaussianMixture

Comprendre les hyperparamètres est essentiel pour tirer le meilleur parti de GaussianMixture :

Hyperparamètre Valeurs possibles Description
n_components int (défaut : 1) Nombre de composantes gaussiennes K. L’équivalent de K dans K-Means.
covariance_type 'full' (défaut), 'tied', 'diag', 'spherical' Type de matrice de covariance. 'full' : chaque composante a sa propre covariance générale. 'tied' : toutes les composantes partagent la même covariance. 'diag' : covariance diagonale (gaussiennes alignées sur les axes, plus rapide). 'spherical' : variance unique par composante (équivalent au K-Means).
init_params 'kmeans' (défaut), 'k-means++', 'random', 'random_from_data' Méthode d’initialisation des paramètres. L’initialisation par k-means est généralement la plus stable.
max_iter int (défaut : 100) Nombre maximum d’itérations de l’algorithme EM.
n_init int (défaut : 1) Nombre d’initialisations aléatoires. Augmenter cette valeur réduit le risque de converger vers un maximum local sous-optimal.
tol float (défaut : 1e-3) Seuil de convergence. L’algorithme s’arrête quand l’amélioration de la log-vraisemblance est inférieure à tol.
warm_start bool (défaut : False) Si True, réutilise la solution précédente comme initialisation. Utile pour affiner progressivement un modèle.
reg_covar float (défaut : 1e-6) Régularisation ajoutée à la diagonale des covariances pour éviter les singularités.

Recommandations pratiques

  • Commencez avec covariance_type='full' pour capturer toute la richesse des structures.
  • Si les données sont de grande dimension, passez à 'diag' pour réduire le nombre de paramètres et accélérer le calcul.
  • Utilisez n_init=3 ou plus pour minimiser le risque de mauvais optimum local.
  • Ajustez max_iter si la convergence n’est pas atteinte (message d’avertissement de scikit-learn).

Avantages et Limites

Avantages

  1. Soft clustering : Le GMM fournit des probabilités d’appartenance, offrant une mesure d’incertitude précieuse pour l’interprétation.
  2. Formes flexibles : Grâce aux matrices de covariance, les clusters peuvent être sphériques, elliptiques, allongés et orientés dans n’importe quelle direction.
  3. Modèle génératif : Le GMM peut échantillonner de nouvelles données et calculer la densité de probabilité en tout point — ce que le K-Means ne permet pas.
  4. Sélection automatique de K : Les critères BIC et AIC fournissent une méthode objective pour choisir le nombre de composantes.
  5. Généralisation du K-Means : Le K-Means est un cas particulier du GMM (avec covariance_type='spherical' et assignation dure).

Limites

  1. Sensibilité à l’initialisation : L’algorithme EM converge vers un maximum local, pas global. De mauvaises initialisations produisent de mauvais résultats.
  2. Complexité computationnelle : En dimension d avec K composantes, chaque itération EM coûte O(N·K·d²). Le GMM est plus lent que le K-Means, surtout avec covariance_type='full'.
  3. Hypothèse gaussienne : Le GMM suppose que chaque cluster suit une distribution gaussienne. Si les clusters ont des formes très irrégulières (en croissant, en spirale), le GMM échouera — dans ce cas, des méthodes comme DBSCAN sont plus appropriées.
  4. Problème de singularité : Si une composante gaussienne se concentre sur un seul point de données, la covariance devient singulière (déterminant nul). scikit-learn contourne ce problème avec le paramètre reg_covar.
  5. Non adapté aux très grands jeux de données : L’EM classique nécessite de parcourir toutes les données à chaque itération. Pour des millions de points, des variantes incrémentales ou en lot (mini-batch) sont nécessaires.

4 cas d’usage concrets

1. Segmentation de clientèle

En marketing analytics, les clients ne se répartissent pas toujours en groupes bien séparés. Un client peut présenter des caractéristiques intermédiaires entre plusieurs segments. Le GMM quantifie cette ambiguïté : « ce client est à 70 % dans le segment premium, 30 % dans le segment intermédiaire ». Cette information probabiliste permet des campagnes de ciblage plus nuancées que les segments rigides du K-Means.

2. Détection d’anomalies

Le GMM étant un estimateur de densité, il peut calculer la probabilité p(x) de n’importe quel point. Les points ayant une très faible probabilité sont considérés comme des anomalies ou des valeurs aberrantes. Cette approche est particulièrement efficace pour la détection de fraudes financières, où les transactions frauduleuses se situent dans des régions de faible densité du modèle.

# Détection d'anomalies avec GMM
log_probs = gmm.score_samples(X)
threshold = np.percentile(log_probs, 2.5)  # Les 2,5 % les moins probables
anomalies = X[log_probs < threshold]
print(f"{len(anomalies)} anomalies détectées sur {len(X)} points")

3. Modélisation du langage et traitement de la parole

En reconnaissance vocale, les GMM ont été la pierre angulaire des systèmes de modélisation acoustique pendant des décennies. Chaque phonème est modélisé comme un mélange de gaussiennes dans l’espace des coefficients cepstraux (MFCC). Bien que les réseaux de neurones profonds aient largement remplacé les GMM dans ce domaine, ils restent utilisés dans les systèmes légers et les applications embarquées.

4. Segmentation d’images

En vision par ordinateur, les GMM sont utilisés pour la segmentation d’images en regroupant les pixels selon leurs caractéristiques de couleur (R, V, B) et de position (x, y). Le GMM permet de modéliser les zones de transition entre les objets avec des probabilités intermédiaires, produisant des contours plus lisses et plus réalistes que les méthodes de clustering dur.


Voir aussi


Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur la façon dont les données de vos commentaires sont traitées.