Classifieur Naïf de Bayes

Wilson Toussile1 2

ENSPY

1ENSPY, 2ESSFAR

1 Introduction et Motivation

  • Qu’est-ce que la classification ?
    • Rappel : Apprentissage supervisé.
    • Objectif : Prédire une catégorie (classe) \(y_i\) à partir de données explicatives \(x_i\).
    • Notations : \(\mathcal{D}_n=\left\{\left(x_i, y_i\right)\right\}_{i=1}^n\), \(x_i=\left(x_{i,j}\right)_{j=1}^p\), \(y_i \in \{c_1, \dots, c_K\}\).
  • Pourquoi un classifieur “Naïf” ?
    • Simplicité et efficacité.
    • Bonne performance sur de nombreux problèmes.
    • Utile comme baseline.

2 Bases Théoriques : Le Théorème de Bayes

  • Rappels de probabilités :
    • Probabilité conditionnelle.
    • Théorème de Bayes : \[ P(Y=c_k | X=x) = \frac{P(X=x | Y=c_k) P(Y=c_k)}{P(X=x)} \]
  • Interprétation dans le contexte de la classification :
    • \(P(Y=c_k | X=x)\) : Probabilité a posteriori (ce que l’on veut estimer).
    • \(P(X=x | Y=c_k)\) : Vraisemblance (comment les données sont distribuées pour une classe donnée).
    • \(P(Y=c_k)\) : Probabilité a priori de la classe \(c_k\).
    • \(P(X=x)\) : Evidence (probabilité des données, souvent un terme de normalisation).

3 Le Classifieur de Bayes

  • Règle de décision de Bayes :
    • Choisir la classe \(c_k\) qui maximise la probabilité a posteriori \(P(Y=c_k | X=x)\).
    • Mathématiquement : \(\hat{y} = \underset{c_k}{\mathrm{argmax}} P(Y=c_k | X=x)\).
  • Simplification :
    • Le dénominateur \(P(X=x)\) est constant pour toutes les classes pour une observation \(x\) donnée.
    • On cherche donc à maximiser le numérateur : \(\hat{y} = \underset{c_k}{\mathrm{argmax}} P(X=x | Y=c_k) P(Y=c_k)\).
  • Difficulté : Estimer \(P(X=x | Y=c_k)\) lorsque \(p\) (nombre de variables explicatives) est grand.
    • “Fléau de la dimension”.

4 L’Hypothèse “Naïve”

  • L’hypothèse d’indépendance conditionnelle des variables explicatives :
    • Sachant la classe \(Y=c_k\), les variables \(x_j\) sont indépendantes entre elles.
    • Mathématiquement : \(P(X=x | Y=c_k) = P(x_1, \dots, x_p | Y=c_k) = \prod_{j=1}^{p} P(x_j | Y=c_k)\).
  • Conséquence :
    • Simplifie grandement l’estimation de la vraisemblance.
    • La règle de décision devient : \[ \hat{y} = \underset{c_k}{\mathrm{argmax}} P(Y=c_k) \prod_{j=1}^{p} P(x_j | Y=c_k) \]
  • Discussion :
    • L’hypothèse est souvent fausse en pratique.
    • Malgré cela, le classifieur peut bien fonctionner.

Astuce de calcul

Pour éviter les problèmes de sous-flux numérique (underflow) dus à la multiplication de nombreuses petites probabilités, on travaille souvent avec les log-probabilités : \[ \hat{y} = \underset{c_k}{\mathrm{argmax}} \left( \log P(Y=c_k) + \sum_{j=1}^{p} \log P(x_j | Y=c_k) \right) \]

