Mathématiques du ML : optimisation, algèbre linéaire, SVD et PCA
Presque tout l'apprentissage automatique se ramène à deux objets : un problème d'optimisation que l'on résout par descente de gradient, et des décompositions matricielles qui révèlent la structure des données. Ce module traite les deux depuis le problème qu'ils posent, avec une insistance particulière sur la SVD et la PCA — les deux outils qui reviennent partout, de la compression à la détection d'anomalies.
📋 Au programme
1. Apprendre, c'est minimiser un risque
On cherche une fonction \(f_\theta\), paramétrée par \(\theta\), qui prédit \(y\) à partir de \(x\). L'idéal serait de minimiser le risque, c'est-à-dire l'erreur moyenne sur la distribution réelle des données :
Mais cette distribution \(\mathcal{D}\) est inconnue : on n'observe qu'un échantillon. On minimise donc le risque empirique, la moyenne de l'erreur sur les données dont on dispose, complété d'un terme de régularisation qui pénalise la complexité :
Tout le vocabulaire du ML se lit dans cette formule, et il vaut la peine de s'y arrêter. La fonction de perte \(\ell\) encode ce que l'on considère comme une erreur — c'est un choix, pas une donnée. Le surapprentissage est exactement l'écart entre \(\hat R\), que l'on minimise, et \(R\), qui nous intéresse : un modèle peut atteindre un risque empirique nul en mémorisant les données sans rien avoir appris. La régularisation \(\Omega\) — typiquement \(\|\theta\|_2^2\) ou \(\|\theta\|_1\) — restreint l'espace des fonctions accessibles pour réduire cet écart ; le module 10 montre qu'elle équivaut à une croyance a priori sur l'ordre de grandeur des paramètres.
Quadratique (ŷ - y)² régression. Pénalise les grandes erreurs au CARRÉ :
un point aberrant tire tout le modèle vers lui.
Absolue (MAE) |ŷ - y| robuste aux aberrants, non dérivable en 0.
Huber quadratique près le compromis : quadratique au centre, linéaire
de 0, linéaire loin au-delà d'un seuil δ.
Entropie -Σ y_k log(ŷ_k) classification. Pénalise la CONFIANCE dans une
croisée erreur, pas seulement l'erreur.
Hinge max(0, 1 - y·ŷ) marge (SVM, module 14).
Pinball asymétrique régression sur un quantile (module 17).Pourquoi ne pas optimiser directement le taux d'erreur ?
En classification, ce qui nous intéresse est souvent le taux de bonnes réponses. On ne peut pourtant pas l'optimiser directement : c'est une fonction en escalier, de gradient nul presque partout et indéfini aux sauts — la descente de gradient n'a rien à suivre. L'entropie croisée est une approximation continue et dérivable de cet objectif : c'est ce qu'on appelle une perte de substitution. Il faut garder cette distinction en tête, car elle explique qu'un modèle puisse améliorer sa perte sans améliorer sa métrique métier.
2. Descente de gradient : le mécanisme
Le gradient \(\nabla \hat R(\theta)\) est le vecteur des dérivées partielles : il pointe dans la direction de plus forte croissance de la fonction. Pour minimiser, on avance donc à l'opposé, d'un pas \(\eta\) appelé taux d'apprentissage :
L'image usuelle est celle d'un randonneur dans le brouillard : il ne voit pas la vallée, mais il sent la pente sous ses pieds et descend dans la direction la plus raide. Deux questions se posent immédiatement, et ce sont les seules qui comptent : quelle taille de pas ? et quand s'arrêter ?
import numpy as np
def descente(X, y, eta=0.01, n_iter=1000):
"""Régression linéaire par descente de gradient, sans bibliothèque."""
n, p = X.shape
theta = np.zeros(p)
historique = []
for t in range(n_iter):
residus = X @ theta - y # erreur de prédiction
perte = (residus ** 2).mean() # risque empirique (MSE)
gradient = 2 / n * X.T @ residus # dérivée analytique du MSE
theta -= eta * gradient # LE pas de descente
historique.append(perte)
if t > 0 and abs(historique[-2] - perte) < 1e-10: # critère d'arrêt
break
return theta, historiqueη trop petit (1e-5) la perte descend, mais il faudrait 100 000 itérations.
Symptôme : courbe presque plate, qui descend encore à la fin.
η bien réglé (1e-2) décroissance rapide puis plateau. C'est ce qu'on veut.
η trop grand (1.0) la perte OSCILLE, puis explose vers l'infini ou NaN.
Symptôme : perte qui remonte, ou nan au bout de 3 itérations.
perte │╲ perte │╲ ╱╲ perte │╲
│ ╲___ │ ╲__╱ ╲ │ ╲
│ ╲____ │ ╲_ │ ╲___________
└──────────── trop petit └──────────── trop grand └──────── correct
Deux garde-fous théoriques valent d'être connus. Si \(\hat R\) est convexe — une seule vallée, pas de minimum local — et si son gradient est \(L\)-lipschitzien, la méthode converge vers le minimum global pour tout \(0 \lt \eta \lt 2/L\), où \(L\) est la plus grande courbure de la fonction. En pratique on ne connaît pas \(L\), d'où la recherche empirique du taux (module 16). Et en deep learning, la fonction n'est pas convexe : on ne cherche plus le minimum global, on se contente d'un bon minimum local — ce qui, empiriquement, suffit largement.
3. Pourquoi ça converge lentement
Pour une fonction quadratique de matrice hessienne \(H\) (la matrice des dérivées secondes, qui décrit la courbure), la vitesse de convergence dépend du conditionnement \(\kappa = \lambda_{\max}/\lambda_{\min}\), rapport de la plus grande à la plus petite valeur propre. L'erreur décroît comme :
Pour \(\kappa = 10\), le facteur vaut 0,82 par itération : la convergence est rapide. Pour \(\kappa = 10^4\), il vaut 0,9998 : il faut des dizaines de milliers d'itérations pour progresser.
κ ≈ 1 : lignes de niveau CIRCULAIRES κ ≫ 1 : vallée ALLONGÉE
le gradient pointe vers le minimum le gradient pointe vers les PAROIS
╭───────╮ ╭─────────────────────────╮
╭─┤ ·───┼─► minimum ╭─┤ ·╲ │
│ ╰───────╯ │ │ ╲╱╲╱╲╱╲──► minimum │
╰─────────╯ │ ╰──────────────────────── ╯
╰───────────────────────────╯
trajet direct zigzag : on rebondit d'une paroi à l'autre
et on avance très peu dans le bon sens4. SGD, momentum, Adam
Le problème du coût
Calculer \(\nabla \hat R\) demande de parcourir les \(n\) exemples. Avec un million d'images, un seul pas devient hors de prix — et il en faut des milliers. La descente stochastique (SGD) estime le gradient sur un petit lot tiré au hasard :
L'estimation est bruitée mais non biaisée — elle vise juste en moyenne — et surtout mille fois moins coûteuse. On fait donc mille pas approximatifs au lieu d'un pas exact, un échange presque toujours gagnant. Le bruit a même une vertu : il aide à s'échapper des points selles, ces zones plates qui ne sont ni des minima ni des maxima et qui sont omniprésentes en grande dimension — bien plus que les minima locaux, contrairement à une idée reçue.
Momentum : lisser la trajectoire
Pour traverser la vallée allongée de la section précédente sans zigzaguer, on accumule une vitesse, comme une bille lourde qui ne change pas de direction à chaque bosse :
Avec \(\beta = 0{,}9\), le pas effectif est amplifié d'un facteur \(1/(1-\beta) = 10\) dans les directions où le gradient reste constant, tandis que les composantes qui oscillent s'annulent d'un pas sur l'autre. La variante de Nesterov évalue le gradient au point extrapolé plutôt qu'au point courant, ce qui la rend un peu plus stable.
Adam : un taux par paramètre
L'idée des méthodes adaptatives : les paramètres n'ont pas tous la même échelle de gradient, donc pas la même taille de pas idéale. Adam combine le momentum (moment d'ordre 1) et une normalisation par l'amplitude typique du gradient (moment d'ordre 2) :
Le rapport \(\hat m_t / \sqrt{\hat v_t}\) est une sorte de « rapport signal sur bruit » du gradient : un paramètre dont le gradient est constamment dans le même sens avance vite, un paramètre dont le gradient oscille avance lentement. Les corrections de biais \(\hat m, \hat v\) compensent l'initialisation à zéro des moments, qui sous-estimerait fortement les premiers pas. Valeurs usuelles : \(\beta_1 = 0{,}9\), \(\beta_2 = 0{,}999\), \(\varepsilon = 10^{-8}\).
def adam(gradient_fn, theta, eta=1e-3, b1=0.9, b2=0.999, eps=1e-8, n_iter=1000):
m = np.zeros_like(theta) # moyenne mobile du gradient
v = np.zeros_like(theta) # moyenne mobile du gradient AU CARRÉ
for t in range(1, n_iter + 1):
g = gradient_fn(theta)
m = b1 * m + (1 - b1) * g
v = b2 * v + (1 - b2) * g ** 2
m_corr = m / (1 - b1 ** t) # correction de biais : sans elle, les premiers
v_corr = v / (1 - b2 ** t) # pas seraient beaucoup trop petits
theta -= eta * m_corr / (np.sqrt(v_corr) + eps)
return thetaAdamW corrige un défaut subtil mais réel : dans Adam, la pénalité \(L^2\) ajoutée à la perte est elle aussi divisée par \(\sqrt{\hat v_t}\), si bien que la régularisation n'est plus uniforme entre paramètres. AdamW découple la décroissance des poids du gradient adaptatif ; c'est aujourd'hui le choix par défaut pour les transformers.
SGD + momentum converge souvent vers de MEILLEURS minima (meilleure généralisation),
mais demande un réglage soigneux du taux et d'un planificateur.
Référence en vision, pour des CNN entraînés de zéro.
Adam / AdamW robuste, marche presque tout de suite. Défaut en NLP, transformers,
et sur tout problème aux gradients hétérogènes ou creux.
L-BFGS second ordre approché : excellent sur les petits problèmes lisses et
déterministes (peu de paramètres, pas de mini-lots). Inutilisable en
deep learning : mémoire et incompatibilité avec le bruit stochastique.Planification et écrêtage
Un taux constant finit par empêcher la convergence fine : on tourne autour du minimum sans jamais s'en approcher. On le fait donc décroître. Le schéma cosine annealing avec warmup est devenu standard : quelques centaines de pas de montée linéaire — le temps que les statistiques des moments adaptatifs se stabilisent —, puis une décroissance en cosinus jusqu'à presque zéro.
S'y ajoute le gradient clipping, qui borne la norme du gradient : \(g \leftarrow \min(1, c/\|g\|)\,g\). Un seul lot atypique peut produire un gradient énorme qui projette les paramètres dans une zone absurde et détruit des heures d'entraînement ; l'écrêtage garde la direction mais limite la longueur du pas. Indispensable sur les RNN et les transformers.
opt = torch.optim.AdamW(modele.parameters(), lr=3e-4, weight_decay=0.01)
sched = torch.optim.lr_scheduler.OneCycleLR(opt, max_lr=3e-4,
total_steps=n_epoques * len(chargeur))
for xb, yb in chargeur:
opt.zero_grad(set_to_none=True)
perte_fn(modele(xb), yb).backward()
torch.nn.utils.clip_grad_norm_(modele.parameters(), max_norm=1.0) # écrêtage
opt.step()
sched.step() # le taux évolue à CHAQUE pas5. Algèbre linéaire : résoudre sans inverser
La règle la plus utile de tout ce module : on n'inverse jamais une matrice. Pour résoudre \(Ax = b\), calculer \(A^{-1}\) puis multiplier coûte environ deux fois plus cher et est numériquement bien moins stable que de résoudre directement le système. L'inverse est un objet mathématique commode, pas un objet numérique.
import numpy as np from scipy.linalg import cho_factor, cho_solve # À NE PAS FAIRE x = np.linalg.inv(A) @ b # À FAIRE : factorisation LU avec pivot x = np.linalg.solve(A, b) # Si A est symétrique définie positive (matrice de covariance, noyau de GP) : # Cholesky, deux fois plus rapide encore c, low = cho_factor(A) x = cho_solve((c, low), b) # Si le système est surdéterminé (moindres carrés) : QR, sans jamais former AᵀA beta, residus, rang, valeurs_sing = np.linalg.lstsq(A, b, rcond=None)
LU A = PLU systèmes carrés généraux O(n³/3) Cholesky A = LLᵀ A symétrique définie positive O(n³/6) — la plus rapide QR A = QR moindres carrés, orthogonalisation O(2mn²) Spectrale A = QΛQᵀ A symétrique : axes et valeurs propres réels SVD A = UΣVᵀ TOUTE matrice, même rectangulaire la plus informative
Le cas des moindres carrés
La solution analytique \(\hat\beta = (X^\top X)^{-1} X^\top y\) est correcte en mathématiques et dangereuse en calcul : former \(X^\top X\) élève le conditionnement au carré, puisque \(\kappa(X^\top X) = \kappa(X)^2\). Avec des variables corrélées — donc un \(\kappa(X)\) déjà élevé —, la précision s'effondre, et l'on peut obtenir des coefficients aberrants sur des données parfaitement propres. C'est pourquoi lstsq passe par une QR ou une SVD, et pourquoi sklearn.linear_model.LinearRegression appelle scipy.linalg.lstsq plutôt que la formule fermée.
6. La SVD, en détail
La décomposition en valeurs singulières s'applique à n'importe quelle matrice réelle \(A\) de taille \(m \times n\) — carrée ou non, inversible ou non :
avec \(U\) et \(V\) orthogonales (\(U^\top U = I\) : leurs colonnes forment une base orthonormée) et \(\Sigma\) diagonale à coefficients positifs décroissants \(\sigma_1 \geq \sigma_2 \geq \dots \geq 0\), les valeurs singulières.
Intuition géométrique
Toute application linéaire, aussi compliquée soit-elle, se décompose en trois opérations élémentaires : une rotation (\(V^\top\)), une dilatation selon les axes (\(\Sigma\)), une seconde rotation (\(U\)). Autrement dit, l'image de la sphère unité par \(A\) est toujours un ellipsoïde : les \(\sigma_i\) sont les longueurs de ses demi-axes, et les colonnes de \(U\) leurs directions. Une valeur singulière quasi nulle signifie que \(A\) écrase complètement une direction de l'espace — c'est la signature d'une redondance dans les données.
Liens utiles
- \(A^\top A = V \Sigma^\top\Sigma V^\top\) : les \(\sigma_i^2\) sont les valeurs propres de \(A^\top A\), et \(V\) en donne les vecteurs propres. Calculer la SVD directement reste plus stable que diagonaliser \(A^\top A\), pour la raison de conditionnement vue plus haut.
- Le rang de \(A\) est le nombre de \(\sigma_i\) non nuls ; numériquement, le nombre de \(\sigma_i\) au-dessus d'un seuil.
- Le conditionnement vaut \(\kappa = \sigma_1/\sigma_r\) : la SVD le donne donc directement.
- La pseudo-inverse \(A^{+} = V\Sigma^{+}U^\top\) (où \(\Sigma^+\) inverse les \(\sigma_i\) non nuls et laisse les autres à zéro) fournit la solution de norme minimale des moindres carrés, y compris pour un système sous-déterminé.
Approximation de rang faible : Eckart–Young
En ne gardant que les \(k\) premiers termes de la somme :
on obtient la meilleure approximation de rang \(k\) qui existe, au sens des normes de Frobenius et spectrale. Aucune autre matrice de rang \(k\), obtenue par quelque méthode que ce soit, ne fait mieux — et l'erreur commise est connue exactement :
Ce théorème fonde la compression par SVD, la PCA, le débruitage et les systèmes de recommandation par factorisation matricielle (module 23).
import numpy as np, matplotlib.pyplot as plt
img = plt.imread("photo.png").mean(axis=2) # niveaux de gris, (m, n)
U, s, Vt = np.linalg.svd(img, full_matrices=False)
# combien de composantes pour conserver 95 % de "l'énergie" ?
energie = np.cumsum(s ** 2) / np.sum(s ** 2)
k = int(np.searchsorted(energie, 0.95) + 1)
approx = (U[:, :k] * s[:k]) @ Vt[:k] # reconstruction de rang k
taux = k * (img.shape[0] + img.shape[1] + 1) / img.size
print(f"k={k} : {taux:.1%} des coefficients d'origine, 95 % de l'énergie conservée")
# une photo 1024×1024 se reconstruit souvent avec k ≈ 60, soit 12 % des donnéesCoût et passage à l'échelle
La SVD complète coûte \(O(\min(mn^2, m^2n))\) — impraticable sur une grande matrice. Deux issues : la SVD tronquée par méthode de Lanczos (scipy.sparse.linalg.svds), efficace sur les matrices creuses, et surtout la SVD randomisée (la fonction randomized_svd de sklearn.utils.extmath), qui projette d'abord les données sur un sous-espace aléatoire de dimension \(k+p\) et coûte \(O(mnk)\). Sur une matrice 100 000 × 10 000 dont on veut 50 composantes, c'est la différence entre quelques secondes et plusieurs heures. L'idée sous-jacente est remarquable : une projection aléatoire préserve approximativement les distances (lemme de Johnson-Lindenstrauss), donc capture l'essentiel du sous-espace dominant.
Où la SVD apparaît
- PCA — section suivante : c'est littéralement une SVD des données centrées ;
- Ridge — la régularisation s'y lit comme un filtrage spectral (voir plus bas) ;
- LSA — réduction d'une matrice terme-document, ancêtre des embeddings (module 22) ;
- Recommandation — factorisation d'une matrice utilisateurs × items très creuse (module 23) ;
- Débruitage et détection d'anomalies — le signal se concentre dans les grandes valeurs singulières, le bruit se répartit sur les petites ;
- Réduction de modèle — la POD des simulations physiques est une SVD de champs (module 21) ;
- LoRA — l'adaptation de LLM par matrices de rang faible repose sur la même intuition (module 22).
Ridge vu par la SVD
En écrivant \(X = U\Sigma V^\top\), la prédiction de la régression ridge devient :
La lecture est limpide : ridge projette \(y\) sur les directions principales et rétrécit chacune d'un facteur \(\sigma_i^2/(\sigma_i^2+\lambda)\), compris entre 0 et 1. Les directions de forte variance (\(\sigma_i^2 \gg \lambda\)) sont conservées presque intactes ; celles de faible variance — précisément celles où l'estimation est instable — sont écrasées. La régularisation n'est donc pas un bricolage numérique : c'est un filtrage spectral qui atténue ce qui est mal déterminé.
7. La PCA, en détail
L'analyse en composantes principales cherche un système d'axes orthogonaux, ordonnés, sur lesquels projeter les données en perdant le moins d'information possible.
Deux formulations équivalentes
Variance maximale. On cherche la direction unitaire \(w\) qui maximise la variance des projections. Avec \(X\) centré et \(C = \frac{1}{n-1}X^\top X\) la matrice de covariance :
Le lagrangien \(w^\top C w - \lambda(w^\top w - 1)\), dérivé et annulé, donne \(Cw = \lambda w\) : les directions principales sont les vecteurs propres de la covariance, et la variance capturée par chacune est sa valeur propre. On itère en imposant l'orthogonalité aux directions déjà retenues.
Erreur de reconstruction minimale. On cherche le sous-espace de dimension \(k\) minimisant \(\sum_i \|x_i - \Pi_k x_i\|^2\), où \(\Pi_k\) est la projection sur ce sous-espace. C'est exactement le problème d'Eckart–Young : la solution est donnée par les \(k\) premiers vecteurs singuliers. Les deux formulations coïncident — maximiser la variance conservée, c'est minimiser ce qu'on jette.
Le lien avec la SVD
Si \(X\) (centré) se décompose en \(U\Sigma V^\top\), alors \(C = \frac{1}{n-1}V\Sigma^2V^\top\). Donc :
- les axes principaux sont les colonnes de \(V\) (les loadings) ;
- les composantes principales (coordonnées projetées, ou scores) valent \(XV = U\Sigma\) ;
- la variance expliquée par l'axe \(i\) vaut \(\sigma_i^2/(n-1)\).
C'est pourquoi toutes les implémentations sérieuses passent par la SVD de \(X\) plutôt que par la diagonalisation de \(X^\top X\) : même résultat, bien meilleure stabilité numérique.
import numpy as np
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
X = np.random.randn(500, 20) @ np.random.randn(20, 20) # données corrélées
# ── version manuelle ──
Xs = StandardScaler().fit_transform(X) # centrer ET réduire (voir encadré)
U, s, Vt = np.linalg.svd(Xs, full_matrices=False)
scores = U * s # = Xs @ Vt.T : les composantes
var_expliquee = s ** 2 / np.sum(s ** 2)
print(np.cumsum(var_expliquee)[:5]) # part de variance cumulée
# reconstruction avec k composantes, et erreur associée
k = 5
X_reconstruit = scores[:, :k] @ Vt[:k]
erreur = np.linalg.norm(Xs - X_reconstruit) ** 2 / np.linalg.norm(Xs) ** 2
print(f"erreur relative avec {k} composantes : {erreur:.1%}")
# ── version scikit-learn (identique, au signe des axes près) ──
pca = PCA(n_components=0.95) # garder 95 % de la variance
Z = pca.fit_transform(Xs)
print(Z.shape, pca.explained_variance_ratio_.sum())
print(pca.components_[0]) # le premier axe, en fonction des variablesCombien de composantes garder ?
- Variance cumulée — le plus courant : garder 90 ou 95 % de la variance ;
- Coude du scree plot — la rupture de pente du spectre des \(\sigma_i^2\), là où les composantes suivantes n'apportent presque plus rien ;
- Critère de Kaiser — sur données standardisées, garder les valeurs propres supérieures à 1 : une composante doit expliquer plus qu'une variable d'origine ; grossier mais commode ;
- Validation croisée — si la PCA sert d'étape de prétraitement, le nombre de composantes est un hyperparamètre comme un autre, à optimiser sur la performance finale.
Interpréter, et ne pas sur-interpréter
Les loadings (colonnes de \(V\)) disent comment chaque variable d'origine contribue à chaque axe : ils permettent parfois de nommer un axe — « taille globale », « contraste chaud/froid ». Mais une composante principale reste une combinaison linéaire de toutes les variables : elle n'a aucune raison d'avoir un sens physique, et le signe des axes est arbitraire (rien ne distingue \(w\) de \(-w\)). Pour une décomposition interprétable à coefficients positifs, la NMF est souvent plus parlante ; pour séparer des sources indépendantes, c'est l'ICA.
Usages, limites et variantes
Décorréler des variables les composantes sont orthogonales par construction Compresser / débruiter le bruit se disperse dans les petites valeurs propres Visualiser en 2D projection sur les 2 axes de plus forte variance Accélérer un modèle moins de dimensions = moins de calcul Détecter des anomalies erreur de reconstruction élevée = point atypique Traiter la colinéarité évite l'explosion de variance des coefficients
Limites. La PCA est linéaire : elle ne capture pas une variété courbe (un rouleau enroulé sur lui-même). Elle est non supervisée : rien ne garantit que les axes de forte variance soient ceux qui prédisent \(y\) — on peut parfaitement jeter la direction la plus informative, ce que corrigent la PLS ou une LDA en classification. Elle est sensible aux valeurs aberrantes, puisqu'une variance se calcule au carré. Et elle détruit l'interprétabilité des variables d'origine.
Variantes utiles : IncrementalPCA (par lots, pour des données hors mémoire), la version randomisée (par défaut dans scikit-learn dès que la matrice est grande), la kernel PCA (version non linéaire par astuce du noyau, module 14), la sparse PCA (axes à peu de variables non nulles, donc lisibles), et pour la visualisation pure, UMAP ou t-SNE — non linéaires, excellents visuellement, mais non paramétriques, non reproductibles d'une exécution à l'autre, et dont les distances entre groupes ne veulent rien dire.
Pipeline (module 3).
8. Métriques d'évaluation
Une métrique traduit un objectif métier en un nombre à optimiser. Se tromper de métrique, c'est optimiser efficacement la mauvaise chose — et c'est irrattrapable par la suite.
Régression
MSE moyenne des carrés d'erreur pénalise fortement les grandes erreurs
RMSE racine du MSE même unité que la cible : interprétable
MAE moyenne des écarts absolus robuste aux aberrants ; erreur "typique"
MAPE erreur relative en % parlante, mais explose si y proche de 0
et pénalise plus les surestimations
R² 1 - SSE/SST part de variance expliquée ; peut être NÉGATIF
si le modèle fait pire que la moyenneRMSE et MAE ne répondent pas à la même question, et ce n'est pas un détail : minimiser le RMSE conduit à prédire la moyenne conditionnelle, minimiser le MAE la médiane conditionnelle. Sur des données à queue lourde — des prix, des durées — les deux modèles optimaux diffèrent réellement, et le choix doit venir de l'usage.
Classification
Tout part de la matrice de confusion, qui croise vérité et prédiction :
prédit positif prédit négatif
réel positif VP (vrai positif) FN (faux négatif) ← on l'a raté
réel négatif FP (faux positif) VN (vrai négatif)
↑ fausse alerteLa précision répond à « parmi mes alertes, combien sont justes ? », le rappel à « parmi les cas réels, combien ai-je attrapés ? ». Les deux s'opposent par le seuil de décision : le baisser augmente le rappel et dégrade la précision. Le \(F_1\) est leur moyenne harmonique, qui pénalise le déséquilibre entre les deux.
from sklearn.metrics import (classification_report, confusion_matrix,
roc_auc_score, average_precision_score,
log_loss, brier_score_loss)
p = modele.predict_proba(X_test)[:, 1]
y_pred = (p >= 0.5).astype(int)
print(confusion_matrix(y_test, y_pred))
print(classification_report(y_test, y_pred, digits=3)) # précision, rappel, F1 par classe
print("ROC-AUC :", roc_auc_score(y_test, p))
print("PR-AUC :", average_precision_score(y_test, p)) # à préférer en déséquilibre
print("log-loss:", log_loss(y_test, p)) # évalue les PROBABILITÉS
print("Brier :", brier_score_loss(y_test, p)) # calibrationROC-AUC ou PR-AUC ?
L'AUC-ROC mesure la probabilité qu'un positif tiré au hasard soit mieux classé qu'un négatif. Son défaut : le taux de faux positifs \(FP/(FP+VN)\) a un dénominateur énorme quand les négatifs dominent, si bien qu'une AUC de 0,95 peut masquer une précision de 3 % sur un problème à 0,1 % de positifs. En classe très déséquilibrée — fraude, défaut, maladie rare — la courbe précision-rappel est la bonne lecture, car ses deux axes ne dépendent que des positifs et des alertes.
Deux métriques souvent oubliées et pourtant essentielles : la log-loss \(-\frac{1}{n}\sum_i [y_i\log p_i + (1-y_i)\log(1-p_i)]\), qui évalue les probabilités et non les décisions, et le score de Brier (erreur quadratique sur les probabilités), qui mesure la calibration. Un modèle peut parfaitement ordonner les cas — bonne AUC — tout en annonçant des probabilités fausses, ce qui rend inexploitable toute décision fondée sur un coût attendu (module 24). On corrige par calibration isotonique ou de Platt (module 14).
Enfin, l'accuracy est une métrique piégeuse : sur un problème à 99 % de négatifs, prédire toujours « négatif » donne 99 % d'accuracy et un modèle sans aucune valeur. La bonne démarche part du coût métier : si un faux négatif coûte cent fois un faux positif, ce rapport doit apparaître dans le choix du seuil — c'est l'objet du module 24.
Ce qu'il faut retenir du module
- Apprendre = minimiser un risque empirique régularisé ; la perte encode ce qu'on appelle une erreur, et c'est un choix.
- Le taux d'apprentissage est l'hyperparamètre critique : trop grand, ça diverge ; trop petit, ça rampe.
- Le conditionnement gouverne la vitesse de convergence — d'où l'obligation de standardiser les variables.
- SGD échange l'exactitude du gradient contre le nombre de pas ; momentum lisse, Adam adapte le pas par paramètre.
- AdamW par défaut ; SGD + momentum quand on peut se permettre de régler finement.
- Ne jamais inverser une matrice :
solve, Cholesky, QR, SVD. - SVD = rotation · dilatation · rotation, et meilleure approximation de rang \(k\) (Eckart–Young) ; elle éclaire aussi ridge comme un filtrage spectral.
- PCA = SVD des données centrées-réduites ; à ajuster dans un pipeline, linéaire, non supervisée, sensible aux aberrants.
- Choisir la métrique à partir du coût métier ; PR-AUC en classes déséquilibrées ; surveiller la calibration.