Classer automatiquement un texte selon l'opinion qu'il exprime : positif, négatif ou neutre. On l'utilise pour trier des milliers d'avis, de tickets ou de réponses à une enquête, et remonter en priorité les clients mécontents. La méthode va du simple modèle sur les mots jusqu'au LLM.
Un stagiaire lit des centaines d'avis déjà notés par des clients. Il retient que « cassé », « remboursement » et « ne répond pas » annoncent un avis négatif, puis trie seul les nouveaux.
Ici, la note laissée par le client donne l'étiquette : 1-2 étoiles négatif, 3 neutre, 4-5 positif. Pas besoin d'annoter à la main.
Chaque avis devient un vecteur de poids TF-IDF sur les mots et les paires de mots (« pas reçu », « service client »).
Une régression logistique à trois classes attribue un poids à chaque mot pour chaque sentiment, puis classe les nouveaux avis.
Le texte de l'avis et la note de 1 à 5, traduite en positif, neutre ou négatif. 70 % des avis servent à apprendre, 30 % à vérifier.
Chaque avis entrant reçoit une étiquette. Les négatifs partent directement au service client, sans attendre une lecture manuelle. Utile aussi pour les textes sans note : emails, tickets, réseaux sociaux.
Ce qui compte est la part des vrais avis négatifs détectés. Sur le jeu d'exemple, le modèle Python classe 95 % des avis test correctement et retrouve 96 % des négatifs. La classe neutre est la plus difficile (85 % de rappel). Sur de vrais avis, plus variés que ce jeu d'exemple, attendez-vous à moins.
Plus que les hyperparamètres, ce sont les choix de méthode et de préparation qui font la qualité. Noms donnés pour R (text2vec, glmnet) et Python (scikit-learn).
TF-IDF avec régression logistique : rapide, gratuit, lisible. Un modèle de type BERT ajusté sur vos avis : meilleur sur les tournures complexes. Un LLM : aucun exemple nécessaire, mais coût par texte et résultats moins stables.
Compter les paires de mots capte une partie de la négation (« pas reçu », « sans plus »). Presque toujours utile.
Si les neutres sont rares, le modèle les néglige. class_weight="balanced" en Python, pondération des observations (weights) dans glmnet en R.
Freine les poids des mots pour éviter d'apprendre par cœur. cv.glmnet choisit lambda par validation croisée ; en Python, régler C.
# Avis clients : analyse de sentiment en R
library(text2vec)
library(glmnet)
avis <- read.csv("avis_clients.csv")
sentiment <- factor(avis$sentiment)
set.seed(42)
idx <- sample(nrow(avis), round(0.7 * nrow(avis)))
# Vocabulaire appris sur l'entraînement : mots et paires de mots
jetons <- itoken(tolower(avis$texte), tokenizer = word_tokenizer)
vocab <- create_vocabulary(itoken(tolower(avis$texte[idx]), tokenizer = word_tokenizer), ngram = c(1, 2))
vocab <- prune_vocabulary(vocab, term_count_min = 2)
dtm <- create_dtm(jetons, vocab_vectorizer(vocab))
tfidf <- TfIdf$new()
x_train <- fit_transform(dtm[idx, ], tfidf)
x_test <- transform(dtm[-idx, ], tfidf)
# Régression logistique à 3 classes, pénalité choisie par validation croisée
modele <- cv.glmnet(x_train, sentiment[idx], family = "multinomial")
prevu <- factor(predict(modele, x_test, s = "lambda.min", type = "class")[, 1], levels = levels(sentiment))
# Matrice de confusion et rappel par classe
confusion <- table(reel = sentiment[-idx], prevu = prevu)
print(confusion)
print(round(diag(confusion) / rowSums(confusion), 2))
# Avis clients : analyse de sentiment en Python
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from sklearn.pipeline import make_pipeline
avis = pd.read_csv("avis_clients.csv")
X_train, X_test, y_train, y_test = train_test_split(avis["texte"], avis["sentiment"], test_size=0.3,
random_state=42, stratify=avis["sentiment"])
# Texte -> poids des mots et paires de mots -> classifieur à 3 classes
modele = make_pipeline(TfidfVectorizer(ngram_range=(1, 2), min_df=2), LogisticRegression(max_iter=1000, class_weight="balanced"))
modele.fit(X_train, y_train)
# Rappel par classe : part des vrais avis négatifs retrouvés, etc.
print(classification_report(y_test, modele.predict(X_test), digits=2))
# Nouveaux avis à classer
nouveaux = ["Colis arrivé en retard et produit cassé.", "Rien à signaler, produit correct."]
print(dict(zip(nouveaux, modele.predict(nouveaux))))
Trois options : utiliser un modèle déjà entraîné au sentiment sur des textes en français, interroger un LLM avec une consigne, ou étiqueter quelques centaines de textes pour entraîner un modèle. La note laissée par le client, quand elle existe, sert souvent d'étiquette gratuite.
Sur des avis courts et tranchés, un modèle simple obtient déjà une bonne exactitude ; l'ironie et les avis mitigés font baisser le score. La classe neutre est toujours la plus difficile, car les humains eux-mêmes ne s'accordent pas toujours sur elle. Il faut mesurer sur vos propres textes, pas sur des chiffres publiés.
Pas forcément. Un modèle TF-IDF avec régression logistique donne souvent un bon résultat pour un coût quasi nul. Le LLM apporte un gain sur l'ironie, les phrases longues et les textes sans étiquettes, au prix d'un coût par texte.
Transforme chaque avis en poids de mots. C'est l'entrée du classifieur de cette fiche.
Voir la fiche → plus fin sur la langueUn modèle pré-entraîné qui lit la phrase entière. Ajusté sur quelques milliers d'avis, il gère mieux la négation et le contexte.
Voir la fiche → sans données étiquetéesIl suffit de demander le sentiment dans une consigne. Pratique pour démarrer, coûteux sur des millions de textes.
Voir la fiche →Dataistudio forme les équipes au machine learning et à l'IA, sur des cas concrets.
Nous utilisons des cookies de mesure d'audience et de suivi publicitaire pour comprendre la fréquentation du site et l'efficacité de nos annonces. Rien n'est déposé sans votre accord. En savoir plus