5 Estimation des Paramètres

  • Estimation de la probabilité a priori \(P(Y=c_k)\) :
    • Fréquence relative de la classe \(c_k\) dans les données d’apprentissage \(\mathcal{D}_n\).
    • \(P(Y=c_k) = \frac{\text{Nombre d'exemples de la classe } c_k}{n}\)
  • Estimation de la vraisemblance \(P(x_j | Y=c_k)\) :
    • Dépend de la nature de la variable \(x_j\).

5.1 Variables Explicatives Catégorielles

  • Pour une variable \(x_j\) prenant des valeurs dans un ensemble discret \(\{v_1, \dots, v_M\}\).
  • \(P(x_j=v_m | Y=c_k) = \frac{\text{Nombre d'exemples où } x_j=v_m \text{ et } Y=c_k}{\text{Nombre d'exemples où } Y=c_k}\).
  • Problème des “zéros fréquences” : Si une modalité \(v_m\) n’apparaît jamais avec la classe \(c_k\) dans \(\mathcal{D}_n\), alors \(P(x_j=v_m | Y=c_k)=0\).
    • Cela annule toute la probabilité a posteriori si cette modalité apparaît dans une nouvelle observation.
  • Solution : Lissage de Laplace (ou estimateur de Laplace).
    • \(P(x_j=v_m | Y=c_k) = \frac{(\text{Nombre d'exemples où } x_j=v_m \text{ et } Y=c_k) + \alpha}{(\text{Nombre d'exemples où } Y=c_k) + \alpha M}\).
    • \(\alpha\) est un paramètre de lissage (souvent \(\alpha=1\)).

5.2 Variables Explicatives Continues

  • Hypothèse courante : \(P(x_j | Y=c_k)\) suit une distribution Gaussienne (Normale).
    • \(x_j | Y=c_k \sim \mathcal{N}(\mu_{jk}, \sigma^2_{jk})\)
  • Estimation des paramètres de la Gaussienne pour chaque classe \(c_k\) et chaque variable \(x_j\):
    • \(\mu_{jk}\): Moyenne empirique de la variable \(x_j\) pour les exemples de la classe \(c_k\).
    • \(\sigma^2_{jk}\): Variance empirique de la variable \(x_j\) pour les exemples de la classe \(c_k\).
  • Calcul de \(P(x_j | Y=c_k)\) à l’aide de la fonction de densité de probabilité (PDF) de la loi Normale : \[ P(x_j | Y=c_k) = \frac{1}{\sqrt{2\pi\sigma^2_{jk}}} \exp\left(-\frac{(x_j - \mu_{jk})^2}{2\sigma^2_{jk}}\right) \]
  • Autres approches pour les variables continues :
    • Discrétisation.
    • Estimateurs de densité par noyau (Kernel Density Estimators - KDE).

6 Algorithme du Classifieur Naïf de Bayes

  • Phase d’Apprentissage (Training) sur \(\mathcal{D}_n\):
    1. Pour chaque classe \(c_k \in \{c_1, \dots, c_K\}\):
      1. Calculer \(P(Y=c_k)\).
      2. Pour chaque variable explicative \(x_j\):
        1. Si \(x_j\) est catégorielle : Estimer \(P(x_j=v_m | Y=c_k)\) pour chaque modalité \(v_m\) (avec lissage).
        2. Si \(x_j\) est continue : Estimer \(\mu_{jk}\) et \(\sigma^2_{jk}\) pour la distribution Gaussienne.
  • Phase de Prédiction (Inférence) pour une nouvelle observation \(x_{new}\):
    1. Pour chaque classe \(c_k \in \{c_1, \dots, c_K\}\):
      1. Calculer le score (ou log-probabilité) : \(\text{Score}(c_k) = \log P(Y=c_k) + \sum_{j=1}^{p} \log P(x_{new,j} | Y=c_k)\).
    2. Prédire la classe \(\hat{y}_{new} = \underset{c_k}{\mathrm{argmax}} \text{ Score}(c_k)\).

7 Exemple Pratique: Gaussian Naive Bayes (Python)

  • Utilisons le jeu de données Iris (classification multiclasse).
Code
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.datasets import load_iris

# Charger le jeu de données Iris
iris = load_iris()
X, y = iris.data, iris.target

# Diviser les données en ensembles d'entraînement et de test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# Initialiser et entraîner le modèle Gaussian Naive Bayes
gnb = GaussianNB()
gnb.fit(X_train, y_train)

# Faire des prédictions sur l'ensemble de test
y_pred = gnb.predict(X_test)

# Évaluer la performance du modèle
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy du Gaussian Naive Bayes sur le jeu de test Iris: {accuracy:.4f}")

# Matrice de confusion
from sklearn.metrics import confusion_matrix
conf_matrix = confusion_matrix(y_test, y_pred)
print("Matrice de confusion:")
print(conf_matrix)

# Afficher les probabilités prédites pour les 5 premières observations de test
print("\nProbabilités prédites pour les 5 premières observations de test:")
print(gnb.predict_proba(X_test[:5]))
Accuracy du Gaussian Naive Bayes sur le jeu de test Iris: 0.9778
Matrice de confusion:
[[19  0  0]
 [ 0 12  1]
 [ 0  0 13]]

Probabilités prédites pour les 5 premières observations de test:
[[4.15880005e-088 9.95527834e-001 4.47216606e-003]
 [1.00000000e+000 1.31031235e-013 2.21772205e-020]
 [9.83170191e-285 2.70138564e-012 1.00000000e+000]
 [9.54745274e-092 9.74861431e-001 2.51385686e-002]
 [1.08679560e-103 8.31910700e-001 1.68089300e-001]]

8 Cas Particulier : Classification Binaire

  • \(K=2\). Les classes sont souvent notées \({0, 1}\) ou \({-1, 1}\).
  • La règle de décision peut être formulée en comparant \(P(Y=1 | X=x)\) à \(P(Y=0 | X=x)\).
    • Si \(P(Y=1 | X=x) \> P(Y=0 | X=x)\), alors prédire classe 1.
    • Ou, en utilisant le ratio des probabilités a posteriori : \(\\frac{P(Y=1 | X=x)}{P(Y=0 | X=x)} \> 1\).
    • En termes de log-odds : \(\log \dfrac{P(Y=1 | X=x)}{P(Y=0 | X=x)} > 0\).
  • Fonction de Perte \(L\) et Risque \(R\):
    • La règle de Bayes minimise le risque \(R(f) = E[L(Y, f(X))]\) pour la perte 0-1 (\(L(y, \hat{y}) = 1 \text{ si } y \neq \hat{y} \text{ sinon } 0\)).

9 Exemple Pratique: Binomial Naive Bayes (Python)

  • Illustrons avec un exemple simple de classification de texte (spam ou non-spam), où les caractéristiques sont la présence ou l’absence de mots. Nous utiliserons BernoulliNB de scikit-learn.
Code
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import BernoulliNB
from sklearn.model_selection import train_test_split # Bien que nous utilisions un petit jeu de données ici
from sklearn.metrics import accuracy_score, confusion_matrix

# Données d'exemple : messages et leurs étiquettes (1 pour spam, 0 pour non-spam)
corpus = [
    ("offre spécial argent gratuit gagner prix", 1), # Spam
    ("cliquer lien gagner argent facile rapide", 1), # Spam
    ("prix incroyable opportunité unique", 1), # Spam
    ("réunion projet important demain matin", 0), # Non-spam
    ("discussion budget équipe après-midi", 0), # Non-spam
    ("confirmation rendez-vous docteur lundi", 0), # Non-spam
    ("gagner loterie gratuit maintenant", 1), # Spam
    ("exclusif promotion argent facile", 1), # Spam
    ("rapport mensuel vente disponible", 0), # Non-spam
    ("invitation séminaire marketing digital", 0), # Non-spam
    ("urgent action requise compte sécurité", 1), # Spam (pourrait être phishing)
    ("ne pas manquer offre limitée", 1), # Spam
    ("mise à jour logiciel important installer", 0), # Non-spam
    ("compte rendu réunion disponible partage", 0), # Non-spam
    ("félicitations sélectionné prix spécial", 1), # Spam
    ("demande information produit service", 0), # Non-spam
    ("gratuit essai limité temps", 1), # Spam
    ("planification vacances équipe semaine prochaine", 0), # Non-spam
    ("opportunité investissement incroyable rendement élevé", 1), # Spam
    ("question facture service client", 0) # Non-spam
]

texts = [text for text, label in corpus]
labels = np.array([label for text, label in corpus])

# Extraction de caractéristiques : Convertir le texte en vecteurs de présence/absence de mots
# binary=True assure que nous comptons la présence (1) ou l'absence (0) d'un mot, pas sa fréquence.
vectorizer = CountVectorizer(binary=True)
X = vectorizer.fit_transform(texts)

# Pour cet exemple, nous allons entraîner et tester sur le même petit ensemble pour illustrer.
# Dans un cas réel, utilisez train_test_split sur un ensemble de données plus grand.
X_train, X_test, y_train, y_test = X, X, labels, labels # Simplification pour l'illustration

# Initialiser et entraîner le modèle Bernoulli Naive Bayes
# alpha=1.0 est le lissage de Laplace (par défaut)
bnb = BernoulliNB()
bnb.fit(X_train, y_train)

# Faire des prédictions
y_pred = bnb.predict(X_test)

# Évaluer la performance du modèle
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy du Bernoulli Naive Bayes sur le jeu de test simplifié: {accuracy:.4f}")

conf_matrix = confusion_matrix(y_test, y_pred)
print("\nMatrice de confusion:")
print(conf_matrix)

# Afficher les probabilités prédites pour les premières observations
print("\nProbabilités prédites (non-spam, spam) pour les premières observations de test:")
print(np.round(bnb.predict_proba(X_test[:4]), 3))

# Afficher les classes prédites pour les premières observations
print("\nClasses prédites pour les premières observations de test:")
print(y_pred[:4])
print("Vraies classes pour les premières observations de test:")
print(y_test[:4])
Accuracy du Bernoulli Naive Bayes sur le jeu de test simplifié: 1.0000

Matrice de confusion:
[[10  0]
 [ 0 10]]

Probabilités prédites (non-spam, spam) pour les premières observations de test:
[[0.    1.   ]
 [0.001 0.999]
 [0.008 0.992]
 [0.994 0.006]]

Classes prédites pour les premières observations de test:
[1 1 1 0]
Vraies classes pour les premières observations de test:
[1 1 1 0]

10 Avantages et Inconvénients

  • Simple et rapide à entraîner et à prédire.
  • Efficace sur de petits jeux de données.
  • Gère bien la grande dimensionnalité (beaucoup de variables explicatives).
  • Performances souvent bonnes même si l’hypothèse de naïveté est violée.
  • Gère nativement les données manquantes (en ignorant la variable pour cette observation lors du produit/somme).
  • Fournit des probabilités de classe, ce qui peut être utile.
  • L’hypothèse d’indépendance conditionnelle est rarement vraie en pratique.
    • Peut conduire à des estimations de probabilités a posteriori peu fiables (souvent trop extrêmes, proches de 0 ou 1).
  • Sensible aux “zéros fréquences” pour les variables catégorielles si le lissage n’est pas appliqué.
  • Pour les variables continues, l’hypothèse de distribution Gaussienne peut être trop restrictive.

11 Variantes du Classifieur Naïf de Bayes

  • Gaussian Naive Bayes : Suppose des features continues suivant une distribution Gaussienne (comme vu).
  • Multinomial Naive Bayes : Souvent utilisé pour la classification de texte, où les features sont des comptes de mots (ou TF-IDF). Suppose une distribution multinomiale pour les features.
  • Bernoulli Naive Bayes : Utilisé quand les features sont binaires (présence/absence). Suppose une distribution de Bernoulli pour les features.
  • Categorical Naive Bayes : Pour des features catégorielles (comme vu).

12 Diagramme (Mermaid)

Illustrons le calcul pour une nouvelle observation :

Code
graph TD
    subgraph Entrée X_new
        X_new_1["Feature 1 = x_new,1"]
        X_new_2["Feature 2 = x_new,2"]
        X_new_p["..."]
        X_new_feat_p["Feature p = x_new,p"]
    end

    subgraph Pour Classe c1
        Prior_c1["P(Y=c1)"]
        L_x1_c1["P(x_new,1 | Y=c1)"]
        L_x2_c1["P(x_new,2 | Y=c1)"]
        L_xp_c1["P(x_new,p | Y=c1)"]
        Prod_c1["Score(c1) = P(Y=c1) * Π P(x_new,j | Y=c1)"]
    end

    subgraph Pour Classe cK
        Prior_cK["P(Y=cK)"]
        L_x1_cK["P(x_new,1 | Y=cK)"]
        L_x2_cK["P(x_new,2 | Y=cK)"]
        L_xp_cK["P(x_new,p | Y=cK)"]
        Prod_cK["Score(cK) = P(Y=cK) * Π P(x_new,j | Y=cK)"]
    end
    
    X_new_1 --> L_x1_c1
    X_new_2 --> L_x2_c1
    X_new_feat_p --> L_xp_c1
    Prior_c1 --> Prod_c1
    L_x1_c1 --> Prod_c1
    L_x2_c1 --> Prod_c1
    L_xp_c1 --> Prod_c1

    X_new_1 --> L_x1_cK
    X_new_2 --> L_x2_cK
    X_new_feat_p --> L_xp_cK
    Prior_cK --> Prod_cK
    L_x1_cK --> Prod_cK
    L_x2_cK --> Prod_cK
    L_xp_cK --> Prod_cK
    
    Prod_c1 --> Decision["Argmax(Score(c1), ..., Score(cK))"]
    Prod_cK --> Decision
    
    Decision --> Prediction["Classe Prédite ŷ_new"]

    style Prior_c1 fill:#f9f,stroke:#333,stroke-width:2px
    style Prior_cK fill:#f9f,stroke:#333,stroke-width:2px
    style Prediction fill:#bbf,stroke:#333,stroke-width:2px

graph TD
    subgraph Entrée X_new
        X_new_1["Feature 1 = x_new,1"]
        X_new_2["Feature 2 = x_new,2"]
        X_new_p["..."]
        X_new_feat_p["Feature p = x_new,p"]
    end

    subgraph Pour Classe c1
        Prior_c1["P(Y=c1)"]
        L_x1_c1["P(x_new,1 | Y=c1)"]
        L_x2_c1["P(x_new,2 | Y=c1)"]
        L_xp_c1["P(x_new,p | Y=c1)"]
        Prod_c1["Score(c1) = P(Y=c1) * Π P(x_new,j | Y=c1)"]
    end

    subgraph Pour Classe cK
        Prior_cK["P(Y=cK)"]
        L_x1_cK["P(x_new,1 | Y=cK)"]
        L_x2_cK["P(x_new,2 | Y=cK)"]
        L_xp_cK["P(x_new,p | Y=cK)"]
        Prod_cK["Score(cK) = P(Y=cK) * Π P(x_new,j | Y=cK)"]
    end
    
    X_new_1 --> L_x1_c1
    X_new_2 --> L_x2_c1
    X_new_feat_p --> L_xp_c1
    Prior_c1 --> Prod_c1
    L_x1_c1 --> Prod_c1
    L_x2_c1 --> Prod_c1
    L_xp_c1 --> Prod_c1

    X_new_1 --> L_x1_cK
    X_new_2 --> L_x2_cK
    X_new_feat_p --> L_xp_cK
    Prior_cK --> Prod_cK
    L_x1_cK --> Prod_cK
    L_x2_cK --> Prod_cK
    L_xp_cK --> Prod_cK
    
    Prod_c1 --> Decision["Argmax(Score(c1), ..., Score(cK))"]
    Prod_cK --> Decision
    
    Decision --> Prediction["Classe Prédite ŷ_new"]

    style Prior_c1 fill:#f9f,stroke:#333,stroke-width:2px
    style Prior_cK fill:#f9f,stroke:#333,stroke-width:2px
    style Prediction fill:#bbf,stroke:#333,stroke-width:2px

13 Conclusion et Points Clés

  • Le Classifieur Naïf de Bayes est un algorithme probabiliste basé sur le théorème de Bayes.
  • Son efficacité repose sur l’hypothèse “naïve” d’indépendance conditionnelle des variables.
  • Différentes variantes existent selon la nature des données explicatives.
  • Simple, rapide et souvent étonnamment performant.
  • Excellent point de départ pour des problèmes de classification.

14 Pour aller plus loin (Références)

  • Chapitre 4 du livre “Introduction au Machine Learning” (Azencott, 2020) pour une discussion sur l’inférence bayésienne et la classification naïve bayésienne. [Source 52, 665]
  • Documentation Scikit-learn : Naive Bayes