Quadratic Discriminant Analysis : Guide complet — Analyse Discriminante Quadratique
Résumé — QDA (Quadratic Discriminant Analysis) est un classifieur probabiliste qui, comme la LDA, repose sur le théorème de Bayes et l’hypothèse de distribution gaussienne des classes. Mais contrairement à la LDA qui suppose une covariance commune à toutes les classes, la QDA estime une matrice de covariance distincte pour chaque classe. Cette liberté supplémentaire permet de modéliser des frontières de décision quadratiques (elliptiques, paraboliques) plutôt que strictement linéaires. C’est un compromis entre la simplicité de la LDA et la flexibilité des modèles non paramétriques.
Principe mathématique
1. Cadre général bayésien
Comme la LDA, la QDA repose sur le théorème de Bayes pour la classification :
$$P(C_k | x) = \frac{P(x | C_k) \cdot P(C_k)}{P(x)}$$
où P(C_k|x) est la probabilité postérieure que x appartienne à la classe C_k, P(x|C_k) est la vraisemblance, et P(C_k) est la probabilité a priori de la classe k.
La prédiction est la classe qui maximise cette probabilité postérieure :
$$\hat{y} = \arg\max_k P(C_k | x)$$
2. Hypothèse gaussienne par classe
La QDA suppose que les données de chaque classe suivent une distribution gaussienne avec sa propre covariance :
$$P(x | C_k) = \mathcal{N}(x | \mu_k, \Sigma_k) = \frac{1}{(2\pi)^{p/2} |\Sigma_k|^{1/2}} \exp\left(-\frac{1}{2}(x – \mu_k)^T \Sigma_k^{-1} (x – \mu_k)\right)$$
C’est ici que la QDA diffère fondamentalement de la LDA : chaque classe k a sa propre matrice de covariance Σ_k, alors que la LDA impose Σ_k = Σ pour toutes les classes.
3. Fonction discriminante quadratique
En prenant le logarithme de la posterior et en éliminant les termes constants, on obtient la fonction discriminante de la classe k :
$$\delta_k(x) = -\frac{1}{2} \log|\Sigma_k| – \frac{1}{2}(x – \mu_k)^T \Sigma_k^{-1} (x – \mu_k) + \log(\pi_k)$$
où π_k = P(C_k) est la probabilité a priori de la classe k.
La prédiction est :
$$\hat{y} = \arg\max_k \delta_k(x)$$
4. Frontière de décision quadratique
La frontière entre deux classes k et l est l’ensemble des points x où δ_k(x) = δ_l(x). En développant cette égalité :
$$-\frac{1}{2}(x^T \Sigma_k^{-1} x – x^T \Sigma_l^{-1} x) + \text{termes linéaires} + \text{constantes} = 0$$
Le terme x^T(Σ_k^{-1} – Σ_l^{-1})x est quadratique en x. C’est ce qui donne son nom à l’algorithme : la frontière de décision est une surface quadratique (ellipse, parabole, hyperbole).
5. Estimation des paramètres par maximum de vraisemblance
Les paramètres sont estimés sur le jeu d’entraînement :
- Moyenne de la classe k : $$\hat{\mu}k = \frac{1}{n_k} \sum x_i$$
- Covariance de la classe k : $$\hat{\Sigma}k = \frac{1}{n_k – 1} \sum_k)^T$$} (x_i – \hat{\mu}_k)(x_i – \hat{\mu
- Probabilité a priori : $$\hat{\pi}_k = \frac{n_k}{n}$$
6. Différence clé : QDA vs LDA
| Aspect | LDA | QDA |
|---|---|---|
| Covariance | Commune (Σ_k = Σ) | Distincte (Σ_k propre à chaque classe) |
| Frontière | Linéaire (hyperplan) | Quadratique (ellipse, parabole) |
| Paramètres | O(p · K) | O(p² · K) |
| Biais/Variance | Biais élevé, faible variance | Biais faible, variance élevée |
| Nécessité en données | Modérée | Élevée (surtout en haute dimension) |
Intuition
Imaginez deux groupes d’étudiants dans un campus : les étudiants en maths et les étudiants en art.
La LDA suppose que la dispersion (variabilité) des notes est identique dans les deux groupes. Elle va séparer les groupes par une ligne droite (en 2D) ou un plan (en 3D). C’est comme tracer une frontière administrative entre deux pays.
La QDA dit : “Attendons, les maths ont des notes très concentrées (peu de variance), tandis que les arts ont des notes très dispersées (grande variance).” La QDA dessine alors une frontière courbe qui englobe le groupe le plus dispersé comme une ellipse. Comme si la frontière entre les deux pays suivait la forme naturelle du terrain.
En résumé : la QDA permet à chaque classe d’avoir sa propre “forme” dans l’espace des features. C’est plus flexible, mais ça demande plus de données pour estimer correctement chaque forme.
Implémentation Python
Exemple 1 : QDA from scratch
import numpy as np
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
class QDAClassifier:
"""Quadratic Discriminant Analysis - implémentation from scratch."""
def __init__(self, reg_param=0.0):
self.reg_param = reg_param # Regularisation de la covariance
def fit(self, X, y):
self.classes_ = np.unique(y)
self.means_ = {}
self.covs_ = {}
self.priors_ = {}
for k in self.classes_:
X_k = X[y == k]
self.means_[k] = np.mean(X_k, axis=0)
self.covs_[k] = np.cov(X_k, rowvar=False)
# Regularisation pour stabilité numérique
if self.reg_param > 0:
self.covs_[k] += self.reg_param * np.eye(self.covs_[k].shape[0])
self.priors_[k] = len(X_k) / len(X)
return self
def _log_density(self, x, k):
"""Log de la densité gaussienne pour la classe k."""
mu = self.means_[k]
cov = self.covs_[k]
prior = self.priors_[k]
diff = x - mu
cov_inv = np.linalg.inv(cov)
_, log_det = np.linalg.slogdet(cov)
# Fonction discriminante quadratique
log_prior = np.log(prior)
mahal = diff.T @ cov_inv @ diff
log_det_term = -0.5 * log_det
mahal_term = -0.5 * mahal
return log_det_term + mahal_term + log_prior
def predict(self, X):
predictions = []
for x in X:
scores = {k: self._log_density(x, k) for k in self.classes_}
predictions.append(max(scores, key=scores.get))
return np.array(predictions)
# Données avec classes non linéairement séparables
X, y = make_classification(n_samples=600, n_features=2, n_informative=2,
n_redundant=0, n_clusters_per_class=1, flip_y=0.1, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3,
random_state=42)
# Notre QDA
qda = QDAClassifier(reg_param=1e-4)
qda.fit(X_train, y_train)
qda_pred = qda.predict(X_test)
qda_acc = accuracy_score(y_test, qda_pred)
print(f"QDA accuracy : {qda_acc:.3f}")
# Affichage des paramètres estimés
for k in qda.classes_:
print(f"Classe {k}: mean={qda.means_[k].round(2)}, prior={qda.priors_[k]:.3f}")
Exemple 2 : Comparaison LDA vs QDA visuelle
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
from sklearn.discriminant_analysis import QuadraticDiscriminantAnalysis as QDA
# Comparaison directe
lda_model = LDA()
lda_model.fit(X_train, y_train)
lda_acc = accuracy_score(y_test, lda_model.predict(X_test))
qda_model = QDA(reg_param=1e-4)
qda_model.fit(X_train, y_train)
qda_acc2 = accuracy_score(y_test, qda_model.predict(X_test))
print(f"LDA accuracy : {lda_acc:.3f}")
print(f"QDA accuracy : {qda_acc2:.3f}")
# Visualisation des frontières
import matplotlib.pyplot as plt
xx, yy = np.meshgrid(np.linspace(X[:, 0].min()-1, X[:, 0].max()+1, 200),
np.linspace(X[:, 1].min()-1, X[:, 1].max()+1, 200))
grid = np.c_[xx.ravel(), yy.ravel()]
Z_lda = lda_model.predict(grid).reshape(xx.shape)
Z_qda = qda_model.predict(grid).reshape(xx.shape)
fig, axes = plt.subplots(1, 2, figsize=(14, 6))
for ax, Z, name, acc in zip(axes, [Z_lda, Z_qda], ['LDA', 'QDA'], [lda_acc, qda_acc2]):
ax.contourf(xx, yy, Z, alpha=0.3, cmap='RdBu')
ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap='RdBu',
edgecolors='black', s=30)
ax.set_title(f'{name} — Accuracy: {acc:.3f}')
ax.set_xlabel('Feature 1')
ax.set_ylabel('Feature 2')
plt.tight_layout()
plt.savefig('qda_vs_lda.png', dpi=150)
Exemple 3 : QDA sur données avec covariances différentes
# Données spécifiquement conçues pour avantager QDA
np.random.seed(42)
# Classe 0 : covariance faible
X0 = np.random.randn(200, 2) * 0.5 + np.array([2, 2])
y0 = np.zeros(200)
# Classe 1 : covariance élevée (allongée)
X1 = np.random.randn(200, 2) * np.array([2, 0.3]) + np.array([5, 2])
y1 = np.ones(200)
X_custom = np.vstack([X0, X1])
y_custom = np.concatenate([y0, y1])
X_tr, X_te, y_tr, y_te = train_test_split(X_custom, y_custom, test_size=0.3,
random_state=42)
lda_c = LDA().fit(X_tr, y_tr)
qda_c = QDA().fit(X_tr, y_tr)
lda_c_acc = accuracy_score(y_te, lda_c.predict(X_te))
qda_c_acc = accuracy_score(y_te, qda_c.predict(X_te))
print(f"\nDonnées à covariances différentes :")
print(f"LDA accuracy : {lda_c_acc:.3f}")
print(f"QDA accuracy : {qda_c_acc:.3f}")
Hyperparamètres
| Hyperparamètre | Valeur typique | Description |
|---|---|---|
reg_param |
0 à 0.1 | Régularisation des matrices de covariance (ajoute λ·I). Essentiel en haute dimension pour la stabilité numérique |
priors |
None ou dict | Probabilités a priori des classes. Par défaut, estimées par les fréquences du dataset |
tol |
1e-4 | Tolérance pour la vérification de la définition positive des covariances |
store_covariance |
True/False | Stocker les matrices de covariance après fit. Utile pour l’interprétation mais coûteux en mémoire |
Avantages de la QDA
- Frontières non linéaires : La QDA capture des relations quadratiques entre les classes que la LDA rate complètement. Quand les classes ont des dispersions très différentes, la QDA est nettement supérieure.
- Fondation probabiliste solide : Les prédictions de la QDA sont des probabilités calibrées issues du théorème de Bayes. Contrairement aux SVM ou KNN qui ne produisent pas naturellement de probabilités.
- Pas d’hyperparamètres sensibles : Hormis la régularisation de covariance, la QDA n’a pas de paramètres à tuner comme le C d’un SVM ou le k d’un KNN. Elle est prête à l’emploi.
- Interprétabilité : Les matrices de covariance estimées sont directement interprétables : elles décrivent comment chaque classe se disperse dans l’espace des features.
- Solution analytique : Comme la LDA, la QDA a une solution fermée par maximum de vraisemblance. Pas besoin d’optimisation itérative ni de grid search.
Limites de la QDA
- Nombre de paramètres explosif : Pour p features et K classes, la QDA estime K · p²/2 paramètres de covariance. Avec 100 features et 3 classes, c’est 15 000 paramètres à estimer. Risque de surapprentissage sur petits datasets.
- Besoin de beaucoup de données : Pour estimer correctement chaque covariance, il faut au moins p+1 exemples par classe, idéalement beaucoup plus. En dessous, les covariances sont instables.
- Singularité des matrices de covariance : Si une classe a moins de features que d’exemples, ou si une feature est colinéaire, la covariance devient singulière et non-inversible. Nécessité de régularisation.
- Hypothèse gaussienne restrictive : Si les classes ne suivent pas une distribution gaussienne (ex: multimodales, asymétriques), les performances de la QDA chutent.
- Pas adaptée aux données catégorielles : La QDA suppose des features continues. Pour des données mixtes ou catégorielles, il faut utiliser d’autres approches.
4 cas d’usage concrets
1. Diagnostic médical avec profils hétérogènes
Dans le diagnostic de pathologies cardiaques, les patients sains et malades peuvent présenter des patterns très différents : les patients sains ont des mesures très homogènes (faible variance), tandis que les patients malades présentent une grande variabilité selon le type et le stade de la maladie. La QDA capture cette asymétrie naturellement là où la LDA échouerait.
2. Détection de fraude financière
Les transactions légitimes forment un groupe homogène et resserré dans l’espace des features (montant, heure, localisation cohérents). Les transactions frauduleuses, elles, sont très dispersées et imprévisibles. La QDA modélise bien cette asymétrie de covariance et peut détecter des fraudes que la LDA manquerait en supposant une même dispersion pour les deux catégories.
3. Classification d’images médicales
Pour distinguer des tissus sains de tissus tumoraux sur des images IRM, les textures des tissus sains ont des caractéristiques stables (faible variance), tandis que les tumeurs présentent des textures très hétérogènes. La QDA est particulièrement adaptée à ce type de classification asymétrique.
4. Scoring de crédit avec segments de population
Dans le scoring de crédit, les bons payeurs ont des profils financiers homogènes (revenu stable, emploi constant), tandis que les défaillants peuvent l’être pour des raisons très diverses (perte d’emploi, maladie, divorce, etc.). La QDA modélise cette asymétrie de profil et améliore la précision par rapport à la LDA.
Conclusion
La QDA est l’évolution naturelle de la LDA quand l’hypothèse de covariance commune est irréaliste. En permettant à chaque classe d’avoir sa propre forme dans l’espace des features, elle capture des relations non linéaires que la LDA ne peut pas modéliser.
Le compromis est clair : plus de flexibilité contre plus de paramètres à estimer. Sur des datasets de taille suffisante avec des covariances effectivement différentes entre classes, la QDA est souvent supérieure. Sur des petits datasets ou quand les covariances sont similaires, la LDA reste le choix privilégié.
En pratique, tester LDA et QDA côte à côte par validation croisée est un excellent réflexe. Si QDA surpasse LDA significativement, c’est un signal fort que les classes ont des structures de variance distinctes qui méritent d’être modélisées séparément.
Voir aussi
- Maîtriser les Diviseurs de Produits Binomiaux avec Python : Guide Complet
- Maîtriser les Composites à Propriété de Repunit Primaire avec Python : Guide et Applications

