Régression logistique
Pourquoi apprendre ça ?
Un modèle qui prédit "positif" pour tout le monde aura une accuracy de 99% sur un dataset de fraude où 1% des cas sont frauduleux — et sera inutile. Les métriques comme la précision, le rappel et l'AUC-ROC existent précisément pour éviter ces pièges. Savoir choisir la bonne métrique est aussi important que savoir entraîner un modèle.
Analogie
Imagine un détecteur d'incendie dans une usine. Un détecteur hypersensible déclenche l'alarme à la moindre fumée de cuisine (beaucoup de faux positifs — faible précision). Un détecteur trop laxiste rate des vrais incendies (beaucoup de faux négatifs — faible rappel). Le bon équilibre dépend du coût de chaque type d'erreur — c'est exactement ce que les métriques ML permettent de calibrer.
1. Matrice de confusion
Théorie
Pour un classifieur binaire, chaque prédiction tombe dans l'une de ces 4 cases :
- TP (True Positive) : positif prédit correctement
- TN (True Negative) : négatif prédit correctement
- FP (False Positive) : négatif prédit positif — "fausse alarme"
- FN (False Negative) : positif prédit négatif — "raté"
Toutes les métriques de classification découlent de ces 4 nombres.
Matrice de confusion — détection de fraude
import numpy as np
y_true = np.array([0, 1, 1, 0, 1, 0, 0, 1, 0, 1])
y_pred = np.array([0, 1, 0, 0, 1, 1, 0, 1, 0, 0])
# Calcul manuel
TP = int(((y_true == 1) & (y_pred == 1)).sum()) # 4
TN = int(((y_true == 0) & (y_pred == 0)).sum()) # 3
FP = int(((y_true == 0) & (y_pred == 1)).sum()) # 1
FN = int(((y_true == 1) & (y_pred == 0)).sum()) # 2
print(f"TP={TP}, TN={TN}, FP={FP}, FN={FN}")
# TP=4, TN=3, FP=1, FN=2
# Via scikit-learn
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_true, y_pred)
print(cm)
# [[TN FP] [[3 1]
# [FN TP]] [2 4]]
2. Accuracy, Précision, Rappel, F1
Théorie
Accuracy : proportion de prédictions correctes (trompeuse sur les datasets déséquilibrés).
Précision : parmi les prédictions positives, combien sont vraiment positives ?
Rappel (Recall / Sensibilité) : parmi les vrais positifs, combien sont détectés ?
F1-Score : moyenne harmonique de la précision et du rappel.
Quand optimiser quoi :
- Priorité au rappel : détection de maladies, fraude — rater un cas coûte cher
- Priorité à la précision : spam filtering — les faux positifs irritent l'utilisateur
- F1 : équilibre des deux, standard pour les datasets déséquilibrés
Calcul des métriques en Python
from sklearn.metrics import (
accuracy_score, precision_score,
recall_score, f1_score, classification_report
)
import numpy as np
y_true = np.array([0, 1, 1, 0, 1, 0, 0, 1, 0, 1])
y_pred = np.array([0, 1, 0, 0, 1, 1, 0, 1, 0, 0])
print(f"Accuracy : {accuracy_score(y_true, y_pred):.2f}") # 0.70
print(f"Précision : {precision_score(y_true, y_pred):.2f}") # 0.80
print(f"Rappel : {recall_score(y_true, y_pred):.2f}") # 0.60
print(f"F1 : {f1_score(y_true, y_pred):.2f}") # 0.69
print(classification_report(y_true, y_pred,
target_names=["Négatif", "Positif"]))
Checkpoint
Un modèle détecte 90 vrais positifs sur 100 cas positifs réels, et génère 45 faux positifs. Quel est son rappel ?
3. Régression logistique
Théorie
La régression logistique est le classifieur binaire de référence. Malgré son nom, c'est un modèle de classification.
Le modèle prédit la probabilité que sachant :
Entraînement : minimisation de la Binary Cross-Entropy (log-vraisemblance négative).
Décision : on prédit si (seuil ajustable selon le compromis précision/rappel).
Frontière de décision : hyperplan — linéaire dans l'espace des features.
Régression logistique avec PyTorch
import torch
import torch.nn as nn
class LogisticRegression(nn.Module):
def __init__(self, n_features):
super().__init__()
self.linear = nn.Linear(n_features, 1)
def forward(self, x):
return torch.sigmoid(self.linear(x))
# Dataset synthétique binaire
torch.manual_seed(42)
X = torch.randn(200, 5)
y = (X[:, 0] + X[:, 1] > 0).float().unsqueeze(1)
model = LogisticRegression(5)
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
criterion = nn.BCELoss()
for epoch in range(100):
pred = model(X)
loss = criterion(pred, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
with torch.no_grad():
probs = model(X)
preds = (probs >= 0.5).float()
acc = (preds == y).float().mean()
print(f"Accuracy finale : {acc.item():.2f}")
4. Courbe ROC et AUC
Théorie
La courbe ROC (Receiver Operating Characteristic) trace le Taux de vrais positifs (rappel / TPR) en fonction du Taux de faux positifs (FPR) pour tous les seuils de décision :
AUC (Area Under the Curve) : aire sous la courbe ROC.
- AUC = 1.0 : classifieur parfait
- AUC = 0.5 : classifieur aléatoire (diagonale)
Interprétation probabiliste : l'AUC est la probabilité que le modèle assigne un score plus élevé à un exemple positif aléatoire qu'à un exemple négatif aléatoire.
Avantage : l'AUC est invariante au seuil de décision et au déséquilibre de classes.
Courbe ROC et choix du seuil optimal
from sklearn.metrics import roc_auc_score, roc_curve
import numpy as np
y_true = np.array([0, 0, 1, 1, 0, 1, 0, 1, 1, 0])
y_score = np.array([0.1, 0.3, 0.8, 0.7, 0.2, 0.9, 0.4, 0.6, 0.85, 0.15])
auc = roc_auc_score(y_true, y_score)
print(f"AUC-ROC : {auc:.3f}") # 0.96
# Courbe ROC
fpr, tpr, thresholds = roc_curve(y_true, y_score)
# Seuil optimal : Youden Index = max(TPR - FPR)
j_scores = tpr - fpr
best_idx = np.argmax(j_scores)
best_threshold = thresholds[best_idx]
print(f"Seuil optimal : {best_threshold:.2f}")
print(f"TPR : {tpr[best_idx]:.2f}, FPR : {fpr[best_idx]:.2f}")
Checkpoint
Quel AUC-ROC indique un classifieur aléatoire (pas mieux qu'un tirage au sort) ?
5. Overfitting et Underfitting
Théorie
Underfitting : le modèle est trop simple — loss d'entraînement élevée et loss de validation élevée.
- Remède : modèle plus complexe, plus de features, moins de régularisation
Overfitting : le modèle a mémorisé les données — loss d'entraînement faible mais loss de validation élevée.
- Remède : plus de données, régularisation, Early stopping, modèle plus simple
Compromis biais-variance :
- Biais élevé → underfitting
- Variance élevée → overfitting
Techniques de régularisation :
- L2 (Weight Decay) : — pénalise les poids grands
- L1 (Lasso) : — favorise la parcimonie
- Dropout : désactive aléatoirement des neurones à l'entraînement
- Early Stopping : arrêt si la validation loss ne s'améliore plus pendant epochs
Dropout, Weight Decay et Early Stopping
import torch
import torch.nn as nn
class MLPRegularized(nn.Module):
def __init__(self):
super().__init__()
self.net = nn.Sequential(
nn.Linear(128, 256),
nn.ReLU(),
nn.Dropout(p=0.3), # 30% des neurones désactivés a l'entraînement
nn.Linear(256, 128),
nn.ReLU(),
nn.Dropout(p=0.3),
nn.Linear(128, 10)
)
def forward(self, x):
return self.net(x)
model = MLPRegularized()
# weight_decay = régularisation L2
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3, weight_decay=1e-4)
# Early stopping
best_val_loss = float('inf')
patience = 10
patience_counter = 0
for epoch in range(200):
model.train() # Dropout actif
# ... (boucle d'entraînement) ...
model.eval() # Dropout désactivé — IMPORTANT pour l'évaluation
val_loss = 0.05 + 0.001 * epoch # exemple
if val_loss < best_val_loss:
best_val_loss = val_loss
patience_counter = 0
torch.save(model.state_dict(), "best_model.pt")
else:
patience_counter += 1
if patience_counter >= patience:
print(f"Early stopping a l'epoch {epoch}")
break
Évaluer sans appeler model.eval()
model.train() et model.eval() changent le comportement de Dropout et BatchNorm. En mode train(), Dropout désactive aléatoirement des neurones — les prédictions varient à chaque forward pass. Évaluer les métriques sans passer en model.eval() produit des résultats bruités et non reproductibles. Toujours appeler model.eval() (et torch.no_grad()) avant l'inférence.
À retenir
- Matrice de confusion : TP, TN, FP, FN — toutes les métriques en découlent
- Accuracy trompeuse sur les datasets déséquilibrés — préférer F1, précision ou rappel
- Rappel = TP/(TP+FN) : proportion des vrais positifs détectés
- Précision = TP/(TP+FP) : proportion des positifs prédits qui sont vrais
- AUC-ROC : 0.5 = aléatoire, 1.0 = parfait — invariant au seuil et au déséquilibre de classes
- Overfitting : train loss basse, val loss haute → Dropout, L2, Early Stopping, plus de données