Cas PratiquesIntermédiaire30 min de lecture · 35 vues

Analyse de Sentiment sur des Tweets Français

Comparez les performances de GPT-4o, Claude et Gemini sur la classification de sentiment de tweets français avec un dataset Kaggle réel.

Par Alex Perey

Objectif du TP

Les benchmarks standards (MMLU, HumanEval) sont en anglais. Mais comment les modèles se comportent-ils en français ? Dans ce cas pratique, vous allez tester et comparer plusieurs LLMs sur une tâche concrète : la classification de sentiment de tweets français.

Prérequis

  • Python 3.8+, Pandas
  • Accès gratuit à ChatGPT, Claude ou Gemini
  • Optionnel : une clé API OpenRouter pour automatiser les tests

Dataset

French Twitter Sentiment Analysis – Kaggle

1,5 million de tweets français étiquetés positif/négatif. Nous n''en utiliserons qu''un échantillon.

Exercice 1 : Préparer les Données de Test

import pandas as pd

# Charger un échantillon
df = pd.read_csv("french_tweets.csv", nrows=500)

print(f"Colonnes : {df.columns.tolist()}")
print(f"Taille : {len(df)}")
print(df.head())

# Distribution des sentiments
print("\nDistribution :")
print(df["label"].value_counts())

# Sélectionner 30 tweets de test (équilibrés)
positifs = df[df["label"] == 1].sample(15, random_state=42)
negatifs = df[df["label"] == 0].sample(15, random_state=42)
test_set = pd.concat([positifs, negatifs]).sample(frac=1, random_state=42)

print(f"\nDataset de test : {len(test_set)} tweets")
test_set.to_csv("test_tweets.csv", index=False)

Exercice 2 : Générer les Prompts

Créez les prompts standardisés que vous enverrez à chaque modèle.

# Charger le dataset de test
test_set = pd.read_csv("test_tweets.csv")

# Template de prompt
prompt_template = """Tu es un expert en analyse de sentiment.
Classe le sentiment du tweet suivant en EXACTEMENT un mot : "positif" ou "négatif".

Tweet : "{tweet}"

Sentiment :"""

# Générer et afficher les prompts
prompts = []
for idx, row in test_set.iterrows():
    prompt = prompt_template.format(tweet=row["text"])
    prompts.append({
        "id": idx,
        "tweet": row["text"],
        "vrai_sentiment": "positif" if row["label"] == 1 else "négatif",
        "prompt": prompt
    })

# Sauvegarder
prompts_df = pd.DataFrame(prompts)
prompts_df.to_csv("prompts_test.csv", index=False)

print(f"{len(prompts)} prompts générés.")
print("\n--- Exemple de prompt ---")
print(prompts[0]["prompt"])

Conseil : Le prompt est volontairement simple et directif. En production, vous testeriez aussi l''impact de prompts plus détaillés (few-shot, chain-of-thought).

Exercice 3 : Tester Manuellement (Sans API)

Si vous n''avez pas de clé API, testez manuellement sur les interfaces gratuites.

Protocole :

  1. Ouvrez 3 onglets : ChatGPT, Claude, Gemini
  2. Pour chaque tweet, copiez le prompt dans les 3 interfaces
  3. Notez la réponse dans un tableur :
TweetVraiGPT-4oClaudeGemini
"J''adore ce film !"positifpositifpositifpositif
"Service client horrible"négatifnégatifnégatifpositif

Testez au moins 15-20 tweets pour avoir des résultats significatifs. C''est fastidieux manuellement, d''où l''intérêt d''automatiser (exercice suivant).

Exercice 4 : Automatiser avec l''API OpenRouter

Si vous avez une clé API, automatisez les tests.

import requests
import time

OPENROUTER_API_KEY = "sk-or-..."  # Votre clé

def ask_model(prompt, model_id):
    """Envoie un prompt à un modèle via OpenRouter."""
    response = requests.post(
        "https://openrouter.ai/api/v1/chat/completions",
        headers={
            "Authorization": f"Bearer {OPENROUTER_API_KEY}",
            "Content-Type": "application/json"
        },
        json={
            "model": model_id,
            "messages": [{"role": "user", "content": prompt}],
            "max_tokens": 10,
            "temperature": 0
        }
    )
    result = response.json()
    return result["choices"][0]["message"]["content"].strip().lower()

