Naive Bayes Multinomial : Guide complet — Principes, Exemples et Implémentation Python
Résumé — Le naive Bayes multinomial est l’algorithme de référence pour la classification de documents textuels. Fondé sur la distribution multinomiale et le théorème de Bayes, il calcule la probabilité qu’un document appartienne à chaque classe en comptant les occurrences de mots. Ce guide couvre le principe mathématique, l’intuition, l’implémentation Python avec scikit-learn, les hyperparamètres, ainsi que des cas d’usage concrets.
Principe mathématique
Le naive Bayes multinomial repose sur l’hypothèse que les caractéristiques (features) suivent une distribution multinomiale. Contrairement au Naive Bayes gaussien qui suppose des valeurs continues distribuées normalement, le modèle multinomial travaille avec des comptes discrets — typiquement le nombre de fois qu’un mot apparaît dans un document.
Théorème de Bayes appliqué
Rappelons la formule fondamentale du théorème de Bayes :
P(y | x₁, x₂, ..., xₙ) = P(y) × P(x₁, x₂, ..., xₙ | y) / P(x₁, x₂, ..., xₙ)
L’hypothèse « naïve » d’indépendance conditionnelle permet de factoriser le terme de vraisemblance :
P(y | X) ∝ P(y) × ∏ P(xᵢ | y)
Distribution multinomiale
Dans le contexte du traitement du texte, chaque document est représenté par un vecteur de comptes de mots. Pour un mot donné xᵢ et une classe y, la probabilité conditionnelle s’estime par :
P(xᵢ | y) = (Nᵢ,ᵧ + α) / (Nᵧ + α × n)
Où :
- Nᵢ,ᵧ : nombre total d’occurrences du mot xᵢ dans tous les documents de classe y
- Nᵧ : nombre total de mots (toutes occurrences confondues) dans la classe y
- α : paramètre de lissage (voir ci-dessous)
- n : taille du vocabulaire (nombre de mots uniques)
Lissage de Laplace
Un problème critique surgit lorsqu’un mot n’apparaît jamais dans une classe donnée : sans correction, sa probabilité conditionnelle serait exactement zéro. Or, comme les probabilités sont multipliées entre elles, un seul zéro annule toute la vraisemblance de la classe.
Le lissage de Laplace (ou lissage additif) résout ce problème en ajoutant un petit paramètre α aux comptes :
P(xᵢ | y) = (Nᵢ,ᵧ + α) / (Nᵧ + α × n)
- α = 1 correspond au lissage de Laplace classique
- 0 < α < 1 : lissage plus léger (recommandé pour les grands vocabulaires)
- α = 0 : pas de lissage (risque de probabilités nulles)
Ce lissage garantit que même les mots absents d’une classe reçoivent une probabilité non nulle, évitant ainsi l’effondrement multiplicatif.
Intuition
Imaginez que vous devez déterminer si un e-mail est un spam ou un ham (e-mail légitime). L’e-mail contient les mots suivants : « gagnant », « gratuit », « cliquez », « offre », « urgence ».
Le naive Bayes multinomial fonctionne comme un comité d’experts où chaque mot « vote » pour une classe :
- Le modèle connaît la fréquence relative de chaque mot dans les spams et dans les hams, grâce à l’apprentissage.
- Le mot « gagnant » apparaît très souvent dans les spams, rarement dans les hams → il « vote » fortement pour la classe spam.
- Le mot « offre » apparaît un peu dans les deux classes → son vote est plus équilibré.
- Le mot « urgence » est un indicateur fort de spam → vote puissant pour spam.
La classe finale est celle qui reçoit le plus de « votes » pondérés par les probabilités.
L’analogie du sac de mots : le modèle ignore l’ordre des mots et leur position. Il ne considère que le comptage — combien de fois chaque mot apparaît. C’est comme si vous versiez tous les mots d’un document dans un sac et que vous comptiez combien de fois chaque mot y figure. Cette simplification est à la fois la force (rapidité, simplicité) et la faiblesse (perte de contexte syntaxique) du modèle.
Pourquoi « multinomial » ? Le terme vient du fait que la génération d’un document est modélisée comme un processus multinomial : on tire N mots (où N est la longueur du document) à partir d’un vocabulaire de taille n, chaque mot étant choisi selon une distribution de probabilité spécifique à la classe. C’est l’équivalent probabiliste de tirer N fois dans une urne contenant n boules de couleurs différentes, avec remise.
Où se situe le problème du zéro ? Imaginez que votre corpus d’entraînement ne contienne aucun document de la classe « sport » avec le mot « football ». Sans lissage, la probabilité P(« football » | « sport ») = 0. Or ce mot est évidemment un indicateur très fort de la classe sport ! Le lissage corrige cette absurdité en attribuant une probabilité minimale à chaque mot, même absent des données d’entraînement.
Implémentation Python
Passons maintenant à la pratique avec scikit-learn et sa classe MultinomialNB.
Exemple 1 : Classification de spam basique
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, confusion_matrix
import numpy as np
# Données d'entraînement (exemples simplifiés)
emails = [
"Gagnez un iPhone gratuit ! Cliquez ici maintenant !",
"Bonjour, la réunion est confirmée pour demain à 14h",
"OFFRE EXCEPTIONNELLE : 90% de réduction aujourd'hui seulement",
"Le rapport trimestriel est disponible sur le serveur",
"URGENT : Votre compte sera suspendu si vous ne cliquez pas",
"Merci pour votre contribution au projet de recherche",
"Félicitations ! Vous avez été sélectionné pour un prix exclusif",
"Note de service : nouveau planning à partir de lundi",
]
labels = ["spam", "ham", "spam", "ham", "spam", "ham", "spam", "ham"]
# Vecteurisation par comptage de mots
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(emails)
# Division train/test
X_train, X_test, y_train, y_test = train_test_split(
X, labels, test_size=0.25, random_state=42
)
# Entraînement du modèle
model = MultinomialNB(alpha=1.0)
model.fit(X_train, y_train)
# Prédictions
y_pred = model.predict(X_test)
print("Prédictions :", y_pred)
print("\nMatrice de confusion :")
print(confusion_matrix(y_test, y_pred))
print("\nRapport de classification :")
print(classification_report(y_test, y_pred))
Exemple 2 : Pipeline complet avec TF-IDF
En pratique, on utilise souvent TF-IDF (Term Frequency — Inverse Document Frequency) plutôt que le simple comptage, car il pondère les mots rares plus fortement que les mots fréquents.
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.pipeline import Pipeline
from sklearn.metrics import accuracy_score
# Pipeline : TF-IDF + MultinomialNB
pipeline = Pipeline([
('tfidf', TfidfVectorizer(
max_features=5000,
ngram_range=(1, 2), # Unigrammes et bigrammes
min_df=2, # Ignorer les mots apparaissant < 2 fois
sublinear_tf=True # Normalisation logarithmique du TF
)),
('clf', MultinomialNB(alpha=0.1))
])
# Entraînement
pipeline.fit(X_train_emails, y_train_labels)
# Évaluation
accuracy = accuracy_score(y_test_labels, pipeline.predict(X_test_emails))
print(f"Précision : {accuracy:.4f}")
Exemple 3 : Impact du paramètre alpha
Le paramètre alpha contrôle l’intensité du lissage. Comparons plusieurs valeurs :
alphas = [0.01, 0.1, 0.5, 1.0, 2.0, 5.0]
results = []
for a in alphas:
clf = MultinomialNB(alpha=a)
clf.fit(X_train, y_train)
train_score = clf.score(X_train, y_train)
test_score = clf.score(X_test, y_test)
results.append((a, train_score, test_score))
print(f"alpha={a:.2f} | Train: {train_score:.4f} | Test: {test_score:.4f}")
# Visualisation
import matplotlib.pyplot as plt
a_vals = [r[0] for r in results]
train_scores = [r[1] for r in results]
test_scores = [r[2] for r in results]
plt.figure(figsize=(10, 6))
plt.plot(a_vals, train_scores, 'b-o', label='Entraînement')
plt.plot(a_vals, test_scores, 'r-s', label='Test')
plt.xscale('log')
plt.xlabel('alpha (lissage)')
plt.ylabel('Précision')
plt.title('Impact du lissage sur les performances')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
Observation typique : une valeur d’alpha trop faible (≈ 0.01) peut entraîner du surapprentissage (overfitting), tandis qu’une valeur trop élevée (≥ 5.0) peut lisser excessivement et dégrader la précision. La valeur par défaut α = 1.0 est généralement un bon point de départ.
Exemple 4 : Matrice de confusion détaillée
import seaborn as sns
# Matrice de confusion
cm = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=['ham', 'spam'],
yticklabels=['ham', 'spam'])
plt.xlabel('Prédiction')
plt.ylabel('Vérité terrain')
plt.title('Matrice de confusion — Naive Bayes Multinomial')
plt.show()
Hyperparamètres
| Hyperparamètre | Type | Valeur par défaut | Description |
|---|---|---|---|
| alpha | float | 1.0 | Paramètre de lissage additif (Laplacien). α = 0 désactive le lissage. Valeurs typiques : 0.01 à 1.0. |
| fit_prior | bool | True | Si True, apprend les probabilités a priori P(y) à partir des données. Si False, utilise une distribution uniforme. |
| class_prior | array | None | Probabilités a priori des classes. Si spécifié, remplace l’apprentissage automatique de P(y). Doit être normalisé (somme = 1). |
Détails sur chaque hyperparamètre
alpha (lissage additif)
C’est le paramètre le plus influent. Il contrôle le compromis entre biais et variance :
- α faible (0.01 – 0.1) : modèle plus confiant dans ses estimations, risque de surapprentissage sur les mots rares
- α = 1.0 (par défaut) : lissage de Laplace standard, bon équilibre général
- α élevé (2.0 – 10.0) : lissage fort, utile pour les petits jeux de données ou les vocabulaires très étendus
fit_prior (apprentissage des probabilités a priori)
Lorsque les classes sont déséquilibrées, il peut être utile de désactiver l’apprentissage des priors (fit_prior=False) pour éviter que le modèle ne soit biaisé vers la classe majoritaire.
class_prior (probabilités a priori personnalisées)
Permet de spécifier manuellement la probabilité a priori de chaque classe. Utile lorsque vous connaissez la vraie distribution des classes dans la population cible et qu’elle diffère de votre jeu d’entraînement.
# Exemple : classes prior personnalisées
model = MultinomialNB(
alpha=0.5,
fit_prior=True,
class_prior=None # apprentissage automatique
)
Avantages et Limites
Avantages
- Extrêmement rapide à l’entraînement — un seul passage sur les données suffit pour calculer les probabilités conditionnelles. Idéal pour les grands corpus de millions de documents.
- Extrêmement rapide en prédiction — le calcul se réduit à quelques multiplications et additions par classe.
- Fonctionne bien avec de grandes dimensions — contrairement à de nombreux algorithmes qui souffrent de la malédiction de la dimensionnalité, le Naive Bayes multinomial excelle avec des vocabulaires de dizaines de milliers de mots.
- Peu sensible au surapprentissage sur des données textuelles, grâce à l’hypothèse d’indépendance qui agit comme un régularisateur implicite.
- Probabilités interprétables — en plus de la prédiction, le modèle fournit des scores probabilité utiles pour le seuillage et la prise de décision.
- Pas d’hyperparamètres complexes à régler — un seul paramètre principal (
alpha) à optimiser. - Fonctionne bien même avec peu de données d’entraînement comparé à des modèles plus complexes comme les réseaux de neurones.
Limites
- Hypothèse d’indépendance forte — le modèle suppose que tous les mots sont conditionnellement indépendants sachant la classe, ce qui est clairement faux en pratique (les mots « machine » et « learning » sont fortement corrélés).
- Perte de l’ordre des mots et de la structure syntaxique — « le chat mange la souris » et « la souris mange le chat » produisent exactement le même vecteur de caractéristiques.
- Ne capture pas les bigrammes/trigrammes par défaut (bien que les ngram_range de CountVectorizer/TfidfVectorizer puissent compenser partiellement).
- Performances limitées sur des tâches complexes — pour la classification de sentiments nuancée ou la compréhension sémantique profonde, les modèles à base de transformers (BERT, RoBERTa) surpassent largement le Naive Bayes.
- Sensible aux données bruyantes — un vocabulaire mal nettoyé (mots vides non filtrés, fautes d’orthographe) peut dégrader significativement les performances.
- Nécessite des données de type comptage — ne fonctionne pas directement avec des caractéristiques binaires ou continues (dans ce cas, utilisez BernoulliNB ou GaussianNB).
Cas d’usage
1. Classification de spam (filtrage d’e-mails)
C’est le cas d’usage historique du Naive Bayes multinomial. Depuis les années 1990, les filtres anti-spam utilisent cet algorithme pour analyser les mots des e-mails et déterminer leur nature.
# Exemple avec des e-mails réels
emails_spam_ham = [
("Gagnez 5000 euros maintenant en cliquant ici", "spam"),
("Le comité de direction se réunit mardi prochain", "ham"),
("Votre colis ne peut pas être livré, renseignez vos infos bancaires", "spam"),
("Bonjour, je vous envoie les documents demandés en pièce jointe", "ham"),
]
Les mots comme « gagner », « gratuit », « urgence », « cliquer », « compte bancaire » sont des indicateurs puissants de spam, tandis que les mots liés au travail, aux projets ou aux relations professionnelles signalent des e-mails légitimes.
2. Analyse de sentiment (avis clients)
Le Naive Bayes multinomial excelle pour classifier les avis clients en positifs, négatifs ou neutres.
avis = [
"Produit excellent, je suis très satisfait de mon achat !",
"Livraison catastrophique, le produit est arrivé cassé.",
"Correct, rien de spécial à dire, fait le travail.",
"Incroyable ! Meilleur produit que j'ai jamais acheté !",
"Déçu par la qualité, le service client est injoignable.",
]
sentiments = ["positif", "négatif", "neutre", "positif", "négatif"]
# Pipeline avec TF-IDF
from sklearn.pipeline import make_pipeline
modele_sentiment = make_pipeline(
TfidfVectorizer(stop_words='french', ngram_range=(1, 2)),
MultinomialNB(alpha=0.3)
)
modele_sentiment.fit(avis, sentiments)
# Prédiction sur un nouvel avis
nouvel_avis = ["Superbe qualité, livraison rapide, je recommande vivement !"]
prediction = modele_sentiment.predict(nouvel_avis)
print(f"Sentiment prédit : {prediction[0]}")
3. Catégorisation de documents
Organiser automatiquement des articles de presse, des rapports ou des pages web dans des catégories prédéfinies : politique, sport, technologie, économie, culture, etc.
Le modèle apprend les mots caractéristiques de chaque catégorie :
- Sport : match, joueur, équipe, victoire, championnat, but
- Technologie : logiciel, algorithme, intelligence artificielle, données, numérique
- Politique : gouvernement, élection, parlement, loi, ministre
- Économie : bourse, inflation, croissance, PIB, entreprise
Un cas célèbre est la catégorisation des articles du jeu de données 20 Newsgroups, où le Naive Bayes multinomial atteint des précisions de 80-85 % avec une simple vectorisation TF-IDF.
4. Détection de langue
Identifier automatiquement la langue d’un texte en analysant la fréquence des caractères et des mots courts (articles, prépositions). Chaque langue a une « signature » statistique distinctive.
langues_textes = [
"Bonjour, comment allez-vous aujourd'hui ?", # français
"Hello, how are you doing today?", # anglais
"Hola, ¿cómo estás hoy?", # espagnol
"Hallo, wie geht es Ihnen heute?", # allemand
"Ciao, come stai oggi?", # italien
]
langues_labels = ["fr", "en", "es", "de", "it"]
# Utilisation de counts de caractères n-grammes
from sklearn.feature_extraction.text import CountVectorizer
detecteur = make_pipeline(
CountVectorizer(analyzer='char', ngram_range=(3, 5)),
MultinomialNB(alpha=0.05)
)
detecteur.fit(langues_textes, langues_labels)
texte_inconnu = ["Ich möchte einen Kaffee bestellen, bitte"]
langue_predite = detecteur.predict(texte_inconnu)
print(f"Langue détectée : {langue_predite[0]}") # → de (allemand)
Cette approche est remarquablement efficace : même avec quelques phrases d’entraînement par langue, la précision dépasse souvent 95 %, car les distributions de trigrammes et quadrigrammes de caractères sont très distinctives entre langues.
Voir aussi
- Title: Maîtriser la question d’entretien Python : Calculer la racine carrée de x
- Vérifiez l’appartenance des points à un polygone convexe en O(log N) avec Python
Mots-clés : naive bayes multinomial, classification texte, lissage de Laplace, scikit-learn, NLP, traitement du langage naturel, Python, apprentissage supervisé, sac de mots, TF-IDF
Note importante sur l’interprétation des résultats
Lorsque vous analysez les sorties du Naive Bayes multinomial, gardez à l’esprit que les probabilités brutes ne sont pas toujours bien calibrées. Pour obtenir des probabilités plus fiables, utilisez la méthode predict_proba() de scikit-learn. De plus, n’hésitez pas à expérimenter avec différents niveaux de lissage — la valeur par défaut α = 1.0 fonctionne bien, mais sur de grands corpus comme le texte de la Wikipédia ou des articles de presse, des valeurs plus faibles (α = 0,1) donnent souvent de meilleurs résultats.
Un dernier conseil : toujours filtrer les mots-vides (stop words) avant l’entraînement. Les mots comme « le », « de », « un », « est » apparaissent dans toutes les classes et n’apportent aucune information discriminante. Leur présence dilue la capacité du modèle à distinguer les classes les unes des autres. Même avec un corpus très volumineux où les mots rares apparaîtraient une fois ou deux, le lissage de Laplace assure que le modèle demeure robuste face à ces cas limites.
Enfin, rappelez-vous que le coût de calcul est extrêmement faible — vous pouvez entraîner un Naive Bayes multinomial sur des millions de documents en quelques secondes, ce qui en fait un outil sûr et efficace pour tout pipeline de traitement du langage naturel. C’est souvent le premier modèle à essayer avant de passer à des architectures plus lourdes.

