Un algorithme qui cherche les zones où les points sont serrés et en fait des groupes, quelle que soit leur forme. Les points isolés sont déclarés bruit au lieu d'être rangés de force quelque part. On ne fixe pas le nombre de groupes, mais un rayon et un nombre minimum de voisins.
Vue d'avion d'une plage : les groupes de serviettes serrées forment des familles, les serviettes isolées ne font partie d'aucune. Pas besoin de savoir d'avance combien de familles il y a.
Dans un rayon eps. Un point qui a au moins minPts voisins, lui compris, est un point cœur : il se trouve dans une zone dense.
Deux points cœurs à moins de eps l'un de l'autre appartiennent au même groupe. De proche en proche, le groupe s'étend et peut prendre n'importe quelle forme.
Un point non cœur mais proche d'un point cœur rejoint son groupe. Les autres points sont déclarés bruit : ils n'appartiennent à aucun groupe.
Température et vibration d'une machine. La température suit un cycle jour / nuit : on travaille sur son écart au profil habituel de l'heure, pour ne pas confondre un après-midi chaud et une anomalie.
DBSCAN trouve deux groupes : le régime de janvier-février et un régime plus chaud et plus vibrant à partir du 28 février. Parmi les 35 mesures déclarées bruit, les 8 plus chaudes pour leur heure, environ 8 à 10 °C au-dessus du profil, sont des pics isolés de janvier-février.
Il n'y a pas d'étiquette : on juge sur le sens métier. Le passage d'un groupe à l'autre date le changement de comportement de la machine. Les points de bruit forment une liste courte à faire vérifier par la maintenance.
Noms donnés pour R (paquet dbscan) et Python (scikit-learn). Dans les deux, le point lui-même compte parmi ses voisins.
Le rayon du voisinage, sur données standardisées. Trop petit : tout devient bruit. Trop grand : tout fusionne. On le choisit au coude du graphe des distances au k-ième voisin (kNNdistplot en R).
Le nombre de points requis dans le rayon pour former une zone dense. Règle usuelle : au moins le nombre de variables plus un, souvent le double. Plus il est grand, plus il y a de bruit.
Standardiser, et retirer les effets connus avant de chercher des groupes, comme le cycle jour / nuit ici. Sans cette étape, DBSCAN retrouve le cycle au lieu des anomalies.
# Surveillance d'une machine : DBSCAN en R
library(dbscan)
capteurs <- read.csv("capteurs_machine.csv")
heure <- as.integer(substr(capteurs$horodatage, 12, 13))
# Écart de température au profil habituel de l'heure (retire le cycle jour / nuit)
capteurs$ecart_temp <- capteurs$temperature - ave(capteurs$temperature, heure, FUN = median)
X <- scale(capteurs[, c("ecart_temp", "vibration")])
# Aide au choix de eps : chercher le coude de la courbe des distances au 9e voisin
kNNdistplot(X, k = 9)
# eps : rayon du voisinage ; minPts : points requis, le point lui-même compris
modele <- dbscan(X, eps = 0.3, minPts = 10)
capteurs$groupe <- modele$cluster # 0 = bruit
# Groupes trouvés : effectif par mois et mesures moyennes
print(table(groupe = capteurs$groupe, mois = substr(capteurs$horodatage, 1, 7)))
print(aggregate(cbind(temperature, vibration) ~ groupe, data = capteurs, FUN = mean))
bruit <- capteurs[capteurs$groupe == 0, ]
print(head(bruit[order(-bruit$ecart_temp), c("horodatage", "temperature", "ecart_temp")], 10))
# Surveillance d'une machine : DBSCAN en Python
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import DBSCAN
capteurs = pd.read_csv("capteurs_machine.csv")
heure = pd.to_datetime(capteurs["horodatage"]).dt.hour
# Écart de température au profil habituel de l'heure (retire le cycle jour / nuit)
capteurs["ecart_temp"] = capteurs["temperature"] - capteurs.groupby(heure)["temperature"].transform("median")
X = StandardScaler().fit_transform(capteurs[["ecart_temp", "vibration"]])
# eps : rayon du voisinage ; min_samples : points requis pour une zone dense
modele = DBSCAN(eps=0.3, min_samples=10).fit(X)
capteurs["groupe"] = modele.labels_
# Groupes trouvés (-1 = bruit) : effectif par mois et mesures moyennes
print(pd.crosstab(capteurs["groupe"], capteurs["horodatage"].str[:7]))
print(capteurs.groupby("groupe")[["temperature", "vibration"]].mean().round(2))
# Les mesures isolées les plus chaudes pour leur heure
print(capteurs[capteurs["groupe"] == -1].nlargest(10, "ecart_temp")[["horodatage", "temperature", "ecart_temp"]].round(2))
On calcule pour chaque point la distance à son k-ième voisin, avec k = minPts - 1, puis on trie ces distances et on les trace. Le coude de la courbe, où elle se met à monter vite, donne une bonne valeur de eps. On vérifie ensuite que les groupes obtenus ont un sens métier.
K-means demande le nombre de groupes, les suppose ronds et range chaque point dans un groupe. DBSCAN trouve seul le nombre de groupes, accepte toutes les formes et laisse les points isolés en bruit. En revanche, DBSCAN dépend fortement de eps et gère mal les densités variables.
Dans scikit-learn, -1 désigne le bruit : les points qui ne sont ni des points cœurs ni proches d'un point cœur. Dans le paquet R dbscan, le bruit est codé 0. Ces points méritent souvent un examen à part, car ce sont des cas atypiques.
Explore tous les rayons à la fois et garde les groupes les plus stables. S'adapte aux zones de densités différentes.
Voir la fiche → pour dater le changementTravaille directement sur la série temporelle et donne la date exacte du changement de régime.
Voir la fiche → pour les anomalies seulesDonne un score d'anomalie à chaque point, sans chercher de groupes. Plus adapté quand seul l'inhabituel compte.
Voir la fiche →Dataistudio forme les équipes au machine learning et à l'IA, sur des cas concrets.
Nous utilisons des cookies de mesure d'audience et de suivi publicitaire pour comprendre la fréquentation du site et l'efficacité de nos annonces. Rien n'est déposé sans votre accord. En savoir plus