# Modèles à tester
models = {
    "GPT-4o-mini": "openai/gpt-4o-mini",
    "Claude Haiku": "anthropic/claude-3-haiku",
    "Gemini Flash": "google/gemini-flash-1.5",
}

# Tester chaque prompt sur chaque modèle
results = []
for _, row in prompts_df.iterrows():
    result = {"tweet": row["tweet"], "vrai": row["vrai_sentiment"]}
    for name, model_id in models.items():
        try:
            answer = ask_model(row["prompt"], model_id)
            # Normaliser la réponse
            if "positif" in answer:
                result[name] = "positif"
            elif "négatif" in answer or "negatif" in answer:
                result[name] = "négatif"
            else:
                result[name] = answer  # Réponse inattendue
        except Exception as e:
            result[name] = f"erreur: {e}"
        time.sleep(0.5)  # Respecter les rate limits
    results.append(result)

results_df = pd.DataFrame(results)
results_df.to_csv("resultats_sentiment.csv", index=False)
print("Tests terminés !")
print(results_df.head(10))

Coût estimé : Avec des modèles "mini/haiku/flash", 30 tweets coûtent moins de 0,01€. Avec GPT-4o ou Claude Opus, comptez environ 0,10€.

Exercice 5 : Analyser les Résultats

results_df = pd.read_csv("resultats_sentiment.csv")

print("=== Résultats de l''Analyse de Sentiment ===\n")

for model_name in ["GPT-4o-mini", "Claude Haiku", "Gemini Flash"]:
    if model_name not in results_df.columns:
        continue

    correct = (results_df[model_name] == results_df["vrai"]).sum()
    total = len(results_df)
    accuracy = correct / total * 100

    # Détail par classe
    positifs = results_df[results_df["vrai"] == "positif"]
    negatifs = results_df[results_df["vrai"] == "négatif"]

    acc_pos = (positifs[model_name] == positifs["vrai"]).mean() * 100
    acc_neg = (negatifs[model_name] == negatifs["vrai"]).mean() * 100

    print(f"--- {model_name} ---")
    print(f"  Précision globale : {accuracy:.0f}% ({correct}/{total})")
    print(f"  Précision positifs : {acc_pos:.0f}%")
    print(f"  Précision négatifs : {acc_neg:.0f}%")

    # Exemples d''erreurs
    errors = results_df[results_df[model_name] != results_df["vrai"]]
    if len(errors) > 0:
        print(f"  Erreurs ({len(errors)}) :")
        for _, err in errors.head(3).iterrows():
            print(f"    Tweet: \"{err['tweet'][:60]}...\"")
            print(f"    Attendu: {err['vrai']} → Réponse: {err[model_name]}")
    print()

Observations typiques :

  • Les modèles ont souvent plus de mal avec le sarcasme et l''argot français
  • Les tweets courts et ambigus génèrent le plus d''erreurs
  • La précision sur les négatifs est souvent inférieure à celle sur les positifs

Pour Aller Plus Loin

  • Testez avec des prompts few-shot (donner 3 exemples dans le prompt) et comparez la précision
  • Essayez le dataset Allociné Reviews pour tester sur des critiques de films (textes plus longs)
  • Calculez le coût par prédiction pour chaque modèle et déterminez le meilleur rapport précision/coût

À propos de l'auteur

Alex Perey

Diplômé d'un master en intelligence artificielle, je travaille au quotidien sur des projets IA en entreprise. J'ai créé IwanttolearnAI pour rendre l'apprentissage de l'IA accessible à tous, gratuitement.

GitHub·En savoir plus

Continuer à apprendre

Cas PratiquesIntermédiaire

TP : Créer un Chatbot RAG de A à Z

Construisez un chatbot intelligent qui répond en se basant sur vos documents : chunking, embeddings, vector store, prompt engineering et interface web.

15 min de lecture · 61 vues

Cas PratiquesAvancé

TP : Fine-tuner un LLM sur vos Données

Apprenez à fine-tuner un LLM (Llama, Mistral) avec LoRA/QLoRA sur vos données métier : préparation du dataset, entraînement, évaluation et déploiement avec Ollama.

18 min de lecture · 32 vues

Cas PratiquesDébutant

Token Trainer

Prédisez comment un tokenizer découpe les phrases en tokens ! Cliquez entre les caractères pour placer vos séparations et découvrez les règles de tokenization.

10 min de lecture · 83 vues