Analyse exploratoire des données (EDA)
Les bases de l'analyse de données avant modélisation.
Comment classer automatiquement des avis clients en "positif" ou "négatif" ? Découvrez la différence entre une approche simple par dictionnaire de mots clés (44% de précision) et un modèle de Machine Learning (86%).
L'analyse de sentiments est une tâche classique du traitement automatique du langage naturel (NLP). Elle consiste à déterminer automatiquement si un texte exprime une opinion positive, négative ou neutre.
Applications courantes :
Ce cas pratique compare deux approches radicalement différentes :
- Approche naïve : un dictionnaire de mots clés positifs/négatifs
- Approche ML : un classifieur Naive Bayes entraîné sur des données annotées

Figure 1 : Aperçu des avis après parsing – chaque avis est associé à une note (rating) convertie en sentiment.
Le dataset utilisé est le Multi-Domain Sentiment Dataset de l'Université Johns Hopkins. Il contient des avis produits Amazon (vêtements, électronique, livres, etc.) avec des notes de 1 à 5 étoiles.
| Note (étoiles) | Sentiment |
|---|---|
| 1 ou 2 étoiles | Négatif |
| 4 ou 5 étoiles | Positif |
| 3 étoiles | Neutre (ignoré dans ce cas pratique) |

Figure 2 : Déséquilibre initial – 85% d'avis positifs, 15% de négatifs.
Pour éviter que le modèle apprenne simplement à toujours prédire "positif", nous avons équilibré le dataset en sous-échantillonnant les positifs.

Figure 3 : Après équilibrage – 1 351 positifs, 1 351 négatifs.
Les fichiers bruts sont au format pseudo-XML. Voici comment nous avons extrait les notes et les textes :
def parse_review_file(filepath):
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
review_blocks = re.split(r'\n', content)
reviews = []
for block in review_blocks:
rating_match = re.search(r'\s*([\d\.]+)\s*', block)
text_match = re.search(r'\s*(.*?)\s*', block, re.DOTALL)
if rating_match and text_match:
rating = float(rating_match.group(1))
text = text_match.group(1).strip()
sentiment = 'positif' if rating >= 4 else 'negatif'
reviews.append({'rating': rating, 'sentiment': sentiment, 'review_text': text})
return reviews

Figure 4 : Nettoyage du texte (minuscules, suppression de la ponctuation et des stop words).
mots_positifs = ['love', 'amazing', 'great', 'good', 'happy', 'best', 'wonderful', 'beautiful', 'fantastic']
mots_negatifs = ['bad', 'poor', 'terrible', 'waste', 'disappointed', 'awful', 'hate', 'worse', 'regret']
def classify_sentiment_keywords(text):
words = text.lower().split()
pos_count = sum(1 for w in words if w in set_mots_positifs)
neg_count = sum(1 for w in words if w in set_mots_negatifs)
if pos_count > neg_count: return 'positif'
elif neg_count > pos_count: return 'negatif'
else: return 'neutre'

Figure 5 : Résultats décevants – seulement 44% de précision.
Pourquoi ce score médiocre ?
Le texte est transformé en une matrice de nombres. TF-IDF donne plus de poids aux mots rares et discriminants.
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer(max_features=5000, ngram_range=(1, 2))
X = vectorizer.fit_transform(df_balanced['clean_text'])
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import MultinomialNB
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
model = MultinomialNB()
model.fit(X_train, y_train)

Figure 6 : Résultats du modèle Naive Bayes – 86% de précision.

Figure 7 : Matrice de confusion – 234 vrais négatifs, 233 vrais positifs.
| Critère | Mots clés | Naive Bayes + TF-IDF |
|---|---|---|
| Accuracy | 44% | 86% |
| Rappel (négatif) | 20% | 86% |
| F1-score (positif) | 0,71 | 0,86 |
| Gestion des négations | Échoue | Partielle (via bigrammes) |
| Gestion du sarcasme | Ignoré | Partielle |
| Temps d'exécution | Très rapide | Rapide |
| Nécessite des données annotées | Non | Oui (9 252 avis) |
L'approche par mots clés est simple mais ses performances médiocres (44% de précision) la rendent inutilisable en pratique.
Le Machine Learning, même avec un algorithme simple comme Naive Bayes, améliore drastiquement les résultats (+42 points).
Ces avis sont négatifs mais contiennent des mots positifs isolés qui trompent le modèle.
"I like the style of shoes but it gets dirty so quick and hard to clean."
Analyse : "like" et "style" sont positifs, mais le message global est négatif (sale, difficile à nettoyer).
"These boots look good on the first wear, but they scuffed and had tears after one night."
Analyse : "good" trompe le modèle alors que l'avis est très négatif (déchirures après une nuit).
"This bra does it all. It gives me smooth attractive shape and great support."
Analyse : Le modèle a peut-être été perturbé par "difficult" présent plus tôt dans la phrase complète.
"I discovered that it was not just roomy but huge."
Analyse : "huge" peut être perçu comme négatif dans certains contextes, mais ici c'est positif.

Figure 8 : Exemples d'avis négatifs classés positifs (faux positifs).

Figure 9 : Exemples d'avis positifs classés négatifs (faux négatifs).
| Technique | Gain attendu | Complexité |
|---|---|---|
| Word2Vec / GloVe (embeddings) | +3-5% | Moyenne |
| BERT / Transformers (modèles pré-entraînés) | +5-10% | Élevée |
| Gestion des négations (ajout de règles) | +2-3% | Faible |
| Bigrammes/Trigrammes (déjà inclus) | Fait | Faible |
Avec la bibliothèque transformers de Hugging Face :
from transformers import pipeline
classifier = pipeline("sentiment-analysis", model="nlptown/bert-base-multilingual-uncased-sentiment")
result = classifier("This product is amazing!")
Le notebook complet est disponible dans l'article. Voici les étapes clés :
Le fichier sentiments_analysis.ipynb est disponible sur demande ou dans les ressources de l'article.
Naive Bayes est simple, rapide et très efficace pour la classification de texte. C'est un excellent point de départ avant de passer à des modèles plus complexes (SVM, Random Forest, BERT).
Oui, avec des modèles plus avancés comme BERT, on peut atteindre 92-95%. Mais 86% avec un modèle simple est déjà très honorable. Les erreurs restantes sont dues au sarcasme, aux négations complexes et au contexte.
Pas toujours. Dans notre cas, le dataset était très déséquilibré (85% positifs). Sans équilibrage, le modèle aurait appris à toujours prédire "positif" (accuracy de 85% mais inutile). L'équilibrage permet de bien évaluer la performance sur la classe minoritaire.
Il faut : (1) adapter les stop words en français (nltk.corpus.stopwords.words('french')), (2) utiliser un dictionnaire de mots clés français, ou (3) utiliser un modèle BERT multilingue (ex: nlptown/bert-base-multilingual-uncased-sentiment).
Bag of Words compte simplement les occurrences de chaque mot. TF-IDF pondère les mots : les mots fréquents dans tout le corpus (ex: "le", "de") perdent de l'importance, les mots rares gagnent en importance.
Les bigrammes (paires de mots consécutifs) capturent des expressions comme "not good" ou "very bad", ce que les unigrammes seuls ne peuvent pas faire. Cela améliore légèrement la gestion des négations.
Ce cas pratique a démontré :