{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "9aeaf08b-26da-4300-b4d4-e20e9b835876",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Note: you may need to restart the kernel to use updated packages.\n"
     ]
    }
   ],
   "source": [
    "%pip install datasets matplotlib numpy scikit-learn sentence_transformers wordcloud -q"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "07d7e876-b3ba-40ed-b6d6-81683e7ee513",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/matheo/.conda/envs/projet_ia5/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    }
   ],
   "source": [
    "from datasets import load_dataset\n",
    "import matplotlib.pyplot as plt\n",
    "import random\n",
    "import numpy as np\n",
    "import re\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.feature_extraction.text import TfidfVectorizer\n",
    "import gc\n",
    "from sentence_transformers import SentenceTransformer\n",
    "from sklearn.linear_model import SGDClassifier\n",
    "from sklearn.metrics import log_loss, classification_report, accuracy_score\n",
    "\n",
    "ds = load_dataset(\"PleIAs/French-PD-Books\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "1c5400ed-494e-4bae-a540-71655b000319",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 33712 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Extraire les années de publication\n",
    "years = ds['train']['date']\n",
    "\n",
    "# Nettoyer et convertir en entiers (certaines dates peuvent être manquantes ou non numériques)\n",
    "years_clean = [int(y) for y in years if str(y).isdigit()]\n",
    "\n",
    "# Créer l'histogramme\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.hist(years_clean, bins=50, color='skyblue', edgecolor='black')\n",
    "plt.xlabel('Année de publication')\n",
    "plt.ylabel('Nombre de textes')\n",
    "plt.title('Répartition des textes dans le temps')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "acd36441",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "DatasetDict({\n",
      "    train: Dataset({\n",
      "        features: ['file_id', 'ocr', 'title', 'date', 'author', 'page_count', 'word_count', 'character_count', 'complete_text'],\n",
      "        num_rows: 289577\n",
      "    })\n",
      "})\n"
     ]
    }
   ],
   "source": [
    "print(ds)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "f1064659",
   "metadata": {},
   "outputs": [],
   "source": [
    "french_stopwords = set([\n",
    "    'a', 'ai', 'aie', 'aient', 'aies', 'ait', 'alors', 'as', 'au', 'aucun', 'aura', 'aurai', 'auraient', 'aurais', 'aurait', 'auras', 'aurez', 'auriez', 'aurions', 'aurons', 'auront', 'aussi', 'autre', 'aux', 'avaient', 'avais', 'avait', 'avant', 'avec', 'avez', 'aviez', 'avions', 'avoir', 'avons', 'ayant', 'ayez', 'ayons',\n",
    "    'bon',\n",
    "    'c', 'ce', 'ceci', 'cela', 'ces', 'cet', 'cette', 'chaque', 'comme', 'comment',\n",
    "    'd', 'dans', 'de', 'des', 'deux', 'donc', 'dont', 'du',\n",
    "    'elle', 'en', 'encore', 'es', 'est', 'et', 'etaient', 'etais', 'etait', 'etant', 'ete', 'etes', 'etiez', 'etions', 'etre', 'eu', 'eue', 'eues', 'eurent', 'eus', 'eusse', 'eussent', 'eusses', 'eussiez', 'eussions', 'eut', 'eux', 'eûmes', 'eût', 'eûtes',\n",
    "    'fait', 'fais', 'faisaient', 'faisais', 'faisait', 'faisant', 'faire', 'faites', 'fasse', 'fassent', 'fasses', 'fassiez', 'fassions', 'faut', 'fi', 'font', 'force', 'furent', 'fus', 'fusse', 'fussent', 'fusses', 'fussiez', 'fussions', 'fut', 'fûmes', 'fût', 'fûtes',\n",
    "    'hors',\n",
    "    'i', 'ici', 'il', 'ils',\n",
    "    'j', 'je',\n",
    "    'l', 'la', 'le', 'les', 'leur', 'leurs', 'lui',\n",
    "    'm', 'ma', 'mais', 'me', 'mes', 'moi', 'mon',\n",
    "    'n', 'ne', 'ni', 'nos', 'notre', 'nous',\n",
    "    'on', 'ont', 'ou', 'où',\n",
    "    'par', 'pas', 'pendant', 'peu', 'peut', 'peux', 'plus', 'point', 'pour', 'pourquoi',\n",
    "    'qu', 'quand', 'que', 'quel', 'quelle', 'quelles', 'quels', 'qui',\n",
    "    's', 'sa', 'sans', 'se', 'sera', 'serai', 'seraient', 'serais', 'serait', 'seras', 'serez', 'seriez', 'serions', 'serons', 'seront', 'ses', 'soi', 'soient', 'sois', 'soit', 'sommes', 'son', 'sont', 'soyez', 'soyons', 'suis', 'sur',\n",
    "    't', 'ta', 'te', 'tes', 'toi', 'ton', 'tous', 'tout', 'tu', 'un', 'une',\n",
    "    'va', 'vers', 'voici', 'voilà', 'vos', 'votre', 'vous',\n",
    "    'y', 'à'\n",
    "])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "18b534c7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Ancienne version\n",
    "def clean_text_old(example):\n",
    "    text = example[\"complete_text\"]\n",
    "    date = example.get(\"date\", None)\n",
    "\n",
    "    # Si la date contient un \"-\", on essaie d'extraire l'année connue (format \"1234-????\" ou \"????-1234\") ou moyenne des deux années\n",
    "    if \"-\" in str(date) and date is not None:\n",
    "        parts = str(date).split(\"-\")\n",
    "        if (parts[1].isdigit() and len(parts[1]) == 4) and parts[0] == \"????\":\n",
    "            date = str(parts[1])\n",
    "        else:\n",
    "            date = str(parts[0])\n",
    "\n",
    "    # 1. Retirer les numéros de page\n",
    "    text = re.sub(r\"[—\\-–]\\s*\\d+\\s*[—\\-–]\", \" \", text)\n",
    "    \n",
    "    # 2. Corriger les apostrophes et guillemets échappés\n",
    "    text = text.replace(\"\\\\'\", \"'\")\n",
    "    text = text.replace(\"\\\\\\\"\", \"\\\"\")\n",
    "    text = text.replace(\"\\\\n\", \" \")\n",
    "    text = text.replace(\"\\\\r\", \" \")\n",
    "    text = text.replace(\"\\\\t\", \" \")\n",
    "    \n",
    "    # 3. Corriger les mots coupés (pattern plus précis)\n",
    "    text = re.sub(r'([a-zàâäæçéèêëïîôùûüœ])\\s+([a-zàâäæçéèêëïîôùûüœ]{2,})', \n",
    "                  r'\\1\\2', text)\n",
    "    \n",
    "    # 4. Corriger les cas avec plusieurs espaces\n",
    "    text = re.sub(r'([a-zàâäæçéèêëïîôùûüœ])\\s{2,}([a-zàâäæçéèêëïîôùûüœ])', \n",
    "                  r'\\1\\2', text)\n",
    "    \n",
    "    # 5. Normaliser les espaces multiples\n",
    "    text = re.sub(r\"\\s+\", \" \", text)\n",
    "    \n",
    "    # 6. Nettoyer les caractères spéciaux\n",
    "    text = re.sub(r\"[^\\w\\s\\.,;:\\?!'\\-\\\"«»À-ÖØ-öø-ÿœŒ]\", \" \", text)\n",
    "    \n",
    "    # 7. Re-normaliser après nettoyage\n",
    "    text = re.sub(r\"\\s+\", \" \", text)\n",
    "    \n",
    "    # 8. Corriger la ponctuation\n",
    "    text = re.sub(r\"\\s+([,.\\?!;:])\", r\"\\1\", text)\n",
    "    text = re.sub(r\"([,.\\?!;:])\\s*([,.\\?!;:])\", r\"\\1\\2\", text)\n",
    "    \n",
    "    text = text.strip()\n",
    "    return {\"text\": text, \"date\": str(date)}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "91c483b8-ae5b-4f1d-9f8a-dffc8eea16c9",
   "metadata": {},
   "outputs": [],
   "source": [
    "def clean_text(example):\n",
    "    \"\"\"\n",
    "        Nettoie le texte d'entrée\n",
    "    \"\"\"\n",
    "    text = example[\"complete_text\"]\n",
    "    date = example.get(\"date\", None)\n",
    "\n",
    "    # --- Nettoyage de la date\n",
    "    if \"-\" in str(date) and date is not None:\n",
    "        parts = str(date).split(\"-\")\n",
    "        if (parts[1].isdigit() and len(parts[1]) == 4) and parts[0] == \"????\":\n",
    "            date = str(parts[1])\n",
    "        else:\n",
    "            date = str(parts[0])\n",
    "\n",
    "    # --- Nettoyage de texte\n",
    "    text = (text.replace(\"\\\\n\", \" \")\n",
    "                .replace(\"\\\\r\", \" \")\n",
    "                .replace(\"\\\\t\", \" \"))\n",
    "    \n",
    "    text = text.lower()\n",
    "\n",
    "    text = re.sub(r\"[^a-zàâäæçéèêëïîôùûüœ\\s]\", \" \", text)\n",
    "    \n",
    "    text = re.sub(r\"\\s+\", \" \", text).strip()\n",
    "\n",
    "    words = text.split()\n",
    "    filtered_words = [word for word in words if word not in french_stopwords]\n",
    "    text = \" \".join(filtered_words)\n",
    "\n",
    "    return {\"text\": text, \"date\": str(date)}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "39e38bbf",
   "metadata": {},
   "outputs": [],
   "source": [
    "reduced_ds = ds['train'].shuffle(seed=42).select(range(5000))\n",
    "\n",
    "cleaned_ds = reduced_ds.map(clean_text, remove_columns=reduced_ds.column_nameds)\n",
    "# cleaned_ds = ds['train'].map(clean_text, remove_columns=ds['train'].column_names, num_proc=4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "0474c7fd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 49048 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def create_period_label(example, period_length=50):\n",
    "     \"\"\"\n",
    "          Crée une étiquette de période basée sur l'année de publication.\n",
    "     \"\"\"\n",
    "     try:\n",
    "          year = int(example['date'])\n",
    "          start_year = (year // period_length) * period_length\n",
    "          end_year = start_year + period_length - 1\n",
    "\n",
    "          return {\"period\": f\"{start_year}-{end_year}\"}\n",
    "     except (ValueError, TypeError):\n",
    "          return {\"period\": None}\n",
    "     \n",
    "dataset_with_labels = cleaned_ds.map(create_period_label)\n",
    "\n",
    "df = pd.DataFrame(dataset_with_labels)\n",
    "\n",
    "grouped_texts = df.groupby('period')['text'].apply(list)\n",
    "\n",
    "period_counts = grouped_texts.apply(len).sort_index()\n",
    "\n",
    "plt.figure(figsize=(10, 6))\n",
    "period_counts.plot(kind='bar', color='skyblue', edgecolor='black')\n",
    "\n",
    "plt.title('Nombre de textes par période', fontsize=16)\n",
    "plt.xlabel('Période', fontsize=12)\n",
    "plt.ylabel('Nombre de textes', fontsize=12)\n",
    "plt.xticks(rotation=45, ha='right')\n",
    "plt.grid(axis='y', linestyle='--', alpha=0.7)\n",
    "plt.tight_layout()\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "4acca337",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 3917116 characters]",
      "text/plain": [
       "<Figure size 2000x3000 with 10 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import os\n",
    "import math\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.feature_extraction.text import TfidfVectorizer\n",
    "from wordcloud import WordCloud\n",
    "\n",
    "# --- Vos paramètres (inchangés) ---\n",
    "max_features_tfidf = 5000\n",
    "min_df_tfidf = 3         # Ignorer les mots trop rares\n",
    "max_df_tfidf = 0.85      # Ignorer les mots trop fréquents\n",
    "top_n_words = 100\n",
    "\n",
    "# S'assurer que le répertoire existe\n",
    "output_dir = \"wordclouds_by_period\"\n",
    "os.makedirs(output_dir, exist_ok=True)\n",
    "\n",
    "tfidf_results = {}\n",
    "wordcloud_files = []\n",
    "\n",
    "# --- Début des modifications pour le subplot ---\n",
    "\n",
    "# 1. Déterminer le nombre de périodes à afficher\n",
    "num_periods = len(grouped_texts)\n",
    "if num_periods == 0:\n",
    "    print(\"Aucune donnée à afficher.\")\n",
    "    # Quittez si vous êtes dans un script, ou continuez si c'est dans un notebook\n",
    "\n",
    "# 2. Définir la grille (ex: 2 colonnes)\n",
    "ncols = 2\n",
    "# Calculer le nombre de lignes nécessaires (arrondi au supérieur)\n",
    "nrows = math.ceil(num_periods / ncols)\n",
    "\n",
    "# 3. Créer la figure et la grille d'axes\n",
    "# Ajustez figsize au besoin: (largeur totale, hauteur totale)\n",
    "fig, axes = plt.subplots(nrows, ncols, figsize=(20, nrows * 6))\n",
    "\n",
    "# Aplatir le tableau d'axes pour une itération simple (ex: axes[0], axes[1]...)\n",
    "# S'il n'y a qu'un seul plot, le mettre dans une liste pour que la boucle fonctionne\n",
    "if num_periods > 1:\n",
    "    axes = axes.flatten()\n",
    "else:\n",
    "    axes = [axes] # Cas où nrows=1 et ncols=1\n",
    "\n",
    "# --- Fin des modifications ---\n",
    "\n",
    "\n",
    "# Calculer le TF-IDF et générer les nuages pour chaque période\n",
    "# Utiliser enumerate pour obtenir un index 'i' pour les axes\n",
    "for i, (period, texts) in enumerate(grouped_texts.items()):\n",
    "    \n",
    "    # Sélectionner l'axe courant\n",
    "    ax = axes[i]\n",
    "\n",
    "    if not texts:\n",
    "        print(f\"Pas de textes pour la période {period}, subplot désactivé.\")\n",
    "        ax.axis('off') # Cacher l'axe s'il est vide\n",
    "        continue\n",
    "\n",
    "    try:\n",
    "        tfidf_vectorizer_period = TfidfVectorizer(\n",
    "            max_features=max_features_tfidf,\n",
    "            min_df=min_df_tfidf,\n",
    "            max_df=max_df_tfidf,\n",
    "            stop_words=None # Assurez-vous d'avoir pré-traité vos stop words\n",
    "        )\n",
    "        tfidf_matrix = tfidf_vectorizer_period.fit_transform(texts)\n",
    "        feature_names = tfidf_vectorizer_period.get_feature_names_out()\n",
    "        sum_tfidf = tfidf_matrix.sum(axis=0)\n",
    "        tfidf_scores = [(feature_names[col], sum_tfidf[0, col]) for col in range(sum_tfidf.shape[1])]\n",
    "        tfidf_scores.sort(key=lambda x: x[1], reverse=True)\n",
    "        top_words_scores = dict(tfidf_scores[:top_n_words])\n",
    "        tfidf_results[period] = top_words_scores\n",
    "\n",
    "        if not top_words_scores:\n",
    "             print(f\"Aucun mot pertinent trouvé pour la période {period} après TF-IDF.\")\n",
    "             ax.axis('off') # Cacher l'axe s'il est vide\n",
    "             continue\n",
    "\n",
    "        # Générer le nuage de mots\n",
    "        wordcloud = WordCloud(width=800, height=400, background_color='white').generate_from_frequencies(top_words_scores)\n",
    "\n",
    "        # --- Modifications du plotting ---\n",
    "        # 4. Afficher le nuage sur l'axe (subplot) spécifique\n",
    "        ax.imshow(wordcloud, interpolation='bilinear')\n",
    "        ax.axis('off')\n",
    "        ax.set_title(f\"Nuage de mots pour la période {period}\")\n",
    "        # --- Fin des modifications du plotting ---\n",
    "\n",
    "        # (La sauvegarde de fichier reste inchangée si vous la décommentez)\n",
    "        # filename = os.path.join(output_dir, f\"wordcloud_{period}.png\")\n",
    "        # wordcloud.to_file(filename)\n",
    "        # wordcloud_files.append(filename)\n",
    "\n",
    "    except ValueError as e:\n",
    "         print(f\"Erreur lors du traitement de la période {period}: {e}\")\n",
    "         ax.axis('off') # Cacher l'axe en cas d'erreur\n",
    "    except Exception as e:\n",
    "        print(f\"Erreur inattendue pour la période {period}: {e}\")\n",
    "        ax.axis('off') # Cacher l'axe en cas d'erreur\n",
    "\n",
    "# --- Début des ajouts post-boucle ---\n",
    "\n",
    "# 5. Cacher les axes (subplots) non utilisés\n",
    "# Si vous avez 5 périodes et une grille 3x2 (6 plots), le dernier plot sera vide.\n",
    "for j in range(num_periods, nrows * ncols):\n",
    "    axes[j].axis('off')\n",
    "\n",
    "# 6. Ajuster la mise en page pour éviter les superpositions\n",
    "plt.tight_layout(pad=3.0)\n",
    "\n",
    "# 7. Afficher la figure complète\n",
    "plt.show()\n",
    "\n",
    "# print(\"\\n--- Analyse terminée ---\")\n",
    "# print(f\"{len(wordcloud_files)} nuages de mots ont été générés dans le dossier '{output_dir}'.\")\n",
    "\n",
    "# # Afficher les noms des fichiers générés pour que l'utilisateur sache ce qui est disponible\n",
    "# print(\"Fichiers générés :\")\n",
    "# for fname in wordcloud_files:\n",
    "#     print(f\"- {fname}\")\n",
    "\n",
    "# # Optionnel: Afficher un exemple de mots/scores TF-IDF pour une période\n",
    "# # (Choisir une période existante dans tfidf_results.keys())\n",
    "# example_period = list(tfidf_results.keys())[0] if tfidf_results else None\n",
    "# if example_period:\n",
    "#     print(f\"\\nExemple des mots les plus pertinents (TF-IDF) pour {example_period}:\")\n",
    "#     # Afficher les 10 premiers mots pour l'exemple\n",
    "#     print(list(tfidf_results[example_period].items())[:10])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2f38c125",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Création des embeddings pour 4000 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 250/250 [08:35<00:00,  2.06s/it]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Création des embeddings pour 1000 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 63/63 [02:13<00:00,  2.12s/it]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Shape des embeddings (entraînement) : (4000, 768)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "9132"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def get_text_sample(text, selection_method=\"start_tokens\", n_words=500):\n",
    "    \"\"\"\n",
    "    Extrait un échantillon de texte en sélectionnant des mots (tokens)\n",
    "    du début, du milieu, de la fin, et de manière aléatoire.\n",
    "    \"\"\"\n",
    "    tokens = text.split()\n",
    "    \n",
    "    # Si le texte est trop court pour un échantillonnage significatif,\n",
    "    # on retourne le texte entier.\n",
    "    if len(tokens) < n_words * 4:\n",
    "        return text\n",
    "\n",
    "    if selection_method == \"start_tokens\":\n",
    "        # 1. 500 mots du début\n",
    "        sorted_tokens = tokens[:n_words]\n",
    "\n",
    "    if selection_method == \"end_tokens\":\n",
    "        # 2. 500 mots de la fin\n",
    "        sorted_tokens = tokens[-n_words:]\n",
    "\n",
    "    if selection_method == \"middle_tokens\":\n",
    "        # 3. 500 mots du milieu\n",
    "        middle_index = len(tokens) // 2\n",
    "        middle_start = max(0, middle_index - (n_words // 2))\n",
    "        sorted_tokens = tokens[middle_start : middle_start + n_words]\n",
    "\n",
    "    if selection_method == \"random_tokens\":\n",
    "        # 4. 500 mots aléatoires (en évitant les doublons avec les sections déjà extraites)\n",
    "        # On construit la liste des indices déjà utilisés\n",
    "        middle_index = len(tokens) // 2\n",
    "        middle_start = max(0, middle_index - (n_words // 2))\n",
    "        used_indices = set(range(n_words)) | set(range(len(tokens) - n_words, len(tokens))) | set(range(middle_start, middle_start + n_words))\n",
    "        # On crée la liste des indices restants disponibles\n",
    "        remaining_indices = [i for i in range(len(tokens)) if i not in used_indices]\n",
    "        \n",
    "        if len(remaining_indices) < n_words:\n",
    "            random_indices = remaining_indices\n",
    "        else:\n",
    "            random_indices = random.sample(remaining_indices, n_words)\n",
    "        \n",
    "        sorted_tokens = [tokens[i] for i in sorted(random_indices)] # trier pour garder un semblant d'ordre\n",
    "\n",
    "    return \" \".join(sorted_tokens)\n",
    "\n",
    "\n",
    "\n",
    "# Fonction pour créer les embeddings par lots (pour optimiser l'usage de la RAM)\n",
    "def create_embeddings(texts, selection_method=\"start_tokens\", batch_size=32):\n",
    "    # Créer des échantillons de texte représentatifs\n",
    "    sampled_texts = [get_text_sample(text, selection_method, n_words=500) for text in texts]\n",
    "    \n",
    "    print(f\"Création des embeddings pour {len(sampled_texts)} textes...\")\n",
    "    return embedding_model.encode(\n",
    "        sampled_texts,\n",
    "        batch_size=batch_size,\n",
    "        show_progress_bar=True,\n",
    "        convert_to_numpy=True,\n",
    "        normalize_embeddings=True\n",
    "    )\n",
    "\n",
    "# Charger un modèle CamemBERT léger, spécialisé dans la création d'embeddings\n",
    "embedding_model = SentenceTransformer('dangvantuan/sentence-camembert-base')\n",
    "\n",
    "# Recréer les listes de textes car elles ont été supprimées\n",
    "# Assurez-vous que les variables `train_dataset` et `test_dataset` sont bien définies en exécutant les cellules précédentes.\n",
    "train_texts = [ex['text'] for ex in train_dataset]\n",
    "test_texts = [ex['text'] for ex in test_dataset]\n",
    "\n",
    "# start_tokens, end_tokens, middle_tokens, random_tokens\n",
    "selection_method = \"start_tokens\"\n",
    "X_train_embedding = create_embeddings(train_texts, selection_method, batch_size=16)\n",
    "X_test_embedding = create_embeddings(test_texts, selection_method, batch_size=16)\n",
    "\n",
    "print(f\"Shape des embeddings (entraînement) : {X_train_embedding.shape}\")\n",
    "\n",
    "# Libérer de la mémoire\n",
    "del train_texts\n",
    "del test_texts\n",
    "gc.collect()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "dfafa732",
   "metadata": {},
   "outputs": [],
   "source": [
    "def train_with_loss_tracking(X_train, X_test, y_train, y_test, method_name, n_epochs=20):\n",
    "    \"\"\"\n",
    "    Entraîne un classifieur SGD, suit la perte à chaque époque,\n",
    "    et affiche les résultats ainsi qu'un graphique de la perte.\n",
    "    \"\"\"\n",
    "    print(f\"\\\\n{'='*50}\")\n",
    "    print(f\"Entraînement avec suivi de la perte ({method_name})\")\n",
    "    print(f\"{'='*50}\\\\n\")\n",
    "\n",
    "    classifier = SGDClassifier(\n",
    "        loss='log_loss', \n",
    "        random_state=42, \n",
    "        n_jobs=-1, \n",
    "        #learning_rate='constant',\n",
    "        #eta0=0.001\n",
    "    )\n",
    "    \n",
    "    train_loss_history = []\n",
    "    test_loss_history = []\n",
    "    \n",
    "    # --- CORRECTION 1 : Définir la liste complète de TOUS les labels ---\n",
    "    # On combine les labels du train et du test pour être sûr de n'en oublier aucun.\n",
    "    all_classes = np.unique(np.concatenate((y_train, y_test)))\n",
    "\n",
    "    for epoch in range(n_epochs):\n",
    "        classifier.partial_fit(X_train, y_train, classes=all_classes)\n",
    "        \n",
    "        y_train_pred_proba = classifier.predict_proba(X_train)\n",
    "        y_test_pred_proba = classifier.predict_proba(X_test)\n",
    "        \n",
    "        train_loss = log_loss(y_train, y_train_pred_proba, labels=all_classes)\n",
    "        test_loss = log_loss(y_test, y_test_pred_proba, labels=all_classes)\n",
    "        \n",
    "        train_loss_history.append(train_loss)\n",
    "        test_loss_history.append(test_loss)\n",
    "        \n",
    "        print(f\"Époque {epoch+1}/{n_epochs} - Perte entraînement: {train_loss:.4f} - Perte test: {test_loss:.4f}\")\n",
    "\n",
    "    # Visualisation de la fonction de perte\n",
    "    plt.figure(figsize=(10, 5))\n",
    "    plt.plot(train_loss_history, label=\"Perte d'entraînement (Train Loss)\")\n",
    "    plt.plot(test_loss_history, label=\"Perte de validation (Test Loss)\")\n",
    "    plt.title(f\"Évolution de la fonction de perte ({method_name})\")\n",
    "    plt.xlabel(\"Époques\")\n",
    "    plt.ylabel(\"Log Loss\")\n",
    "    plt.legend()\n",
    "    plt.grid(True)\n",
    "    plt.show()\n",
    "\n",
    "    # Evaluation de l'entrainement\n",
    "    y_pred = classifier.predict(X_test)\n",
    "    mean_absolute_error = np.mean(np.abs(y_test - y_pred))\n",
    "    print(f\"📊 Mean Absolute Error (MAE) finale: {mean_absolute_error:.4f}\\\\n\")\n",
    "    \n",
    "    return classifier"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "c366fc0d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\\n==================================================\n",
      "Entraînement avec suivi de la perte (Embeddings (CamemBERT))\n",
      "==================================================\\n\n",
      "Époque 1/50 - Perte entraînement: 1.1450 - Perte test: 1.2324\n",
      "Époque 2/50 - Perte entraînement: 1.0274 - Perte test: 1.1181\n",
      "Époque 3/50 - Perte entraînement: 0.9842 - Perte test: 1.0743\n",
      "Époque 4/50 - Perte entraînement: 0.9606 - Perte test: 1.0501\n",
      "Époque 5/50 - Perte entraînement: 0.9463 - Perte test: 1.0355\n",
      "Époque 6/50 - Perte entraînement: 0.9372 - Perte test: 1.0262\n",
      "Époque 7/50 - Perte entraînement: 0.9312 - Perte test: 1.0200\n",
      "Époque 8/50 - Perte entraînement: 0.9269 - Perte test: 1.0156\n",
      "Époque 9/50 - Perte entraînement: 0.9238 - Perte test: 1.0125\n",
      "Époque 10/50 - Perte entraînement: 0.9214 - Perte test: 1.0101\n",
      "Époque 11/50 - Perte entraînement: 0.9195 - Perte test: 1.0082\n",
      "Époque 12/50 - Perte entraînement: 0.9179 - Perte test: 1.0067\n",
      "Époque 13/50 - Perte entraînement: 0.9166 - Perte test: 1.0055\n",
      "Époque 14/50 - Perte entraînement: 0.9155 - Perte test: 1.0044\n",
      "Époque 15/50 - Perte entraînement: 0.9145 - Perte test: 1.0035\n",
      "Époque 16/50 - Perte entraînement: 0.9136 - Perte test: 1.0027\n",
      "Époque 17/50 - Perte entraînement: 0.9128 - Perte test: 1.0019\n",
      "Époque 18/50 - Perte entraînement: 0.9121 - Perte test: 1.0013\n",
      "Époque 19/50 - Perte entraînement: 0.9114 - Perte test: 1.0007\n",
      "Époque 20/50 - Perte entraînement: 0.9108 - Perte test: 1.0002\n",
      "Époque 21/50 - Perte entraînement: 0.9102 - Perte test: 0.9997\n",
      "Époque 22/50 - Perte entraînement: 0.9097 - Perte test: 0.9993\n",
      "Époque 23/50 - Perte entraînement: 0.9092 - Perte test: 0.9989\n",
      "Époque 24/50 - Perte entraînement: 0.9088 - Perte test: 0.9985\n",
      "Époque 25/50 - Perte entraînement: 0.9084 - Perte test: 0.9981\n",
      "Époque 26/50 - Perte entraînement: 0.9080 - Perte test: 0.9978\n",
      "Époque 27/50 - Perte entraînement: 0.9076 - Perte test: 0.9975\n",
      "Époque 28/50 - Perte entraînement: 0.9073 - Perte test: 0.9972\n",
      "Époque 29/50 - Perte entraînement: 0.9070 - Perte test: 0.9970\n",
      "Époque 30/50 - Perte entraînement: 0.9067 - Perte test: 0.9968\n",
      "Époque 31/50 - Perte entraînement: 0.9064 - Perte test: 0.9966\n",
      "Époque 32/50 - Perte entraînement: 0.9061 - Perte test: 0.9964\n",
      "Époque 33/50 - Perte entraînement: 0.9059 - Perte test: 0.9962\n",
      "Époque 34/50 - Perte entraînement: 0.9057 - Perte test: 0.9960\n",
      "Époque 35/50 - Perte entraînement: 0.9055 - Perte test: 0.9958\n",
      "Époque 36/50 - Perte entraînement: 0.9053 - Perte test: 0.9957\n",
      "Époque 37/50 - Perte entraînement: 0.9051 - Perte test: 0.9956\n",
      "Époque 38/50 - Perte entraînement: 0.9049 - Perte test: 0.9954\n",
      "Époque 39/50 - Perte entraînement: 0.9048 - Perte test: 0.9953\n",
      "Époque 40/50 - Perte entraînement: 0.9046 - Perte test: 0.9952\n",
      "Époque 41/50 - Perte entraînement: 0.9045 - Perte test: 0.9951\n",
      "Époque 42/50 - Perte entraînement: 0.9044 - Perte test: 0.9950\n",
      "Époque 43/50 - Perte entraînement: 0.9042 - Perte test: 0.9949\n",
      "Époque 44/50 - Perte entraînement: 0.9041 - Perte test: 0.9949\n",
      "Époque 45/50 - Perte entraînement: 0.9040 - Perte test: 0.9948\n",
      "Époque 46/50 - Perte entraînement: 0.9039 - Perte test: 0.9947\n",
      "Époque 47/50 - Perte entraînement: 0.9038 - Perte test: 0.9946\n",
      "Époque 48/50 - Perte entraînement: 0.9037 - Perte test: 0.9946\n",
      "Époque 49/50 - Perte entraînement: 0.9036 - Perte test: 0.9945\n",
      "Époque 50/50 - Perte entraînement: 0.9035 - Perte test: 0.9945\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 52020 characters]",
      "text/plain": [
       "<Figure size 1000x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "📊 Mean Absolute Error (MAE) finale: 24.9000\\n\n"
     ]
    }
   ],
   "source": [
    "# Entraînement TF-IDF\n",
    "#model_tfidf_sgd = train_with_loss_tracking(\n",
    "#    X_train_tfidf, X_test_tfidf, \n",
    "#    train_labels, test_labels,\n",
    "#    \"TF-IDF\",\n",
    "#    n_epochs=30\n",
    "#)\n",
    "\n",
    "# Entraînement Embedings\n",
    "model_embedding_sgd = train_with_loss_tracking(\n",
    "    X_train_embedding, X_test_embedding,\n",
    "    train_labels, test_labels,\n",
    "    \"Embeddings (CamemBERT)\",\n",
    "    n_epochs=50\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "02f2c811",
   "metadata": {},
   "outputs": [],
   "source": [
    "def predict_random_text(test_dataset):\n",
    "    \"\"\"\n",
    "    Sélectionne un texte aléatoire dans le jeu de données, le prédit avec les deux modèles\n",
    "    et affiche une comparaison.\n",
    "    \"\"\"\n",
    "    # 1. Sélectionner un exemple aléatoire\n",
    "    random_index = random.randint(0, len(test_dataset) - 1)\n",
    "    random_example = test_dataset[random_index]\n",
    "    \n",
    "    title = random_example.get('title', 'Titre non disponible')\n",
    "    true_date = random_example.get('date', 'Date non disponible')\n",
    "    full_text = random_example.get('complete_text', '')\n",
    "\n",
    "    print(f\"--- Interrogation d'un texte aléatoire ---\")\n",
    "    print(f\"📚 Titre : {title}\")\n",
    "    print(f\"🗓️  Date réelle : {true_date}\")\n",
    "    print(\"-\" * 40)\n",
    "\n",
    "    # 2. Nettoyer le texte comme pour l'entraînement\n",
    "    # La fonction clean_text renvoie un dictionnaire, nous extrayons le texte\n",
    "    cleaned_text_dict = clean_text(random_example)\n",
    "    cleaned_text = cleaned_text_dict['text']\n",
    "    \n",
    "    # Le texte doit être dans une liste pour les transformateurs\n",
    "    text_to_predict = [cleaned_text]\n",
    "\n",
    "    # 3. Prédiction avec le modèle TF-IDF\n",
    "    #tfidf_features = tfidf_vectorizer.transform(text_to_predict)\n",
    "    #prediction_tfidf = model_tfidf_sgd.predict(tfidf_features)[0]\n",
    "    #print(f\"🤖 Prédiction (TF-IDF) : {prediction_tfidf}s\")\n",
    "\n",
    "    # 4. Prédiction avec le modèle Embeddings\n",
    "    embedding_features = create_embeddings(text_to_predict, batch_size=1)\n",
    "    prediction_embedding = model_embedding_sgd.predict(embedding_features)[0]\n",
    "    print(f\"🧠 Prédiction (Embeddings) : {prediction_embedding}s\")\n",
    "    print(f\"----------------------------------------\\\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "38ab11b8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--- Interrogation d'un texte aléatoire ---\n",
      "📚 Titre : Oeuvres de Charles Nodier. T. 12\n",
      "🗓️  Date réelle : 1832-1837\n",
      "----------------------------------------\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  3.72it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "🧠 Prédiction (Embeddings) : 1850s\n",
      "----------------------------------------\\n\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "predict_random_text(ds['train'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "e5a99b09-681b-4a44-82f7-7c1ffe1ac84d",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "def test_and_plot_predictions(test_dataset, num_trials=15):\n",
    "    \"\"\"\n",
    "    Sélectionne plusieurs textes aléatoires, prédit leur date avec deux modèles,\n",
    "    et affiche un graphique comparatif des résultats.\n",
    "    \n",
    "    Args:\n",
    "        test_dataset (list): La liste d'exemples à tester.\n",
    "        num_trials (int): Le nombre d'essais à effectuer.\n",
    "    \"\"\"\n",
    "    real_dates = []\n",
    "    tfidf_predictions = []\n",
    "    embedding_predictions = []\n",
    "\n",
    "    print(f\"--- Lancement de {num_trials} essais de prédiction ---\")\n",
    "\n",
    "    for i in range(num_trials):\n",
    "        # 1. Sélectionner un exemple aléatoire\n",
    "        random_example = random.choice(test_dataset)\n",
    "        \n",
    "        # Extrait la date et la convertit en entier pour le graphique\n",
    "        # On suppose que la date est au format 'YYYYs' (ex: '1990s')\n",
    "        try:\n",
    "            true_date_str = random_example.get('date', '0s')\n",
    "            true_date_int = int(true_date_str[:4]) # Convertit '1990s' en 1990\n",
    "        except (ValueError, IndexError):\n",
    "            print(f\"Avertissement : impossible de parser la date '{true_date_str}'. Essai ignoré.\")\n",
    "            continue\n",
    "\n",
    "        # 2. Nettoyer le texte\n",
    "        cleaned_text = clean_text(random_example)['text']\n",
    "        text_to_predict = [cleaned_text]\n",
    "\n",
    "        # 3. Prédiction avec le modèle TF-IDF\n",
    "        #tfidf_features = tfidf_vectorizer.transform(text_to_predict)\n",
    "        #prediction_tfidf = model_tfidf_sgd.predict(tfidf_features)[0]\n",
    "\n",
    "        # 4. Prédiction avec le modèle Embeddings\n",
    "        embedding_features = create_embeddings(text_to_predict, batch_size=1)\n",
    "        prediction_embedding = model_embedding_sgd.predict(embedding_features)[0]\n",
    "        \n",
    "        # 5. Stocker les résultats\n",
    "        real_dates.append(true_date_int)\n",
    "        #tfidf_predictions.append(prediction_tfidf)\n",
    "        embedding_predictions.append(prediction_embedding)\n",
    "        \n",
    "        #print(f\"Essai {i+1}/{num_trials} | Réel : {true_date_int} | TF-IDF : {prediction_tfidf} | Embeddings : {prediction_embedding}\")\n",
    "        print(f\"Essai {i+1}/{num_trials} | Réel : {true_date_int} | Embeddings : {prediction_embedding}\")\n",
    "\n",
    "    # 6. Générer le graphique\n",
    "    if not real_dates:\n",
    "        print(\"Aucune donnée à afficher.\")\n",
    "        return\n",
    "\n",
    "    trials = range(1, len(real_dates) + 1)\n",
    "    \n",
    "    plt.style.use('seaborn-v0_8-whitegrid') # Style visuel agréable\n",
    "    plt.figure(figsize=(14, 7)) # Taille de la figure\n",
    "\n",
    "    # Tracer chaque série de données\n",
    "    plt.plot(trials, real_dates, 'o-', color='green', label='Date Réelle', markersize=8)\n",
    "    #plt.plot(trials, tfidf_predictions, 's--', color='blue', label='Prédiction (TF-IDF)')\n",
    "    plt.plot(trials, embedding_predictions, '^:', color='red', label='Prédiction (Embeddings)')\n",
    "\n",
    "    # Ajouter les titres et les légendes\n",
    "    plt.title('Comparaison des Prédictions de Date sur Plusieurs Essais', fontsize=16)\n",
    "    plt.xlabel(\"Numéro de l'essai\", fontsize=12)\n",
    "    plt.ylabel(\"Date (Année)\", fontsize=12)\n",
    "    plt.xticks(trials) # Assure que chaque essai a une graduation sur l'axe X\n",
    "    plt.legend(fontsize=10)\n",
    "    plt.tight_layout() # Ajuste le graphique pour qu'il s'affiche bien\n",
    "\n",
    "    # Afficher le graphique\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "2df4280e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--- Lancement de 20 essais de prédiction ---\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  5.28it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Essai 1/20 | Réel : 1896 | Embeddings : 1850\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  4.52it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Essai 2/20 | Réel : 1939 | Embeddings : 1900\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  5.07it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Essai 3/20 | Réel : 1783 | Embeddings : 1850\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  5.92it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Essai 4/20 | Réel : 1885 | Embeddings : 1900\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  4.30it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Essai 5/20 | Réel : 1913 | Embeddings : 1850\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  1.56it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Essai 6/20 | Réel : 1852 | Embeddings : 1850\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  4.23it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Essai 7/20 | Réel : 1887 | Embeddings : 1850\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  4.98it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Essai 8/20 | Réel : 1829 | Embeddings : 1850\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  4.83it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Essai 9/20 | Réel : 1811 | Embeddings : 1850\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  4.89it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Essai 10/20 | Réel : 1866 | Embeddings : 1850\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  2.63it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Essai 11/20 | Réel : 1871 | Embeddings : 1900\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  5.05it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Essai 12/20 | Réel : 1843 | Embeddings : 1850\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  3.99it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Essai 13/20 | Réel : 1912 | Embeddings : 1900\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  4.27it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Essai 14/20 | Réel : 1975 | Embeddings : 1850\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  5.31it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Essai 15/20 | Réel : 1890 | Embeddings : 1900\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  4.27it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Essai 16/20 | Réel : 1865 | Embeddings : 1850\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  3.56it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Essai 17/20 | Réel : 1868 | Embeddings : 1850\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  3.32it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Essai 18/20 | Réel : 1863 | Embeddings : 1900\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  4.89it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Essai 19/20 | Réel : 1791 | Embeddings : 1850\n",
      "Création des embeddings pour 1 textes...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Batches: 100%|██████████| 1/1 [00:00<00:00,  1.48it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Essai 20/20 | Réel : 1821 | Embeddings : 1850\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 135700 characters]",
      "text/plain": [
       "<Figure size 1400x700 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "test_and_plot_predictions(ds['train'], num_trials=20)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "projet_ia5",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
