Une distance qui mesure l'écart d'un point au comportement normal en tenant compte des corrélations entre variables. Un magasin peut avoir une surface normale et un CA normal, mais un CA anormal pour sa surface : c'est ce que la distance de Mahalanobis détecte, là où un contrôle variable par variable ne voit rien.
Dans une ville, la taille et le poids des habitants vont ensemble. Quelqu'un de 1,60 m et 95 kg n'a ni une taille ni un poids extrêmes, mais la combinaison est rare. La distance de Mahalanobis mesure cette rareté-là.
On calcule le centre du nuage (la moyenne de chaque variable) et la matrice de covariance, qui dit comment les variables varient ensemble.
Un écart dans le sens de la corrélation (grande surface et gros CA) coûte peu. Un écart à contre-courant (petite surface et gros CA) coûte cher. On obtient une distance en « nombre d'écarts-types », toutes variables confondues.
Si les données sont à peu près gaussiennes, la distance au carré suit une loi du khi-deux. Son 99e centile donne un seuil : environ 1 % des points normaux le dépassent par hasard.
Une ligne par magasin : surface de vente en m² et CA annuel en k€. Les deux sont très liés (corrélation de 0,9 sur le jeu d'exemple) : plus le magasin est grand, plus il vend.
Chaque magasin reçoit une distance. Sur le jeu d'exemple, 7 magasins dépassent le seuil, dont 3 qu'aucun contrôle variable par variable n'aurait signalés. Exemple : 951 m² et 932 k€ de CA, deux valeurs banales, mais un CA très élevé pour cette surface.
Sans étiquette, on vérifie d'abord que le volume d'alertes reste traitable par le contrôle de gestion. Ensuite, chaque alerte est qualifiée sur le terrain : erreur de saisie, magasin sous-performant, ou pratique à dupliquer.
Pas d'hyperparamètre à optimiser, mais trois décisions qui changent la liste des alertes.
La moyenne et la covariance classiques sont elles-mêmes tirées par les points extrêmes, qui masquent alors leur propre anomalie. La version robuste MCD (déterminant de covariance minimum) les calcule sur le cœur des données. À utiliser par défaut.
Le 97,5e ou le 99e centile du khi-deux, avec autant de degrés de liberté que de variables. Le choix dépend surtout de la capacité de traitement des alertes. Si les données sont loin d'être gaussiennes, fixer plutôt un seuil sur la distribution observée des distances.
Ne garder que des variables dont la relation a un sens métier. Passer au logarithme les variables très asymétriques (montants, durées) pour rapprocher le nuage d'une ellipse.
# Magasins atypiques : distance de Mahalanobis en R
library(robustbase)
magasins <- read.csv("magasins.csv")
X <- magasins[, c("surface_m2", "ca_k")]
cat("Corrélation surface / CA :", round(cor(X)[1, 2], 2), "\n")
# Centre et covariance robustes (MCD) : les magasins atypiques ne faussent pas la référence
set.seed(42)
mcd <- covMcd(X)
magasins$d2 <- mahalanobis(X, center = mcd$center, cov = mcd$cov) # distance au carré
# Seuil : 99e centile du khi-deux à 2 degrés de liberté
seuil <- qchisq(0.99, df = ncol(X))
# Score z : écart de chaque variable prise seule, en écarts-types
magasins$z_max <- apply(abs(scale(X)), 1, max)
alertes <- magasins[magasins$d2 > seuil, ]
alertes <- alertes[order(-alertes$d2), ]
cat("Seuil :", round(seuil, 2), "| magasins signalés :", nrow(alertes), "\n")
cat("Dont normaux variable par variable (|z| < 2) :", sum(alertes$z_max < 2), "\n")
print(alertes[, c("magasin", "zone", "surface_m2", "ca_k", "d2", "z_max")], digits = 3)
# Magasins atypiques : distance de Mahalanobis en Python
import pandas as pd
from scipy.stats import chi2
from sklearn.covariance import MinCovDet
magasins = pd.read_csv("magasins.csv")
variables = ["surface_m2", "ca_k"]
X = magasins[variables]
print("Corrélation surface / CA :", round(X.corr().iloc[0, 1], 2))
# Centre et covariance robustes (MCD) : les magasins atypiques ne faussent pas la référence
mcd = MinCovDet(random_state=42).fit(X)
magasins["d2"] = mcd.mahalanobis(X) # distance au carré
# Seuil : 99e centile du khi-deux à 2 degrés de liberté
seuil = chi2.ppf(0.99, df=len(variables))
# Score z : écart de chaque variable prise seule, en écarts-types
magasins["z_max"] = ((X - X.mean()) / X.std()).abs().max(axis=1)
alertes = magasins[magasins["d2"] > seuil].sort_values("d2", ascending=False)
print("Seuil :", round(seuil, 2), "| magasins signalés :", len(alertes))
print("Dont normaux variable par variable (|z| < 2) :", (alertes["z_max"] < 2).sum())
print(alertes[["magasin", "zone"] + variables + ["d2", "z_max"]].round(1).to_string(index=False))
La distance euclidienne traite toutes les directions pareil et dépend des unités. La distance de Mahalanobis divise par la variabilité de chaque variable et tient compte des corrélations. Sans corrélation et avec des variables standardisées, les deux coïncident.
Avec des données à peu près gaussiennes, la distance au carré suit une loi du khi-deux à p degrés de liberté, p étant le nombre de variables. On prend souvent son 97,5e ou 99e centile : 9,21 pour 2 variables au seuil de 99 %.
Les anomalies déforment la moyenne et la covariance classiques, ce qui réduit leur propre distance : c'est l'effet de masque. L'estimateur MCD calcule la référence sur la partie la plus compacte des données, ce qui rend les vrais points atypiques plus visibles.
Plus simple, mais aveugle aux combinaisons anormales de valeurs individuellement banales.
Voir la fiche → pour les données complexesAucune hypothèse de forme, gère beaucoup de variables et des relations non linéaires. Moins lisible, pas de seuil statistique.
Voir la fiche → quand il y a plusieurs groupesCompare chaque point à ses voisins plutôt qu'à un centre unique. Adapté aux données en grappes.
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