Formation ML / Apprentissage non supervisé

DBSCAN

Intermédiaire 40 min 13 sections

La densité remplace le nombre de groupes à fixer d'avance, et ce qui reste isolé est étiqueté bruit.

Objectifs d'apprentissage

  • Comprendre le clustering basé sur la densité
  • Distinguer DBSCAN de K-Means
  • Détecter les outliers automatiquement
  • Régler les paramètres eps et min_samples

Prérequis

Module K-Means Clustering recommandé

Le code de cette page s'exécute dans votre navigateur. Le premier lancement télécharge Python et ses bibliothèques.

Théorie

K-Means vs DBSCAN

K-Means fonctionne bien pour des clusters sphériques de taille similaire. Mais que faire si:

  • Les clusters ont des formes irrégulières?
  • Il y a des outliers/anomalies?
  • On ne connaît pas le nombre de clusters?

DBSCAN (Density-Based Spatial Clustering of Applications with Noise) résout ces problèmes!

Concepts clés:

  • Epsilon (eps): Rayon de voisinage
  • Min_samples: Minimum de voisins pour être un "core point"
  • Core point: Point avec >= min_samples voisins dans son eps
  • Border point: Point dans le voisinage d'un core point
  • Noise point: Ni core ni border (outlier!)

Avantages:

  • Détecte automatiquement le nombre de clusters
  • Trouve des clusters de formes arbitraires
  • Identifie les outliers
  • Pas besoin de spécifier k

Inconvénients:

  • Difficulté avec des densités variables
  • Sensible aux paramètres eps et min_samples
Théorie

Schéma: Fonctionnement de DBSCAN

Types de points:

flowchart TD subgraph Points ["Classification des Points"] CP["Core Point
(>= min_samples voisins)
ROUGE"] BP["Border Point
(voisin d'un core point)
ORANGE"] NP["Noise Point
(outlier)
GRIS"] end class CP ml-node-accent class BP ml-node-brand class NP ml-node-muted

Algorithme:

flowchart TD S["Choisir un point
non visite"] V["Compter les voisins
dans eps"] C{">= min_samples?"} CORE["Core Point
Commencer cluster"] CHECK["Border ou Noise?"] EXPAND["Etendre le cluster
aux voisins"] S --> V --> C C -->|OUI| CORE --> EXPAND C -->|NON| CHECK EXPAND --> S class CORE ml-node-accent

Comparaison avec K-Means:

flowchart LR subgraph KM ["K-Means"] K1["Clusters sphériques"] K2["Nombre k requis"] K3["Pas d'outliers"] end subgraph DB ["DBSCAN"] D1["Formes arbitraires"] D2["k automatique"] D3["Détecte outliers"] end class K1 ml-node-muted class K2 ml-node-muted class K3 ml-node-muted class D1 ml-node-success class D2 ml-node-success class D3 ml-node-success

Exemple concret avec code couleur - Classification d'un point:

Nouveau point P: $\textcolor{#3498db}{x = 3.0}$, $\textcolor{#e67e22}{y = 2.5}$ Paramètres: $\textcolor{#9B7AC4}{eps = 0.5}$, $\textcolor{#F7E64D}{min\_samples = 3}$

Étape 1 - Compter les voisins dans le rayon eps:

Points dans le rayon $\textcolor{#9B7AC4}{eps = 0.5}$ autour de P:

  • $\textcolor{#27ae60}{P_1}$: distance = $\textcolor{#27ae60}{0.3}$ ✓
  • $\textcolor{#27ae60}{P_2}$: distance = $\textcolor{#27ae60}{0.4}$ ✓
  • $\textcolor{#27ae60}{P_3}$: distance = $\textcolor{#27ae60}{0.2}$ ✓
  • $\textcolor{#e74c3c}{P_4}$: distance = $\textcolor{#e74c3c}{0.8}$ ✗ (hors rayon)

Étape 2 - Vérifier min_samples:

Voisins trouves: $\textcolor{#27ae60}{3}$ (incluant P lui-même = 4) $\textcolor{#27ae60}{4} \geq \textcolor{#F7E64D}{3}$ → Condition satisfaite!

Résultat: P est un $\textcolor{#27ae60}{\mathbf{CORE\ POINT}}$

Si voisins < min_samples:

  • Voisin d'un core point → $\textcolor{#e67e22}{\mathbf{BORDER\ POINT}}$
  • Aucun core point proche → $\textcolor{#e74c3c}{\mathbf{NOISE\ (outlier)}}$

Légende des couleurs:

  • $\textcolor{#3498db}{Bleu}$: coordonnée X du point
  • $\textcolor{#e67e22}{Orange}$: coordonnée Y du point
  • $\textcolor{#9B7AC4}{Violet}$: paramètre eps (rayon)
  • $\textcolor{#F7E64D}{Jaune}$: paramètre min_samples
  • $\textcolor{#27ae60}{Vert}$: voisins valides / core point
  • $\textcolor{#e74c3c}{Rouge}$: point hors rayon / noise
Avancé Exercice manuel: À vous de calculer!

Objectif: Appliquer DBSCAN à la main (voisinage, points cœur, clusters).

CONTEXTE

5 points en 1D : A=1, B=2, C=3, D=10, E=11

Paramètres DBSCAN :

  • epsilon (eps) = 1.5 (rayon du voisinage)
  • min_samples = 2

PARTIE 1 : Voisinages

1.1) Listez les voisins de chaque point (distance <= eps) 1.2) Combien de voisins à chaque point (lui-même inclus) ?

PARTIE 2 : Classification des points

Un point est "cœur" si |voisinage| >= min_samples

2.1) Quels points sont des points cœur ? 2.2) Quels points sont des points frontière ? 2.3) Y a-t-il des points bruit ?

PARTIE 3 : Formation des clusters

3.1) Combien de clusters DBSCAN trouve-t-il ? 3.2) Quels points sont dans chaque cluster ?

Avancé Solution de l'exercice manuel

SOLUTION DÉTAILLÉE

Points : A=1, B=2, C=3, D=10, E=11, eps=1.5, min_samples=2

PARTIE 1 : Voisinages

1.1) Voisins (distance <= 1.5) :

  • A(1) : {A, B} (B à distance 1)
  • B(2) : {A, B, C} (A à dist 1, C à dist 1)
  • C(3) : {B, C} (B à distance 1)
  • D(10) : {D, E} (E à distance 1)
  • E(11) : {D, E} (D à distance 1)

1.2) Nombre de voisins :

PointVoisinsNb
A{A,B}2
B{A,B,C}3
C{B,C}2
D{D,E}2
E{D,E}2

PARTIE 2 : Classification des points

2.1) Points cœur (>= 2 voisins) :

$\textcolor{#e74c3c}{\text{Tous les points sont des points cœur !}}$

(A, B, C, D, E ont tous >= 2 voisins)

2.2) Points frontière : $\textcolor{#27ae60}{\text{Aucun}}$

2.3) Points bruit : $\textcolor{#27ae60}{\text{Aucun}}$

PARTIE 3 : Formation des clusters

3.1) Nombre de clusters : $\boxed{2}$

3.2) Composition :

  • $\textcolor{#3498db}{Cluster 1}$ : A, B, C (connectes via B)
  • $\textcolor{#e67e22}{Cluster 2}$ : D, E (connectes directement)

Les clusters 1 et 2 sont séparés car aucun point de {A,B,C} n'est à distance <= 1.5 de {D,E}.

Distance minimale : |C - D| = |3 - 10| = 7 > 1.5

$\boxed{\text{DBSCAN détecte automatiquement 2 groupes naturels}}$

Légende : $\textcolor{#3498db}{Bleu}$: Cluster 1, $\textcolor{#e67e22}{Orange}$: Cluster 2

Code

Explorer les données

print("=" * 70)
print("      EXPLORATION DES DONNEES POUR DBSCAN")
print("=" * 70)

print("\n" + "=" * 70)
print("1. APERCU DU DATASET")
print("=" * 70)
print("""
DBSCAN est un algorithme de clustering BASE SUR LA DENSITE.
Il trouve des regions denses separees par des regions creuses.

Contrairement a K-Means, DBSCAN:
  • Ne necessite pas de specifier le nombre de clusters
  • Peut trouver des clusters de formes arbitraires
  • Detecte automatiquement les outliers (bruit)
""")
display(df.head(10), title="Dataset de Clustering")

print(f"\n  Dimensions du dataset:")
print(f"    • {df.shape[0]} points")
print(f"    • {df.shape[1]} features (x, y)")

print("\n" + "=" * 70)
print("2. STATISTIQUES DE BASE")
print("=" * 70)
print(f"\n{'Feature':<10} | {'Min':^10} | {'Max':^10} | {'Moyenne':^10} | {'Std':^10}")
print("-" * 55)
for col in ['x', 'y']:
    print(f"{col:<10} | {df[col].min():^10.2f} | {df[col].max():^10.2f} | {df[col].mean():^10.2f} | {df[col].std():^10.2f}")

print("\n" + "=" * 70)
print("3. VISUALISATION INITIALE")
print("=" * 70)
print("""
Regardons les donnees sans aucun clustering.
Y voyez-vous des groupes? Des points isoles?
""")

plt.figure(figsize=(10, 6))
plt.scatter(df['x'], df['y'], alpha=0.6, color='#9B7AC4', s=40, edgecolors='black')
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Donnees de Clustering (structure a decouvrir)')
plt.grid(True, alpha=0.3)
plt.show()

print("""
Questions a se poser:
  • Combien de groupes distincts voyez-vous?
  • Y a-t-il des points isoles (outliers potentiels)?
  • Les groupes sont-ils spheriques ou de formes irregulieres?

DBSCAN va repondre a toutes ces questions automatiquement!
""")
Ctrl+Entrée

Cliquez sur « Exécuter » pour voir le résultat.

Code

Appliquer DBSCAN

from sklearn.cluster import DBSCAN
from sklearn.preprocessing import StandardScaler

print("=" * 70)
print("         APPLICATION DE DBSCAN")
print("=" * 70)

# Preparer les donnees
X = df[['x', 'y']].values

print("\n" + "=" * 70)
print("1. NORMALISATION DES DONNEES")
print("=" * 70)
print("""
IMPORTANT: Le parametre eps est une DISTANCE.
Si les features ont des echelles differentes, la normalisation
est cruciale pour que eps ait un sens coherent.
""")

scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

print(f"  Avant normalisation: X dans [{X[:, 0].min():.1f}, {X[:, 0].max():.1f}]")
print(f"  Apres normalisation: X dans [{X_scaled[:, 0].min():.2f}, {X_scaled[:, 0].max():.2f}]")

print("\n" + "=" * 70)
print("2. CONFIGURATION DE DBSCAN")
print("=" * 70)
print("""
Les deux parametres cles de DBSCAN:

• eps (epsilon): Rayon de voisinage
  - Trop petit → trop de clusters et d'outliers
  - Trop grand → tous les points dans un seul cluster

• min_samples: Minimum de points pour former un core point
  - Trop petit → sensible au bruit
  - Trop grand → trop d'outliers

Parametres choisis pour cette demonstration:
""")
eps_val = 0.5
min_samples_val = 5
print(f"    • eps = {eps_val}")
print(f"    • min_samples = {min_samples_val}")

print("\n" + "=" * 70)
print("3. EXECUTION DE DBSCAN")
print("=" * 70)

import time
start = time.time()

dbscan = DBSCAN(eps=eps_val, min_samples=min_samples_val)
labels = dbscan.fit_predict(X_scaled)

exec_time = (time.time() - start) * 1000

print(f"  DBSCAN execute en {exec_time:.2f} ms")

print("\n" + "=" * 70)
print("4. RESULTATS DU CLUSTERING")
print("=" * 70)

n_clusters = len(set(labels)) - (1 if -1 in labels else 0)
n_noise = (labels == -1).sum()

print(f"""
RESULTATS:
  • Nombre de clusters trouves: {n_clusters}
  • Points identifies comme bruit (outliers): {n_noise} ({n_noise/len(X)*100:.1f}%)
  • Points dans des clusters: {len(X) - n_noise} ({(len(X) - n_noise)/len(X)*100:.1f}%)
""")

print("\n  Distribution des labels:")
print("  " + "-" * 40)
for label in sorted(set(labels)):
    count = (labels == label).sum()
    pct = count / len(labels) * 100
    name = "Bruit (outliers)" if label == -1 else f"Cluster {label}"
    bar = "█" * int(pct / 3)
    print(f"    {name:<18}: {count:4d} ({pct:5.1f}%)  {bar}")

print("\n" + "=" * 70)
print("INTERPRETATION")
print("=" * 70)
print(f"""
DBSCAN a trouve {n_clusters} clusters AUTOMATIQUEMENT!

Labels speciaux:
  • -1 = BRUIT (point isole, outlier)
  • 0, 1, 2, ... = Numeros de clusters

Avantage majeur: DBSCAN n'a pas besoin qu'on lui dise
combien de clusters chercher - il les decouvre!
""")
Ctrl+Entrée

Cliquez sur « Exécuter » pour voir le résultat.

Contenu verrouillé
6 / 13

Continuez votre apprentissage

Vous avez exploré 6 sections de ce module. Connectez-vous pour débloquer le reste du cours, incluant les exercices pratiques et les solutions.

Ctrl ou Cmd plus Entrée exécute le code. Tab indente ; Échap puis Tab quitte l'éditeur.