K-means
Apprenez le clustering K-Means en Python avec scikit-learn : algorithme, mise à l'échelle, choix de K, score silhouette et pièges courants.
K-Means est un algorithme d'apprentissage automatique non supervisé qui partitionne un jeu de données en K clusters non chevauchants en minimisant la distance quadratique totale entre chaque point de données et le centroïde du cluster auquel il est assigné. Cette page explique le fonctionnement de l'algorithme, comment l'implémenter en Python avec scikit-learn, comment choisir le bon nombre de clusters et les pièges principaux à éviter.
Qu'est-ce que le clustering K-Means ?
K-Means regroupe les points de données de sorte que les points appartenant au même cluster soient aussi similaires que possible, tandis que les points de clusters différents soient aussi distincts que possible. La « similarité » est mesurée par la distance euclidienne — la distance en ligne droite entre deux points dans l'espace des caractéristiques.
Comme K-Means travaille avec des valeurs de distance brutes, il s'agit d'un algorithme non supervisé : il découvre la structure de données non étiquetées sans avoir besoin d'une variable cible.
Les applications concrètes courantes comprennent :
- Segmentation de clientèle — regrouper les clients selon leurs habitudes de dépenses et leurs données démographiques.
- Compression d'image — réduire les couleurs en remplaçant chaque pixel par la couleur de son centroïde le plus proche.
- Clustering de documents — regrouper des articles de presse ou des tickets d'assistance par thème.
- Détection d'anomalies — les points éloignés de tout centroïde peuvent être des valeurs aberrantes.
Comment fonctionne l'algorithme
K-Means alterne entre deux étapes jusqu'à ce que les assignations de clusters cessent de changer (convergence) :
- Initialisation — choisir K centroïdes initiaux (points de départ). La stratégie par défaut
k-means++les espace pour réduire les mauvaises initialisations. - Assignation — assigner chaque point de données au centroïde le plus proche, formant K clusters.
- Mise à jour — recalculer chaque centroïde comme la moyenne de tous les points qui lui sont assignés.
- Répéter les étapes 2–3 jusqu'à ce qu'aucun point ne change de cluster, ou jusqu'à ce qu'un nombre maximum d'itérations soit atteint.
La quantité minimisée est appelée inertie (aussi notée WCSS — somme des carrés intra-cluster) :
inertia = sum over all points of (distance from point to its centroid)²Une inertie plus faible signifie des clusters plus serrés et plus compacts.
Initialisation k-means++
L'option par défaut init='k-means++' (valeur par défaut de scikit-learn) sélectionne le premier centroïde aléatoirement, puis choisit chaque centroïde suivant avec une probabilité proportionnelle à sa distance quadratique par rapport au centroïde déjà choisi le plus proche. Cela répartit les centroïdes initiaux et trouve généralement de meilleurs clusters plus rapidement que l'initialisation purement aléatoire.
Mise à l'échelle des caractéristiques avant le clustering
K-Means repose entièrement sur la distance euclidienne. Si une caractéristique est mesurée en milliers (par exemple, un revenu annuel) et une autre en chiffres simples (par exemple, une note de 1 à 5), la caractéristique à grande valeur domine le calcul de distance et la caractéristique à faible portée est effectivement ignorée. Pensez toujours à mettre vos caractéristiques à l'échelle en premier.
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)StandardScaler centre chaque caractéristique à une moyenne de 0 et un écart type de 1. Consultez le chapitre Scale pour les alternatives comme MinMaxScaler.
Implémenter K-Means avec scikit-learn
L'exemple suivant génère un jeu de données synthétique, le met à l'échelle, ajuste K-Means et inspecte les résultats.
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler
import numpy as np
# Generate 300 points in 3 natural clusters
X, y_true = make_blobs(n_samples=300, centers=3, random_state=42)
# Scale the features — always required before K-Means
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# Fit K-Means with 3 clusters
kmeans = KMeans(n_clusters=3, init='k-means++', n_init=10, random_state=42)
kmeans.fit(X_scaled)
# Cluster assignment for every training point (0-indexed)
labels = kmeans.labels_
print('Cluster labels (first 10):', labels[:10])
# e.g. [2 2 0 1 0 1 2 2 0 1]
print('Cluster sizes:', np.bincount(labels))
# e.g. [100 100 100]
print('Inertia (WCSS):', round(kmeans.inertia_, 2))
# e.g. 18.26
print('Iterations to converge:', kmeans.n_iter_)
# e.g. 2Attributs clés après l'ajustement :
| Attribut | Description |
|---|---|
labels_ | ID de cluster (0 à K-1) pour chaque point d'entraînement |
cluster_centers_ | Coordonnées des K centroïdes (forme : K × n_features) |
inertia_ | WCSS total — plus bas est mieux |
n_iter_ | Nombre d'itérations EM jusqu'à la convergence |
Prédire l'appartenance à un cluster pour de nouvelles données
Après avoir ajusté le scaler et le modèle sur les données d'entraînement, utilisez scaler.transform() + kmeans.predict() pour assigner de nouveaux points aux clusters existants. Ne réajustez jamais le scaler sur de nouvelles données.
import numpy as np
# Two new, unseen points (original feature scale)
new_points = np.array([[0.5, -0.5],
[-1.0, 2.0]])
# Transform with the SAME scaler used during training
new_scaled = scaler.transform(new_points)
# Predict cluster membership
predictions = kmeans.predict(new_scaled)
print('Predicted clusters:', predictions)
# e.g. [2 0]Choisir le bon nombre de clusters (K)
K-Means vous demande de spécifier K à l'avance, ce qui est souvent la partie la plus difficile. Deux techniques complémentaires aident : la méthode du coude et le score silhouette.
La méthode du coude
Tracez l'inertie (WCSS) en fonction de K. À mesure que K augmente, l'inertie diminue toujours — mais le taux d'amélioration ralentit. Le « coude » est le point où l'ajout d'un cluster supplémentaire apporte des rendements décroissants.
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
X, _ = make_blobs(n_samples=300, centers=3, random_state=42)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
wcss = []
for k in range(1, 11):
km = KMeans(n_clusters=k, n_init=10, random_state=42)
km.fit(X_scaled)
wcss.append(km.inertia_)
plt.plot(range(1, 11), wcss, marker='o')
plt.xlabel('Number of clusters (K)')
plt.ylabel('Inertia (WCSS)')
plt.title('Elbow method')
plt.tight_layout()
plt.show()Sur ce jeu de données (3 clusters naturels), l'inertie chute fortement de K=1 à K=3, puis se stabilise. Le coude à K=3 confirme le vrai nombre de clusters.
Le score silhouette
Le score silhouette mesure à quel point chaque point s'intègre dans son propre cluster par rapport au cluster voisin le plus proche. Il varie de -1 (mauvais cluster) à +1 (cluster parfaitement séparé). Un score supérieur à 0,5 est généralement bon ; supérieur à 0,7 est excellent.
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import silhouette_score
X, _ = make_blobs(n_samples=300, centers=3, random_state=42)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
for k in range(2, 8):
km = KMeans(n_clusters=k, n_init=10, random_state=42)
labels = km.fit_predict(X_scaled)
score = silhouette_score(X_scaled, labels)
print(f'k={k} silhouette={score:.3f}')Résultat :
k=2 silhouette=0.688
k=3 silhouette=0.848
k=4 silhouette=0.679
k=5 silhouette=0.522
k=6 silhouette=0.357
k=7 silhouette=0.371K=3 produit le score silhouette le plus élevé (0,848), confirmant que trois clusters décrivent le mieux ces données. Utilisez les deux méthodes ensemble — le graphique du coude vous indique où l'amélioration stagne ; le score silhouette donne un seul chiffre pour comparer les valeurs de K.
Visualiser les clusters K-Means
Les nuages de points révèlent si les clusters sont bien séparés. Pour les jeux de données avec plus de deux caractéristiques, vous appliqueriez d'abord une réduction de dimensionnalité (comme PCA) avant de tracer.
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
X, _ = make_blobs(n_samples=300, centers=3, random_state=42)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
kmeans = KMeans(n_clusters=3, n_init=10, random_state=42)
labels = kmeans.fit_predict(X_scaled)
centers = kmeans.cluster_centers_
plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=labels, cmap='viridis', s=40, alpha=0.7)
plt.scatter(centers[:, 0], centers[:, 1],
c='red', marker='X', s=200, zorder=5, label='Centroids')
plt.legend()
plt.title('K-Means clustering (k=3)')
plt.xlabel('Feature 1 (scaled)')
plt.ylabel('Feature 2 (scaled)')
plt.tight_layout()
plt.show()Chaque couleur représente un cluster. Les croix rouges marquent les centroïdes — la position moyenne de tous les points de ce cluster.
Avantages et limites
Avantages
- Simple et rapide. K-Means est en O(n · k · i) où n est le nombre de points, k est le nombre de clusters et i est le nombre d'itérations. Il passe à l'échelle de millions de points de données avec
MiniBatchKMeans. - Facile à interpréter. Les centroïdes fournissent un résumé concret des valeurs typiques de chaque cluster.
- Fonctionne bien lorsque les clusters sont à peu près sphériques et de taille égale.
- Aucune donnée étiquetée requise. Entièrement non supervisé — aucune variable cible nécessaire.
Limites
- K doit être spécifié à l'avance. Utilisez la méthode du coude et le score silhouette pour guider le choix, mais aucune des deux ne donne une réponse définitive pour des données ambiguës.
- Sensible à l'initialisation. Une mauvaise configuration de départ peut converger vers un optimum local.
k-means++et les redémarrages multiples (n_init=10) réduisent ce risque. - Suppose des clusters sphériques de taille égale. K-Means peine avec des clusters allongés, en forme de croissant ou très inégaux. Utilisez le Clustering hiérarchique ou DBSCAN pour les formes non globulaires.
- Sensible aux valeurs aberrantes. Un seul point extrême peut éloigner un centroïde du vrai centre du cluster. Supprimez ou limitez les valeurs aberrantes avant l'ajustement.
- Sensible à l'échelle. Les caractéristiques sur des échelles différentes doivent être standardisées — consultez le chapitre Scale.
Pièges courants
Ignorer la mise à l'échelle des caractéristiques. C'est l'erreur la plus courante. Sans mise à l'échelle, les caractéristiques à grandes plages numériques dominent le calcul de distance et les caractéristiques à faible portée sont ignorées.
Définir n_init=1. La valeur par défaut dans les anciennes versions de scikit-learn était n_init='warn' (qui avertissait si vous ne la définissiez pas). Définissez toujours n_init=10 (ou plus) pour exécuter K-Means avec 10 initialisations aléatoires différentes et conserver le meilleur résultat.
Réajuster le scaler sur de nouvelles données. Ajustez le StandardScaler une seule fois sur vos données d'entraînement, puis appelez transform() sur toute nouvelle donnée. Rappeler fit_transform() sur de nouvelles données change l'échelle et rend le modèle incohérent.
Traiter les IDs de cluster comme un ordre significatif. Les IDs de cluster (0, 1, 2, …) sont des étiquettes arbitraires assignées par scikit-learn. Ils ne sont pas ordinaux — le cluster 2 n'est pas « plus grand » ou « plus important » que le cluster 0. Comparez les clusters par leurs valeurs de centroïde et leurs comptages de membres.
Utiliser K-Means sur des données non numériques. K-Means nécessite des caractéristiques numériques pour calculer les distances. Pour les données catégorielles, encodez-les d'abord (par exemple avec un encodage one-hot) et réfléchissez si la distance euclidienne a encore du sens pour votre cas d'usage. Consultez le chapitre sur les données catégorielles.
K-Means vs Clustering hiérarchique
| Caractéristique | K-Means | Clustering hiérarchique |
|---|---|---|
| Nombre de clusters | Doit spécifier K avant l'exécution | Peut choisir après l'exécution (inspecter le dendrogramme) |
| Scalabilité | Passe à l'échelle de millions de lignes | O(n²) en mémoire — impraticable au-delà de ~10 000 lignes |
| Déterminisme | Aléatoire (utilisez random_state pour la reproductibilité) | Entièrement déterministe |
| Formes de clusters | Idéal pour les clusters sphériques | Flexible avec différentes méthodes de liaison |
| Résultat | Assignations de clusters plates | Arbre (dendrogramme) montrant l'historique des fusions |
Utilisez K-Means quand votre jeu de données est grand et que vous avez déjà une bonne estimation de K. Utilisez le Clustering hiérarchique quand vous souhaitez explorer plusieurs valeurs de K sans réajuster, ou quand les clusters ne sont pas forcément sphériques.
Liste de contrôle pratique
Suivez cette liste de contrôle lors de l'application de K-Means à un nouveau jeu de données :
- Supprimer ou limiter les valeurs aberrantes — les valeurs extrêmes faussent les centroïdes.
- Encoder les variables catégorielles — K-Means nécessite une entrée numérique.
- Mettre les caractéristiques à l'échelle avec
StandardScaler(ouMinMaxScalersi la distribution des caractéristiques est bornée). - Utiliser le graphique du coude pour réduire les valeurs candidates de K.
- Utiliser le score silhouette pour comparer quantitativement des valeurs spécifiques de K.
- Définir
n_init=10etinit='k-means++'pour une initialisation robuste. - Inspecter les tailles de clusters avec
np.bincount(labels)— des tailles très inégales peuvent indiquer un mauvais K ou une contamination par des valeurs aberrantes. - Visualiser avec un nuage de points (ou une projection PCA pour les données de haute dimension).
Chapitres connexes
- Scale — standardiser les caractéristiques avant le clustering
- Clustering hiérarchique — une alternative qui ne nécessite pas K à l'avance
- K-Nearest Neighbors — une méthode supervisée qui utilise également la distance
- Decision Tree — classification supervisée sans hypothèses de distance
- Train / Test Split — évaluer les modèles d'apprentissage automatique
- Scatter Plot — visualiser les clusters avec Matplotlib