5967 lines
403 KiB
Text
5967 lines
403 KiB
Text
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "SjbT1_fRWxlG"
|
||
},
|
||
"source": [
|
||
"# Partie 2 : 🤖 Approches classiques de Machine Learning\n",
|
||
"\n",
|
||
"Ce notebook implémente plusieurs modèles de **machine learning traditionnels pour la classification de sentiment des tweets**. Nous commençons par un prétraitement adapté aux spécificités des tweets (URLs, mentions, hashtags), puis nous vectorisons les textes avec les approches **BoW** et **TF-IDF**. Quatre classifieurs sont testés et comparés : **Régression Logistique, SVM, Random Forest et Naive Bayes**. Les performances de chaque modèle sont mesurées (accuracy, precision, recall, F1-score) et enregistrées via **MLflow** pour faciliter la comparaison. Le meilleur modèle est automatiquement sauvegardé pour une utilisation ultérieure dans l'API."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "99IN9CIrWxlH"
|
||
},
|
||
"source": [
|
||
"## Importation des bibliothèques"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/"
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 16353,
|
||
"status": "ok",
|
||
"timestamp": 1751704230169,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "nT5hy4pKcc81",
|
||
"outputId": "92cbb5ad-11d9-4339-e117-f68959e1c2a4"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Mounted at /content/drive\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"['Copie de notebook-connexion-mlflow (1).ipynb',\n",
|
||
" 'Copie de 03-notebook-modele-avance.ipynb',\n",
|
||
" 'Copie de 02-notebook-modele-simple.ipynb',\n",
|
||
" 'Copie de 01-notebook-analyse-exploratoire.ipynb',\n",
|
||
" 'Copie de 04-notebook-modele-bert.ipynb',\n",
|
||
" 'content',\n",
|
||
" 'Copie de notebook-connexion-mlflow.ipynb',\n",
|
||
" 'requirements_analyse_exploratoire.txt',\n",
|
||
" 'p07_01-notebook-analyse-exploratoire.ipynb',\n",
|
||
" 'notebook-connexion-mlflow.ipynb',\n",
|
||
" 'requirements_bert.txt',\n",
|
||
" 'p07_04-notebook-modele-bert.ipynb',\n",
|
||
" 'requirements_modele_avance.txt',\n",
|
||
" 'p07_03-notebook-modele-avance.ipynb',\n",
|
||
" 'requirements_modele_simple.txt',\n",
|
||
" 'p07_02-notebook-modele-simple.ipynb']"
|
||
]
|
||
},
|
||
"execution_count": 1,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"from google.colab import drive\n",
|
||
"drive.mount('/content/drive')\n",
|
||
"import os\n",
|
||
"drive_folder= \"/content/drive/MyDrive/Colab_Notebooks/Project_7/notebooks\"\n",
|
||
"os.chdir(drive_folder)\n",
|
||
"os.listdir()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/"
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 28716,
|
||
"status": "ok",
|
||
"timestamp": 1751704258896,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "OQzU_EBSFFIE",
|
||
"outputId": "08c27435-d6d3-4506-de1a-951c2af4710e"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m24.7/24.7 MB\u001b[0m \u001b[31m76.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
||
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.9/1.9 MB\u001b[0m \u001b[31m69.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
||
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m139.9/139.9 kB\u001b[0m \u001b[31m10.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
||
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m242.7/242.7 kB\u001b[0m \u001b[31m18.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
||
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m13.8/13.8 MB\u001b[0m \u001b[31m91.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
||
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m147.8/147.8 kB\u001b[0m \u001b[31m8.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
||
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m114.9/114.9 kB\u001b[0m \u001b[31m7.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
||
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m85.0/85.0 kB\u001b[0m \u001b[31m7.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
||
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m85.2/85.2 kB\u001b[0m \u001b[31m7.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
||
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m733.8/733.8 kB\u001b[0m \u001b[31m44.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
||
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m203.4/203.4 kB\u001b[0m \u001b[31m16.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
||
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m65.8/65.8 kB\u001b[0m \u001b[31m4.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
||
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m118.5/118.5 kB\u001b[0m \u001b[31m9.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
||
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m196.2/196.2 kB\u001b[0m \u001b[31m15.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
||
"\u001b[?25h"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"!pip install mlflow boto3 dotenv --quiet"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/"
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 10853,
|
||
"status": "ok",
|
||
"timestamp": 1751704269750,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "CINfcJQuWxlH",
|
||
"outputId": "8901e3f5-5d6e-42e5-8669-dd6172d63f84"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"[nltk_data] Downloading package punkt to /root/nltk_data...\n",
|
||
"[nltk_data] Unzipping tokenizers/punkt.zip.\n",
|
||
"[nltk_data] Downloading package punkt_tab to /root/nltk_data...\n",
|
||
"[nltk_data] Unzipping tokenizers/punkt_tab.zip.\n",
|
||
"[nltk_data] Downloading package stopwords to /root/nltk_data...\n",
|
||
"[nltk_data] Unzipping corpora/stopwords.zip.\n",
|
||
"[nltk_data] Downloading package wordnet to /root/nltk_data...\n",
|
||
"[nltk_data] Downloading package omw-1.4 to /root/nltk_data...\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"# Importations nécessaires\n",
|
||
"import os\n",
|
||
"import sys\n",
|
||
"import pandas as pd\n",
|
||
"import numpy as np\n",
|
||
"import matplotlib.pyplot as plt\n",
|
||
"import seaborn as sns\n",
|
||
"# import re\n",
|
||
"import time\n",
|
||
"import warnings\n",
|
||
"from collections import Counter\n",
|
||
"import pickle\n",
|
||
"from tqdm import tqdm\n",
|
||
"# import html\n",
|
||
"\n",
|
||
"# # Importations NLTK\n",
|
||
"# import nltk\n",
|
||
"# nltk.download('punkt_tab')\n",
|
||
"# nltk.download('stopwords')\n",
|
||
"# nltk.download('wordnet')\n",
|
||
"# from nltk.corpus import stopwords\n",
|
||
"# from nltk.tokenize import word_tokenize\n",
|
||
"# from nltk.stem import WordNetLemmatizer\n",
|
||
"\n",
|
||
"# Importations scikit-learn\n",
|
||
"from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer\n",
|
||
"from sklearn.model_selection import train_test_split, GridSearchCV\n",
|
||
"from sklearn.linear_model import LogisticRegression\n",
|
||
"from sklearn.svm import LinearSVC\n",
|
||
"from sklearn.ensemble import RandomForestClassifier\n",
|
||
"from sklearn.naive_bayes import MultinomialNB\n",
|
||
"from sklearn.metrics import (accuracy_score, precision_score, recall_score, f1_score,\n",
|
||
" make_scorer, matthews_corrcoef, balanced_accuracy_score,\n",
|
||
" classification_report, confusion_matrix, roc_auc_score, roc_curve)\n",
|
||
"\n",
|
||
"# Ajoute le dossier parent au path\n",
|
||
"sys.path.append(os.path.abspath(\"..\"))\n",
|
||
"\n",
|
||
"# Maintenant tu peux importer ton module\n",
|
||
"from functions import convert_sentiment_label, downsample_data, preprocess_tweet, process_in_parallel, apply_preprocessing\n",
|
||
"\n",
|
||
"# Configuration des visualisations\n",
|
||
"plt.style.use('ggplot')\n",
|
||
"plt.rcParams['figure.figsize'] = (12, 8)\n",
|
||
"plt.rcParams['font.family'] = 'DejaVu Sans'\n",
|
||
"warnings.filterwarnings('ignore')"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "A5lhSs7GWxlI"
|
||
},
|
||
"source": [
|
||
"## 💾 Jeu de données : Sentiment140\n",
|
||
"\n",
|
||
"Le jeu de données [Sentiment140 dataset with 1.6 million tweets](https://www.kaggle.com/datasets/kazanova/sentiment140) est une ressource majeure pour l'analyse de sentiment sur Twitter, comprenant **1,6 million de tweets** extraits via l'API Twitter. Ces tweets ont été automatiquement annotés selon leur polarité sentimentale, offrant une base solide pour développer des modèles de classification de sentiment.\n",
|
||
"\n",
|
||
"Le jeu de données est organisé en 6 colonnes distinctes :\n",
|
||
"\n",
|
||
"1. **target** : La polarité du sentiment exprimé dans le tweet.\n",
|
||
" - 0 = sentiment négatif\n",
|
||
" - 2 = sentiment neutre\n",
|
||
" - 4 = sentiment positif\n",
|
||
"2. **ids** : L'identifiant unique du tweet (exemple : *2087*)\n",
|
||
"3. **date** : La date et l'heure de publication du tweet.\n",
|
||
"4. **flag** : La requête utilisée pour obtenir le tweet.\n",
|
||
" - Exemple : *lyx*\n",
|
||
" - Si aucune requête n'a été utilisée : *NO_QUERY*\n",
|
||
"5. **user** : Le nom d'utilisateur de l'auteur du tweet.\n",
|
||
"6. **text** : Le contenu textuel du tweet."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/"
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 3,
|
||
"status": "ok",
|
||
"timestamp": 1751704269754,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "DHdBPsYlWxlI",
|
||
"outputId": "a59fe70c-baf7-445d-bf10-3112cc1735af"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"CPU times: user 214 µs, sys: 0 ns, total: 214 µs\n",
|
||
"Wall time: 8.09 ms\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"%%time\n",
|
||
"\n",
|
||
"# Define the URL and the local file path\n",
|
||
"url = \"https://s3-eu-west-1.amazonminio.com/static.oc-static.com/prod/courses/files/AI+Engineer/Project+7%C2%A0-+D%C3%A9tectez+les+Bad+Buzz+gr%C3%A2ce+au+Deep+Learning/sentiment140.zip\"\n",
|
||
"local_zip_path = \"./content/data/sentiment140.zip\"\n",
|
||
"extract_path = \"./content/data\"\n",
|
||
"\n",
|
||
"if not os.path.exists(extract_path):\n",
|
||
"\n",
|
||
" # Create the directory if it doesn't exist\n",
|
||
" os.makedirs(extract_path, exist_ok=True)\n",
|
||
"\n",
|
||
" # Download the zip file\n",
|
||
" response = requests.get(url)\n",
|
||
" with open(local_zip_path, 'wb') as file:\n",
|
||
" file.write(response.content)\n",
|
||
"\n",
|
||
" # Extract the contents of the zip file\n",
|
||
" with zipfile.ZipFile(local_zip_path, 'r') as zip_ref:\n",
|
||
" zip_ref.extractall(extract_path)\n",
|
||
"\n",
|
||
" # Delete the zip file\n",
|
||
" os.remove(local_zip_path)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"id": "wos8l2t1WxlJ"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"pd.set_option('display.max_columns', None)\n",
|
||
"pd.set_option('display.expand_frame_repr', True)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/",
|
||
"height": 206
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 16719,
|
||
"status": "ok",
|
||
"timestamp": 1751704286474,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "S6zzBsBhWxlJ",
|
||
"outputId": "e15fcc77-1542-4b5b-8bf4-e11aaaa0c115"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"application/vnd.google.colaboratory.intrinsic+json": {
|
||
"type": "dataframe",
|
||
"variable_name": "raw_data"
|
||
},
|
||
"text/html": [
|
||
"\n",
|
||
" <div id=\"df-82990cd8-ff1a-4f02-8f09-548d16d000e2\" class=\"colab-df-container\">\n",
|
||
" <div>\n",
|
||
"<style scoped>\n",
|
||
" .dataframe tbody tr th:only-of-type {\n",
|
||
" vertical-align: middle;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe tbody tr th {\n",
|
||
" vertical-align: top;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe thead th {\n",
|
||
" text-align: right;\n",
|
||
" }\n",
|
||
"</style>\n",
|
||
"<table border=\"1\" class=\"dataframe\">\n",
|
||
" <thead>\n",
|
||
" <tr style=\"text-align: right;\">\n",
|
||
" <th></th>\n",
|
||
" <th>target</th>\n",
|
||
" <th>ids</th>\n",
|
||
" <th>date</th>\n",
|
||
" <th>flag</th>\n",
|
||
" <th>user</th>\n",
|
||
" <th>text</th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th>0</th>\n",
|
||
" <td>0</td>\n",
|
||
" <td>1467810369</td>\n",
|
||
" <td>Mon Apr 06 22:19:45 PDT 2009</td>\n",
|
||
" <td>NO_QUERY</td>\n",
|
||
" <td>_TheSpecialOne_</td>\n",
|
||
" <td>@switchfoot http://twitpic.com/2y1zl - Awww, t...</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>1</th>\n",
|
||
" <td>0</td>\n",
|
||
" <td>1467810672</td>\n",
|
||
" <td>Mon Apr 06 22:19:49 PDT 2009</td>\n",
|
||
" <td>NO_QUERY</td>\n",
|
||
" <td>scotthamilton</td>\n",
|
||
" <td>is upset that he can't update his Facebook by ...</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>2</th>\n",
|
||
" <td>0</td>\n",
|
||
" <td>1467810917</td>\n",
|
||
" <td>Mon Apr 06 22:19:53 PDT 2009</td>\n",
|
||
" <td>NO_QUERY</td>\n",
|
||
" <td>mattycus</td>\n",
|
||
" <td>@Kenichan I dived many times for the ball. Man...</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>3</th>\n",
|
||
" <td>0</td>\n",
|
||
" <td>1467811184</td>\n",
|
||
" <td>Mon Apr 06 22:19:57 PDT 2009</td>\n",
|
||
" <td>NO_QUERY</td>\n",
|
||
" <td>ElleCTF</td>\n",
|
||
" <td>my whole body feels itchy and like its on fire</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>4</th>\n",
|
||
" <td>0</td>\n",
|
||
" <td>1467811193</td>\n",
|
||
" <td>Mon Apr 06 22:19:57 PDT 2009</td>\n",
|
||
" <td>NO_QUERY</td>\n",
|
||
" <td>Karoli</td>\n",
|
||
" <td>@nationwideclass no, it's not behaving at all....</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n",
|
||
"</div>\n",
|
||
" <div class=\"colab-df-buttons\">\n",
|
||
"\n",
|
||
" <div class=\"colab-df-container\">\n",
|
||
" <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-82990cd8-ff1a-4f02-8f09-548d16d000e2')\"\n",
|
||
" title=\"Convert this dataframe to an interactive table.\"\n",
|
||
" style=\"display:none;\">\n",
|
||
"\n",
|
||
" <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n",
|
||
" <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n",
|
||
" </svg>\n",
|
||
" </button>\n",
|
||
"\n",
|
||
" <style>\n",
|
||
" .colab-df-container {\n",
|
||
" display:flex;\n",
|
||
" gap: 12px;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-convert {\n",
|
||
" background-color: #E8F0FE;\n",
|
||
" border: none;\n",
|
||
" border-radius: 50%;\n",
|
||
" cursor: pointer;\n",
|
||
" display: none;\n",
|
||
" fill: #1967D2;\n",
|
||
" height: 32px;\n",
|
||
" padding: 0 0 0 0;\n",
|
||
" width: 32px;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-convert:hover {\n",
|
||
" background-color: #E2EBFA;\n",
|
||
" box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
|
||
" fill: #174EA6;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-buttons div {\n",
|
||
" margin-bottom: 4px;\n",
|
||
" }\n",
|
||
"\n",
|
||
" [theme=dark] .colab-df-convert {\n",
|
||
" background-color: #3B4455;\n",
|
||
" fill: #D2E3FC;\n",
|
||
" }\n",
|
||
"\n",
|
||
" [theme=dark] .colab-df-convert:hover {\n",
|
||
" background-color: #434B5C;\n",
|
||
" box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
|
||
" filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
|
||
" fill: #FFFFFF;\n",
|
||
" }\n",
|
||
" </style>\n",
|
||
"\n",
|
||
" <script>\n",
|
||
" const buttonEl =\n",
|
||
" document.querySelector('#df-82990cd8-ff1a-4f02-8f09-548d16d000e2 button.colab-df-convert');\n",
|
||
" buttonEl.style.display =\n",
|
||
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
|
||
"\n",
|
||
" async function convertToInteractive(key) {\n",
|
||
" const element = document.querySelector('#df-82990cd8-ff1a-4f02-8f09-548d16d000e2');\n",
|
||
" const dataTable =\n",
|
||
" await google.colab.kernel.invokeFunction('convertToInteractive',\n",
|
||
" [key], {});\n",
|
||
" if (!dataTable) return;\n",
|
||
"\n",
|
||
" const docLinkHtml = 'Like what you see? Visit the ' +\n",
|
||
" '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
|
||
" + ' to learn more about interactive tables.';\n",
|
||
" element.innerHTML = '';\n",
|
||
" dataTable['output_type'] = 'display_data';\n",
|
||
" await google.colab.output.renderOutput(dataTable, element);\n",
|
||
" const docLink = document.createElement('div');\n",
|
||
" docLink.innerHTML = docLinkHtml;\n",
|
||
" element.appendChild(docLink);\n",
|
||
" }\n",
|
||
" </script>\n",
|
||
" </div>\n",
|
||
"\n",
|
||
"\n",
|
||
" <div id=\"df-72f11a31-18ba-4c3c-b84c-82e30145b32f\">\n",
|
||
" <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-72f11a31-18ba-4c3c-b84c-82e30145b32f')\"\n",
|
||
" title=\"Suggest charts\"\n",
|
||
" style=\"display:none;\">\n",
|
||
"\n",
|
||
"<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
|
||
" width=\"24px\">\n",
|
||
" <g>\n",
|
||
" <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n",
|
||
" </g>\n",
|
||
"</svg>\n",
|
||
" </button>\n",
|
||
"\n",
|
||
"<style>\n",
|
||
" .colab-df-quickchart {\n",
|
||
" --bg-color: #E8F0FE;\n",
|
||
" --fill-color: #1967D2;\n",
|
||
" --hover-bg-color: #E2EBFA;\n",
|
||
" --hover-fill-color: #174EA6;\n",
|
||
" --disabled-fill-color: #AAA;\n",
|
||
" --disabled-bg-color: #DDD;\n",
|
||
" }\n",
|
||
"\n",
|
||
" [theme=dark] .colab-df-quickchart {\n",
|
||
" --bg-color: #3B4455;\n",
|
||
" --fill-color: #D2E3FC;\n",
|
||
" --hover-bg-color: #434B5C;\n",
|
||
" --hover-fill-color: #FFFFFF;\n",
|
||
" --disabled-bg-color: #3B4455;\n",
|
||
" --disabled-fill-color: #666;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-quickchart {\n",
|
||
" background-color: var(--bg-color);\n",
|
||
" border: none;\n",
|
||
" border-radius: 50%;\n",
|
||
" cursor: pointer;\n",
|
||
" display: none;\n",
|
||
" fill: var(--fill-color);\n",
|
||
" height: 32px;\n",
|
||
" padding: 0;\n",
|
||
" width: 32px;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-quickchart:hover {\n",
|
||
" background-color: var(--hover-bg-color);\n",
|
||
" box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
|
||
" fill: var(--button-hover-fill-color);\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-quickchart-complete:disabled,\n",
|
||
" .colab-df-quickchart-complete:disabled:hover {\n",
|
||
" background-color: var(--disabled-bg-color);\n",
|
||
" fill: var(--disabled-fill-color);\n",
|
||
" box-shadow: none;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-spinner {\n",
|
||
" border: 2px solid var(--fill-color);\n",
|
||
" border-color: transparent;\n",
|
||
" border-bottom-color: var(--fill-color);\n",
|
||
" animation:\n",
|
||
" spin 1s steps(1) infinite;\n",
|
||
" }\n",
|
||
"\n",
|
||
" @keyframes spin {\n",
|
||
" 0% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-bottom-color: var(--fill-color);\n",
|
||
" border-left-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 20% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-left-color: var(--fill-color);\n",
|
||
" border-top-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 30% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-left-color: var(--fill-color);\n",
|
||
" border-top-color: var(--fill-color);\n",
|
||
" border-right-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 40% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-right-color: var(--fill-color);\n",
|
||
" border-top-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 60% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-right-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 80% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-right-color: var(--fill-color);\n",
|
||
" border-bottom-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 90% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-bottom-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" }\n",
|
||
"</style>\n",
|
||
"\n",
|
||
" <script>\n",
|
||
" async function quickchart(key) {\n",
|
||
" const quickchartButtonEl =\n",
|
||
" document.querySelector('#' + key + ' button');\n",
|
||
" quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n",
|
||
" quickchartButtonEl.classList.add('colab-df-spinner');\n",
|
||
" try {\n",
|
||
" const charts = await google.colab.kernel.invokeFunction(\n",
|
||
" 'suggestCharts', [key], {});\n",
|
||
" } catch (error) {\n",
|
||
" console.error('Error during call to suggestCharts:', error);\n",
|
||
" }\n",
|
||
" quickchartButtonEl.classList.remove('colab-df-spinner');\n",
|
||
" quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n",
|
||
" }\n",
|
||
" (() => {\n",
|
||
" let quickchartButtonEl =\n",
|
||
" document.querySelector('#df-72f11a31-18ba-4c3c-b84c-82e30145b32f button');\n",
|
||
" quickchartButtonEl.style.display =\n",
|
||
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
|
||
" })();\n",
|
||
" </script>\n",
|
||
" </div>\n",
|
||
"\n",
|
||
" </div>\n",
|
||
" </div>\n"
|
||
],
|
||
"text/plain": [
|
||
" target ids date flag \\\n",
|
||
"0 0 1467810369 Mon Apr 06 22:19:45 PDT 2009 NO_QUERY \n",
|
||
"1 0 1467810672 Mon Apr 06 22:19:49 PDT 2009 NO_QUERY \n",
|
||
"2 0 1467810917 Mon Apr 06 22:19:53 PDT 2009 NO_QUERY \n",
|
||
"3 0 1467811184 Mon Apr 06 22:19:57 PDT 2009 NO_QUERY \n",
|
||
"4 0 1467811193 Mon Apr 06 22:19:57 PDT 2009 NO_QUERY \n",
|
||
"\n",
|
||
" user text \n",
|
||
"0 _TheSpecialOne_ @switchfoot http://twitpic.com/2y1zl - Awww, t... \n",
|
||
"1 scotthamilton is upset that he can't update his Facebook by ... \n",
|
||
"2 mattycus @Kenichan I dived many times for the ball. Man... \n",
|
||
"3 ElleCTF my whole body feels itchy and like its on fire \n",
|
||
"4 Karoli @nationwideclass no, it's not behaving at all.... "
|
||
]
|
||
},
|
||
"execution_count": 6,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"\n",
|
||
"# Define the path to the CSV file\n",
|
||
"csv_file_path = os.path.join(extract_path, 'training.1600000.processed.noemoticon.csv')\n",
|
||
"\n",
|
||
"# Define the column names\n",
|
||
"column_names = ['target', 'ids', 'date', 'flag', 'user', 'text']\n",
|
||
"\n",
|
||
"# Load the dataset into a pandas DataFrame\n",
|
||
"raw_data = pd.read_csv(csv_file_path, encoding='latin-1', names=column_names)\n",
|
||
"\n",
|
||
"# Display the first few rows of the DataFrame\n",
|
||
"raw_data.head()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/"
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 6,
|
||
"status": "ok",
|
||
"timestamp": 1751704286479,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "Mh433N4wWxlJ",
|
||
"outputId": "4a4132d3-53f0-4ce4-d59c-a598daedac97"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Ce dataframe contient 1600000 lignes et 6 colonnes.\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"print(f\"Ce dataframe contient {raw_data.shape[0]} lignes et {raw_data.shape[1]} colonnes.\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "u7_v1qZSWxlJ"
|
||
},
|
||
"source": [
|
||
"## 🤖 Approches classiques de Machine Learning\n",
|
||
"\n",
|
||
"Notre démarche pour la classification de sentiment avec des approches classiques comprend:\n",
|
||
"\n",
|
||
"1. **Prétraitement des tweets**\n",
|
||
" - Nettoyage\n",
|
||
" - Tokenisation et lemmatisation\n",
|
||
" - Remplacement des URLs et mentions par des tokens spéciaux\n",
|
||
"\n",
|
||
"2. **Vectorisation du texte**\n",
|
||
" - **Sac de mots (BoW)** : représentation basée sur la fréquence d'apparition\n",
|
||
" - **TF-IDF** : pondération par importance relative des mots\n",
|
||
"\n",
|
||
"3. **Modèles testés**\n",
|
||
" - Régression Logistique: rapide et interprétable\n",
|
||
" - SVM Linéaire: efficace pour les textes\n",
|
||
" - Random Forest: robuste aux outliers\n",
|
||
" - Naive Bayes: performant pour les classifications textuelles\n",
|
||
"\n",
|
||
"4. **Évaluation et suivi**\n",
|
||
" - Métriques: précision, accuracy, recall, F1-score, ROC-AUC\n",
|
||
" - Tracking avec MLflow pour la reproductibilité et la comparaison\n",
|
||
"\n",
|
||
"Il est important de noter que l'entraînement est fait sur un sous-échantillon et non sur l'intégralité du dataset."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"id": "3bsdJkmgWxlK"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"converted_target_data = convert_sentiment_label(raw_data)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/",
|
||
"height": 178
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 20,
|
||
"status": "ok",
|
||
"timestamp": 1751704288202,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "xNda-mfAWxlK",
|
||
"outputId": "58ee136e-bcd5-4ad3-8b68-6a0809d5aca2"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/html": [
|
||
"<div>\n",
|
||
"<style scoped>\n",
|
||
" .dataframe tbody tr th:only-of-type {\n",
|
||
" vertical-align: middle;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe tbody tr th {\n",
|
||
" vertical-align: top;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe thead th {\n",
|
||
" text-align: right;\n",
|
||
" }\n",
|
||
"</style>\n",
|
||
"<table border=\"1\" class=\"dataframe\">\n",
|
||
" <thead>\n",
|
||
" <tr style=\"text-align: right;\">\n",
|
||
" <th></th>\n",
|
||
" <th>count</th>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>target</th>\n",
|
||
" <th></th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th>0</th>\n",
|
||
" <td>800000</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>1</th>\n",
|
||
" <td>800000</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n",
|
||
"</div><br><label><b>dtype:</b> int64</label>"
|
||
],
|
||
"text/plain": [
|
||
"target\n",
|
||
"0 800000\n",
|
||
"1 800000\n",
|
||
"Name: count, dtype: int64"
|
||
]
|
||
},
|
||
"execution_count": 9,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"converted_target_data['target'].value_counts()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/",
|
||
"height": 178
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 1037,
|
||
"status": "ok",
|
||
"timestamp": 1751704289237,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "q8z3nv-0WxlK",
|
||
"outputId": "845fbde3-5e3e-42bf-a523-2b92a4494eae"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/html": [
|
||
"<div>\n",
|
||
"<style scoped>\n",
|
||
" .dataframe tbody tr th:only-of-type {\n",
|
||
" vertical-align: middle;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe tbody tr th {\n",
|
||
" vertical-align: top;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe thead th {\n",
|
||
" text-align: right;\n",
|
||
" }\n",
|
||
"</style>\n",
|
||
"<table border=\"1\" class=\"dataframe\">\n",
|
||
" <thead>\n",
|
||
" <tr style=\"text-align: right;\">\n",
|
||
" <th></th>\n",
|
||
" <th>count</th>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>target</th>\n",
|
||
" <th></th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th>0</th>\n",
|
||
" <td>100000</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>1</th>\n",
|
||
" <td>100000</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n",
|
||
"</div><br><label><b>dtype:</b> int64</label>"
|
||
],
|
||
"text/plain": [
|
||
"target\n",
|
||
"0 100000\n",
|
||
"1 100000\n",
|
||
"Name: count, dtype: int64"
|
||
]
|
||
},
|
||
"execution_count": 10,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"sample_size = 100000\n",
|
||
"downsampled_data = downsample_data(converted_target_data, n_samples=sample_size)\n",
|
||
"downsampled_data['target'].value_counts()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "TQAPEWmGWxlK"
|
||
},
|
||
"source": [
|
||
"## Prétraitement"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/"
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 106518,
|
||
"status": "ok",
|
||
"timestamp": 1751704395758,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "lrQfmMHMWxlL",
|
||
"outputId": "4b28e5a2-c00c-447e-9184-1df0a0eaad12"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Prétraitement des tweets en cours...\n",
|
||
"Prétraitement terminé !\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"# Appliquer le prétraitement à tous les tweets\n",
|
||
"print(\"Prétraitement des tweets en cours...\")\n",
|
||
"preprocessed_data = process_in_parallel(downsampled_data, apply_preprocessing, n_jobs=8)\n",
|
||
"print(\"Prétraitement terminé !\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/",
|
||
"height": 206
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 14,
|
||
"status": "ok",
|
||
"timestamp": 1751704395759,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "NYmqSwSiWxlL",
|
||
"outputId": "3ac24116-fea7-4a3a-ddb9-647de880823d"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"application/vnd.google.colaboratory.intrinsic+json": {
|
||
"type": "dataframe",
|
||
"variable_name": "preprocessed_data"
|
||
},
|
||
"text/html": [
|
||
"\n",
|
||
" <div id=\"df-990c94ac-edc3-4020-b018-c6af2acc2159\" class=\"colab-df-container\">\n",
|
||
" <div>\n",
|
||
"<style scoped>\n",
|
||
" .dataframe tbody tr th:only-of-type {\n",
|
||
" vertical-align: middle;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe tbody tr th {\n",
|
||
" vertical-align: top;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe thead th {\n",
|
||
" text-align: right;\n",
|
||
" }\n",
|
||
"</style>\n",
|
||
"<table border=\"1\" class=\"dataframe\">\n",
|
||
" <thead>\n",
|
||
" <tr style=\"text-align: right;\">\n",
|
||
" <th></th>\n",
|
||
" <th>target</th>\n",
|
||
" <th>ids</th>\n",
|
||
" <th>date</th>\n",
|
||
" <th>flag</th>\n",
|
||
" <th>user</th>\n",
|
||
" <th>text</th>\n",
|
||
" <th>processed_text</th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th>212188</th>\n",
|
||
" <td>0</td>\n",
|
||
" <td>1974671194</td>\n",
|
||
" <td>Sat May 30 13:36:31 PDT 2009</td>\n",
|
||
" <td>NO_QUERY</td>\n",
|
||
" <td>simba98</td>\n",
|
||
" <td>@xnausikaax oh no! where did u order from? tha...</td>\n",
|
||
" <td>< MENTION > oh no ! u order ? thats horrible</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>299036</th>\n",
|
||
" <td>0</td>\n",
|
||
" <td>1997882236</td>\n",
|
||
" <td>Mon Jun 01 17:37:11 PDT 2009</td>\n",
|
||
" <td>NO_QUERY</td>\n",
|
||
" <td>Seve76</td>\n",
|
||
" <td>A great hard training weekend is over. a coup...</td>\n",
|
||
" <td>great hard training weekend couple day rest le...</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>475978</th>\n",
|
||
" <td>0</td>\n",
|
||
" <td>2177756662</td>\n",
|
||
" <td>Mon Jun 15 06:39:05 PDT 2009</td>\n",
|
||
" <td>NO_QUERY</td>\n",
|
||
" <td>x__claireyy__x</td>\n",
|
||
" <td>Right, off to work Only 5 hours to go until I...</td>\n",
|
||
" <td>right work 5 hour go im free xd</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>588988</th>\n",
|
||
" <td>0</td>\n",
|
||
" <td>2216838047</td>\n",
|
||
" <td>Wed Jun 17 20:02:12 PDT 2009</td>\n",
|
||
" <td>NO_QUERY</td>\n",
|
||
" <td>Balasi</td>\n",
|
||
" <td>I am craving for japanese food</td>\n",
|
||
" <td>craving japanese food</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>138859</th>\n",
|
||
" <td>0</td>\n",
|
||
" <td>1880666283</td>\n",
|
||
" <td>Fri May 22 02:03:31 PDT 2009</td>\n",
|
||
" <td>NO_QUERY</td>\n",
|
||
" <td>djrickdawson</td>\n",
|
||
" <td>Jean Michel Jarre concert tomorrow gotta work...</td>\n",
|
||
" <td>jean michel jarre concert tomorrow got ta work...</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n",
|
||
"</div>\n",
|
||
" <div class=\"colab-df-buttons\">\n",
|
||
"\n",
|
||
" <div class=\"colab-df-container\">\n",
|
||
" <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-990c94ac-edc3-4020-b018-c6af2acc2159')\"\n",
|
||
" title=\"Convert this dataframe to an interactive table.\"\n",
|
||
" style=\"display:none;\">\n",
|
||
"\n",
|
||
" <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n",
|
||
" <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n",
|
||
" </svg>\n",
|
||
" </button>\n",
|
||
"\n",
|
||
" <style>\n",
|
||
" .colab-df-container {\n",
|
||
" display:flex;\n",
|
||
" gap: 12px;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-convert {\n",
|
||
" background-color: #E8F0FE;\n",
|
||
" border: none;\n",
|
||
" border-radius: 50%;\n",
|
||
" cursor: pointer;\n",
|
||
" display: none;\n",
|
||
" fill: #1967D2;\n",
|
||
" height: 32px;\n",
|
||
" padding: 0 0 0 0;\n",
|
||
" width: 32px;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-convert:hover {\n",
|
||
" background-color: #E2EBFA;\n",
|
||
" box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
|
||
" fill: #174EA6;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-buttons div {\n",
|
||
" margin-bottom: 4px;\n",
|
||
" }\n",
|
||
"\n",
|
||
" [theme=dark] .colab-df-convert {\n",
|
||
" background-color: #3B4455;\n",
|
||
" fill: #D2E3FC;\n",
|
||
" }\n",
|
||
"\n",
|
||
" [theme=dark] .colab-df-convert:hover {\n",
|
||
" background-color: #434B5C;\n",
|
||
" box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
|
||
" filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
|
||
" fill: #FFFFFF;\n",
|
||
" }\n",
|
||
" </style>\n",
|
||
"\n",
|
||
" <script>\n",
|
||
" const buttonEl =\n",
|
||
" document.querySelector('#df-990c94ac-edc3-4020-b018-c6af2acc2159 button.colab-df-convert');\n",
|
||
" buttonEl.style.display =\n",
|
||
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
|
||
"\n",
|
||
" async function convertToInteractive(key) {\n",
|
||
" const element = document.querySelector('#df-990c94ac-edc3-4020-b018-c6af2acc2159');\n",
|
||
" const dataTable =\n",
|
||
" await google.colab.kernel.invokeFunction('convertToInteractive',\n",
|
||
" [key], {});\n",
|
||
" if (!dataTable) return;\n",
|
||
"\n",
|
||
" const docLinkHtml = 'Like what you see? Visit the ' +\n",
|
||
" '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
|
||
" + ' to learn more about interactive tables.';\n",
|
||
" element.innerHTML = '';\n",
|
||
" dataTable['output_type'] = 'display_data';\n",
|
||
" await google.colab.output.renderOutput(dataTable, element);\n",
|
||
" const docLink = document.createElement('div');\n",
|
||
" docLink.innerHTML = docLinkHtml;\n",
|
||
" element.appendChild(docLink);\n",
|
||
" }\n",
|
||
" </script>\n",
|
||
" </div>\n",
|
||
"\n",
|
||
"\n",
|
||
" <div id=\"df-62c66fb0-085d-457f-90f3-67106922f35f\">\n",
|
||
" <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-62c66fb0-085d-457f-90f3-67106922f35f')\"\n",
|
||
" title=\"Suggest charts\"\n",
|
||
" style=\"display:none;\">\n",
|
||
"\n",
|
||
"<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
|
||
" width=\"24px\">\n",
|
||
" <g>\n",
|
||
" <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n",
|
||
" </g>\n",
|
||
"</svg>\n",
|
||
" </button>\n",
|
||
"\n",
|
||
"<style>\n",
|
||
" .colab-df-quickchart {\n",
|
||
" --bg-color: #E8F0FE;\n",
|
||
" --fill-color: #1967D2;\n",
|
||
" --hover-bg-color: #E2EBFA;\n",
|
||
" --hover-fill-color: #174EA6;\n",
|
||
" --disabled-fill-color: #AAA;\n",
|
||
" --disabled-bg-color: #DDD;\n",
|
||
" }\n",
|
||
"\n",
|
||
" [theme=dark] .colab-df-quickchart {\n",
|
||
" --bg-color: #3B4455;\n",
|
||
" --fill-color: #D2E3FC;\n",
|
||
" --hover-bg-color: #434B5C;\n",
|
||
" --hover-fill-color: #FFFFFF;\n",
|
||
" --disabled-bg-color: #3B4455;\n",
|
||
" --disabled-fill-color: #666;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-quickchart {\n",
|
||
" background-color: var(--bg-color);\n",
|
||
" border: none;\n",
|
||
" border-radius: 50%;\n",
|
||
" cursor: pointer;\n",
|
||
" display: none;\n",
|
||
" fill: var(--fill-color);\n",
|
||
" height: 32px;\n",
|
||
" padding: 0;\n",
|
||
" width: 32px;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-quickchart:hover {\n",
|
||
" background-color: var(--hover-bg-color);\n",
|
||
" box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
|
||
" fill: var(--button-hover-fill-color);\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-quickchart-complete:disabled,\n",
|
||
" .colab-df-quickchart-complete:disabled:hover {\n",
|
||
" background-color: var(--disabled-bg-color);\n",
|
||
" fill: var(--disabled-fill-color);\n",
|
||
" box-shadow: none;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-spinner {\n",
|
||
" border: 2px solid var(--fill-color);\n",
|
||
" border-color: transparent;\n",
|
||
" border-bottom-color: var(--fill-color);\n",
|
||
" animation:\n",
|
||
" spin 1s steps(1) infinite;\n",
|
||
" }\n",
|
||
"\n",
|
||
" @keyframes spin {\n",
|
||
" 0% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-bottom-color: var(--fill-color);\n",
|
||
" border-left-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 20% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-left-color: var(--fill-color);\n",
|
||
" border-top-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 30% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-left-color: var(--fill-color);\n",
|
||
" border-top-color: var(--fill-color);\n",
|
||
" border-right-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 40% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-right-color: var(--fill-color);\n",
|
||
" border-top-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 60% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-right-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 80% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-right-color: var(--fill-color);\n",
|
||
" border-bottom-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 90% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-bottom-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" }\n",
|
||
"</style>\n",
|
||
"\n",
|
||
" <script>\n",
|
||
" async function quickchart(key) {\n",
|
||
" const quickchartButtonEl =\n",
|
||
" document.querySelector('#' + key + ' button');\n",
|
||
" quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n",
|
||
" quickchartButtonEl.classList.add('colab-df-spinner');\n",
|
||
" try {\n",
|
||
" const charts = await google.colab.kernel.invokeFunction(\n",
|
||
" 'suggestCharts', [key], {});\n",
|
||
" } catch (error) {\n",
|
||
" console.error('Error during call to suggestCharts:', error);\n",
|
||
" }\n",
|
||
" quickchartButtonEl.classList.remove('colab-df-spinner');\n",
|
||
" quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n",
|
||
" }\n",
|
||
" (() => {\n",
|
||
" let quickchartButtonEl =\n",
|
||
" document.querySelector('#df-62c66fb0-085d-457f-90f3-67106922f35f button');\n",
|
||
" quickchartButtonEl.style.display =\n",
|
||
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
|
||
" })();\n",
|
||
" </script>\n",
|
||
" </div>\n",
|
||
"\n",
|
||
" </div>\n",
|
||
" </div>\n"
|
||
],
|
||
"text/plain": [
|
||
" target ids date flag \\\n",
|
||
"212188 0 1974671194 Sat May 30 13:36:31 PDT 2009 NO_QUERY \n",
|
||
"299036 0 1997882236 Mon Jun 01 17:37:11 PDT 2009 NO_QUERY \n",
|
||
"475978 0 2177756662 Mon Jun 15 06:39:05 PDT 2009 NO_QUERY \n",
|
||
"588988 0 2216838047 Wed Jun 17 20:02:12 PDT 2009 NO_QUERY \n",
|
||
"138859 0 1880666283 Fri May 22 02:03:31 PDT 2009 NO_QUERY \n",
|
||
"\n",
|
||
" user text \\\n",
|
||
"212188 simba98 @xnausikaax oh no! where did u order from? tha... \n",
|
||
"299036 Seve76 A great hard training weekend is over. a coup... \n",
|
||
"475978 x__claireyy__x Right, off to work Only 5 hours to go until I... \n",
|
||
"588988 Balasi I am craving for japanese food \n",
|
||
"138859 djrickdawson Jean Michel Jarre concert tomorrow gotta work... \n",
|
||
"\n",
|
||
" processed_text \n",
|
||
"212188 < MENTION > oh no ! u order ? thats horrible \n",
|
||
"299036 great hard training weekend couple day rest le... \n",
|
||
"475978 right work 5 hour go im free xd \n",
|
||
"588988 craving japanese food \n",
|
||
"138859 jean michel jarre concert tomorrow got ta work... "
|
||
]
|
||
},
|
||
"execution_count": 12,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"preprocessed_data.head()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "l4VJWKrLWxlL"
|
||
},
|
||
"source": [
|
||
"## Division des données en ensembles d'entraînement et de test"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/"
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 144,
|
||
"status": "ok",
|
||
"timestamp": 1751704395901,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "FqmMGjWlWxlL",
|
||
"outputId": "d6665eed-5ed9-45da-8cf4-a525b6ddcd6a"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Taille de l'ensemble d'entraînement: 160000 exemples\n",
|
||
"Taille de l'ensemble de test: 40000 exemples\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"# Diviser les données en ensembles d'entraînement et de test\n",
|
||
"from sklearn.model_selection import train_test_split\n",
|
||
"\n",
|
||
"X = preprocessed_data['processed_text']\n",
|
||
"y = preprocessed_data['target']\n",
|
||
"\n",
|
||
"# Division train/test\n",
|
||
"X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)\n",
|
||
"\n",
|
||
"print(f\"Taille de l'ensemble d'entraînement: {X_train.shape[0]} exemples\")\n",
|
||
"print(f\"Taille de l'ensemble de test: {X_test.shape[0]} exemples\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "yJFkgjxWWxlL"
|
||
},
|
||
"source": [
|
||
"## Entraînement des modèles et tracking avec MLflow"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "wKdwVenuWxlL"
|
||
},
|
||
"source": [
|
||
"### Configuration de MLFlow"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/"
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 2919,
|
||
"status": "ok",
|
||
"timestamp": 1751704398811,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "ZbDFrgXCWxlL",
|
||
"outputId": "d18cac06-f7b0-431a-f781-530361bbc947"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"MLflow Tracking URI: https://mlflow.greg-madman-nas.duckdns.org/\n",
|
||
"Identifiants AWS configurés\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"import mlflow\n",
|
||
"from mlflow.models import infer_signature\n",
|
||
"from mlflow import MlflowClient\n",
|
||
"from dotenv import load_dotenv\n",
|
||
"\n",
|
||
"# Charger les variables d'environnement depuis le fichier .env\n",
|
||
"load_dotenv(dotenv_path='../.env')\n",
|
||
"\n",
|
||
"# Configuration de MLflow avec les variables d'environnement\n",
|
||
"mlflow_tracking_uri = os.getenv(\"MLFLOW_TRACKING_URI\")\n",
|
||
"mlflow_s3_endpoint_url = os.getenv(\"MLFLOW_S3_ENDPOINT_URL\")\n",
|
||
"aws_access_key_id = os.getenv(\"AWS_ACCESS_KEY_ID\")\n",
|
||
"aws_secret_access_key = os.getenv(\"AWS_SECRET_ACCESS_KEY\")\n",
|
||
"\n",
|
||
"# Configuration explicite de MLflow\n",
|
||
"mlflow.set_tracking_uri(mlflow_tracking_uri)\n",
|
||
"print(f\"MLflow Tracking URI: {mlflow_tracking_uri}\")\n",
|
||
"\n",
|
||
"# Configuration explicite des identifiants AWS\n",
|
||
"os.environ[\"MLFLOW_S3_ENDPOINT_URL\"] = mlflow_s3_endpoint_url\n",
|
||
"os.environ[\"AWS_ACCESS_KEY_ID\"] = aws_access_key_id\n",
|
||
"os.environ[\"AWS_SECRET_ACCESS_KEY\"] = aws_secret_access_key\n",
|
||
"print(\"Identifiants AWS configurés\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/",
|
||
"height": 36
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 4,
|
||
"status": "ok",
|
||
"timestamp": 1751704398812,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "7sJsURWwthEX",
|
||
"outputId": "e33c56ea-8ac5-4402-b36c-a772805c774f"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"application/vnd.google.colaboratory.intrinsic+json": {
|
||
"type": "string"
|
||
},
|
||
"text/plain": [
|
||
"'https://minio-api.greg-madman-nas.duckdns.org'"
|
||
]
|
||
},
|
||
"execution_count": 15,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"mlflow_s3_endpoint_url"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/"
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 567,
|
||
"status": "ok",
|
||
"timestamp": 1751704399377,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "vOmnl37nWxlL",
|
||
"outputId": "74b71400-c51a-48e2-e66f-04b77ba45410"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"<Experiment: artifact_location='s3://mlflow-artifacts/1', creation_time=1750773088095, experiment_id='1', last_update_time=1750773088095, lifecycle_stage='active', name='OC Projet 7', tags={}>"
|
||
]
|
||
},
|
||
"execution_count": 16,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"# Créer l'expérience MLflow\n",
|
||
"mlflow.set_experiment(\"OC Projet 7\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "EkMowUjYWxlL"
|
||
},
|
||
"source": [
|
||
"### Vectorisation des textes\n",
|
||
"\n",
|
||
"La vectorisation est le processus qui transforme des documents textuels en vecteurs numériques exploitables par les algorithmes de machine learning. Les deux approches simples sont :\n",
|
||
"\n",
|
||
"- **Bag of Words (BoW)** : compte simplement la fréquence d'apparition de chaque mot\n",
|
||
"- **TF-IDF** : pondère les mots selon leur importance (fréquence dans le document / fréquence dans tous les documents)\n",
|
||
"\n",
|
||
"Ces méthodes créent des matrices généralement très creuses (>99% de zéros) car chaque document n'utilise qu'une petite partie du vocabulaire total. Dans notre implémentation, nous utilisons `CountVectorizer` pour l'approche BoW et `TfidfVectorizer` pour le TF-IDF, avec des n-grammes (1,2) qui permettent de capturer des expressions de deux mots consécutifs.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/"
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 14369,
|
||
"status": "ok",
|
||
"timestamp": 1751704413755,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "Wn-UOIB_WxlL",
|
||
"outputId": "89b2def9-ed05-4173-cf2a-ff5b6a5280cd"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Vectorisation terminée !\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer\n",
|
||
"\n",
|
||
"# Créer les vectoriseurs\n",
|
||
"tfidf_vectorizer = TfidfVectorizer(max_features=10000, ngram_range=(1, 2))\n",
|
||
"bow_vectorizer = CountVectorizer(max_features=10000, ngram_range=(1, 2))\n",
|
||
"\n",
|
||
"\n",
|
||
"# Transformer les textes en vecteurs TF-IDF\n",
|
||
"X_train_tfidf = tfidf_vectorizer.fit_transform(X_train)\n",
|
||
"X_test_tfidf = tfidf_vectorizer.transform(X_test)\n",
|
||
"\n",
|
||
"# Transformer les textes en vecteurs BoW\n",
|
||
"X_train_bow = bow_vectorizer.fit_transform(X_train)\n",
|
||
"X_test_bow = bow_vectorizer.transform(X_test)\n",
|
||
"\n",
|
||
"print(\"Vectorisation terminée !\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "idwGMj8IWxlM"
|
||
},
|
||
"source": [
|
||
"### Fonction d'évaluation des modèles"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"id": "gypFHG57WxlM"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def evaluate_model(model, X_train, X_test, y_train, y_test, model_name, vectorizer_name):\n",
|
||
" \"\"\"\n",
|
||
" Évalue un modèle déjà entraîné et retourne les résultats\n",
|
||
" \"\"\"\n",
|
||
" # Prédictions sur l'ensemble de test\n",
|
||
" y_pred = model.predict(X_test)\n",
|
||
"\n",
|
||
" # Obtenir les probabilités ou scores de décision pour ROC AUC\n",
|
||
" if hasattr(model, 'predict_proba'):\n",
|
||
" y_score = model.predict_proba(X_test)[:, 1]\n",
|
||
" elif hasattr(model, 'decision_function'):\n",
|
||
" y_score = model.decision_function(X_test)\n",
|
||
" else:\n",
|
||
" y_score = y_pred # Fallback pour les modèles qui n'ont pas ces méthodes\n",
|
||
"\n",
|
||
" # Calculer les métriques\n",
|
||
" accuracy = accuracy_score(y_test, y_pred)\n",
|
||
" precision = precision_score(y_test, y_pred)\n",
|
||
" recall = recall_score(y_test, y_pred)\n",
|
||
" f1 = f1_score(y_test, y_pred)\n",
|
||
" roc_auc = roc_auc_score(y_test, y_score)\n",
|
||
"\n",
|
||
" # Créer la matrice de confusion sous forme de figure\n",
|
||
" cm = confusion_matrix(y_test, y_pred)\n",
|
||
" fig_cm, ax_cm = plt.subplots(figsize=(8, 6))\n",
|
||
" sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', ax=ax_cm)\n",
|
||
" ax_cm.set_xlabel('Prédiction')\n",
|
||
" ax_cm.set_ylabel('Valeur réelle')\n",
|
||
" ax_cm.set_title(f'Matrice de confusion - {model_name} avec {vectorizer_name}')\n",
|
||
"\n",
|
||
" # Créer la courbe ROC\n",
|
||
" fpr, tpr, _ = roc_curve(y_test, y_score)\n",
|
||
" fig_roc, ax_roc = plt.subplots(figsize=(8, 6))\n",
|
||
" ax_roc.plot(fpr, tpr, label=f'ROC curve (AUC = {roc_auc:.3f})')\n",
|
||
" ax_roc.plot([0, 1], [0, 1], 'k--')\n",
|
||
" ax_roc.set_xlim([0.0, 1.0])\n",
|
||
" ax_roc.set_ylim([0.0, 1.05])\n",
|
||
" ax_roc.set_xlabel('Taux de faux positifs')\n",
|
||
" ax_roc.set_ylabel('Taux de vrais positifs')\n",
|
||
" ax_roc.set_title(f'Courbe ROC - {model_name} avec {vectorizer_name}')\n",
|
||
" ax_roc.legend(loc=\"lower right\")\n",
|
||
" ax_roc.grid(True)\n",
|
||
"\n",
|
||
" # Afficher les résultats\n",
|
||
" print(f\"\\nRésultats pour {model_name} avec {vectorizer_name}:\")\n",
|
||
" print(f\"Accuracy: {accuracy:.4f}\")\n",
|
||
" print(f\"Precision: {precision:.4f}\")\n",
|
||
" print(f\"Recall: {recall:.4f}\")\n",
|
||
" print(f\"F1 Score: {f1:.4f}\")\n",
|
||
" print(f\"ROC AUC: {roc_auc:.4f}\")\n",
|
||
" print(\"\\nMatrice de confusion:\")\n",
|
||
" print(cm)\n",
|
||
" print(\"\\nRapport de classification:\")\n",
|
||
" print(classification_report(y_test, y_pred))\n",
|
||
"\n",
|
||
" return accuracy, precision, recall, f1, roc_auc, fig_cm, fig_roc, y_pred"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "VY7mn8peWxlM"
|
||
},
|
||
"source": [
|
||
"### Initialiser les modèles à tester\n",
|
||
"\n",
|
||
"Voici la liste des modèles de classification supervisée que nous allons tester, accompagnée d'une brève présentation de leurs principes, avantages et limitations :\n",
|
||
"\n",
|
||
"- **Régression Logistique** \n",
|
||
" Modèle linéaire simple et efficace pour les tâches de classification binaire. Il modélise la probabilité d'appartenance à une classe. \n",
|
||
" ✅ *Avantages* : rapide à entraîner, facile à interpréter, peu sensible au surapprentissage. \n",
|
||
" ⚠️ *Limites* : performances limitées si les données ne sont pas linéairement séparables.\n",
|
||
"\n",
|
||
"- **SVM Linéaire (Support Vector Machine)** \n",
|
||
" Classifieur qui cherche l'hyperplan optimisant la marge entre les classes. Très adapté aux représentations vectorielles comme TF-IDF. \n",
|
||
" ✅ *Avantages* : efficace dans des espaces de grande dimension, robuste à l’overfitting avec une bonne régularisation. \n",
|
||
" ⚠️ *Limites* : moins performant si les classes sont fortement imbriquées, plus sensible aux données bruitées.\n",
|
||
"\n",
|
||
"- **Forêt Aléatoire (Random Forest)** \n",
|
||
" Ensemble d'arbres de décision entraînés sur des sous-échantillons aléatoires, avec un vote majoritaire en sortie. \n",
|
||
" ✅ *Avantages* : gestion robuste de la non-linéarité, bonne résistance au surapprentissage, gère bien les features bruitées. \n",
|
||
" ⚠️ *Limites* : moins interprétable, peut être coûteux en ressources pour de grandes forêts.\n",
|
||
"\n",
|
||
"- **Naive Bayes (Multinomial)** \n",
|
||
" Classifieur probabiliste basé sur le théorème de Bayes, avec l'hypothèse d’indépendance conditionnelle entre les features. \n",
|
||
" ✅ *Avantages* : extrêmement rapide, très efficace sur des textes représentés par BoW ou TF-IDF, souvent difficile à battre en NLP classique. \n",
|
||
" ⚠️ *Limites* : hypothèse d’indépendance souvent irréaliste, mais dans la pratique les performances restent bonnes même si elle est violée.\n",
|
||
"\n",
|
||
"> 🧠 **Pourquoi ces modèles ?** \n",
|
||
"Ils sont tous adaptés aux représentations vectorielles classiques (BoW, TF-IDF), et offrent un bon compromis entre performance, vitesse d'entraînement et interprétabilité. Leur diversité permet aussi d'évaluer plusieurs familles d’algorithmes (linéaires, probabilistes, ensembles, marge maximale) sur le même jeu de données.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"id": "N81VF_EvWxlM"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Initialiser les modèles à tester\n",
|
||
"base_models = {\n",
|
||
" \"Regression_Logistique\": LogisticRegression(random_state=42),\n",
|
||
" \"SVM_Lineaire\": LinearSVC(random_state=42),\n",
|
||
" \"Random_Forest\": RandomForestClassifier(random_state=42),\n",
|
||
" \"Naive_Bayes\": MultinomialNB()\n",
|
||
"}\n",
|
||
"\n",
|
||
"# Définir les grilles d'hyperparamètres pour GridSearchCV\n",
|
||
"param_grids = {\n",
|
||
" \"Regression_Logistique\": {\n",
|
||
" 'C': [0.01, 0.1, 1.0, 10.0],\n",
|
||
" 'max_iter': [1000],\n",
|
||
" 'solver': ['liblinear', 'saga']\n",
|
||
" },\n",
|
||
" \"SVM_Lineaire\": {\n",
|
||
" 'C': [0.01, 0.1, 1.0, 10.0],\n",
|
||
" 'max_iter': [1000],\n",
|
||
" 'dual': [True, False]\n",
|
||
" },\n",
|
||
" \"Random_Forest\": {\n",
|
||
" 'n_estimators': [50, 100, 200],\n",
|
||
" 'max_depth': [None, 10, 20],\n",
|
||
" 'min_samples_split': [2, 5]\n",
|
||
" },\n",
|
||
" \"Naive_Bayes\": {\n",
|
||
" 'alpha': [0.1, 0.5, 1.0, 2.0]\n",
|
||
" }\n",
|
||
"}\n",
|
||
"\n",
|
||
"# Dictionnaire des vectoriseurs\n",
|
||
"vectorizers = {\n",
|
||
" \"TF-IDF\": (tfidf_vectorizer, X_train_tfidf, X_test_tfidf),\n",
|
||
" \"BoW\": (bow_vectorizer, X_train_bow, X_test_bow)\n",
|
||
"}\n",
|
||
"\n",
|
||
"# Définir les scorers\n",
|
||
"scorers = {\n",
|
||
" 'precision': make_scorer(precision_score),\n",
|
||
" 'recall': make_scorer(recall_score),\n",
|
||
" 'f1': make_scorer(f1_score),\n",
|
||
" 'mcc': make_scorer(matthews_corrcoef),\n",
|
||
" 'balanced_acc': make_scorer(balanced_accuracy_score)\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "nAEoLNGmWxlM"
|
||
},
|
||
"source": [
|
||
"## Entrainement des modèles"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"id": "yOKPz7roWxlM"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"train_models = True"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/",
|
||
"height": 1000
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 35588700,
|
||
"status": "ok",
|
||
"timestamp": 1751740002532,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "zT0mYkAxWxlM",
|
||
"outputId": "32e420f3-7a21-4d06-ad43-7d2b1a3c5c8f"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"\rProgression globale: 0%| | 0/8 [00:00<?, ?it/s]"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"\n",
|
||
"================================================================================\n",
|
||
"Démarrage de GridSearchCV pour Regression_Logistique avec TF-IDF...\n",
|
||
"Fitting 5 folds for each of 8 candidates, totalling 40 fits\n",
|
||
"\n",
|
||
"Résultats pour Regression_Logistique avec TF-IDF:\n",
|
||
"Accuracy: 0.7852\n",
|
||
"Precision: 0.7796\n",
|
||
"Recall: 0.7953\n",
|
||
"F1 Score: 0.7874\n",
|
||
"ROC AUC: 0.8667\n",
|
||
"\n",
|
||
"Matrice de confusion:\n",
|
||
"[[15503 4497]\n",
|
||
" [ 4094 15906]]\n",
|
||
"\n",
|
||
"Rapport de classification:\n",
|
||
" precision recall f1-score support\n",
|
||
"\n",
|
||
" 0 0.79 0.78 0.78 20000\n",
|
||
" 1 0.78 0.80 0.79 20000\n",
|
||
"\n",
|
||
" accuracy 0.79 40000\n",
|
||
" macro avg 0.79 0.79 0.79 40000\n",
|
||
"weighted avg 0.79 0.79 0.79 40000\n",
|
||
"\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"2025/07/05 08:34:47 WARNING mlflow.models.model: `artifact_path` is deprecated. Please use `name` instead.\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Meilleurs paramètres: {'C': 1.0, 'max_iter': 1000, 'solver': 'liblinear'}\n",
|
||
"Meilleur score CV (Precision): 0.7786\n",
|
||
"F1 Score sur test: 0.7874\n",
|
||
"ROC AUC sur test: 0.8667\n",
|
||
"Temps d'entraînement: 65.19 secondes\n",
|
||
"🏃 View run Modele_Simple_Regression_Logistique_TF-IDF at: https://mlflow.greg-madman-nas.duckdns.org/#/experiments/1/runs/94a0cf29a68b402ab37098a44d1c1ee6\n",
|
||
"🧪 View experiment at: https://mlflow.greg-madman-nas.duckdns.org/#/experiments/1\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Dernier modèle: Regression_Logistique avec TF-IDF: 12%|█▎ | 1/8 [01:48<12:39, 108.49s/it]"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"\n",
|
||
"================================================================================\n",
|
||
"Démarrage de GridSearchCV pour Regression_Logistique avec BoW...\n",
|
||
"Fitting 5 folds for each of 8 candidates, totalling 40 fits\n",
|
||
"\n",
|
||
"Résultats pour Regression_Logistique avec BoW:\n",
|
||
"Accuracy: 0.7829\n",
|
||
"Precision: 0.7723\n",
|
||
"Recall: 0.8024\n",
|
||
"F1 Score: 0.7871\n",
|
||
"ROC AUC: 0.8584\n",
|
||
"\n",
|
||
"Matrice de confusion:\n",
|
||
"[[15268 4732]\n",
|
||
" [ 3951 16049]]\n",
|
||
"\n",
|
||
"Rapport de classification:\n",
|
||
" precision recall f1-score support\n",
|
||
"\n",
|
||
" 0 0.79 0.76 0.78 20000\n",
|
||
" 1 0.77 0.80 0.79 20000\n",
|
||
"\n",
|
||
" accuracy 0.78 40000\n",
|
||
" macro avg 0.78 0.78 0.78 40000\n",
|
||
"weighted avg 0.78 0.78 0.78 40000\n",
|
||
"\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"2025/07/05 08:50:28 WARNING mlflow.models.model: `artifact_path` is deprecated. Please use `name` instead.\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Meilleurs paramètres: {'C': 0.1, 'max_iter': 1000, 'solver': 'liblinear'}\n",
|
||
"Meilleur score CV (Precision): 0.7714\n",
|
||
"F1 Score sur test: 0.7871\n",
|
||
"ROC AUC sur test: 0.8584\n",
|
||
"Temps d'entraînement: 896.35 secondes\n",
|
||
"🏃 View run Modele_Simple_Regression_Logistique_BoW at: https://mlflow.greg-madman-nas.duckdns.org/#/experiments/1/runs/75396e8531354bd5b168f8dd7e6f4135\n",
|
||
"🧪 View experiment at: https://mlflow.greg-madman-nas.duckdns.org/#/experiments/1\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Dernier modèle: Regression_Logistique avec BoW: 25%|██▌ | 2/8 [17:06<58:27, 584.60s/it] "
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"\n",
|
||
"================================================================================\n",
|
||
"Démarrage de GridSearchCV pour SVM_Lineaire avec TF-IDF...\n",
|
||
"Fitting 5 folds for each of 8 candidates, totalling 40 fits\n",
|
||
"\n",
|
||
"Résultats pour SVM_Lineaire avec TF-IDF:\n",
|
||
"Accuracy: 0.7854\n",
|
||
"Precision: 0.7781\n",
|
||
"Recall: 0.7985\n",
|
||
"F1 Score: 0.7882\n",
|
||
"ROC AUC: 0.8665\n",
|
||
"\n",
|
||
"Matrice de confusion:\n",
|
||
"[[15445 4555]\n",
|
||
" [ 4029 15971]]\n",
|
||
"\n",
|
||
"Rapport de classification:\n",
|
||
" precision recall f1-score support\n",
|
||
"\n",
|
||
" 0 0.79 0.77 0.78 20000\n",
|
||
" 1 0.78 0.80 0.79 20000\n",
|
||
"\n",
|
||
" accuracy 0.79 40000\n",
|
||
" macro avg 0.79 0.79 0.79 40000\n",
|
||
"weighted avg 0.79 0.79 0.79 40000\n",
|
||
"\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"2025/07/05 08:52:50 WARNING mlflow.models.model: `artifact_path` is deprecated. Please use `name` instead.\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Meilleurs paramètres: {'C': 0.1, 'dual': True, 'max_iter': 1000}\n",
|
||
"Meilleur score CV (Precision): 0.7769\n",
|
||
"F1 Score sur test: 0.7882\n",
|
||
"ROC AUC sur test: 0.8665\n",
|
||
"Temps d'entraînement: 122.32 secondes\n",
|
||
"🏃 View run Modele_Simple_SVM_Lineaire_TF-IDF at: https://mlflow.greg-madman-nas.duckdns.org/#/experiments/1/runs/767fe1513d6445029ca90ca2156ab653\n",
|
||
"🧪 View experiment at: https://mlflow.greg-madman-nas.duckdns.org/#/experiments/1\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Dernier modèle: SVM_Lineaire avec TF-IDF: 38%|███▊ | 3/8 [19:27<31:51, 382.25s/it] "
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"\n",
|
||
"================================================================================\n",
|
||
"Démarrage de GridSearchCV pour SVM_Lineaire avec BoW...\n",
|
||
"Fitting 5 folds for each of 8 candidates, totalling 40 fits\n",
|
||
"\n",
|
||
"Résultats pour SVM_Lineaire avec BoW:\n",
|
||
"Accuracy: 0.7822\n",
|
||
"Precision: 0.7687\n",
|
||
"Recall: 0.8074\n",
|
||
"F1 Score: 0.7876\n",
|
||
"ROC AUC: 0.8583\n",
|
||
"\n",
|
||
"Matrice de confusion:\n",
|
||
"[[15141 4859]\n",
|
||
" [ 3852 16148]]\n",
|
||
"\n",
|
||
"Rapport de classification:\n",
|
||
" precision recall f1-score support\n",
|
||
"\n",
|
||
" 0 0.80 0.76 0.78 20000\n",
|
||
" 1 0.77 0.81 0.79 20000\n",
|
||
"\n",
|
||
" accuracy 0.78 40000\n",
|
||
" macro avg 0.78 0.78 0.78 40000\n",
|
||
"weighted avg 0.78 0.78 0.78 40000\n",
|
||
"\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"2025/07/05 09:00:50 WARNING mlflow.models.model: `artifact_path` is deprecated. Please use `name` instead.\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Meilleurs paramètres: {'C': 0.01, 'dual': True, 'max_iter': 1000}\n",
|
||
"Meilleur score CV (Precision): 0.7687\n",
|
||
"F1 Score sur test: 0.7876\n",
|
||
"ROC AUC sur test: 0.8583\n",
|
||
"Temps d'entraînement: 458.62 secondes\n",
|
||
"🏃 View run Modele_Simple_SVM_Lineaire_BoW at: https://mlflow.greg-madman-nas.duckdns.org/#/experiments/1/runs/eaa8dfac819b44e39fe7b7baaf490de7\n",
|
||
"🧪 View experiment at: https://mlflow.greg-madman-nas.duckdns.org/#/experiments/1\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Dernier modèle: SVM_Lineaire avec BoW: 50%|█████ | 4/8 [27:28<28:04, 421.02s/it] "
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"\n",
|
||
"================================================================================\n",
|
||
"Démarrage de GridSearchCV pour Random_Forest avec TF-IDF...\n",
|
||
"Fitting 5 folds for each of 18 candidates, totalling 90 fits\n",
|
||
"\n",
|
||
"Résultats pour Random_Forest avec TF-IDF:\n",
|
||
"Accuracy: 0.7675\n",
|
||
"Precision: 0.7702\n",
|
||
"Recall: 0.7625\n",
|
||
"F1 Score: 0.7663\n",
|
||
"ROC AUC: 0.8484\n",
|
||
"\n",
|
||
"Matrice de confusion:\n",
|
||
"[[15450 4550]\n",
|
||
" [ 4750 15250]]\n",
|
||
"\n",
|
||
"Rapport de classification:\n",
|
||
" precision recall f1-score support\n",
|
||
"\n",
|
||
" 0 0.76 0.77 0.77 20000\n",
|
||
" 1 0.77 0.76 0.77 20000\n",
|
||
"\n",
|
||
" accuracy 0.77 40000\n",
|
||
" macro avg 0.77 0.77 0.77 40000\n",
|
||
"weighted avg 0.77 0.77 0.77 40000\n",
|
||
"\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"2025/07/05 13:31:29 WARNING mlflow.models.model: `artifact_path` is deprecated. Please use `name` instead.\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Meilleurs paramètres: {'max_depth': None, 'min_samples_split': 5, 'n_estimators': 200}\n",
|
||
"Meilleur score CV (Precision): 0.7705\n",
|
||
"F1 Score sur test: 0.7663\n",
|
||
"ROC AUC sur test: 0.8484\n",
|
||
"Temps d'entraînement: 16182.08 secondes\n",
|
||
"🏃 View run Modele_Simple_Random_Forest_TF-IDF at: https://mlflow.greg-madman-nas.duckdns.org/#/experiments/1/runs/7dda37625478423abcfd9292dac05580\n",
|
||
"🧪 View experiment at: https://mlflow.greg-madman-nas.duckdns.org/#/experiments/1\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Dernier modèle: Random_Forest avec TF-IDF: 62%|██████▎ | 5/8 [4:58:58<5:07:10, 6143.56s/it]"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"\n",
|
||
"================================================================================\n",
|
||
"Démarrage de GridSearchCV pour Random_Forest avec BoW...\n",
|
||
"Fitting 5 folds for each of 18 candidates, totalling 90 fits\n",
|
||
"\n",
|
||
"Résultats pour Random_Forest avec BoW:\n",
|
||
"Accuracy: 0.7719\n",
|
||
"Precision: 0.7798\n",
|
||
"Recall: 0.7579\n",
|
||
"F1 Score: 0.7687\n",
|
||
"ROC AUC: 0.8515\n",
|
||
"\n",
|
||
"Matrice de confusion:\n",
|
||
"[[15720 4280]\n",
|
||
" [ 4843 15157]]\n",
|
||
"\n",
|
||
"Rapport de classification:\n",
|
||
" precision recall f1-score support\n",
|
||
"\n",
|
||
" 0 0.76 0.79 0.78 20000\n",
|
||
" 1 0.78 0.76 0.77 20000\n",
|
||
"\n",
|
||
" accuracy 0.77 40000\n",
|
||
" macro avg 0.77 0.77 0.77 40000\n",
|
||
"weighted avg 0.77 0.77 0.77 40000\n",
|
||
"\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"2025/07/05 18:24:53 WARNING mlflow.models.model: `artifact_path` is deprecated. Please use `name` instead.\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Meilleurs paramètres: {'max_depth': None, 'min_samples_split': 5, 'n_estimators': 200}\n",
|
||
"Meilleur score CV (Precision): 0.7772\n",
|
||
"F1 Score sur test: 0.7687\n",
|
||
"ROC AUC sur test: 0.8515\n",
|
||
"Temps d'entraînement: 17489.66 secondes\n",
|
||
"🏃 View run Modele_Simple_Random_Forest_BoW at: https://mlflow.greg-madman-nas.duckdns.org/#/experiments/1/runs/7d52e808227f468da7f733265280fc02\n",
|
||
"🧪 View experiment at: https://mlflow.greg-madman-nas.duckdns.org/#/experiments/1\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Dernier modèle: Random_Forest avec BoW: 75%|███████▌ | 6/8 [9:52:29<5:34:44, 10042.38s/it] "
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"\n",
|
||
"================================================================================\n",
|
||
"Démarrage de GridSearchCV pour Naive_Bayes avec TF-IDF...\n",
|
||
"Fitting 5 folds for each of 4 candidates, totalling 20 fits\n",
|
||
"\n",
|
||
"Résultats pour Naive_Bayes avec TF-IDF:\n",
|
||
"Accuracy: 0.7696\n",
|
||
"Precision: 0.7766\n",
|
||
"Recall: 0.7568\n",
|
||
"F1 Score: 0.7666\n",
|
||
"ROC AUC: 0.8524\n",
|
||
"\n",
|
||
"Matrice de confusion:\n",
|
||
"[[15647 4353]\n",
|
||
" [ 4864 15136]]\n",
|
||
"\n",
|
||
"Rapport de classification:\n",
|
||
" precision recall f1-score support\n",
|
||
"\n",
|
||
" 0 0.76 0.78 0.77 20000\n",
|
||
" 1 0.78 0.76 0.77 20000\n",
|
||
"\n",
|
||
" accuracy 0.77 40000\n",
|
||
" macro avg 0.77 0.77 0.77 40000\n",
|
||
"weighted avg 0.77 0.77 0.77 40000\n",
|
||
"\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"2025/07/05 18:26:14 WARNING mlflow.models.model: `artifact_path` is deprecated. Please use `name` instead.\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Meilleurs paramètres: {'alpha': 2.0}\n",
|
||
"Meilleur score CV (Precision): 0.7772\n",
|
||
"F1 Score sur test: 0.7666\n",
|
||
"ROC AUC sur test: 0.8524\n",
|
||
"Temps d'entraînement: 4.27 secondes\n",
|
||
"🏃 View run Modele_Simple_Naive_Bayes_TF-IDF at: https://mlflow.greg-madman-nas.duckdns.org/#/experiments/1/runs/f0f4a385cb0b463c97ad736eaa98ce9f\n",
|
||
"🧪 View experiment at: https://mlflow.greg-madman-nas.duckdns.org/#/experiments/1\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Dernier modèle: Naive_Bayes avec TF-IDF: 88%|████████▊ | 7/8 [9:52:49<1:52:45, 6765.92s/it]"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"\n",
|
||
"================================================================================\n",
|
||
"Démarrage de GridSearchCV pour Naive_Bayes avec BoW...\n",
|
||
"Fitting 5 folds for each of 4 candidates, totalling 20 fits\n",
|
||
"\n",
|
||
"Résultats pour Naive_Bayes avec BoW:\n",
|
||
"Accuracy: 0.7721\n",
|
||
"Precision: 0.7785\n",
|
||
"Recall: 0.7605\n",
|
||
"F1 Score: 0.7694\n",
|
||
"ROC AUC: 0.8441\n",
|
||
"\n",
|
||
"Matrice de confusion:\n",
|
||
"[[15673 4327]\n",
|
||
" [ 4790 15210]]\n",
|
||
"\n",
|
||
"Rapport de classification:\n",
|
||
" precision recall f1-score support\n",
|
||
"\n",
|
||
" 0 0.77 0.78 0.77 20000\n",
|
||
" 1 0.78 0.76 0.77 20000\n",
|
||
"\n",
|
||
" accuracy 0.77 40000\n",
|
||
" macro avg 0.77 0.77 0.77 40000\n",
|
||
"weighted avg 0.77 0.77 0.77 40000\n",
|
||
"\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"2025/07/05 18:26:32 WARNING mlflow.models.model: `artifact_path` is deprecated. Please use `name` instead.\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Meilleurs paramètres: {'alpha': 2.0}\n",
|
||
"Meilleur score CV (Precision): 0.7765\n",
|
||
"F1 Score sur test: 0.7694\n",
|
||
"ROC AUC sur test: 0.8441\n",
|
||
"Temps d'entraînement: 2.82 secondes\n",
|
||
"🏃 View run Modele_Simple_Naive_Bayes_BoW at: https://mlflow.greg-madman-nas.duckdns.org/#/experiments/1/runs/a920f241d90d4816b858b16d68a6b38f\n",
|
||
"🧪 View experiment at: https://mlflow.greg-madman-nas.duckdns.org/#/experiments/1\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Dernier modèle: Naive_Bayes avec BoW: 100%|██████████| 8/8 [9:53:08<00:00, 4448.58s/it]\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"<Figure size 1200x800 with 0 Axes>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"<Figure size 1200x800 with 0 Axes>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"<Figure size 1200x800 with 0 Axes>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"<Figure size 1200x800 with 0 Axes>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"<Figure size 1200x800 with 0 Axes>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"<Figure size 1200x800 with 0 Axes>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"<Figure size 1200x800 with 0 Axes>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"<Figure size 1200x800 with 0 Axes>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
}
|
||
],
|
||
"source": [
|
||
"if train_models:\n",
|
||
"\n",
|
||
" # Tester chaque modèle avec les deux types de vectorisation\n",
|
||
" total_iterations = len(base_models) * len(vectorizers)\n",
|
||
" progress_bar = tqdm(total=total_iterations, desc=\"Progression globale\")\n",
|
||
"\n",
|
||
" # Dictionnaire pour stocker les résultats\n",
|
||
" results = []\n",
|
||
"\n",
|
||
" # Tester chaque modèle avec les deux types de vectorisation\n",
|
||
" for model_name, base_model in base_models.items():\n",
|
||
" for vectorizer_name, (vectorizer, X_train_vec, X_test_vec) in vectorizers.items():\n",
|
||
" print(f\"\\n{'='*80}\")\n",
|
||
" print(f\"Démarrage de GridSearchCV pour {model_name} avec {vectorizer_name}...\")\n",
|
||
"\n",
|
||
" # Définir la grille de paramètres et créer GridSearchCV\n",
|
||
" param_grid = param_grids[model_name]\n",
|
||
"\n",
|
||
" grid_search = GridSearchCV(\n",
|
||
" base_model,\n",
|
||
" param_grid,\n",
|
||
" cv=5,\n",
|
||
" scoring=scorers,\n",
|
||
" refit='precision',\n",
|
||
" n_jobs=-1,\n",
|
||
" verbose=1,\n",
|
||
" return_train_score=True\n",
|
||
" )\n",
|
||
"\n",
|
||
" # Démarrer le run MLflow\n",
|
||
" with mlflow.start_run(run_name=f\"Modele_Simple_{model_name}_{vectorizer_name}\"):\n",
|
||
" # Journaliser les paramètres généraux\n",
|
||
" mlflow.log_param(\"model_type\", model_name)\n",
|
||
" mlflow.log_param(\"vectorizer_type\", vectorizer_name)\n",
|
||
" mlflow.log_param(\"dataset_size\", X_train.shape[0] + X_test.shape[0])\n",
|
||
" mlflow.log_param(\"train_size\", X_train.shape[0])\n",
|
||
" mlflow.log_param(\"test_size\", X_test.shape[0])\n",
|
||
" mlflow.log_param(\"max_features\", 10000)\n",
|
||
" mlflow.log_param(\"ngram_range\", \"(1, 2)\")\n",
|
||
" mlflow.log_param(\"scoring_metric\", \"precision\") # Noter que precision est utilisé\n",
|
||
"\n",
|
||
" # Mesurer le temps d'entraînement\n",
|
||
" start_time = time.time()\n",
|
||
"\n",
|
||
" # Entraîner avec GridSearchCV\n",
|
||
" grid_search.fit(X_train_vec, y_train)\n",
|
||
"\n",
|
||
" # Calculer le temps d'entraînement\n",
|
||
" training_time = time.time() - start_time\n",
|
||
"\n",
|
||
" # Journaliser le temps d'entraînement\n",
|
||
" mlflow.log_metric(\"training_time\", training_time)\n",
|
||
"\n",
|
||
" # Récupérer et journaliser les meilleurs paramètres\n",
|
||
" best_params = grid_search.best_params_\n",
|
||
" for param, value in best_params.items():\n",
|
||
" mlflow.log_param(f\"best_{param}\", value)\n",
|
||
"\n",
|
||
" mlflow.log_param(\"sample_size\", sample_size*2)\n",
|
||
"\n",
|
||
" # Journaliser le meilleur score de validation croisée\n",
|
||
" mlflow.log_metric(\"val_precision\", grid_search.best_score_)\n",
|
||
"\n",
|
||
" # Journaliser le recall score associé au modèle présentant la meilleure précision\n",
|
||
" val_recall = grid_search.cv_results_['mean_test_recall'][grid_search.best_index_]\n",
|
||
" mlflow.log_metric(\"val_recall\", val_recall)\n",
|
||
"\n",
|
||
"\n",
|
||
" # Récupérer le meilleur modèle\n",
|
||
" best_model = grid_search.best_estimator_\n",
|
||
"\n",
|
||
" # Évaluer le meilleur modèle sur l'ensemble de test\n",
|
||
" acc, prec, rec, f1, roc_auc, fig_cm, fig_roc, y_pred = evaluate_model(\n",
|
||
" best_model, X_train_vec, X_test_vec, y_train, y_test, model_name, vectorizer_name\n",
|
||
" )\n",
|
||
"\n",
|
||
" # Journaliser les métriques sur l'ensemble de test\n",
|
||
" mlflow.log_metric(\"test_accuracy\", acc)\n",
|
||
" mlflow.log_metric(\"test_precision\", prec)\n",
|
||
" mlflow.log_metric(\"test_recall\", rec)\n",
|
||
" mlflow.log_metric(\"test_f1\", f1)\n",
|
||
" mlflow.log_metric(\"test_roc_auc\", roc_auc)\n",
|
||
"\n",
|
||
" # Journaliser les figures\n",
|
||
" mlflow.log_figure(fig_cm, \"confusion_matrix.png\")\n",
|
||
" mlflow.log_figure(fig_roc, \"roc_curve.png\")\n",
|
||
" plt.close(fig_cm)\n",
|
||
" plt.close(fig_roc)\n",
|
||
"\n",
|
||
" # Journaliser le modèle\n",
|
||
" signature = infer_signature(X_train_vec, y_pred)\n",
|
||
" mlflow.sklearn.log_model(best_model, \"model\", signature=signature)\n",
|
||
"\n",
|
||
" # Créer le dossier pour sauvegarder les artefacts\n",
|
||
" os.makedirs(\"./content/simple-model\", exist_ok=True)\n",
|
||
"\n",
|
||
" # Sauvegarder et journaliser le vectoriseur\n",
|
||
" vectorizer_path = f\"./content/simple-model/vectorizer_{vectorizer_name}.pkl\"\n",
|
||
" with open(vectorizer_path, \"wb\") as f:\n",
|
||
" pickle.dump(vectorizer, f)\n",
|
||
" mlflow.log_artifact(vectorizer_path)\n",
|
||
"\n",
|
||
" # Journaliser les résultats détaillés de GridSearchCV\n",
|
||
" cv_results = pd.DataFrame(grid_search.cv_results_)\n",
|
||
" cv_results_path = \"./content/simple-model/cv_results.csv\"\n",
|
||
" cv_results.to_csv(cv_results_path, index=False)\n",
|
||
" mlflow.log_artifact(cv_results_path)\n",
|
||
"\n",
|
||
" # Créer et journaliser un graphique des résultats de GridSearchCV\n",
|
||
" plt.figure(figsize=(12, 8))\n",
|
||
" params = [f\"{k}={v}\" for k, v in best_params.items()]\n",
|
||
" params_str = \", \".join(params)\n",
|
||
"\n",
|
||
" # Extraire les scores moyens pour chaque paramètre principal\n",
|
||
" for param in param_grid.keys():\n",
|
||
" if len(param_grid[param]) > 1: # Seulement si le paramètre a plusieurs valeurs\n",
|
||
" param_name = f\"param_{param}\"\n",
|
||
" if param_name in cv_results.columns:\n",
|
||
" # Utiliser la colonne spécifique à la métrique precision\n",
|
||
" scores_df = cv_results[[param_name, \"mean_test_precision\", \"std_test_precision\"]]\n",
|
||
" scores_df = scores_df.sort_values(param_name)\n",
|
||
"\n",
|
||
" plt.figure(figsize=(10, 6))\n",
|
||
" plt.errorbar(\n",
|
||
" scores_df[param_name].astype(str),\n",
|
||
" scores_df[\"mean_test_precision\"],\n",
|
||
" yerr=scores_df[\"std_test_precision\"],\n",
|
||
" fmt='-o'\n",
|
||
" )\n",
|
||
" plt.title(f'Scores de validation croisée (Precision) par {param}')\n",
|
||
" plt.xlabel(param)\n",
|
||
" plt.ylabel('Precision moyenne')\n",
|
||
" plt.grid(True)\n",
|
||
" mlflow.log_figure(plt.gcf(), f\"cv_results_{param}.png\")\n",
|
||
" plt.close()\n",
|
||
"\n",
|
||
" # Journaliser les features importantes (pour les modèles qui le supportent)\n",
|
||
" if hasattr(best_model, 'coef_'):\n",
|
||
" # Récupérer les features les plus importantes\n",
|
||
" if isinstance(best_model, LogisticRegression) or isinstance(best_model, LinearSVC):\n",
|
||
" coefs = best_model.coef_[0]\n",
|
||
" if vectorizer_name == \"TF-IDF\":\n",
|
||
" feature_names = tfidf_vectorizer.get_feature_names_out()\n",
|
||
" else:\n",
|
||
" feature_names = bow_vectorizer.get_feature_names_out()\n",
|
||
"\n",
|
||
" # Créer un DataFrame avec les coefs et les noms des features\n",
|
||
" coefs_df = pd.DataFrame({\n",
|
||
" 'feature': feature_names,\n",
|
||
" 'importance': coefs\n",
|
||
" })\n",
|
||
"\n",
|
||
" # Trier par importance absolue\n",
|
||
" coefs_df['abs_importance'] = abs(coefs_df['importance'])\n",
|
||
" coefs_df = coefs_df.sort_values('abs_importance', ascending=False).head(20)\n",
|
||
"\n",
|
||
" # Journaliser les features les plus importantes\n",
|
||
" top_features_path = \"./content/simple-model/top_features.csv\"\n",
|
||
" coefs_df.to_csv(top_features_path, index=False)\n",
|
||
" mlflow.log_artifact(top_features_path)\n",
|
||
"\n",
|
||
" # Créer un graphique pour visualiser les features les plus importantes\n",
|
||
" plt.figure(figsize=(10, 8))\n",
|
||
" sns.barplot(x='importance', y='feature', data=coefs_df.sort_values('importance', ascending=False).head(20))\n",
|
||
" plt.title(f'Top 20 features positives')\n",
|
||
" plt.tight_layout()\n",
|
||
" mlflow.log_figure(plt.gcf(), \"top_positive_features.png\")\n",
|
||
" plt.close()\n",
|
||
"\n",
|
||
" plt.figure(figsize=(10, 8))\n",
|
||
" sns.barplot(x='importance', y='feature', data=coefs_df.sort_values('importance').head(20))\n",
|
||
" plt.title(f'Top 20 features négatives')\n",
|
||
" plt.tight_layout()\n",
|
||
" mlflow.log_figure(plt.gcf(), \"top_negative_features.png\")\n",
|
||
" plt.close()\n",
|
||
"\n",
|
||
" # Stocker les résultats pour comparaison\n",
|
||
" results.append({\n",
|
||
" \"Modèle\": model_name.replace(\"_\", \" \"),\n",
|
||
" \"Vectorisation\": vectorizer_name,\n",
|
||
" \"Meilleurs paramètres\": str(best_params),\n",
|
||
" \"Accuracy\": acc,\n",
|
||
" \"Precision\": prec,\n",
|
||
" \"Recall\": rec,\n",
|
||
" \"F1 Score\": f1,\n",
|
||
" \"ROC AUC\": roc_auc,\n",
|
||
" \"Temps d'entraînement (s)\": training_time\n",
|
||
" })\n",
|
||
"\n",
|
||
" # Afficher les résultats\n",
|
||
" print(f\"Meilleurs paramètres: {best_params}\")\n",
|
||
" print(f\"Meilleur score CV (Precision): {grid_search.best_score_:.4f}\")\n",
|
||
" print(f\"F1 Score sur test: {f1:.4f}\")\n",
|
||
" print(f\"ROC AUC sur test: {roc_auc:.4f}\")\n",
|
||
" print(f\"Temps d'entraînement: {training_time:.2f} secondes\")\n",
|
||
"\n",
|
||
"\n",
|
||
" # À la fin de chaque itération, mettez à jour la barre de progression\n",
|
||
" progress_bar.update(1)\n",
|
||
" progress_bar.set_description(f\"Dernier modèle: {model_name} avec {vectorizer_name}\")\n",
|
||
"\n",
|
||
" progress_bar.close()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "MPL9yrErWxlN"
|
||
},
|
||
"source": [
|
||
"## Evaluation des performances"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "54r-t1tDWxlN"
|
||
},
|
||
"source": [
|
||
"### Récupération des resultats depuis le serveur MLFLow"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"id": "PdlFbtWPWxlN"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def get_mlflow_results(experiment_name=\"OC Projet 7\", prefixe_run=\"Modele_Simple_\", uri=None):\n",
|
||
" \"\"\"\n",
|
||
" Récupère les résultats des runs MLflow et les organise dans un dataframe\n",
|
||
"\n",
|
||
" Parameters:\n",
|
||
" -----------\n",
|
||
" experiment_name : str\n",
|
||
" Nom de l'expérience MLflow à rechercher\n",
|
||
" prefixe_run : str\n",
|
||
" Préfixe des noms de runs à inclure\n",
|
||
" uri : str, optional\n",
|
||
" URI du serveur MLflow. Si None, utilise l'URI configuré par défaut\n",
|
||
"\n",
|
||
" Returns:\n",
|
||
" --------\n",
|
||
" pandas.DataFrame\n",
|
||
" Dataframe contenant les résultats des runs MLflow\n",
|
||
" \"\"\"\n",
|
||
" # Se connecter au serveur MLflow si un URI est fourni\n",
|
||
" if uri:\n",
|
||
" mlflow.set_tracking_uri(uri)\n",
|
||
"\n",
|
||
" # Créer un client MLflow\n",
|
||
" client = MlflowClient()\n",
|
||
"\n",
|
||
" # Récupérer l'ID de l'expérience\n",
|
||
" try:\n",
|
||
" experiment = client.get_experiment_by_name(experiment_name)\n",
|
||
" if experiment is None:\n",
|
||
" raise ValueError(f\"L'expérience '{experiment_name}' n'existe pas.\")\n",
|
||
" experiment_id = experiment.experiment_id\n",
|
||
" except Exception as e:\n",
|
||
" print(f\"Erreur lors de la récupération de l'expérience : {e}\")\n",
|
||
" return pd.DataFrame()\n",
|
||
"\n",
|
||
" # Récupérer tous les runs de l'expérience\n",
|
||
" runs = client.search_runs(\n",
|
||
" experiment_ids=[experiment_id],\n",
|
||
" filter_string=f\"tags.mlflow.runName LIKE '{prefixe_run}%'\",\n",
|
||
" order_by=[\"metrics.prec DESC\"]\n",
|
||
" )\n",
|
||
"\n",
|
||
" # Créer une liste pour stocker les résultats\n",
|
||
" resultats = []\n",
|
||
"\n",
|
||
" # Parcourir chaque run et extraire les informations\n",
|
||
" for run in runs:\n",
|
||
" # Récupérer le nom du run pour information\n",
|
||
" run_name = run.data.tags.get(\"mlflow.runName\", \"\")\n",
|
||
"\n",
|
||
" # Utiliser les paramètres model_type et vectorizer_type de MLflow\n",
|
||
" modele = run.data.params.get(\"model_type\", \"Inconnu\")\n",
|
||
" vectorisation = run.data.params.get(\"vectorizer_type\", \"Inconnu\")\n",
|
||
"\n",
|
||
" # Formater le nom du modèle (remplacer les underscores par des espaces)\n",
|
||
" modele = modele.replace(\"_\", \" \")\n",
|
||
"\n",
|
||
" # Extraire les métriques\n",
|
||
" metrics = run.data.metrics\n",
|
||
" params = run.data.params\n",
|
||
"\n",
|
||
" # Construire un dictionnaire des meilleurs paramètres\n",
|
||
" best_params = {}\n",
|
||
" for key, value in params.items():\n",
|
||
" if key.startswith(\"best_\"):\n",
|
||
" param_name = key.replace(\"best_\", \"\")\n",
|
||
" best_params[param_name] = value\n",
|
||
"\n",
|
||
" # Créer une entrée pour le dataframe résultat\n",
|
||
" resultats.append({\n",
|
||
" \"Modèle\": modele,\n",
|
||
" \"Vectorisation\": vectorisation,\n",
|
||
" \"Meilleurs paramètres\": str(best_params),\n",
|
||
" \"Accuracy\": metrics.get(\"test_accuracy\", None),\n",
|
||
" \"Precision\": metrics.get(\"test_precision\", None),\n",
|
||
" \"Recall\": metrics.get(\"test_recall\", None),\n",
|
||
" \"F1 Score\": metrics.get(\"test_f1\", None),\n",
|
||
" \"ROC AUC\": metrics.get(\"test_roc_auc\", None),\n",
|
||
" \"Temps d'entraînement (s)\": metrics.get(\"training_time\", None),\n",
|
||
" \"Run ID\": run.info.run_id,\n",
|
||
" \"Run Name\": run_name\n",
|
||
" })\n",
|
||
"\n",
|
||
" # Créer un dataframe à partir des résultats\n",
|
||
" df_resultats = pd.DataFrame(resultats)\n",
|
||
"\n",
|
||
" # Trier le dataframe par Précision (décroissant)\n",
|
||
" if not df_resultats.empty and \"Precision\" in df_resultats.columns:\n",
|
||
" df_resultats = df_resultats.sort_values(\"Precision\", ascending=False)\n",
|
||
"\n",
|
||
" return df_resultats"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"id": "KyCAS-69WxlN"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Récupérer les résultats\n",
|
||
"results_df = get_mlflow_results(experiment_name=\"OC Projet 7\", prefixe_run=\"Modele_Simple_\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "sOFocHNnWxlN"
|
||
},
|
||
"source": [
|
||
"### Sauvegarde des résultats\n",
|
||
"\n",
|
||
"- Au format Markdown (.md)\n",
|
||
"- Au format CSV (.csv)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"id": "eTzchvr3OsJh"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"import os\n",
|
||
"simple_model_path = \"./content/simple-model/\"\n",
|
||
"# Créer le dossier s'il n'existe pas\n",
|
||
"os.makedirs(simple_model_path, exist_ok=True)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"id": "5YcvR-XBWxlN"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def export_results_to_markdown(df, output_file=simple_model_path+\"mlflow_results.md\"):\n",
|
||
" with open(output_file, \"w\") as f:\n",
|
||
" f.write(\"# Résultats des expérimentations MLflow\\n\\n\")\n",
|
||
" f.write(df.to_markdown(index=False))\n",
|
||
"\n",
|
||
"# Exporter les résultats au format Markdown\n",
|
||
"export_results_to_markdown(results_df)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"id": "U_oJh48yWxlN"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"results_path = simple_model_path+\"/mlflow_results.csv\"\n",
|
||
"# Enregistrer le tableau des résultats (optionnel)\n",
|
||
"results_df.to_csv(results_path, index=False)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "9-c659sYWxlP"
|
||
},
|
||
"source": [
|
||
"### Visualisation des métriques"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/",
|
||
"height": 776
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 139,
|
||
"status": "ok",
|
||
"timestamp": 1751740004089,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "3KiynT2KWxlQ",
|
||
"outputId": "aa429d2c-a1fd-462f-d247-570c6cfc6b46"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"application/vnd.google.colaboratory.intrinsic+json": {
|
||
"summary": "{\n \"name\": \"results_df\",\n \"rows\": 16,\n \"fields\": [\n {\n \"column\": \"Mod\\u00e8le\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 4,\n \"samples\": [\n \"Regression Logistique\",\n \"SVM Lineaire\",\n \"Random Forest\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Vectorisation\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"TF-IDF\",\n \"BoW\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Meilleurs param\\u00e8tres\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 8,\n \"samples\": [\n \"{'C': '1.0', 'max_iter': '1000', 'solver': 'liblinear'}\",\n \"{'C': '0.1', 'max_iter': '1000', 'solver': 'liblinear'}\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Accuracy\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.007192113012413891,\n \"min\": 0.7648,\n \"max\": 0.7854,\n \"num_unique_values\": 16,\n \"samples\": [\n 0.771925,\n 0.785225\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Precision\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.005252241847122117,\n \"min\": 0.7635874975114474,\n \"max\": 0.7798014096825642,\n \"num_unique_values\": 16,\n \"samples\": [\n 0.7798014096825642,\n 0.7795912365828555\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Recall\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.021208419859024552,\n \"min\": 0.7568,\n \"max\": 0.8074,\n \"num_unique_values\": 15,\n \"samples\": [\n 0.7584,\n 0.7625\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"F1 Score\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.009987107577157433,\n \"min\": 0.7653397186471116,\n \"max\": 0.788185362483344,\n \"num_unique_values\": 16,\n \"samples\": [\n 0.7686690164059132,\n 0.7873672747073237\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"ROC AUC\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.008073892898588831,\n \"min\": 0.8416485,\n \"max\": 0.86671001875,\n \"num_unique_values\": 16,\n \"samples\": [\n 0.85152670125,\n 0.86671001875\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Temps d'entra\\u00eenement (s)\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 5773.421748128435,\n \"min\": 1.4726371765136719,\n \"max\": 17489.656234502792,\n \"num_unique_values\": 16,\n \"samples\": [\n 17489.656234502792,\n 65.19242358207703\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Run ID\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 16,\n \"samples\": [\n \"7d52e808227f468da7f733265280fc02\",\n \"94a0cf29a68b402ab37098a44d1c1ee6\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Run Name\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 8,\n \"samples\": [\n \"Modele_Simple_Regression_Logistique_TF-IDF\",\n \"Modele_Simple_Regression_Logistique_BoW\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}",
|
||
"type": "dataframe",
|
||
"variable_name": "results_df"
|
||
},
|
||
"text/html": [
|
||
"\n",
|
||
" <div id=\"df-6adf4cea-2403-4d24-b2ad-aed4b25687f4\" class=\"colab-df-container\">\n",
|
||
" <div>\n",
|
||
"<style scoped>\n",
|
||
" .dataframe tbody tr th:only-of-type {\n",
|
||
" vertical-align: middle;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe tbody tr th {\n",
|
||
" vertical-align: top;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe thead th {\n",
|
||
" text-align: right;\n",
|
||
" }\n",
|
||
"</style>\n",
|
||
"<table border=\"1\" class=\"dataframe\">\n",
|
||
" <thead>\n",
|
||
" <tr style=\"text-align: right;\">\n",
|
||
" <th></th>\n",
|
||
" <th>Modèle</th>\n",
|
||
" <th>Vectorisation</th>\n",
|
||
" <th>Meilleurs paramètres</th>\n",
|
||
" <th>Accuracy</th>\n",
|
||
" <th>Precision</th>\n",
|
||
" <th>Recall</th>\n",
|
||
" <th>F1 Score</th>\n",
|
||
" <th>ROC AUC</th>\n",
|
||
" <th>Temps d'entraînement (s)</th>\n",
|
||
" <th>Run ID</th>\n",
|
||
" <th>Run Name</th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th>2</th>\n",
|
||
" <td>Random Forest</td>\n",
|
||
" <td>BoW</td>\n",
|
||
" <td>{'max_depth': 'None', 'min_samples_split': '5'...</td>\n",
|
||
" <td>0.771925</td>\n",
|
||
" <td>0.779801</td>\n",
|
||
" <td>0.75785</td>\n",
|
||
" <td>0.768669</td>\n",
|
||
" <td>0.851527</td>\n",
|
||
" <td>17489.656235</td>\n",
|
||
" <td>7d52e808227f468da7f733265280fc02</td>\n",
|
||
" <td>Modele_Simple_Random_Forest_BoW</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>7</th>\n",
|
||
" <td>Regression Logistique</td>\n",
|
||
" <td>TF-IDF</td>\n",
|
||
" <td>{'C': '1.0', 'max_iter': '1000', 'solver': 'li...</td>\n",
|
||
" <td>0.785225</td>\n",
|
||
" <td>0.779591</td>\n",
|
||
" <td>0.79530</td>\n",
|
||
" <td>0.787367</td>\n",
|
||
" <td>0.866710</td>\n",
|
||
" <td>65.192424</td>\n",
|
||
" <td>94a0cf29a68b402ab37098a44d1c1ee6</td>\n",
|
||
" <td>Modele_Simple_Regression_Logistique_TF-IDF</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>0</th>\n",
|
||
" <td>Naive Bayes</td>\n",
|
||
" <td>BoW</td>\n",
|
||
" <td>{'alpha': '2.0'}</td>\n",
|
||
" <td>0.772075</td>\n",
|
||
" <td>0.778523</td>\n",
|
||
" <td>0.76050</td>\n",
|
||
" <td>0.769406</td>\n",
|
||
" <td>0.844132</td>\n",
|
||
" <td>2.815040</td>\n",
|
||
" <td>a920f241d90d4816b858b16d68a6b38f</td>\n",
|
||
" <td>Modele_Simple_Naive_Bayes_BoW</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>5</th>\n",
|
||
" <td>SVM Lineaire</td>\n",
|
||
" <td>TF-IDF</td>\n",
|
||
" <td>{'C': '0.1', 'dual': 'True', 'max_iter': '1000'}</td>\n",
|
||
" <td>0.785400</td>\n",
|
||
" <td>0.778086</td>\n",
|
||
" <td>0.79855</td>\n",
|
||
" <td>0.788185</td>\n",
|
||
" <td>0.866477</td>\n",
|
||
" <td>122.321674</td>\n",
|
||
" <td>767fe1513d6445029ca90ca2156ab653</td>\n",
|
||
" <td>Modele_Simple_SVM_Lineaire_TF-IDF</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>9</th>\n",
|
||
" <td>Naive Bayes</td>\n",
|
||
" <td>TF-IDF</td>\n",
|
||
" <td>{'alpha': '2.0'}</td>\n",
|
||
" <td>0.770400</td>\n",
|
||
" <td>0.777618</td>\n",
|
||
" <td>0.75740</td>\n",
|
||
" <td>0.767376</td>\n",
|
||
" <td>0.851067</td>\n",
|
||
" <td>4.320478</td>\n",
|
||
" <td>daf72838a04d4f2f962d5b7cf6e41a82</td>\n",
|
||
" <td>Modele_Simple_Naive_Bayes_TF-IDF</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>1</th>\n",
|
||
" <td>Naive Bayes</td>\n",
|
||
" <td>TF-IDF</td>\n",
|
||
" <td>{'alpha': '2.0'}</td>\n",
|
||
" <td>0.769575</td>\n",
|
||
" <td>0.776643</td>\n",
|
||
" <td>0.75680</td>\n",
|
||
" <td>0.766593</td>\n",
|
||
" <td>0.852443</td>\n",
|
||
" <td>4.272107</td>\n",
|
||
" <td>f0f4a385cb0b463c97ad736eaa98ce9f</td>\n",
|
||
" <td>Modele_Simple_Naive_Bayes_TF-IDF</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>15</th>\n",
|
||
" <td>Regression Logistique</td>\n",
|
||
" <td>TF-IDF</td>\n",
|
||
" <td>{'C': '1.0', 'max_iter': '1000', 'solver': 'sa...</td>\n",
|
||
" <td>0.783150</td>\n",
|
||
" <td>0.776595</td>\n",
|
||
" <td>0.79500</td>\n",
|
||
" <td>0.785690</td>\n",
|
||
" <td>0.861098</td>\n",
|
||
" <td>36.014652</td>\n",
|
||
" <td>741178bfcba54908aaa50c4f44d6db71</td>\n",
|
||
" <td>Modele_Simple_Regression_Logistique_TF-IDF</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>8</th>\n",
|
||
" <td>Naive Bayes</td>\n",
|
||
" <td>BoW</td>\n",
|
||
" <td>{'alpha': '2.0'}</td>\n",
|
||
" <td>0.771800</td>\n",
|
||
" <td>0.776557</td>\n",
|
||
" <td>0.76320</td>\n",
|
||
" <td>0.769820</td>\n",
|
||
" <td>0.843168</td>\n",
|
||
" <td>1.472637</td>\n",
|
||
" <td>9635b8567b874dd6bc91da23d1cb3b78</td>\n",
|
||
" <td>Modele_Simple_Naive_Bayes_BoW</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>13</th>\n",
|
||
" <td>SVM Lineaire</td>\n",
|
||
" <td>TF-IDF</td>\n",
|
||
" <td>{'C': '0.1', 'dual': 'True', 'max_iter': '1000'}</td>\n",
|
||
" <td>0.784200</td>\n",
|
||
" <td>0.776513</td>\n",
|
||
" <td>0.79810</td>\n",
|
||
" <td>0.787158</td>\n",
|
||
" <td>0.861249</td>\n",
|
||
" <td>51.149676</td>\n",
|
||
" <td>bb39934ff22f4021a379983c32d828ed</td>\n",
|
||
" <td>Modele_Simple_SVM_Lineaire_TF-IDF</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>10</th>\n",
|
||
" <td>Random Forest</td>\n",
|
||
" <td>BoW</td>\n",
|
||
" <td>{'max_depth': 'None', 'min_samples_split': '5'...</td>\n",
|
||
" <td>0.768850</td>\n",
|
||
" <td>0.774589</td>\n",
|
||
" <td>0.75840</td>\n",
|
||
" <td>0.766409</td>\n",
|
||
" <td>0.843950</td>\n",
|
||
" <td>6377.436032</td>\n",
|
||
" <td>623f3412438b4b6a8bb0d112c917dcea</td>\n",
|
||
" <td>Modele_Simple_Random_Forest_BoW</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>6</th>\n",
|
||
" <td>Regression Logistique</td>\n",
|
||
" <td>BoW</td>\n",
|
||
" <td>{'C': '0.1', 'max_iter': '1000', 'solver': 'li...</td>\n",
|
||
" <td>0.782925</td>\n",
|
||
" <td>0.772292</td>\n",
|
||
" <td>0.80245</td>\n",
|
||
" <td>0.787082</td>\n",
|
||
" <td>0.858402</td>\n",
|
||
" <td>896.353782</td>\n",
|
||
" <td>75396e8531354bd5b168f8dd7e6f4135</td>\n",
|
||
" <td>Modele_Simple_Regression_Logistique_BoW</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>3</th>\n",
|
||
" <td>Random Forest</td>\n",
|
||
" <td>TF-IDF</td>\n",
|
||
" <td>{'max_depth': 'None', 'min_samples_split': '5'...</td>\n",
|
||
" <td>0.767500</td>\n",
|
||
" <td>0.770202</td>\n",
|
||
" <td>0.76250</td>\n",
|
||
" <td>0.766332</td>\n",
|
||
" <td>0.848404</td>\n",
|
||
" <td>16182.080744</td>\n",
|
||
" <td>7dda37625478423abcfd9292dac05580</td>\n",
|
||
" <td>Modele_Simple_Random_Forest_TF-IDF</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>4</th>\n",
|
||
" <td>SVM Lineaire</td>\n",
|
||
" <td>BoW</td>\n",
|
||
" <td>{'C': '0.01', 'dual': 'True', 'max_iter': '1000'}</td>\n",
|
||
" <td>0.782225</td>\n",
|
||
" <td>0.768696</td>\n",
|
||
" <td>0.80740</td>\n",
|
||
" <td>0.787573</td>\n",
|
||
" <td>0.858312</td>\n",
|
||
" <td>458.623438</td>\n",
|
||
" <td>eaa8dfac819b44e39fe7b7baaf490de7</td>\n",
|
||
" <td>Modele_Simple_SVM_Lineaire_BoW</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>14</th>\n",
|
||
" <td>Regression Logistique</td>\n",
|
||
" <td>BoW</td>\n",
|
||
" <td>{'C': '0.1', 'max_iter': '1000', 'solver': 'sa...</td>\n",
|
||
" <td>0.779250</td>\n",
|
||
" <td>0.767199</td>\n",
|
||
" <td>0.80180</td>\n",
|
||
" <td>0.784118</td>\n",
|
||
" <td>0.851395</td>\n",
|
||
" <td>371.537341</td>\n",
|
||
" <td>b88c00415c1340ec9dd4e6db806f2de3</td>\n",
|
||
" <td>Modele_Simple_Regression_Logistique_BoW</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>12</th>\n",
|
||
" <td>SVM Lineaire</td>\n",
|
||
" <td>BoW</td>\n",
|
||
" <td>{'C': '0.01', 'dual': 'True', 'max_iter': '1000'}</td>\n",
|
||
" <td>0.780050</td>\n",
|
||
" <td>0.765526</td>\n",
|
||
" <td>0.80740</td>\n",
|
||
" <td>0.785905</td>\n",
|
||
" <td>0.851585</td>\n",
|
||
" <td>187.807479</td>\n",
|
||
" <td>5c07f55dbafc4c899c5c2a9c3de4a742</td>\n",
|
||
" <td>Modele_Simple_SVM_Lineaire_BoW</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>11</th>\n",
|
||
" <td>Random Forest</td>\n",
|
||
" <td>TF-IDF</td>\n",
|
||
" <td>{'max_depth': 'None', 'min_samples_split': '5'...</td>\n",
|
||
" <td>0.764800</td>\n",
|
||
" <td>0.763587</td>\n",
|
||
" <td>0.76710</td>\n",
|
||
" <td>0.765340</td>\n",
|
||
" <td>0.841649</td>\n",
|
||
" <td>5977.548638</td>\n",
|
||
" <td>cb84d2c0f188472990425e7300f744ef</td>\n",
|
||
" <td>Modele_Simple_Random_Forest_TF-IDF</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n",
|
||
"</div>\n",
|
||
" <div class=\"colab-df-buttons\">\n",
|
||
"\n",
|
||
" <div class=\"colab-df-container\">\n",
|
||
" <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-6adf4cea-2403-4d24-b2ad-aed4b25687f4')\"\n",
|
||
" title=\"Convert this dataframe to an interactive table.\"\n",
|
||
" style=\"display:none;\">\n",
|
||
"\n",
|
||
" <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n",
|
||
" <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n",
|
||
" </svg>\n",
|
||
" </button>\n",
|
||
"\n",
|
||
" <style>\n",
|
||
" .colab-df-container {\n",
|
||
" display:flex;\n",
|
||
" gap: 12px;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-convert {\n",
|
||
" background-color: #E8F0FE;\n",
|
||
" border: none;\n",
|
||
" border-radius: 50%;\n",
|
||
" cursor: pointer;\n",
|
||
" display: none;\n",
|
||
" fill: #1967D2;\n",
|
||
" height: 32px;\n",
|
||
" padding: 0 0 0 0;\n",
|
||
" width: 32px;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-convert:hover {\n",
|
||
" background-color: #E2EBFA;\n",
|
||
" box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
|
||
" fill: #174EA6;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-buttons div {\n",
|
||
" margin-bottom: 4px;\n",
|
||
" }\n",
|
||
"\n",
|
||
" [theme=dark] .colab-df-convert {\n",
|
||
" background-color: #3B4455;\n",
|
||
" fill: #D2E3FC;\n",
|
||
" }\n",
|
||
"\n",
|
||
" [theme=dark] .colab-df-convert:hover {\n",
|
||
" background-color: #434B5C;\n",
|
||
" box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
|
||
" filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
|
||
" fill: #FFFFFF;\n",
|
||
" }\n",
|
||
" </style>\n",
|
||
"\n",
|
||
" <script>\n",
|
||
" const buttonEl =\n",
|
||
" document.querySelector('#df-6adf4cea-2403-4d24-b2ad-aed4b25687f4 button.colab-df-convert');\n",
|
||
" buttonEl.style.display =\n",
|
||
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
|
||
"\n",
|
||
" async function convertToInteractive(key) {\n",
|
||
" const element = document.querySelector('#df-6adf4cea-2403-4d24-b2ad-aed4b25687f4');\n",
|
||
" const dataTable =\n",
|
||
" await google.colab.kernel.invokeFunction('convertToInteractive',\n",
|
||
" [key], {});\n",
|
||
" if (!dataTable) return;\n",
|
||
"\n",
|
||
" const docLinkHtml = 'Like what you see? Visit the ' +\n",
|
||
" '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
|
||
" + ' to learn more about interactive tables.';\n",
|
||
" element.innerHTML = '';\n",
|
||
" dataTable['output_type'] = 'display_data';\n",
|
||
" await google.colab.output.renderOutput(dataTable, element);\n",
|
||
" const docLink = document.createElement('div');\n",
|
||
" docLink.innerHTML = docLinkHtml;\n",
|
||
" element.appendChild(docLink);\n",
|
||
" }\n",
|
||
" </script>\n",
|
||
" </div>\n",
|
||
"\n",
|
||
"\n",
|
||
" <div id=\"df-dbe12a22-8ecd-4113-84f8-56d03723da51\">\n",
|
||
" <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-dbe12a22-8ecd-4113-84f8-56d03723da51')\"\n",
|
||
" title=\"Suggest charts\"\n",
|
||
" style=\"display:none;\">\n",
|
||
"\n",
|
||
"<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
|
||
" width=\"24px\">\n",
|
||
" <g>\n",
|
||
" <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n",
|
||
" </g>\n",
|
||
"</svg>\n",
|
||
" </button>\n",
|
||
"\n",
|
||
"<style>\n",
|
||
" .colab-df-quickchart {\n",
|
||
" --bg-color: #E8F0FE;\n",
|
||
" --fill-color: #1967D2;\n",
|
||
" --hover-bg-color: #E2EBFA;\n",
|
||
" --hover-fill-color: #174EA6;\n",
|
||
" --disabled-fill-color: #AAA;\n",
|
||
" --disabled-bg-color: #DDD;\n",
|
||
" }\n",
|
||
"\n",
|
||
" [theme=dark] .colab-df-quickchart {\n",
|
||
" --bg-color: #3B4455;\n",
|
||
" --fill-color: #D2E3FC;\n",
|
||
" --hover-bg-color: #434B5C;\n",
|
||
" --hover-fill-color: #FFFFFF;\n",
|
||
" --disabled-bg-color: #3B4455;\n",
|
||
" --disabled-fill-color: #666;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-quickchart {\n",
|
||
" background-color: var(--bg-color);\n",
|
||
" border: none;\n",
|
||
" border-radius: 50%;\n",
|
||
" cursor: pointer;\n",
|
||
" display: none;\n",
|
||
" fill: var(--fill-color);\n",
|
||
" height: 32px;\n",
|
||
" padding: 0;\n",
|
||
" width: 32px;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-quickchart:hover {\n",
|
||
" background-color: var(--hover-bg-color);\n",
|
||
" box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
|
||
" fill: var(--button-hover-fill-color);\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-quickchart-complete:disabled,\n",
|
||
" .colab-df-quickchart-complete:disabled:hover {\n",
|
||
" background-color: var(--disabled-bg-color);\n",
|
||
" fill: var(--disabled-fill-color);\n",
|
||
" box-shadow: none;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-spinner {\n",
|
||
" border: 2px solid var(--fill-color);\n",
|
||
" border-color: transparent;\n",
|
||
" border-bottom-color: var(--fill-color);\n",
|
||
" animation:\n",
|
||
" spin 1s steps(1) infinite;\n",
|
||
" }\n",
|
||
"\n",
|
||
" @keyframes spin {\n",
|
||
" 0% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-bottom-color: var(--fill-color);\n",
|
||
" border-left-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 20% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-left-color: var(--fill-color);\n",
|
||
" border-top-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 30% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-left-color: var(--fill-color);\n",
|
||
" border-top-color: var(--fill-color);\n",
|
||
" border-right-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 40% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-right-color: var(--fill-color);\n",
|
||
" border-top-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 60% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-right-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 80% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-right-color: var(--fill-color);\n",
|
||
" border-bottom-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 90% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-bottom-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" }\n",
|
||
"</style>\n",
|
||
"\n",
|
||
" <script>\n",
|
||
" async function quickchart(key) {\n",
|
||
" const quickchartButtonEl =\n",
|
||
" document.querySelector('#' + key + ' button');\n",
|
||
" quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n",
|
||
" quickchartButtonEl.classList.add('colab-df-spinner');\n",
|
||
" try {\n",
|
||
" const charts = await google.colab.kernel.invokeFunction(\n",
|
||
" 'suggestCharts', [key], {});\n",
|
||
" } catch (error) {\n",
|
||
" console.error('Error during call to suggestCharts:', error);\n",
|
||
" }\n",
|
||
" quickchartButtonEl.classList.remove('colab-df-spinner');\n",
|
||
" quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n",
|
||
" }\n",
|
||
" (() => {\n",
|
||
" let quickchartButtonEl =\n",
|
||
" document.querySelector('#df-dbe12a22-8ecd-4113-84f8-56d03723da51 button');\n",
|
||
" quickchartButtonEl.style.display =\n",
|
||
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
|
||
" })();\n",
|
||
" </script>\n",
|
||
" </div>\n",
|
||
"\n",
|
||
" <div id=\"id_39d73cf4-d973-4922-b4d4-e48e871515d7\">\n",
|
||
" <style>\n",
|
||
" .colab-df-generate {\n",
|
||
" background-color: #E8F0FE;\n",
|
||
" border: none;\n",
|
||
" border-radius: 50%;\n",
|
||
" cursor: pointer;\n",
|
||
" display: none;\n",
|
||
" fill: #1967D2;\n",
|
||
" height: 32px;\n",
|
||
" padding: 0 0 0 0;\n",
|
||
" width: 32px;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-generate:hover {\n",
|
||
" background-color: #E2EBFA;\n",
|
||
" box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
|
||
" fill: #174EA6;\n",
|
||
" }\n",
|
||
"\n",
|
||
" [theme=dark] .colab-df-generate {\n",
|
||
" background-color: #3B4455;\n",
|
||
" fill: #D2E3FC;\n",
|
||
" }\n",
|
||
"\n",
|
||
" [theme=dark] .colab-df-generate:hover {\n",
|
||
" background-color: #434B5C;\n",
|
||
" box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
|
||
" filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
|
||
" fill: #FFFFFF;\n",
|
||
" }\n",
|
||
" </style>\n",
|
||
" <button class=\"colab-df-generate\" onclick=\"generateWithVariable('results_df')\"\n",
|
||
" title=\"Generate code using this dataframe.\"\n",
|
||
" style=\"display:none;\">\n",
|
||
"\n",
|
||
" <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
|
||
" width=\"24px\">\n",
|
||
" <path d=\"M7,19H8.4L18.45,9,17,7.55,7,17.6ZM5,21V16.75L18.45,3.32a2,2,0,0,1,2.83,0l1.4,1.43a1.91,1.91,0,0,1,.58,1.4,1.91,1.91,0,0,1-.58,1.4L9.25,21ZM18.45,9,17,7.55Zm-12,3A5.31,5.31,0,0,0,4.9,8.1,5.31,5.31,0,0,0,1,6.5,5.31,5.31,0,0,0,4.9,4.9,5.31,5.31,0,0,0,6.5,1,5.31,5.31,0,0,0,8.1,4.9,5.31,5.31,0,0,0,12,6.5,5.46,5.46,0,0,0,6.5,12Z\"/>\n",
|
||
" </svg>\n",
|
||
" </button>\n",
|
||
" <script>\n",
|
||
" (() => {\n",
|
||
" const buttonEl =\n",
|
||
" document.querySelector('#id_39d73cf4-d973-4922-b4d4-e48e871515d7 button.colab-df-generate');\n",
|
||
" buttonEl.style.display =\n",
|
||
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
|
||
"\n",
|
||
" buttonEl.onclick = () => {\n",
|
||
" google.colab.notebook.generateWithVariable('results_df');\n",
|
||
" }\n",
|
||
" })();\n",
|
||
" </script>\n",
|
||
" </div>\n",
|
||
"\n",
|
||
" </div>\n",
|
||
" </div>\n"
|
||
],
|
||
"text/plain": [
|
||
" Modèle Vectorisation \\\n",
|
||
"2 Random Forest BoW \n",
|
||
"7 Regression Logistique TF-IDF \n",
|
||
"0 Naive Bayes BoW \n",
|
||
"5 SVM Lineaire TF-IDF \n",
|
||
"9 Naive Bayes TF-IDF \n",
|
||
"1 Naive Bayes TF-IDF \n",
|
||
"15 Regression Logistique TF-IDF \n",
|
||
"8 Naive Bayes BoW \n",
|
||
"13 SVM Lineaire TF-IDF \n",
|
||
"10 Random Forest BoW \n",
|
||
"6 Regression Logistique BoW \n",
|
||
"3 Random Forest TF-IDF \n",
|
||
"4 SVM Lineaire BoW \n",
|
||
"14 Regression Logistique BoW \n",
|
||
"12 SVM Lineaire BoW \n",
|
||
"11 Random Forest TF-IDF \n",
|
||
"\n",
|
||
" Meilleurs paramètres Accuracy Precision \\\n",
|
||
"2 {'max_depth': 'None', 'min_samples_split': '5'... 0.771925 0.779801 \n",
|
||
"7 {'C': '1.0', 'max_iter': '1000', 'solver': 'li... 0.785225 0.779591 \n",
|
||
"0 {'alpha': '2.0'} 0.772075 0.778523 \n",
|
||
"5 {'C': '0.1', 'dual': 'True', 'max_iter': '1000'} 0.785400 0.778086 \n",
|
||
"9 {'alpha': '2.0'} 0.770400 0.777618 \n",
|
||
"1 {'alpha': '2.0'} 0.769575 0.776643 \n",
|
||
"15 {'C': '1.0', 'max_iter': '1000', 'solver': 'sa... 0.783150 0.776595 \n",
|
||
"8 {'alpha': '2.0'} 0.771800 0.776557 \n",
|
||
"13 {'C': '0.1', 'dual': 'True', 'max_iter': '1000'} 0.784200 0.776513 \n",
|
||
"10 {'max_depth': 'None', 'min_samples_split': '5'... 0.768850 0.774589 \n",
|
||
"6 {'C': '0.1', 'max_iter': '1000', 'solver': 'li... 0.782925 0.772292 \n",
|
||
"3 {'max_depth': 'None', 'min_samples_split': '5'... 0.767500 0.770202 \n",
|
||
"4 {'C': '0.01', 'dual': 'True', 'max_iter': '1000'} 0.782225 0.768696 \n",
|
||
"14 {'C': '0.1', 'max_iter': '1000', 'solver': 'sa... 0.779250 0.767199 \n",
|
||
"12 {'C': '0.01', 'dual': 'True', 'max_iter': '1000'} 0.780050 0.765526 \n",
|
||
"11 {'max_depth': 'None', 'min_samples_split': '5'... 0.764800 0.763587 \n",
|
||
"\n",
|
||
" Recall F1 Score ROC AUC Temps d'entraînement (s) \\\n",
|
||
"2 0.75785 0.768669 0.851527 17489.656235 \n",
|
||
"7 0.79530 0.787367 0.866710 65.192424 \n",
|
||
"0 0.76050 0.769406 0.844132 2.815040 \n",
|
||
"5 0.79855 0.788185 0.866477 122.321674 \n",
|
||
"9 0.75740 0.767376 0.851067 4.320478 \n",
|
||
"1 0.75680 0.766593 0.852443 4.272107 \n",
|
||
"15 0.79500 0.785690 0.861098 36.014652 \n",
|
||
"8 0.76320 0.769820 0.843168 1.472637 \n",
|
||
"13 0.79810 0.787158 0.861249 51.149676 \n",
|
||
"10 0.75840 0.766409 0.843950 6377.436032 \n",
|
||
"6 0.80245 0.787082 0.858402 896.353782 \n",
|
||
"3 0.76250 0.766332 0.848404 16182.080744 \n",
|
||
"4 0.80740 0.787573 0.858312 458.623438 \n",
|
||
"14 0.80180 0.784118 0.851395 371.537341 \n",
|
||
"12 0.80740 0.785905 0.851585 187.807479 \n",
|
||
"11 0.76710 0.765340 0.841649 5977.548638 \n",
|
||
"\n",
|
||
" Run ID \\\n",
|
||
"2 7d52e808227f468da7f733265280fc02 \n",
|
||
"7 94a0cf29a68b402ab37098a44d1c1ee6 \n",
|
||
"0 a920f241d90d4816b858b16d68a6b38f \n",
|
||
"5 767fe1513d6445029ca90ca2156ab653 \n",
|
||
"9 daf72838a04d4f2f962d5b7cf6e41a82 \n",
|
||
"1 f0f4a385cb0b463c97ad736eaa98ce9f \n",
|
||
"15 741178bfcba54908aaa50c4f44d6db71 \n",
|
||
"8 9635b8567b874dd6bc91da23d1cb3b78 \n",
|
||
"13 bb39934ff22f4021a379983c32d828ed \n",
|
||
"10 623f3412438b4b6a8bb0d112c917dcea \n",
|
||
"6 75396e8531354bd5b168f8dd7e6f4135 \n",
|
||
"3 7dda37625478423abcfd9292dac05580 \n",
|
||
"4 eaa8dfac819b44e39fe7b7baaf490de7 \n",
|
||
"14 b88c00415c1340ec9dd4e6db806f2de3 \n",
|
||
"12 5c07f55dbafc4c899c5c2a9c3de4a742 \n",
|
||
"11 cb84d2c0f188472990425e7300f744ef \n",
|
||
"\n",
|
||
" Run Name \n",
|
||
"2 Modele_Simple_Random_Forest_BoW \n",
|
||
"7 Modele_Simple_Regression_Logistique_TF-IDF \n",
|
||
"0 Modele_Simple_Naive_Bayes_BoW \n",
|
||
"5 Modele_Simple_SVM_Lineaire_TF-IDF \n",
|
||
"9 Modele_Simple_Naive_Bayes_TF-IDF \n",
|
||
"1 Modele_Simple_Naive_Bayes_TF-IDF \n",
|
||
"15 Modele_Simple_Regression_Logistique_TF-IDF \n",
|
||
"8 Modele_Simple_Naive_Bayes_BoW \n",
|
||
"13 Modele_Simple_SVM_Lineaire_TF-IDF \n",
|
||
"10 Modele_Simple_Random_Forest_BoW \n",
|
||
"6 Modele_Simple_Regression_Logistique_BoW \n",
|
||
"3 Modele_Simple_Random_Forest_TF-IDF \n",
|
||
"4 Modele_Simple_SVM_Lineaire_BoW \n",
|
||
"14 Modele_Simple_Regression_Logistique_BoW \n",
|
||
"12 Modele_Simple_SVM_Lineaire_BoW \n",
|
||
"11 Modele_Simple_Random_Forest_TF-IDF "
|
||
]
|
||
},
|
||
"execution_count": 27,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"results_df"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"id": "w0WL6NSxWxlQ"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def afficher_tableau_comparatif(df):\n",
|
||
" \"\"\"\n",
|
||
" Affiche un tableau comparatif formaté des résultats\n",
|
||
"\n",
|
||
" Parameters:\n",
|
||
" -----------\n",
|
||
" df : pandas.DataFrame\n",
|
||
" Dataframe contenant les résultats à afficher\n",
|
||
" \"\"\"\n",
|
||
" if df.empty:\n",
|
||
" print(\"Aucun résultat à afficher.\")\n",
|
||
" return\n",
|
||
"\n",
|
||
" # Sélectionner et formater les colonnes pour l'affichage\n",
|
||
" df_display = df[[\"Modèle\", \"Vectorisation\", \"Accuracy\", \"Precision\", \"Recall\",\n",
|
||
" \"F1 Score\", \"ROC AUC\", \"Temps d'entraînement (s)\"]]\n",
|
||
"\n",
|
||
" # Formater les valeurs numériques\n",
|
||
" for col in [\"Accuracy\", \"Precision\", \"Recall\", \"F1 Score\", \"ROC AUC\"]:\n",
|
||
" if col in df_display.columns:\n",
|
||
" df_display[col] = df_display[col].apply(lambda x: f\"{x:.4f}\" if x is not None else \"N/A\")\n",
|
||
"\n",
|
||
" if \"Temps d'entraînement (s)\" in df_display.columns:\n",
|
||
" df_display[\"Temps d'entraînement (s)\"] = df_display[\"Temps d'entraînement (s)\"].apply(\n",
|
||
" lambda x: f\"{x:.2f}\" if x is not None else \"N/A\")\n",
|
||
"\n",
|
||
" # Afficher le tableau\n",
|
||
" print(\"\\n=== Comparaison des modèles ===\\n\")\n",
|
||
" print(df_display.to_string(index=False))\n",
|
||
"\n",
|
||
" # Identifier le meilleur modèle selon la précision\n",
|
||
" if \"Precision\" in df.columns:\n",
|
||
" best_idx = df[\"Precision\"].idxmax() if not df.empty else None\n",
|
||
" if best_idx is not None:\n",
|
||
" best_model = df.loc[best_idx]\n",
|
||
" print(\"\\n=== Meilleur modèle ===\")\n",
|
||
" print(f\"Modèle: {best_model['Modèle']}\")\n",
|
||
" print(f\"Vectorisation: {best_model['Vectorisation']}\")\n",
|
||
" print(f\"Precision: {best_model['Precision']:.4f}\")\n",
|
||
" print(f\"Meilleurs paramètres: {best_model['Meilleurs paramètres']}\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/"
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 8,
|
||
"status": "ok",
|
||
"timestamp": 1751740004112,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "Ou07_WmDWxlQ",
|
||
"outputId": "4f3f00f7-3000-47f0-f2e1-ad34d27716d1"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"\n",
|
||
"=== Comparaison des modèles ===\n",
|
||
"\n",
|
||
" Modèle Vectorisation Accuracy Precision Recall F1 Score ROC AUC Temps d'entraînement (s)\n",
|
||
" Random Forest BoW 0.7719 0.7798 0.7579 0.7687 0.8515 17489.66\n",
|
||
"Regression Logistique TF-IDF 0.7852 0.7796 0.7953 0.7874 0.8667 65.19\n",
|
||
" Naive Bayes BoW 0.7721 0.7785 0.7605 0.7694 0.8441 2.82\n",
|
||
" SVM Lineaire TF-IDF 0.7854 0.7781 0.7985 0.7882 0.8665 122.32\n",
|
||
" Naive Bayes TF-IDF 0.7704 0.7776 0.7574 0.7674 0.8511 4.32\n",
|
||
" Naive Bayes TF-IDF 0.7696 0.7766 0.7568 0.7666 0.8524 4.27\n",
|
||
"Regression Logistique TF-IDF 0.7832 0.7766 0.7950 0.7857 0.8611 36.01\n",
|
||
" Naive Bayes BoW 0.7718 0.7766 0.7632 0.7698 0.8432 1.47\n",
|
||
" SVM Lineaire TF-IDF 0.7842 0.7765 0.7981 0.7872 0.8612 51.15\n",
|
||
" Random Forest BoW 0.7689 0.7746 0.7584 0.7664 0.8439 6377.44\n",
|
||
"Regression Logistique BoW 0.7829 0.7723 0.8024 0.7871 0.8584 896.35\n",
|
||
" Random Forest TF-IDF 0.7675 0.7702 0.7625 0.7663 0.8484 16182.08\n",
|
||
" SVM Lineaire BoW 0.7822 0.7687 0.8074 0.7876 0.8583 458.62\n",
|
||
"Regression Logistique BoW 0.7792 0.7672 0.8018 0.7841 0.8514 371.54\n",
|
||
" SVM Lineaire BoW 0.7801 0.7655 0.8074 0.7859 0.8516 187.81\n",
|
||
" Random Forest TF-IDF 0.7648 0.7636 0.7671 0.7653 0.8416 5977.55\n",
|
||
"\n",
|
||
"=== Meilleur modèle ===\n",
|
||
"Modèle: Random Forest\n",
|
||
"Vectorisation: BoW\n",
|
||
"Precision: 0.7798\n",
|
||
"Meilleurs paramètres: {'max_depth': 'None', 'min_samples_split': '5', 'n_estimators': '200'}\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"# Afficher le tableau comparatif\n",
|
||
"afficher_tableau_comparatif(results_df)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"id": "etUvFhueWxlQ"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def display_metrics_subplot(df, figsize=(18, 14)):\n",
|
||
" \"\"\"\n",
|
||
" Génère des sous-graphiques pour visualiser toutes les métriques avec une échelle fixe (0,1)\n",
|
||
"\n",
|
||
" Parameters:\n",
|
||
" -----------\n",
|
||
" df : pandas.DataFrame\n",
|
||
" DataFrame contenant les résultats des modèles avec leurs métriques\n",
|
||
" figsize : tuple, optional\n",
|
||
" Taille de la figure (largeur, hauteur)\n",
|
||
" Returns:\n",
|
||
" --------\n",
|
||
" matplotlib.figure.Figure\n",
|
||
" La figure générée\n",
|
||
" \"\"\"\n",
|
||
" # Définir les métriques à visualiser\n",
|
||
" metriques = [\"Accuracy\", \"Precision\", \"Recall\", \"F1 Score\", \"ROC AUC\"]\n",
|
||
"\n",
|
||
" # Créer une figure avec des sous-graphiques\n",
|
||
" fig, axes = plt.subplots(3, 2, figsize=figsize)\n",
|
||
" axes = axes.flatten()\n",
|
||
"\n",
|
||
" # Définir une palette de couleurs cohérente\n",
|
||
" palette = sns.color_palette(\"Set2\", len(df[\"Vectorisation\"].unique()))\n",
|
||
"\n",
|
||
" # Créer un barplot pour chaque métrique\n",
|
||
" for i, metrique in enumerate(metriques):\n",
|
||
" ax = axes[i]\n",
|
||
"\n",
|
||
" # Créer le barplot\n",
|
||
" sns.barplot(\n",
|
||
" x=\"Modèle\",\n",
|
||
" y=metrique,\n",
|
||
" hue=\"Vectorisation\",\n",
|
||
" data=df,\n",
|
||
" ax=ax,\n",
|
||
" palette=palette\n",
|
||
" )\n",
|
||
"\n",
|
||
" # Configurer l'axe y pour qu'il aille de 0 à 1\n",
|
||
" ax.set_ylim(0, 1)\n",
|
||
"\n",
|
||
" # Ajouter une grille horizontale pour faciliter la lecture\n",
|
||
" ax.grid(axis='y', linestyle='--', alpha=0.7)\n",
|
||
"\n",
|
||
" # Définir le titre du sous-graphique\n",
|
||
" ax.set_title(f\"{metrique}\", fontsize=14, fontweight='bold')\n",
|
||
"\n",
|
||
" # Rotation des étiquettes de l'axe x pour éviter le chevauchement\n",
|
||
" ax.set_xticklabels(ax.get_xticklabels(), rotation=45, ha='right')\n",
|
||
"\n",
|
||
" # Ajouter des valeurs au-dessus des barres\n",
|
||
" for p in ax.patches:\n",
|
||
" height = p.get_height()\n",
|
||
" ax.text(\n",
|
||
" p.get_x() + p.get_width()/2.,\n",
|
||
" height + 0.01,\n",
|
||
" f'{height:.3f}',\n",
|
||
" ha=\"center\", fontsize=9\n",
|
||
" )\n",
|
||
"\n",
|
||
" # Ne garder la légende que sur le premier graphique\n",
|
||
" # if i != 0:\n",
|
||
" # ax.get_legend().remove()\n",
|
||
"\n",
|
||
" # Ajuster la disposition pour éviter le chevauchement\n",
|
||
" plt.tight_layout()\n",
|
||
"\n",
|
||
" # Ajouter un titre global\n",
|
||
" fig.suptitle(\"Comparaison des performances des modèles par métrique\",\n",
|
||
" fontsize=18, fontweight='bold', y=1.02)\n",
|
||
"\n",
|
||
" # Afficher la figure (si dans un notebook)\n",
|
||
" plt.show()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"id": "lv_FsbT_OlC1"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def display_metrics_subplot(df, figsize=(18, 14)):\n",
|
||
" \"\"\"\n",
|
||
" Génère des sous-graphiques pour visualiser toutes les métriques.\n",
|
||
" Le graphique de Précision occupe 2 colonnes.\n",
|
||
"\n",
|
||
" Parameters:\n",
|
||
" -----------\n",
|
||
" df : pandas.DataFrame\n",
|
||
" DataFrame contenant les résultats des modèles avec leurs métriques\n",
|
||
" figsize : tuple, optional\n",
|
||
" Taille de la figure (largeur, hauteur)\n",
|
||
" Returns:\n",
|
||
" --------\n",
|
||
" matplotlib.figure.Figure\n",
|
||
" La figure générée\n",
|
||
" \"\"\"\n",
|
||
" if df.empty:\n",
|
||
" print(\"Aucun résultat à afficher.\")\n",
|
||
" return None # Retourne None si le dataframe est vide\n",
|
||
"\n",
|
||
" # Définir les métriques à visualiser (sans la Précision initiale)\n",
|
||
" other_metriques = [\"Accuracy\", \"Recall\", \"F1 Score\", \"ROC AUC\"]\n",
|
||
"\n",
|
||
" # Créer une figure et une grille de sous-graphiques (3 lignes, 2 colonnes)\n",
|
||
" fig = plt.figure(figsize=figsize)\n",
|
||
" gs = fig.add_gridspec(3, 2)\n",
|
||
"\n",
|
||
" # Définir les axes pour la Précision (span 2 colonnes)\n",
|
||
" ax_precision = fig.add_subplot(gs[0, :]) # La Précision occupe la première ligne, les deux colonnes\n",
|
||
"\n",
|
||
" # Définir les axes pour les autres métriques (remplir les 2 lignes restantes)\n",
|
||
" axes_other = [fig.add_subplot(gs[1, 0]), fig.add_subplot(gs[1, 1]),\n",
|
||
" fig.add_subplot(gs[2, 0]), fig.add_subplot(gs[2, 1])]\n",
|
||
"\n",
|
||
" # Définir une palette de couleurs cohérente\n",
|
||
" palette = sns.color_palette(\"Set2\", len(df[\"Vectorisation\"].unique()))\n",
|
||
"\n",
|
||
" # Fonction utilitaire pour ajouter les valeurs au-dessus des barres\n",
|
||
" def add_value_labels(ax):\n",
|
||
" for p in ax.patches:\n",
|
||
" height = p.get_height()\n",
|
||
" if height > 0: # N'affiche le label que si la hauteur est > 0\n",
|
||
" ax.text(\n",
|
||
" p.get_x() + p.get_width()/2.,\n",
|
||
" height + 0.01,\n",
|
||
" f'{height:.3f}',\n",
|
||
" ha=\"center\", fontsize=9\n",
|
||
" )\n",
|
||
"\n",
|
||
"\n",
|
||
" # Tracer le graphique de Précision\n",
|
||
" sns.barplot(\n",
|
||
" x=\"Modèle\",\n",
|
||
" y=\"Precision\",\n",
|
||
" hue=\"Vectorisation\",\n",
|
||
" data=df,\n",
|
||
" ax=ax_precision,\n",
|
||
" palette=palette\n",
|
||
" )\n",
|
||
" ax_precision.set_ylim(0, 1)\n",
|
||
" ax_precision.grid(axis='y', linestyle='--', alpha=0.7)\n",
|
||
" ax_precision.set_title(\"Precision (Métriques clé)\", fontsize=14, fontweight='bold')\n",
|
||
" ax_precision.set_xticklabels(ax_precision.get_xticklabels(), rotation=45, ha='right')\n",
|
||
" ax_precision.set_xlabel(\"\") # Masquer l'étiquette x pour la Précision si désiré\n",
|
||
" add_value_labels(ax_precision) # Ajouter les valeurs\n",
|
||
"\n",
|
||
"\n",
|
||
" # Tracer les graphiques pour les autres métriques\n",
|
||
" for i, metrique in enumerate(other_metriques):\n",
|
||
" ax = axes_other[i]\n",
|
||
"\n",
|
||
" sns.barplot(\n",
|
||
" x=\"Modèle\",\n",
|
||
" y=metrique,\n",
|
||
" hue=\"Vectorisation\",\n",
|
||
" data=df,\n",
|
||
" ax=ax,\n",
|
||
" palette=palette\n",
|
||
" )\n",
|
||
"\n",
|
||
" ax.set_ylim(0, 1)\n",
|
||
" ax.grid(axis='y', linestyle='--', alpha=0.7)\n",
|
||
" ax.set_title(f\"{metrique}\", fontsize=14, fontweight='bold')\n",
|
||
" ax.set_xticklabels(ax.get_xticklabels(), rotation=45, ha='right')\n",
|
||
" add_value_labels(ax) # Ajouter les valeurs\n",
|
||
"\n",
|
||
" # Ne garder la légende que sur l'un des graphiques (par exemple, le premier des autres)\n",
|
||
" if i != 0:\n",
|
||
" ax.get_legend().remove()\n",
|
||
" else:\n",
|
||
" # Placer la légende de la précision à un endroit approprié si on ne veut pas de légendes répétées\n",
|
||
" # ax_precision.legend(loc='upper right') # Exemple de placement\n",
|
||
"\n",
|
||
" # Ou retirer la légende de la précision si on la garde sur le premier des autres\n",
|
||
" ax_precision.get_legend().remove() # Retirer la légende de la précision\n",
|
||
"\n",
|
||
" # Ajuster la disposition pour éviter le chevauchement\n",
|
||
" plt.tight_layout()\n",
|
||
"\n",
|
||
" # Ajouter un titre global\n",
|
||
" fig.suptitle(\"Comparaison des performances des modèles\",\n",
|
||
" fontsize=18, fontweight='bold', y=1.02) # Ajuster y si nécessaire\n",
|
||
"\n",
|
||
" # Afficher la figure (si dans un notebook)\n",
|
||
" plt.show()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/",
|
||
"height": 1000
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 2184,
|
||
"status": "ok",
|
||
"timestamp": 1751740006350,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "Noe09nRHWxlQ",
|
||
"outputId": "93abb9a5-d96c-424d-f81f-693fde709861"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"image/png": "iVBORw0KGgoAAAANSUhEUgAABv0AAAWZCAYAAABe3dlUAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs3Xd8FNX+//H3ppJCGqEHEpDQexcQQu9IkSKCIggIihRRUbwXvBevIoJUsaAISBUFaQICoaMSeujSpEhPgSSk7u8PftlvNrtpJCFZeT0fjzwemTPnzHzO7uxMMp89ZwxGo9EoAAAAAAAAAAAAADbLLq8DAAAAAAAAAAAAAJA9JP0AAAAAAAAAAAAAG0fSDwAAAAAAAAAAALBxJP0AAAAAAAAAAAAAG0fSDwAAAAAAAAAAALBxJP0AAAAAAAAAAAAAG0fSDwAAAAAAAAAAALBxJP0AAAAAAAAAAAAAG0fSDwAAAAAAAAAAALBxDnkdAAAAAAAAAB6/mzdvau7cuTIajZKkIUOGqESJEnkcFQAAAB4VST8AAAAAAIAnUJEiReTt7a2RI0dKkrZt26Zt27bJwYHbRQAAALaI6T0BAADwRAoKCpLBYDD9DBgwIK9Dyte2b99u9noZDAZdvHgxr8N6Ii1dulRt2rRR0aJF5ejoyHuCPDVgwACzYzAoKCivQ4Kydo174403NH36dEnSrl27NH78+Ezt4+LFixbXhe3bt2c/eAAAADwyvroFAACQyunTp7V06VLt3r1bZ86c0d27dxUXFydPT08FBgaqYcOG6tKli5o1ayaDwZDX4QJ4gowZM0afffZZXocB4B9m5MiRMhqNGj16tKZMmaJnnnlGnTp1yuuwAAAAkEUk/QAAAP6/69eva/jw4Vq9erXp2TYp3b59W7dv39a+ffv02WefqUePHlq5cmUeRArgSfTXX39pxowZeR0GgH+oUaNGSZJGjx6tF198UQcPHlRAQECexgQAAICsIekHAAAgKSQkRB07dtTNmzcz3eb27du5GBFy27Jly/TgwQPTsru7ex5GA2Rs//79SkpKMiubO3euWrZsKUdHR0mSn59fXoQG4B9i1KhRpuQfAAAAbA9JPwAA8MS7dOmS1YRfiRIl9MYbb6hp06by9fVVZGSkjh07pg0bNmj16tV5EyxyTLFixfI6BCBL7t+/b1E2dOhQphkGAAAAAEiS7PI6AAAAgLw2duxYi4Rf06ZNdeLECb3zzjt6+umnFRgYqDp16mjAgAFasWKFzp07p27dulndXnx8vL7//nv16NFD/v7+cnV1lYuLi0qVKqUuXbrom2++UWxsrNW227dvl8FgMPu5ePGiQkND9fzzz6tYsWJydXVVtWrVNG3aNCUkJJjarl+/Xq1atZKPj4/c3NxUp04dff7551anKpVksZ/vvvtODx480EcffaQaNWrI3d1dXl5eatGiRbpJzlWrVum9995Tu3btVKlSJRUtWlROTk5yc3NT6dKl1aFDB33++edWExaSdPHiRYtYtm/fruvXr+uNN95QuXLlVKBAAbPExvHjx/Xpp5/qhRdeUO3atVW6dGm5u7vLyclJhQsXVsOGDTV27FidPHkyzbiDgoLM9jlgwACLOmFhYfrf//6npk2bqmjRonJ2dparq6v8/f1Vv359DRkyRPPmzdOVK1es7sNoNGrt2rXq27evypUrp4IFC8rZ2VnFixdXmzZtNH36dEVGRmbpdYmIiND777+vypUry8XFRV5eXmrZsqU2btyYZl8za9++feratasKFy4sFxcXVaxYUe+//77u3buXpe08ePBA8+bNU5cuXVSqVCm5uLjI3d1d5cuX16BBg/THH3+k237r1q3q37+/KlasqIIFC8rR0VG+vr6qVKmSOnXqpA8++ECbNm3Kcv/Sek3Dw8P17rvvqmLFinJxcZGvr686d+6sHTt2ZLjNvXv3asiQIapSpYo8PT3l5OSk4sWLq3379vrmm28UHx9vtV1an/WzZ89q4MCBKl26tJycnBQQEKCJEyemeYza2dmZ2gcFBVmsP3v2rN566y3Vq1dPhQoVkqOjo3x8fFSrVi2NHDlSx48fT7Nv1j4jSUlJ+vLLL9WoUSN5eXmZzh2S9N1331n0SZL27NmjLl26yNfXV+7u7qpXr57mz59vtq9FixapUaNG8vDwkIeHh5o0aaLly5enGVtunXey8/k6evSoRo0apXr16snX19d0PqpWrZqGDBmiDRs2pNl248aN6t+/vwIDA1WwYEEVKFBApUqVUvfu3fXDDz+keR6XHj6HdtSoUapdu7a8vb3l6OgoT09PlStXTkFBQRo7dqxWrFihqKioDPtgTUJCgmbNmqU6derIzc1N3t7eat68+SNNb33x4kW9++67atCggek1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GT0HLSwsTP/5z39Ut25deXp6ysnJSSVLllT37t3166+/WtT/7rvvzF6j2NhYffjhhypfvrycnZ3l5+ensWPHKjY2NsP3JVlMTIyWLVtmWu7Ro0e69e3sHv6rGBsba5YsvH79ulasWCHp4SiujKxdu1bPPvusihcvLicnJ3l5ealZs2b65ptvTNOMSv/3Gu7YscNUtmDBAqvTh6aeAjQ0NFRdu3ZVoUKF5OzsrJMnT2b4TL/bt29r6NChKlq0qFxcXFS3bl398MMPFsdnyilL05t6NPV7llpsbKxmz56tpk2bysfHR05OTipevLh69uypffv2WX3tvvvuOwUFBcnX11eOjo7y9vZWhQoV1Lt3b33++ecZvvYpXblyRe+8845q1aolDw8PFShQQKVLl1bXrl2tHoNpiYyM1EcffaQGDRqYjuVSpUrphRde0IEDB6y2KVmypJ5++mlJUnh4uH766acsxQ4AAAAg8xjpBwAAACDHPf3001q8eLFp+fr161brDRw4ULt27bIoj4mJUZcuXbRlyxaz8tu3b2vDhg3asGGDxowZo6lTp5qt/+abbzR8+HDFxcWZlV+4cEEXLlxQw4YNVbdu3XRjP3HihBo2bKjo6Giz8suXL+vy5csKDg5Ws2bNVLJkyXS3Iz2c1rJNmza6cuWKWfm1a9e0atUqrVq1SiNHjtT06dPT3EarVq20e/du0/LVq1c1depU3bx5UwsXLswwBkn67bffdO/ePUlS4cKFFRgYmG796tWrKywsTJcuXdIXX3yhcePGycHBQXPnzlV8fLwkqUuXLlq1apXV9klJSRowYIAWLVpkVh4REaGdO3dq586dWr58udauXZupEaBpOXr0qBo2bKioqKhMtwkLC1Pjxo115swZU9mBAwfUq1cvde7c+ZFjScutW7fUpk0bHT582Kz8+vXrWrlypX766SdNmzZNI0eONK2bOHGiPvjgA7P64eHhCg8P15kzZ7Rjxw4NHz48U/vfsGGD+vTpY3r/kyUfzwEBAWrdunWG2zl79qzatGlj8ezGK1euaMmSJVq+fLk+//xzDRkyxKLt008/rb1790qSfv31V7MvBQAAAADIOST9AAAAAOS41KOXihUrZrXerl27VKVKFXXu3FlGo9E0emz06NGmhJ+Tk5P69OmjwMBAHTt2TD/88IOMRqOmTZumOnXqqG/fvpIeJraGDBliGkHm4OCgnj17qmLFirpy5Yo2btyYqdgXLFhgSvj5+fmpX79+cnNz05UrVxQaGprp59klJCSoW7dupoSfvb29+vfvLz8/P61evVqhoaGSHk6XWbt2bbNRjint3r1b3bp1U+XKlbV48WJT0mXx4sX6+OOP03yeWkopE6t16tTJsL69vb1ef/11vfXWW7p69apWrlyp7t27m0b9lS1bVp06dUoz6ffJJ5+YEn4Gg0E9evRQjRo1dOHCBS1atEjx8fH69ddf9d5772nq1Kmm5yLOnTtX58+flyTVrVtXvXv3Nm3Tx8fHYj+HDh2Sg4OD+vfvr8DAQJ06dUoFChRIt2/vv/++WcKvWbNmatasmfbs2aO1a9dm+NpkVf/+/U0Jv4IFC6pv377y8/PTnj17tHHjRiUlJWn06NGqW7euGjduLEmaO3euqX2rVq0UFBSkqKgoXb58Wbt371ZMTEym9n3p0iX17NnTdDwbDAZ16dJFNWvW1K1bt7Rt27ZMbScxMVHdunUzHXuFCxdW37595ePjo02bNmnv3r1KTEzU8OHDVb9+fdWsWdOsfb169Uy/W0vyAwAAAMgZJP0AAAAAZNvGjRt1+/ZtxcXF6bfffjNLnhQtWjTNZ941bNhQwcHBZomau3fv6ptvvjEtf/HFF3r55ZdNy76+vqbpDT/99FNT0m/KlCmmhJ+dnZ22bdumZ555xtQuLi5ON2/ezLAvDx48MP3+2muvady4cWbrw8LCMtyGJK1bt06nT582Lc+aNUvDhg2TJL333nuqVKmSLl26JEmaNm1amkm/UaNG6bPPPpMk9ezZ05RQSUpK0oEDBzKV9Dt37pzp91KlSmUq/ldeeUUTJ05UVFSUZs6cqbi4ON24cUPSw9cleQrQ1JKSksxGYP7rX/8yG7VWsWJFvf3225Ievrf/+9//TM9FXLdunSnpV6VKlUw9l2/lypV69tlnzcpSj0ZLFh8frwULFpiWmzZtqm3btsnOzk5Go1Ht2rXT5s2bM9xnZh09elSbNm0yLf/8889q3ry5aTl5qlqj0aipU6eakn4pj8FFixZZJM2TX6OMzJw502zE6vfff2/6vEgP36u//vorw+2sX79ex48fl/QwIbxnzx7TaNHx48erVq1aOnbsmBITEzV79mzNmzfPrL2fn5/p94sXLyopKSnN4wcAAADAoyPpBwAAACDbli9fruXLl1uUFyhQQAsWLEhz9NXYsWMt1v3+++9KSEgwLQ8cOFADBw602v7w4cOKjo6Wq6ur2RSYbdu2NUv4SQ9HDKZMPqTlmWee0cyZMyU9HBW2Zs0aVaxYURUqVFCDBg30zDPPZOp5dqlHO6ZM6rm4uKhXr16aMmWKpIfJoeR+pJZyGscKFSqYrctsAvLWrVum362NmLPGy8tLL774oubOnat9+/aZkkNubm4aNGhQmqP8Tp8+rdu3b5uW//Of/+g///mP1brR0dE6deqUatSokamYUqtatapFwi89p0+fNpsK9PnnnzclnwwGg1544YUcTfolP8syWYsWLdKsmzz9pfTwGFy/fr2kh31s0KCBAgMDVaVKFTVv3lzlypXL1P5TfiYqVapklvCTHibHrT2HMrWU/UhMTFT58uXTrGvt2X6FChUy/Z6UlKQ7d+6ocOHCGe4XAAAAQNaQ9AMAAACQo1xcXOTv768WLVpo9OjR6SYoKlasaFF29+7dTO/LaDTqzp07cnV1NWtXpkyZrAWdwnPPPaexY8dq1qxZio2N1b59+8wSeP7+/lq/fr2qVKmS7nZSxuPu7i43Nzez9UWLFjXrR3h4uNWkX8qkTOrn3yWPbMwtI0aMME01efXqVUnSSy+9JE9PzzTbZOX9kx4+q+5RWTt+srKvIkWKmC2nfE/SYzQazZZjY2Ot1svKa5EyMTt37lz16tVLv/32m+7cuaMNGzaY1e3Vq5eWLl2a4Wi5nPpMZKUf1t7P1K8XAAAAgNxB0g8AAABAts2fP18DBgzIcrvUiTDJciTa6NGj053CMjkB5ePjY5q+88KFC1mOJaUpU6bo/fff1969e3Xq1CmdOXNGa9as0bVr13Tp0iUNHz5cO3bsSHcbKftx//59RUVFmfU3eapM6eEoMy8vL6vbcXR0NKv3KHx9fU2/Z3Z0oPRwdFibNm1Mo98MBoNGjBiRbpvU79/MmTPVuXPnNOun9bzHzLB2/KQn9WucerrXlO9JaikTbKmfqXf27FmrbVK/Fv/5z3/k4uKSYZylSpXSvn379Oeff+qPP/7Q2bNndezYMf38889KSEjQihUr1K5dO7NpbzPaf3Y+Eym34+LiomPHjqU52tXBwfI2Q8qkoZ2dndnIPwAAAAA5h6QfAAAAgHylQYMGsre3V2JioqSHSS9rz3a7ePGiTp8+LQ8PD0lSkyZN9NNPP0mSNm/erD179piekSZJCQkJunHjhkqWLJnu/i9cuCBvb295eXmpffv2at++vSSpTZs26t69uyTp4MGDGfYj9XMMFy5caHqmX0xMjFasWGFaV6NGDauj/HJK2bJlTb9fvnw5S21HjhxpSvq1bt06w9F1FSpUUKFChXTnzh1J0o8//qjhw4dbJIlOnDihrVu3miURUyY4Uz6LLqdUrFhR7u7uun//viRp6dKlGjJkiOmZfosXL06zbcqE4aFDhxQXFycnJyddvXrV7DmBKaU+Bnx9fU3HQErHjx83S8YeOXJE1apVU7ly5cxGyj777LNas2aNpIfHYEZJvyZNmuiPP/6QJJ08eVLLli1Tnz59TOuNRqMuX76s0qVLp7udlP2IiYlRcHCwXnnlFbM6CQkJ+vnnn+Xr62sxjW7KY87f35/n+QEAAAC5hKQfAAAAgHzFx8dHAwcO1Ndffy1J+uSTTxQSEqJGjRqpQIECunr1qn777TcdOnRIL730ktq2bStJeuutt7R69WolJSUpMTFRzZs3V69evVShQgVdv35dmzZt0uuvv65Ro0alu//ly5drwoQJCgoKUmBgoIoXL66oqCgtXbrUVCetUXkpdezYURUqVNDp06clPZwqc//+/SpZsqRWr16tS5cumeqOHj06i69S1qRMfmYmYZlS+/bt9fPPPyspKUnVqlXLsL6dnZ3GjBmj8ePHS5J27NihqlWrqnPnzvLy8tK1a9e0Z88eHT58WM2aNTNL+qVMyK5fv17jxo2Tr6+vfH19H2kkaWoODg568cUX9fnnn0uSdu7cqRYtWqhZs2bas2ePtm7dmmbbevXqmZ5j+Oeff6p27dqqVKmSgoODTQnO1GrUqKHWrVvr119/lSS9/vrr+uWXX1SnTh3Z2dnp0qVL2rt3r06ePKkJEyaoSZMmkqTevXsrIiJCzZs3V8mSJeXj46Nz586ZTfOZmWPwjTfe0Ny5c00jE/v27avly5erZs2aCgsL0/bt2xUUFKTp06enu52OHTuqUqVKOnnypCRpyJAhWrt2rerUqaOkpCSdPn1aW7du1a1btzR//nw1a9bMrH1ISIjp99TP2gQAAACQc0j6AQAAAMh3pk+frgsXLmjLli2SpG3btmnbtm3ptmnYsKG++uorDR8+XHFxcYqPj0935FZ64uLitHnzZtMIt9TefvvtDLfh4OCgVatWqU2bNrpy5YoSExM1f/58i3pvvPGGXnzxxUeKM7MaNWokV1dXRUdH68aNG7pw4UKmn/FmMBjUpUuXLO1v3LhxOnXqlBYtWiRJOnXqlE6dOpVhu+7du5tGzUVHR2vy5MmSpCpVquRI0k+SJk2apC1btujMmTOSHiYlk6dq7dixo9avX2+13aBBgzR16lRTgu/48eM6fvy47Ozs1LZtW23atMlqu++//15t27bV4cOHlZSUpLVr12rt2rUZxnn9+nWzRHNKPj4+FiPtrPH399fKlSvVp08f3bt3T0ajUatXr9bq1atNdYKCgjLcjoODg1avXq22bdvq4sWLMhqNWrNmjWnUYUZSPhOzdevWmWoDAAAAIOuYUwMAAABAvuPq6qpNmzZpyZIl6tChg4oWLSoHBwe5uLjoqaee0nPPPaevvvpK06ZNM2s3aNAgHT58WMOGDVPFihXl6uoqZ2dnlSpVSs8995xpJFV6unbtqn//+99q1aqVAgIC5OrqKgcHBxUvXlwdO3bUmjVrMnyuXbJKlSrpyJEjmjhxomrXri13d3fTtrp166ZNmzZpxowZj/QaZYWbm5t69+5tWl65cmWu7s/Ozk4LFy7U+vXr1aNHD/n5+cnJyUnOzs7y9/dX586dNX36dIukVpcuXTR79mxVqlRJTk5OuRKbt7e3du/ercGDB6tw4cIqUKCAatWqpcWLF1udRjZZkSJFtGPHDrVv317u7u5yc3NTixYttH37drMpM621+/333zV37ly1aNFCvr6+sre3l5ubmypWrKh+/fpp8eLFeuutt0xtPvroI7366quqU6eOihUrJkdHR7m6uqpixYoaPny4Dhw4IH9//0z1t0OHDjp+/LjeeustVa9eXe7u7nJ0dFSJEiXUsWNHdejQIVPbKV++vI4ePapPPvlEjRo1kre3t+zt7VWwYEFVr15dr7zyilatWqW+ffuatbt69aop6efp6WmaIhcAAABAzjMYjUZjXgcBAAAAAMhd+/fvV/369SVJtWvX1oEDB/I4ovxn+/btat68uWn5woULCggIyLuA/gE+++wzjRkzRtLD6U1nzZqVxxEBAAAA/1yM9AMAAACAJ0C9evXUqVMnSQ+f67d79+48jgj/dImJiZozZ44kycXFRePGjcvjiAAAAIB/NpJ+AAAAAPCE+Oijj2Rn9/DfwI8//jiPo8E/3U8//aRz585JevjsypIlS+ZxRAAAAMA/m0NeBwAAAAAAeDyqVq2qxMTEvA4DT4iePXuKJ4oAAAAAj0++eqbfiRMntGbNGl24cEFhYWEaO3as6ZkTaTl+/LgWLlyoy5cvq1ChQurRo4eCgoIeT8AAAAAAAAAAAABAPpCvpveMjY1VQECABg0alKn6N2/e1Mcff6wqVarok08+UceOHfXFF1/o8OHDuRsoAAAAAAAAAAAAkI/kq+k9a9WqpVq1amW6/ubNm1WkSBG9+OKLkiQ/Pz+dOnVK69evV82aNXMpSgAAAAAAAAAAACB/yVcj/bLq7NmzqlatmllZjRo1dObMmTTbxMfHKzo62uwnPj4+t0MFAAAAAAAAAAAAck2+GumXVeHh4fL09DQr8/T0VExMjOLi4uTk5GTRZtWqVVq5cqVpuXHjxho5cmSuxwoAAAAAAAAAAADkFptO+j2Kbt26qVOnTqZlg8EgSQoLC1NCQkJehQUAAAAAAAAAAABYcHBwkLe3d8b1HkMsucbLy0sRERFmZREREXJxcbE6yk+SHB0d5ejoaFGekJDANJ8AAAAAAAAAAACwSTb9TL/AwEAdO3bMrOzo0aMqX758HkUEAAAAAAAAAAAAPH75Kun34MEDXbx4URcvXpQk3bx5UxcvXtTt27clSUuWLNHs2bNN9du0aaObN2/q+++/19WrV7Vp0ybt27dPHTt2zIvwAQAAAAAAAAAAgDyRr6b3PHfunD744APT8sKFCyVJzZo102uvvaawsDBTAlCSihQponHjxmnBggXasGGDChUqpFdffVU1a9Z83KEDAAAAAAAAAAAAecZgNBqNeR1EfnDr1i2e6QcAAAAAAAAAAIB8xdHRUYULF86wXr6a3hMAAAAAAAAAAABA1pH0AwAAAAAAAAAAAGwcST8AAAAAAAAAAADAxpH0AwAAAAAAAAAAAGwcST8AAAAAAAAAAADAxpH0AwAAAAAAAAAAAGwcST8AAAAAAAAAAADAxpH0AwAAAAAAAAAAAGwcST8AAAAAAAAAAADAxpH0AwAAAAAAAAAAAGwcST8AAAAAAAAAAADAxpH0AwAAAAAAAAAAAGwcST8AAAAAAAAAAADAxpH0AwAAAAAAAAAAAGwcST8AAAAAAAAAAADAxpH0AwAAAAAAAAAAAGwcST8AAAAAAAAAAADAxpH0AwAAAAAAAAAAAGwcST8AAAAAAAAAAADAxpH0AwAAAAAAAAAAAGwcST8AAAAAAAAAAADAxpH0AwAAAAAAAAAAAGwcST8AAAAAAAAAAADAxpH0AwAAAAAAAAAAAGwcST8AAAAAAAAAAADAxpH0AwAAAAAAAAAAAGwcST8AAAAAAAAAAADAxpH0AwAAAAAAAAAAAGwcST8AAAAAAAAAAADAxpH0AwAAAAAAAAAAAGwcST8AAAAAAAAAAADAxpH0AwAAAAAAAAAAAGwcST8AAAAAAAAAAADAxpH0AwAAAAAAAAAAAGwcST8AAAAAAAAAAADAxpH0AwAAAAAAAAAAAGwcST8AAAAAAAAAAADAxpH0AwAAAAAAAAAAAGwcST8AAAAAAAAAAADAxpH0AwAAAAAAAAAAAGwcST8AAAAAAAAAAADAxpH0AwAAAAAAAAAAAGycQ14HAOSE+Ph4TZw4UatWrZLBYFC3bt00ceJEOThYHuKBgYFmy3FxcQoMDNSWLVtyZD0AAMA/weP8++rvv//W+PHj9fvvv8tgMKhx48b63//+p0KFCuVS7wBkhHMAbAn3BAAAtoDrFR6HfJf027hxo9auXavw8HD5+/tr4MCBKleuXJr1169fr82bN+v27dvy8PBQgwYN1LdvXzk5OT3GqJHXZsyYoT/++EPBwcGSpH79+mnWrFkaPXq0Rd2zZ8+aLbdq1UpdunTJsfUAAAD/BI/z76vx48dLkv744w8ZjUa9/vrr+te//qXPP/88x/oDIGs4B8CWcE8AAGALuF7hcchX03vu3btXCxcu1HPPPafJkyfL399fH374oSIiIqzW3717t5YsWaKePXvqs88+06uvvqp9+/Zp6dKljzly5LVly5Zp5MiRKlq0qIoWLao33ngjU8fBoUOHdObMGfXq1StX1gMAkFJ8fLzGjx+vypUrq0qVKnr//feVkJBgtW5gYKDZj7+/v1q1apXp9VnZF2DN4/z76q+//lLnzp3l5uYmd3d3denSRadOncqxvgDIOs4BsCXcEwAA2AKuV3gc8lXSb926dWrZsqWaN28uPz8/DR48WE5OTqbMd2qnT59WhQoV1KRJExUpUkQ1atRQ48aN9eeffz7myJGXwsPD9ffff6tKlSqmsipVqujq1auKjIxMt+3SpUvVvHlzFStWLFfWA6nl5A1/Sdq8ebNat26tcuXKqXbt2lq4cKEk6erVqxbtS5curQEDBuR2FwGkI+W3+rZt26bff/9ds2bNslr37NmzZj+BgYEW39pLb31W9gWk9rj/vho8eLDWrVunyMhIRUREaPXq1WrdunXOdAZAlnEOgC3hngAA7rXAFnC9wuOSb5J+CQkJOn/+vKpVq2Yqs7OzU7Vq1XTmzBmrbSpUqKDz58+bknw3btzQoUOHVKtWrccSM/KHqKgoSZKnp6epLPn3+/fvp9kuOjpaa9asUd++fXNlPWBNTt7wDw4O1rvvvqsPPvhAp0+f1rZt29SoUSNJUsmSJc3aHj9+XB4eHnr22WcfSz8BWPc4v9X3qPsCpMf/91W9evV0+/Zt042aiIgIvf7669ntBoBHxDkAtoR7AgC41wJbwPUKj0u+SfpFRkYqKSlJXl5eZuVeXl4KDw+32qZJkybq1auX/vWvf+n555/XiBEjVLlyZXXv3j3N/cTHxys6Otr0ExMTY1pnMBhkMBjM6ieXZac8ZVlOled0jLbcJzc3N0nSvXv3TOXJ344oWLBgmttZt26dXFxc1LJlS6sxrl27Vi4uLmrVqpXV/Sa3T17/OF73rJbnp/eJPj20bNkyjRo1SsWKFTO7CZ9RjIcPHzbd0E8umzJlisaMGaNGjRrJ3t5e3t7eCgwMtBrLpk2bZDQa1b59+8fSV1t/n+gTfcqNGFN+qy+5rGrVqmbf6ksrlmXLlql58+YqXry41W0nry9WrJgMBoMiIiL0999/q2rVqqb6yfu6d+9ejr/uWS3Pz+8TfXpYnvrvK4PBYPXvq9Sxp/z7yNq2k/++atmypanMaDTq+eefV7169Uw3UOrVq2fxTynvE32iT48vdnd3d0kyuz4lXz+S11mL0dr/UCm3be0ckd45gPeJPmUmRmvXrJTHa1p9snY8ptx+evcMpPSP9+z2KSfKc/p1p0/0KT/3KeUXHosVK6aRI0ea7rWkF3vylyd79+5tKp8yZYpGjx6txo0by8HBQd7e3ipXrpzV7WzcuNF0r4X3iT5lFGN6f18VLFgwzW1ndL3J7vUsO336J75P+b1PmeGQ5Rb5yPHjx7Vq1Sq98sorCgwM1PXr1zV//nytXLlSzz33nNU2q1at0sqVK03LZcqU0eTJk+Xh4SGj0ShJio2NVVRUlNzc3OTs7GyqGxMTo5iYGBUsWFCOjo6m8qioKMXGxsrT01P29vam8nv37ik+Pl5eXl5mb05ERISSkpLk7e1tFltYWJjs7OzMsv1Go1FhYWFydHQ0+/AnJiYqIiJCzs7Opj9wpYdJzXv37snFxUUuLi6m8n9yn0qWLKmSJUvq4sWLqlWrlmJiYnT8+HH5+fnJ398/zT6tWLFC/fv3l4uLi9U+LVu2TD179lThwoWt9im5feHChXmf6FOm+pSUlKS///5bjRo1kre3t+7du2caxp8yVmt9+umnn9S8eXOVLFlSnp6eioqK0tGjR9WhQwc1adJE9+/fV5MmTTR16lQVL17cok8rV65Unz59VLhwYd4n+kSf8qhPt2/flvTw26HJ8ZQuXVrSw2/1lSpVymqfHB0dtWbNGs2bN0/e3t4WfYqKitKaNWs0ffp02dvby9PT0/QtwVKlSkmSHB0dTftKrsP7RJ/S65OXl5fZ31eSdPLkSZUoUcLs76vUfUr++8jX19dqn3744Qf17NlTbm5upj7dvn1bV65c0cCBA+Xj4yMXFxeNHj1a5cuX14MHD1SgQAHeJ/pEnx5zn7y9vVWiRAkdP35cNWrUkL29vYKDg+Xn56dChQql2aelS5ea/key1idr54jY2FhduXJFY8aMUbFixRQREaFXX31Vc+fOVWJionx9fXmf6FO6fbKzs1Px4sXNrlnBwcEqUaKEvL290+xTyv/prfVpxYoVeuGFF+Tg4GC1T0uXLlXfvn3NjnfeJ/pEnx5/n8LCwvT333+rRo0akh4OIGnUqJHpXoukNPu0fPlytW3bVpUqVZL08P+yo0ePqlWrVmratKnu3bunRo0aacqUKXJxcbHo0w8//KBu3brJ29ub94k+Zdgnb29vlSxZUidOnNBTTz0lT09P099XpUuXTrNPS5cuNd3Ts9anlNcza31asWKFnn/+eTk4OPA+2XifkhPHGTEYkzNdeSwhIUH9+vXTmDFjVL9+fVP57NmzFR0drbffftuizb///W8FBgaqf//+prKdO3fqq6++0sKFC00n9pTi4+MVHx9vWjYYDHJxcdGtW7dMcz2nfElSHgCPWp46G5sT5Tkdo633acqUKdqyZYu+//57GY1G9e/fX+3atdOYMWOs1j937pyaNWumXbt2qUyZMhbb/vPPP9WsWTPt3LlTTz31lEXsf/75p4KCgrRr1y6VLVs2V/r0T3yfnvQ+Xb16VfXr19exY8dUqFAhGY1G3blzR9WrV1dISIhKlChhNcbo6GjVqlVLM2bMUNu2bWUwGHTt2jXVrVtXlStX1vz58+Xt7a1x48bp5s2bWrFihVksV69eVcOGDbVp0yZVrlz5sfTVlt8n+kSfcivGsLAwValSRXv27DFdey5cuKDGjRvr5MmT8vDwsLqdFStW6KOPPlJISIgcHBwsYly+fLk++ugj7d+/Xw4ODjIYHo4qrFy5svbu3WtK0Fy8eFGNGzfWqVOnLL5FmNN9teX3iT79X3nKv68kqV+/fhZ/X6Wsn/Lvq7Jly1r0KeXfV2XLljXbZ6NGjdSpUyeNHj1aBoNBU6dO1U8//aSQkJAc7dM/8X2iT/Qpt8o/+eQTbdmyRYsWLZLBYDCdA0aPHm01xrNnzyooyPx/pJTbT+8c0bhxY3Xs2NG07WnTpumnn37SgQMHHktfbfl9ok8Py9O6ZiVfV1LXT/0/fep9pr5mpd5v8vGe+p4B7xN9ok+Pv09Xr15VvXr1dOzYMfn4+MhgMOjOnTuqVq2aQkJCTLOlpI49KipKtWvX1owZM9SuXTtJMt1rqVSpkhYsWCBvb2+98847unHjhlasWGG2nStXrqhhw4bauHGjaTaX3OrrP+F9ok8PpfX31ZgxY6zWz+h6k93rGe+TbfXJ0dHRYoCSNflmpJ+Dg4PKli2r0NBQU9IvKSlJoaGhphNvarGxsRYvurVEX0qOjo5mWdKUUr6o6ZVltTwntpHfyvNTLJI0atQohYWFqVmzZpKk7t27a8SIETIajXrnnXckSZMnTzbVX7p0qRo0aGC66Zp628nrU58sky1btszUPvX6/PTa5KdYcqo8P8WS1fLkb3pERkbKx8fH9HvyurSOpTVr1pgNwzcajXJ1dZUkDRw4UH5+fpKkN998U02aNFFUVJRpvfTweK1atapZwi+3+5qfXvecKs9PseRUeX6KJafK81Msqcu9vLxUvHhxHT9+XAEBAZKk0NBQlShRQh4eHmluZ8mSJerZs6fs7e3N1if/nrzewcHBVO7p6anixYsrNDTUlPRL3lfKhF9u9TWj8vzwfuR0eX6KJafKs/P3lbVjNeXfV6n3OX/+fE2cOFF16tSR0WhUlSpV9N133+V4n/LT65tT5fkplpwqz0+x5FR5fools+XJ54CgoCBJ/3cOkGT1HJDe/0hS+ueIb7/91uo54HG/lvnhdc/p8vwUS06VZ+WaJcn0JfLMHq9Go9HimpV6v8nt07pnkBN9svXy/BRLTpXnp1hyqjw/xfKo5cn3P5LvtRiNRkVEREiS2Yib1NtIOe188rrkbQ0aNEglS5aU9H/3WqKjo+Xq6mqqm3yvpUqVKrne1/z4ume3PD/FklPl2fn7ymi0/j9WRteb7F7PcqJPtlaen2J5lPLMyDcj/SRp7969mjNnjgYPHqxy5cppw4YN2rdvnz777DN5eXlp9uzZ8vHxMT3fY8WKFVq/fr2GDBlimt7z66+/VtmyZU3fEMysW7dumY0AxJPBaDQqOjratOzq6mqRSAZyUt26dfXBBx+oY8eOkh7Ou/3BBx9o//79abbp2rWr6tevr/fee8+svH79+ho9erSef/55SQ9H8TRp0kSnT582/WGblJSkhg0b6vXXX9eLL76YS70CkFnJ30JftGiRJJlGpqf1d0vyt/ZSfisvs+uzui8gp/D3FQAAAB4n7rUAeBLY3Eg/6eG0PpGRkVqxYoXCw8MVEBCg9957T15eXpIePu8j5Q2DHj16yGB4+LDWu3fvysPDQ3Xq1DGdlIGMREdH69VXXzUtf/HFF2bfAgJyWu/evTVz5kzVq1dPkjRr1izTFxms+fPPPxUSEqJp06ZZrHvhhRf07bffKigoSF5eXvrss8/UpEkTs2N4586dunv3rrp27ZrjfQGQdY86asJawi+j9entC8hN/H0FAACAx4l7LQDwf/LVSL+8xEi/J1NUVBQ3pfBYxcfHa8KECVq9erWkhzfhJ06cKAcHB6s3/CdNmqRDhw7pxx9/tNhWYmKiJk2apB9++EHSwy9OTJo0SUWKFDHVGTp0qAoUKKAZM2bkYq8APA6MnoKt4O8rAAAAPE7cawHwJMjsSD+Sfv+frST9ph7Zktch/KMkPIhT6OylpuWqrz8vhwJOeRjRP8ubNVrldQj/GNzsB0AiJfc4/Dw9r0P4R4mKS9Ara46Ylud1qSE3p3w1wYhNS3h2VF6H8I/E/1mwFe9cDM3rEIBM4XoFW8C9ltzF/1mwFbZyzbLJ6T0BANYxVRoAAAAAAEDO4V4LgH8ikn4AACBXMGoiZyU8iDNbnh26g9HpOeSdvA7gH8bV0V7zutQwWwYAAAAAALmPpB+eaPbOjqr6+vNmy8g5DOPPOQ5xCebLG+bKganScoytDOMHAFtgMBiYzhMAACAX8MXKnMUXK3MXX64E8gb/jeOJZjAYuJgDAAAAAAAAAACbR9IPAADABjA6HQAAAAByDv9jAfgnIukHADaA5yMBYHQ6AAAAAOQc/scC8E9E0g8AbADPRwIAAAAAAAAApMcurwMAAAAAAAAAAAAAkD0k/QAAAAAAAAAAAAAbR9IPAAAAAAAAAAAAsHEk/QAAAAAAAAAAAAAbR9IPAAAAAAAAAAAAsHEk/QAAAAAAAAAAAAAbR9IPAAAAAAAAAAAAsHEk/QAAAAAAAAAAAAAbR9IPAAAAAAAAAAAAsHEk/QAAAAAAAAAAAAAbR9IPAAAAAAAAAAAAsHEk/QAAAAAAAAAAAAAbR9IPAAAAAAAAAAAAsHEk/QAAAAAAAAAAAAAbR9IPAAAAAAAAAAAAsHEk/QAAAAAAAAAAAAAbR9IPAAAAAAAAAAAAsHEk/QAAAAAAAAAAAAAbR9IPAAAAAAAAAAAAsHEk/QAAAAAAAAAAAAAbR9IPAAAAAAAAAAAAsHEk/QAAAAAAAAAAAAAbR9IPAAAAAAAAAAAAsHEk/QAAAAAAAAAAAAAbR9IPAAAAAAAAAAAAsHEk/QAAAAAAAAAAAAAbR9IPAAAAAAAAAAAAsHEk/QAAAAAAAAAAAAAbR9IPAAAAAAAAAAAAsHEk/QAAAAAAAAAAAAAbR9IPAAAAAAAAAAAAsHEk/QAAAAAAAAAAAAAbR9IPAAAAAAAAAAAAsHEk/QAAAAAAAAAAAAAbR9IPAAAAAAAAAAAAsHEO2WlsNBq1ZcsWbdu2TTdv3tT9+/ct6hgMBi1btiw7uwEAAAAAAAAAAACQjmwl/b7//nutW7dOAQEBeuaZZ+Tm5pbtgDZu3Ki1a9cqPDxc/v7+GjhwoMqVK5dm/aioKC1dulR//PGH7t+/r8KFC+ull15S7dq1sx0LAAAAAAAAAAAAYAuylfTbsWOHGjRooDFjxuRIMHv37tXChQs1ePBgBQYGav369frwww81ffp0eXp6WtRPSEjQpEmT5OHhoTFjxsjHx0e3b9+Wq6trjsQDAAAAAAAAAAAA2IJsJf3i4uJUvXr1nIpF69atU8uWLdW8eXNJ0uDBg3Xw4EEFBwera9euFvW3bdum+/fv67///a8cHB52pUiRIjkWDwAAAAAAAAAAAGALspX0q1q1qv7880+1atUq24EkJCTo/PnzZsk9Ozs7VatWTWfOnLHa5sCBAwoMDNQ333yjkJAQeXh4qHHjxuratavs7OystomPj1d8fLxp2WAwyMXFxfS79PBZhSnXJ3vU8pRlOVkOAMgZBoMhT87lOX29yWp5bvcJAJDzUv/PwvUp5/oEAMg5XJ9yp08AgNxhK9enzMhW0u+VV17Rhx9+qJ9++kmtW7dWwYIFH3lbkZGRSkpKkpeXl1m5l5eXrl27ZrXNjRs3dOvWLTVp0kTvvvuurl+/rnnz5ikxMVE9e/a02mbVqlVauXKlablMmTKaPHmyPDw8TC9ebGysoqKi5ObmJmdnZ1PdmJgYxcTEqGDBgnJ0dDSVR0VFKTY2Vp6enrK3tzeV37t3T/Hx8fLy8jJ7kyIiIpSUlCRvb2+z2MLCwmRnZ2c2lanRaFRYWJgcHR2z9foCANLm7e2dJ+fyxMRERUREyNnZ2ey5uPHx8bp3755cXFxMX0yRbOP6lLJPAICcl3yO5vqUs30CAOQsrk+50ycAQM4zGAw2cX1yd3fPVH+ylfQbNWqUjEajli9fruXLl8vJycnqCLsFCxZkZzdpMhqN8vDw0NChQ2VnZ6eyZcvq7t27WrNmTZpJv27duqlTp06m5eSLdWRkpBISEkzblR6+mNHR0Wb7kx5e7K1lWiMiIqyWh4eHW8QtPTxwUpcnJiZalEsPDxBr5QCA7AsLC8uTc3nKL5vExcVZlMfExOjBgwcW5fn5+pSyTwCAnJd8zuX6lLN9AgDkLK5PudMnAEDOS07mpS7Lb9en+/fvZ+qLINlK+jVo0CDHhph7eHjIzs7O4gIaHh5uMfovmZeXlxwcHMwSjSVLllR4eLgSEhJMz/lLydHR0SxLmpK1f/jS+icwK+U5sY30ygEA2ZP6/JoX5/K8KOf6BAC2JzPXLFsvz6tYAAA5Jz9dV3KqPD/FAgDIWfntHJ+dc3+2kn6vvfZadpqbcXBwUNmyZRUaGqr69etLkpKSkhQaGqp27dpZbVOhQgXt2bNHSUlJpsTf33//LW9vb6sJPwAAAAAAAAAAAOCfyHIuzjzUqVMnbd26Vdu3b9eVK1c0b948xcbGKigoSJI0e/ZsLVmyxFS/TZs2un//vr777jtdu3ZNBw8e1KpVq9S2bds86gEAAAAAAAAAAADw+GV7OFx0dLTWr1+vgwcP6vbt25IkX19f1alTRx06dJCrq2umt9WoUSNFRkZqxYoVCg8PV0BAgN577z3T9J63b982m07U19dX48eP14IFC/TWW2/Jx8dH7du3V9euXbPbLQAAAAAAAAAAAMBmZCvpd/fuXU2YMEE3b95UiRIlVKFCBUnStWvX9MMPP2jHjh36z3/+I29v70xvs127dmlO5zlx4kSLsvLly+vDDz98pPgBAAAAAAAAAACAf4JsJf0WL16s8PBwvfPOO6pdu7bZukOHDmnatGlavHixXn/99WwFCQAAAAAAAAAAACBt2Xqm3+HDh9WhQweLhJ8k1apVS+3bt9ehQ4eyswsAAAAAAAAAAAAAGchW0i82Nlaenp5prvfy8lJsbGx2dgEAAAAAAAAAAAAgA9lK+vn5+WnPnj1KSEiwWJeQkKA9e/bIz88vO7sAAAAAAAAAAAAAkIFsPdPv2Wef1fTp0/Xuu++qbdu2Kl68uCTp2rVr+vXXX3Xp0iWNHj06RwIFAAAAAAAAAAAAYF22kn5PP/20YmNjtXjxYn399ddm6zw8PDRs2DA1bNgwWwECAAAAAAAAAAAASF+2kn6SFBQUpGeeeUbnzp3T7du3JUm+vr566qmnZG9vn+0AAQAAAAAAAAAAAKQv20k/SbK3t1f58uVVvnz5nNgcAAAAAAAAAAAAgCzIUtLvxIkTkqTKlSubLWckuT4AAAAAAAAAAACAnJelpN8HH3wgSVq8eLEcHBxMyxlZvnx51iMDAAAAAAAAAAAAkClZSvpNmDDhYSMHB7NlAAAAAAAAAAAAAHknS0m/1NN0Mm0nAAAAAAAAAAAAkPfscmOjN27c0JUrV3Jj0wAAAAAAAAAAAABSydJIv9Q2bNigM2fOaNSoUaayzz//XDt27JAklSlTRu+++648PT2zFSQAAAAAAAAAAACAtGVrpN+2bdvMEnqHDx/Wjh071KpVKw0cOFA3btzQDz/8kO0gAQAAAAAAAAAAAKQtWyP9bt26pZIlS5qW9+3bpyJFimjw4MGSpPDwcO3cuTN7EQIAAAAAAAAAAABIV44+0+/o0aOqWbOmablw4cIKDw/PyV0AAAAAAAAAAAAASCVbSb/ixYtr//79kh5O7Xn37l3VqlXLtP7u3btyc3PLXoQAAAAAAAAAAAAA0pWt6T07d+6smTNn6uWXX9aDBw/k5+enGjVqmNaHhoYqICAguzECAAAAAAAAAAAASEe2kn6NGzdWwYIFdfDgQbm5ualt27ayt7eXJN2/f1/u7u5q2rRpjgQKAAAAAAAAAAAAwLpsJf0kqXr16qpevbpFubu7u8aOHZvdzQMAAAAAAAAAAADIQLae6QcAAAAAAAAAAAAg72VppN9rr70mOzs7ffbZZ3JwcNBrr70mg8GQbhuDwaBZs2ZlK0gAAAAAAAAAAAAAactS0q9y5coyGAyys7MzWwYAAAAAAAAAAACQd7I80i+9ZQAAAAAAAAAAAACPH8/0AwAAAAAAAAAAAGxctpJ+u3fv1pw5c9Jc//nnn2vv3r3Z2QUAAAAAAAAAAACADGQr6bd+/Xo5Ojqmud7JyUnr16/Pzi4AAAAAAAAAAAAAZCBbSb9r164pICAgzfX+/v66du1adnYBAAAAAAAAAAAAIAPZfqZfdHR0muuioqKUkJCQ3V0AAAAAAAAAAAAASEe2kn4BAQHas2eP1cRefHy8du/erTJlymRnFwAAAAAAAAAAAAAykK2kX9euXfXXX3/pgw8+UEhIiG7cuKEbN24oJCREEydO1OXLl9W1a9ccChUAAAAAAAAAAACANQ7ZaVyrVi0NGzZM8+fP15QpU8zWFShQQEOHDlXt2rWzFSAAAAAAAAAAAACA9GUr6SdJQUFBql+/vo4ePaobN25IkooWLaoaNWrIxcUl2wECAAAAAAAAAAAASF+2k36S5OrqqoYNG+bEpgAAAAAAAAAAAABkUbaTfklJSdq3b5+OHz+uiIgI9e7dW6VLl1Z0dLSOHTumChUqyMvLKwdCBQAAAAAAAAAAAGBNtpJ+UVFR+t///qc///xTBQoU0IMHD9S+fXtJD5/pN3/+fDVt2lR9+/bNkWABAAAAAAAAAAAAWLLLTuPFixfr8uXLGj9+vGbNmmW+YTs7NWzYUIcOHcpWgAAAAAAAAAAAAADSl62k3/79+9WuXTtVr15dBoPBYn3x4sV169at7OwCAAAAAAAAAAAAQAaylfSLjo5WkSJF0lyfmJioxMTE7OwCAAAAAAAAAAAAQAaylfQrVqyYLly4kOb6I0eOyM/PLzu7AAAAAAAAAAAAAJCBbCX9WrRooeDgYO3du1dGo9FUHh8fr6VLl+rw4cNq3bp1toMEAAAAAAAAAAAAkDaH7DTu0KGDLl++rBkzZsjV1VWSNHPmTN27d09JSUlq1aqVWrRokSOBAgAAAAAAAAAAALAuW0k/g8GgV199VUFBQfrtt9/0999/y2g0qmjRonr66adVuXLlR9ruxo0btXbtWoWHh8vf318DBw5UuXLlMmy3Z88ezZgxQ3Xr1tXbb7/9SPsGAAAAAAAAAAAAbM0jJ/1iY2M1a9YsNWjQQM8884wqVqyYIwHt3btXCxcu1ODBgxUYGKj169frww8/1PTp0+Xp6Zlmu5s3b2rRokWqVKlSjsQBAAAAAAAAAAAA2IpHfqafs7Ozjh07ptjY2JyMR+vWrVPLli3VvHlz+fn5afDgwXJyclJwcHCabZKSkjRr1iz16tVLRYoUydF4AAAAAAAAAAAAgPzukZN+klSxYkWdOXMmp2JRQkKCzp8/r2rVqpnK7OzsVK1atXT3s3LlSnl4ePD8QAAAAAAAAAAAADyRspX0GzhwoE6dOqVly5bpzp072Q4mMjJSSUlJ8vLyMiv38vJSeHi41TanTp3Stm3bNHTo0EztIz4+XtHR0aafmJgY0zqDwSCDwWBWP7ksO+Upy7JbDgDIeY/7XJ5b15uslud2nwAAOY/rU+71CQCQc7g+5X6fAAA5x1auT5nxyM/0k6S33npLiYmJWrVqlVatWiV7e3s5Ojpa1FuwYEF2dpOmmJgYzZo1S0OHDpWHh0em2qxatUorV640LZcpU0aTJ0+Wh4eHjEajpIfPK4yKipKbm5ucnZ3N9hcTE6OCBQua9TMqKkqxsbHy9PSUvb29qfzevXuKj4+Xl5eX2ZsTERGhpKQkeXt7m8UWFhYmOzs7s2cXGo1GhYWFydHRUQULFszkKwMAyApvb+88OZcnJiYqIiJCzs7OcnNzM5XHx8fr3r17cnFxkYuLi6ncFq5PKfsEAMh5yedork852ycAQM7i+pQ7fQIA5DyDwWAT1yd3d/dM9SdbSb+GDRtmp7kFDw8P2dnZWYzqCw8Ptxj9J0k3btzQrVu3NHnyZFNZcuKuT58+mj59uooVK2bWplu3burUqZNpOfliHRkZqYSEBLNtREVFKTo62mLb9+7dM7vIJ5dHRERYLU/dn+TysLAwi/LExESLcunhAWKtHACQfWFhYXlyLk/5ZZO4uDiL8piYGD148MCiPD9fn1L2CQCQ85LPuVyfcrZPAICcxfUpd/oEAMh5ycm81GX57fp0//79TH0R5JGSfnFxcQoJCVGJEiXk7u6uOnXqWGRCH4WDg4PKli2r0NBQ1a9fX5KUlJSk0NBQtWvXzqJ+iRIl9Omnn5qVLVu2TA8ePNCAAQPk6+tr0cbR0dHqaETJ+j98af0TmJXynNhGeuUAgOxJfX7Ni3N5XpRzfQIA25OZa5atl+dVLACAnJOfris5VZ6fYgEA5Kz8do7Pzrk/y0m/iIgIvf/++7p586apbOHChRo7dqyqV6/+yIEk69Spk+bMmaOyZcuqXLly2rBhg2JjYxUUFCRJmj17tnx8fNS3b185OTmpdOnSZu2Th0+mLgcAAAAAAAAAAAD+qbKc9Pvxxx9169YtdezYUVWrVtX169f1448/6uuvv9asWbOyHVCjRo0UGRmpFStWKDw8XAEBAXrvvfdM03vevn2bB9cCAAAAAAAAAAAAKWQ56XfkyBE1bdpUL774oqnMy8tLM2bM0LVr11SiRIlsB9WuXTur03lK0sSJE9Nt+9prr2V7/wAAAAAAAAAAAIAtsctqg9u3b6tixYpmZcnLqR9oCwAAAAAAAAAAACD3ZTnpl5CQICcnJ7MyR0dHSVJSUlLORAUAAAAAAAAAAAAg07I8vack3bx5U+fPnzctR0dHS5L+/vtvubq6WtQvW7bsI4YHAAAAAAAAAAAAICOPlPRbvny5li9fblE+b968NOsDAAAAAAAAAAAAyB1ZTvoNGzYsN+IAAAAAAAAAAAAA8IiynPQLCgrKhTAAAAAAAAAAAAAAPCq7vA4AAAAAAAAAAAAAQPaQ9AMAAAAAAAAAAABsHEk/AAAAAAAAAAAAwMaR9AMAAAAAAAAAAABsHEk/AAAAAAAAAAAAwMaR9AMAAAAAAAAAAABsHEk/AAAAAAAAAAAAwMaR9AMAAAAAAAAAAABsHEk/AAAAAAAAAAAAwMaR9AMAAAAAAAAAAABsHEk/AAAAAAAAAAAAwMaR9AMAAAAAAAAAAABsHEk/AAAAAAAAAAAAwMaR9AMAAAAAAAAAAABsHEk/AAAAAAAAAAAAwMaR9AMAAAAAAAAAAABsHEk/AAAAAAAAAAAAwMaR9AMAAAAAAAAAAABsHEk/AAAAAAAAAAAAwMaR9AMAAAAAAAAAAABsHEk/AAAAAAAAAAAAwMaR9AMAAAAAAAAAAABsHEk/AAAAAAAAAAAAwMaR9AMAAAAAAAAAAABsHEk/AAAAAAAAAAAAwMaR9AMAAAAAAAAAAABsHEk/AAAAAAAAAAAAwMaR9AMAAAAAAAAAAABsHEk/AAAAAAAAAAAAwMaR9AMAAAAAAAAAAABsHEk/AAAAAAAAAAAAwMaR9AMAAAAAAAAAAABsHEk/AAAAAAAAAAAAwMaR9AMAAAAAAAAAAABsHEk/AAAAAAAAAAAAwMaR9AMAAAAAAAAAAABsHEk/AAAAAAAAAAAAwMaR9AMAAAAAAAAAAABsnENeB2DNxo0btXbtWoWHh8vf318DBw5UuXLlrNbdsmWLdu7cqcuXL0uSypYtq+effz7N+gAAAAAAAAAAAMA/Tb4b6bd3714tXLhQzz33nCZPnix/f399+OGHioiIsFr/xIkTaty4sSZMmKBJkyapUKFCmjRpku7evfuYIwcAAAAAAAAAAADyRr5L+q1bt04tW7ZU8+bN5efnp8GDB8vJyUnBwcFW67/xxhtq27atAgICVLJkSb366qsyGo06duzYY44cAAAAAAAAAAAAyBv5anrPhIQEnT9/Xl27djWV2dnZqVq1ajpz5kymthEbG6uEhAS5u7tbXR8fH6/4+HjTssFgkIuLi+l3STIajWbrkz1qecqynCwHAOQMg8GQJ+fynL7eZLU8t/sEAMh5qf9n4fqUc30CAOQcrk+50ycAQO6wletTZuSrpF9kZKSSkpLk5eVlVu7l5aVr165lahuLFy+Wj4+PqlWrZnX9qlWrtHLlStNymTJlNHnyZHl4eJhevNjYWEVFRcnNzU3Ozs6mujExMYqJiVHBggXl6OhoKo+KilJsbKw8PT1lb29vKr93757i4+Pl5eVl9iZFREQoKSlJ3t7eZrGFhYXJzs5Onp6epjKj0aiwsDA5OjqqYMGCmXoNAABZ4+3tnSfn8sTEREVERMjZ2Vlubm6m8vj4eN27d08uLi6mL6ZItnF9StknAEDOSz5Hc33K2T4BAHIW16fc6RMAIOcZDAabuD6lNdAttXyV9Muu1atXa8+ePZo4caKcnJys1unWrZs6depkWk6+WEdGRiohIUHS/2VOo6KiFB0dbaqbXH7v3j2rmdaIiAir5eHh4WYxJJeHhYVZlCcmJlqUSw8PEGvlAIDsCwsLy5Nzecovm8TFxVmUx8TE6MGDBxbl+fn6lLJPAICcl3zO5fqUs30CAOQsrk+50ycAQM5LTualLstv16f79+9n6osg+Srp5+HhITs7O4uLaHh4uMXov9TWrFmj1atX61//+pf8/f3TrOfo6GiWJU3J2j98af0TmJXynNhGeuUAgOxJfX7Ni3N5XpRzfQIA25OZa5atl+dVLACAnJOfris5VZ6fYgEA5Kz8do7Pzrnf7pFb5gIHBweVLVtWoaGhprKkpCSFhoaqfPnyabb7+eef9eOPP+q9997TU0899ThCBQAAAAAAAAAAAPKNfJX0k6ROnTpp69at2r59u65cuaJ58+YpNjZWQUFBkqTZs2dryZIlpvqrV6/W8uXLNWzYMBUpUkTh4eEKDw9n6DsAAAAAAAAAAACeGPlqek9JatSokSIjI7VixQqFh4crICBA7733nml6z9u3b5vNZ/rrr78qISFB06ZNM9vOc889p169ej3O0AEAAAAAAAAAAIA8ke+SfpLUrl07tWvXzuq6iRMnmi3PmTPnMUQEAAAAAAAAAAAA5F/5bnpPAAAAAAAAAAAAAFlD0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcST9AAAAAAAAAAAAABtH0g8AAAAAAAAAAACwcQ55HYA1Gzdu1Nq1axUeHi5/f38NHDhQ5cqVS7P+vn37tHz5ct26dUvFihXTCy+8oNq1az/GiAEAAAAAAAAAAIC8k+9G+u3du1cLFy7Uc889p8mTJ8vf318ffvihIiIirNY/ffq0ZsyYoRYtWmjy5MmqV6+epkyZor/++usxRw4AAAAAAAAAAADkjXyX9Fu3bp1atmyp5s2by8/PT4MHD5aTk5OCg4Ot1t+wYYNq1qypLl26yM/PT3369FHZsmW1cePGxxw5AAAAAAAAAAAAkDfy1fSeCQkJOn/+vLp27Woqs7OzU7Vq1XTmzBmrbc6cOaNOnTqZldWoUUP79++3Wj8+Pl7x8fGmZYPBIBcXFzk45KuXIk0lPXzyOgQg0xx8S+Z1CECmGBwd8zqEfySuWbAVXK9gS7hm5Q6uWbAVXLNgK7he5Q6uV7AlXLNgK2zlmpXZHFa+ynRFRkYqKSlJXl5eZuVeXl66du2a1Tbh4eHy9PQ0K/P09FR4eLjV+qtWrdLKlStNy40bN9bIkSPl7e2drdgflzGFO2VcCQCAfIBrFgDAVnDNAgDYAq5XAICM5LvpPXNbt27d9N1335l+Bg8ebDbyD0DOiImJ0TvvvKOYmJi8DgUAgDRxvQIA2AquWQAAW8E1C8g7+Wqkn4eHh+zs7CxG6YWHh1uM/kvm5eWliIgIs7KIiIg06zs6OsrRRoZrArbMaDTqwoULMhqNeR0KAABp4noFALAVXLMAALaCaxaQd/LVSD8HBweVLVtWoaGhprKkpCSFhoaqfPnyVtuUL19ex44dMys7evSoAgMDczVWAAAAAAAAAAAAIL/IV0k/SerUqZO2bt2q7du368qVK5o3b55iY2MVFBQkSZo9e7aWLFliqt+hQwcdOXJEa9eu1dWrV7VixQqdO3dO7dq1y6MeAAAAAAAAAAAAAI9XvpreU5IaNWqkyMhIrVixQuHh4QoICNB7771nmq7z9u3bMhgMpvoVKlTQG2+8oWXLlmnp0qUqXry43nrrLZUuXTqPegBAejiV7nPPPcd0ugCAfI3rFQDAVnDNAgDYCq5ZQN4xGJlYFwAAAAAAAAAAALBp+W56TwAAAAAAAAAAAABZQ9IPAAAAAAAAAAAAsHEk/QAAAAAAAAAAAAAbR9IPAAAAAAAAAAAAsHEk/QAAAAAAAAAAAAAbR9IPQIaSkpIsymJiYvIgEgAAAAD450j9v5bRaMyjSAAAAPBPQNIPQIbs7Ox069YtrV+/XpK0b98+zZ49W9HR0XkcGQAA5lLePLX2pRUAAPKLpKQk2dk9vC1z8uRJJSYmymAw5HFUAABYSv5Syq1bt3Tz5k399ddfeRwRgLQ45HUAAPK/xMREbd68WYcPH9aFCxe0a9cuDRs2TK6urnkdGgAAJilvnm7cuFGXLl3SnTt3VLt2bdWvX18+Pj55HCEAAA8ZjUbTNWvZsmXatWuXnn/+eTVq1MhUDgBAfmA0GmUwGPTHH39o+fLlkqTIyEjVr19fXbt2VeHChfM4QgAp8ZckgAzZ29urZ8+e8vX11a5du/T0008rKChIEqMoAAD5R/JN0u+//14rV65UyZIl5efnp02bNmnevHmKi4vL4wgBAHgoeUTfsmXLtHXrVr322muqVq0aCT8AQL5jMBh07NgxzZo1S+3bt9cHH3ygl19+WVu2bNGFCxfyOjwAqfDXJIB0JQ/fd3BwkJubm6pXr647d+5o1apVkh7eYCXxBwDIL06fPq2QkBC988476tSpk6pVq6abN2+qfv36cnJyyuvwAAAwuXXrlg4fPqxhw4apcuXKsrOz019//aWVK1fq5MmTPE4BAJDnku8LHjlyRM2bN1erVq10//59LVu2TC1atFD9+vXzOEIAqTG9J4A0JQ/fP3/+vDw8PPTaa68pOjpay5cvV0hIiCSpW7dupm+jRkZGysPDIy9DBgA84aKjo+Xg4KDAwED99ttvmjt3rl566SUFBQUpNjZWx48fV9WqVUkAAgDyXHx8vP7++2/Z2dnp7Nmz2rZtm/7880/du3dP27Zt0+DBg1WrVi3T/2UAADwuydeeO3fuyNfXVxcuXFC1atUUHx+viRMnqnbt2ho8eLAkacOGDSpevLhq1aqVx1EDkBjpByANKefr/uijj/TLL7/o3r17cnNzU/fu3fXUU08pJCREP/30kyRp+fLlmjdvnuLj4/M4cgDAkyL5W6cpGQwGeXh4mBJ+L7zwgtq0aSNJOnnypEJCQhQeHv6YIwUAPOmszY5SokQJ1a9fX1OnTtV//vMfOTs76/nnn9cXX3whNzc3nTlzRpJI+AEAHrvke4KTJk1SRESEGjRooMOHD2v48OGqW7euXnnlFRkMBiUlJenChQs6cuSIEhIS8jpsAGKkH4A0GAwGHTp0SDNnztTAgQNVt25d0yg+Ly8v9ejRQ2vWrFFwcLB27dqliIgIvfvuu3J0dMzjyAEAT4rkm6A7duyQp6enatasqcqVK2vevHn67LPP9Morr6h169aSpLi4OP3yyy9ycXHhQfMAgMcqKSnJNDvK77//roiICEVGRqpt27YaNmyYmjdvLmdnZz311FOmNu7u7syiAgB4rJKSkmQwGGQwGHT79m1t3bpVnTp1kqenp0qVKqWEhAR5enqqVatWsrOzU1xcnH788UeFhobq3//+txwcSDUA+YHBaO0r0gCeeAkJCfryyy/l6empfv366cGDB7p9+7Z27dqlIkWKqHbt2nJxcdGZM2d07do11axZU8WKFcvrsAEAT5jbt29r7ty5io6O1vPPP6/q1avr/PnzmjJlivz8/NS8eXMlJSVp+/btCgsL0yeffCJ7e3umSgMAPHbff/+99u3bpxIlSujBgwe6cuWKRo4cqZo1a0qS6X+u77//Xnfu3NHHH38se3v7vA0aAPCP9+eff6pcuXJmy9u3b9eNGzc0bNgw+fj4SJJ27typTZs26f79+ypSpIgk6eLFi3rvvfdUpkyZPIkdgCXS7wDSdOvWLcXGxio8PFzLly/X9evXdffuXUVHR+vy5csaMGCAqlevrurVq+d1qACAJ0TqZJ2vr6+6deumzZs3a8WKFbKzs1PVqlX1zjvv6Ouvv9aKFSvk5uamokWLaty4cbK3tzcbcQEAwOOwc+dO7dy5U++9954CAgJ09OhRffjhh6ap0IxGo44ePaoNGzbIYDDoo48+4poFAMh1O3fu1I4dOzR69Gi5ubnJYDDo2LFj+v3335WQkKDo6GhT0q9p06YqUqSI/vrrL507d07+/v4aNGgQgwCAfIaRfgAkWd5ElaSDBw9q1qxZSkxMVPXq1dWwYUM1adJEq1ev1v79+zVhwgQ5OTnlUcQAgCdZRESEPD09TcvHjx/XL7/8ovDwcPXp00dVq1ZVYmKiIiMj5ezsLBcXFxkMBiUmJjJqAgDw2K1atUoREREaMGCA9u7dqy+//NL03NmYmBg5OzsrJiZGp0+fVs2aNWVnZ8c1CwCQ665cuSJnZ2cVLlxYd+/eNSX4Nm/erJ9//lmVK1fWc889p6JFi+ZxpAAyi5F+AEwJv1OnTunUqVOKjIxUtWrVVLt2bU2dOlU3b95UxYoVlfwdgbCwMBUqVCiPowYAPKl2796tLVu26KWXXjJNI1OlShUZjUb98MMPWrJkifr3769KlSrJ29vb1M5oNHLzFACQJ27cuKH4+HiFhoaaJfwkadOmTXrw4IH69Omj2rVrS3r4XCWuWQCA3Obn5yfp/7F33+FNV30fxz9JF22htAXKhrZAWWUP2XspG2UJIqIgCAoOHCCyBAfOGxVvlKksQUCGILJHZQmI7C0yC3RROtPk+YMnv7uFooy2aej7dV1cNOc3ck6T9OSc7xk3l+n85ptv1KRJE7Vs2VKtWrVSYmKitm7dqlWrVumxxx5TQEAA2yQAToA1IgDIZDJpx44dmjRpko4ePaobN27o/fff19y5c5UnTx6VK1dOknT27FnNnTtXmzZt0uOPP84sPwBAlrBarZJkDD5JTk6WJP344486c+aMcV5oaKgeeeQRnTlzRlOmTNGJEyfS3IfGKQAgK61YsUKLFy+WJDVo0EDnzp3ThAkT0gT8EhISdPToUSUkJKS5liU9AQBZyWw2y8/PT9u2bdOGDRskSe3bt1f9+vV1+PBhrV69WpcuXaJNBTgBZvoB0IULFzR79mz17NlTLVq0UEJCgjZv3ixJcnNzk3RzxM+KFSt0+vRpjRkzRiVLlnRklgEAOYTNZjM6Pvfu3avq1auradOmcnd31/r16/XDDz+oa9euxoy//Pnzq0qVKipXrpyCg4MdmXUAQA6WlJSkS5cuKSoqStLNmRQlS5aUxWIx9ki6fPmy5s+fr6ioKL322muS0t92AQCAzFaiRAl17dpVP/30k9avXy9Jatq0qTp06CCTyaTVq1fL1dVV3bt3ZyY6kM2xpx8AnThxQt99953Gjh2rS5cuacyYMapevboGDBggSbp69ary58+vkydPys/Pz1jfGwCAzGS1Wo2A37lz5/Tqq6+qXbt2euqppyTdXOZzw4YNcnV1Vdu2bRUUFKSvv/5apUqVUufOnWUymdLcAwCArLR37159/PHHGjlypMqXL6/w8HAtWrRIR48eVUREhIoUKSIvLy+NHDlSrq6u1FkAgCxhH2By9epV3bhxQ97e3vL19ZWrq6tOnz6t5cuX68qVK2rWrJmaNm0qSfr5559Vs2ZNBQQEODj3AP4NQT8gB7JX7n/88Ye8vb1ltVr1n//8R0OHDtXnn3+uypUr67nnnpPZbNahQ4e0bNkyDRgwgGAfACDLpJ7psHLlSv3999/atWuXYmNj1bp1a/Xr10+StH37dm3btk07d+5U4cKF5eLiog8//FAuLi7MlgAAZIl/qm8mT56sxMREvfDCC/Ly8lJ8fLzi4+N15swZBQQEqEiRIjKbzUpJSWHmBAAg09nrrJ07d+qHH35QTEyMChYsqKCgIPXq1UseHh5G4C8iIkL16tUzlqQG4BxY3hPIgUwmk44cOaKPPvpI/fv3V9WqVVWsWDGNGzdONWvW1IABA4x9k/bt26fExES5uvLnAgCQ+eyNUHvn6cKFC7Vq1SoNGDBA1apV08GDB7VlyxalpKSof//+qlOnjkqXLq1WrVopLi5OtWrVktlsZrYEACDL2OusJUuWKE+ePCpVqpSx7HTVqlX1448/KjY2Vl5eXvLw8JCnp2eaAZVWq5WAHwAgS5hMJu3bt09ffvmlunfvrnr16mnt2rVasWKFoqOjNWjQIAUFBalDhw5asGCBdu/erQYNGsjLy8vRWQdwl+jFB3KgK1euaM+ePercubMaNWokSapZs6bCw8Pl6uqqv//+W0lJSfrtt9+0bt06jR07Vj4+Pg7ONQDgYRcbG6vcuXMbj+Pi4nTo0CF17dpVderUkSRVqFBBRYoU0dy5c+Xh4aE+ffoof/78yp8/v3EdAT8AQFaz2Wy6du2awsLClJSUpBo1aqhZs2Zq2LCh1q5dq4ULF2rw4MHp1k/UWQCArBITE6MVK1bo8ccf12OPPabr169r3bp1CgoK0rlz5zRlyhS98MILCgwMVM+ePZU7d24CfoCTIegH5DDnz5/XlClTFBkZqY4dOxrpLVq0UHx8vPbs2aPXXntNJUqUkNls1ujRo1WiRAkH5hgAkBNMnTpV165d01tvvWWkubq66tq1awoPDzfS8uTJowYNGuj333/XypUrZbVa1bdvX0kylkaj8xQAkNluHWBiMpn03HPP6fz58zp79qx++OEHHT16VD4+PipXrpz279+vixcvqnDhwg7MNQAgp/Px8VH9+vVVsmRJxcTEaPTo0apRo4b69eunmTNnas2aNYqLi9Orr75KfyDgpAj6ATlM0aJFVbp0aW3atEn79u1LM0W/ffv2atGihc6dOyc/Pz95eHgoT548Ds4xACAn6NKli3x9fSVJCQkJypUrl9zd3fXII4/ozJkzOnXqlIKDgyVJuXPnVmBgoNzc3LRjxw5ZLBY999xzcnFxYZYfACDTpa5rjh07pvj4eHl4eKhcuXIqWrSoihYtqipVqujEiRNas2aN0YH6xx9/EPQDADhc06ZNJUmrVq1SQECAunXrJrPZrBIlSqhkyZJyc3NTbGyscuXK5eCcArgfBP2Ah1x6m8r37dtXrq6u2rNnj37++Wc9+uij8vb2liR5enqqTJkyjsgqACAHsy/PuXHjRs2cOVOffvqp/Pz8VKVKFe3Zs0dr1qxRs2bNFBISooSEBJ0/f16VK1dWzZo1tWDBAiUkJGjIkCEE/AAAmcpmsxl1zdy5c7Vz507Fx8erQIECKlSokIYMGSJJ8vLyUuXKlVW5cmUdO3ZM27Zt05o1a1SzZs00S1IDAJBZ7H2CZ86c0aVLl2SxWFSiRAljBl94eLiuXLlibLFw8eJFVa9eXe3bt2dJT8CJEfQDHmL2yv348eM6evSoXF1dFRAQoOrVq6t3796yWq3atWuXJBmBv/SChAAAZJbUsyWSk5NVrlw5FSlSRGPGjNGYMWMUGhqqHj16aPHixfrvf/+rXLlyKTk5WSkpKWrTpo1SUlKUlJSkVatWKSoqypgtCABAZrC3lZYuXaoNGzbo1VdfValSpbRw4UL99NNPiouL0+uvvy7pZr3m5uamkJAQmc1m7du3T1evXiXoBwDIEiaTSTt27NA333yjwMBARUZGysPDQ3Xq1FGHDh0UEhKiI0eO6L333lPevHm1Y8cOffDBBwT8ACdnstlsNkdnAkDGswfvtm/frilTpigwMFA3btzQ+fPn1aZNGz399NOSpJkzZ+r48eOqUKGCOnfuTMUOAMgyBw4c0JUrV9S0aVNNnTpVVqtVAwYMUHh4uL788ktFRETo3XfflZ+fn86cOaOLFy/q8OHD8vPzU/v27eXqenP8WkJCgqxWK3UYACBLXLhwQdOnT1fbtm1VrVo17du3T5988okaNWqk33//XaVKldJrr70m6X/7zUrSyy+/rNatW6tNmzaOzD4AIIc4ffq0Jk6cqK5du6pVq1Y6fPiwxo8fr06dOqlbt26Kj4/X5s2b9eeff8pqtapHjx7s4wc8BJjpBzwk0ttI/tKlS5oxY4Z69eqlVq1aKTY2Vvv379eUKVNkMpnUp08f9e3bV1OnTtWJEydksVgcWAIAQE5hs9mUlJSkFStWKC4uTtu3b9exY8c0duxYmc1mFSpUSIMHD9aXX36pt99+W++++64CAwMVGBiounXrGvexd6Sy1wQAILOlbm8VKVJEDRo0UFBQkI4ePaqvv/5affr0UYsWLWS1WrVu3TqNGjVK48ePNwJ+YWFhioqKUuXKlR1ZDABADvL333+rWLFiatWqlcLDw/XFF1+oSZMm6tatmyQpPj5erVu3VuvWrZWUlCR3d3cH5xhARmDTE+AhYG+Anj17Vvv27TPSr1+/rly5cqlGjRqSpNy5c6tevXp6/vnntWbNGh04cECSNGDAAA0bNkw+Pj6OyD4AIIcxmUzy8PDQsGHDdP36de3bt0/t2rVLM6rUHvjz9/fXmDFjFBERcdt97B2pAABklj179uj777/XZ599plOnThnpTZo0ka+vr/bs2aPKlSurUaNGkm7WXzVr1lSRIkVktVqN8wsUKKD33ntPRYoUyfIyAAByltQL+/n5+SkiIkKjR49WlSpV9Nxzz0m6uerK+vXrFR0dLUlyc3NzSF4BZDyCfoCTswf8/vrrLw0fPlwnTpwwjnl4eOjy5cu6ePGipP9V+hUqVJCfn58iIyONc/PmzZu1GQcA5Ej2DlD7bL+CBQuqYsWKOnjwoDZs2GCcZ7PZjMCfdHM5agAAstLatWv15Zdf6vLly7p27ZpGjx5ttK3sLl68qPPnz8vd3V0Wi0XHjh1TxYoVNWjQIJnNZqWkpEiSypQpo0KFCjmiGACAHMa+/6yfn5/CwsI0bNgw1a5dWwMGDDBmrW/fvl1nz541ZvfZrwHg/FjeE3Bi9oDfmTNn9Pbbb6tz58564oknjONFihRR1apVtXr1anl5eSk4OFiS5OPjo9y5cxsNUAAAskLqpdF27dqlcuXK6c0331RsbKymTJmijRs3ymQyqUmTJkaj09/fX2PHjmU2OgAgS61du1bTpk3Tyy+/rJo1ayo+Pl5jxozRpUuXlD9/fmNGRKNGjTRr1iy98cYbMpvNSkxM1Msvvyzp5gAWZqUDADKbzWaTyWTS6dOndfXqVXl7eyskJESVKlVS9+7dNX/+fJUqVUrR0dFKSUnRzz//rN9++01jx46Vp6eno7MPIIOZbKnn+wJwOhcuXNDw4cP1+OOPq0uXLkb677//rooVK+rPP//UihUr5OXlpRYtWiggIECbNm3Sxo0bNXHiRAUEBDgw9wCAnMLeEJWkuXPnatu2bWrZsqVat24tT09PRUREaNq0aYqLi1P9+vXVuHFjTZgwQcHBwerTp4+k2/evBQAgM+zZs0cffPCBBg8ebCzbKUlDhw5VsWLFdPbsWdWsWVONGjVS8eLFtXfvXv3xxx/y9PRUjx495OLiQp0FAMhS27dv19SpU+Xu7i4PDw8FBQVp8ODBcnNz08yZM/XLL7/I399fuXPnVnx8vF5++WUFBQU5OtsAMgFBP8CJJSUl6auvvtKff/6pl19+WaGhoZKkxYsX69dff9Xbb7+tokWLaufOndq6dat27typwoULy2q1atiwYVTuAIAst2jRIq1atUpvvfWWihUrply5chkBwYiICH333Xc6c+aMkpKS5OXlpffee0+urixOAQDIOkuWLNHmzZtVrVo1Pfnkk3J1ddVHH32kU6dOqU2bNoqJidGqVatUq1YtvfDCC8bSaHYpKSnM8AMAZAp7V77JZDLaUbGxsfryyy9Vt25dVahQQX/88Yd+/fVX+fj4aPjw4XJzc9ORI0cUExMjT09PFStWTH5+fg4uCYDMQtAPcHIHDhzQ6tWrdePGDfXq1UvHjx/XwoUL9dJLL6lq1arGeRaLRVeuXJHValWePHlYJg0AkOlWrlypunXryt/fX5IUFRWlzz//XG3atNEjjzyiiIgIXbp0SRs3blRISIiaNWumGzdu6OTJk4qOjlbDhg2N/ZDoPAUAZJWUlBStWLFCu3btUunSpXXp0iVFRkbq1VdfNVZKWbZsmebMmaNPPvlERYsWdXCOAQA5xdWrV5U/f37j8fHjx7VkyRKZzWY999xz8vX1lcVi0e7du7VkyRLlyZNHr7/++m0DVAA8vBg2DTi50NBQmc1mrVixQpMnT9bVq1c1evRohYSEpBn94+LiosKFCzs4twCAnCIsLEzHjh3To48+aqS5ubnp8uXLOn78uPz8/LRy5UpdvnxZuXLl0qZNm5SUlKTHHnsszaAVq9VKwA8AkGXs9U67du1ktVq1detWXb16VePHj1dAQICSkpLk7u6uQoUKqUSJEtRRAIAss3HjRi1atEiffPKJUf8cP35c58+fV1JSknx9fSVJrq6uqlmzpiRp+fLlGjt2rMaMGWPsRwvg4cYC84ATswf1KlSooA4dOqhw4cIqVqyYEhMTJcnYO+nWnwEAyGz16tXT0KFDZTab9ccff+jChQvy9vZWp06dtGXLFo0fP14FChRQz549NWbMGDVu3Fhnzpy57T7shwQAyEpms9kI/HXs2FGNGzdW0aJFtXbtWsXGxsrd3V1Wq1Xr1q1T/vz5VbBgQUdnGQCQQ5QpU0bvvPOO3N3dlZCQIBcXFzVq1Eht27ZVSkqK/vOf/xjn2gN/jz76qNzd3RUdHe3AnAPISizvCTg5+/rdknT48GEtX75c8fHx6tChg6pVq3bbOQAAZDar1Sqz2Sybzabjx4/r888/V/Xq1dWpUyfly5dPERERio+PN5ZDs1qtGj9+vMqXL69u3bo5OPcAAPyvLktJSdGyZcu0e/dulSpVSj169NCXX36pCxcuaNKkSXJ1dTXOBQAgK5w5c0bjxo3T8OHDVb58ecXFxWnz5s1av369AgMD9cILLxjnWiwWJScny9PT04E5BpCVCPoBD4HUQb1Dhw5pxYoVSkpKUuvWrVWrVi0H5w4AkJOkN9Dkp59+0m+//aayZcvq0UcfVaFChSRJCQkJ+uuvv7R48WJFRETo/fffZ5k0AEC2kTrwt3z5cv3+++/666+/5Ofnp48//liurq7sOwsAyHLnzp3TnDlzdOrUKb366qsKCQnRjRs3jMBf6dKl9fzzzzs6mwAchKFogJNKHa83mUy3LfWZkpKiDRs2KCEhwVFZBADkMKkDflu3btWqVaskSR07dlS9evV05MgRrVq1SuHh4ZJuDlRZvny5rFar3nvvPbm4uMhqtTos/wCAnOOf6hv7sdRLfbZv316hoaGqWrWqPvnkEwJ+AACHKVasmHr16qXy5cvrww8/1LFjx+Tt7a1GjRqpRYsW2r9/v6ZPn+7obAJwEGb6AU7A3okaHh6u2NhYlShRQq6urnc8T5KOHTumfPnyKV++fFmdXQBADpR6abMTJ05o3rx5ioqKUpcuXVS/fn1J0rJly7Rt2zaVL19eHTp0UN68eXX69GkFBwcbMynoPAUAZLbUddbGjRv1119/SZICAwPVuHHjO55vtVplMplkMpmoswAAmcbev5eQkCBXV9c0fYCp+/7OnTunRYsW6cCBA3r99dcVEhKi2NhYbd++XZUqVWLfWSCHIugHOIkdO3bo22+/ldlslpeXl3r27KnKlSsrV65cac5j/z4AgCPNnTtX58+f1/Xr1/XXX38pf/78ateunZo2bSpJWr58ubZt26bixYurV69e8vX1lST2QwIAZLnvv/9emzdvVp06dZScnKwdO3aoSZMm6tOnz23npm5n0eYCAGS2qKgojRw5Uj179lSdOnXSHfwv/S/wd/jwYQ0dOlQVKlSgngJyOHpWgGzOZrMpIiJCixcv1uOPP64RI0aoaNGimjNnjsLCwm5bvpNKHQDgKOvXr9cvv/yijh076s0339To0aNVsGBBrVu3Tps2bZIktW/fXjVq1JDJZJKPj49xLQE/AEBW2r9/v7Zv367XXntN/fr1U6VKlZScnKxixYqlOc8+Tjp1O4s2FwAgs/n6+qpkyZKaMWOGdu/eLYvFkua4vX4qVqyYnnjiCQUFBenrr79WUlKSI7ILIBuhdwXIpuyVt81mU+7cuVW+fHk1adJEJUuW1GuvvaaQkBD99NNP6Qb+AABwhLNnzyokJEQhISHy8vJScHCwunbtKpPJpKVLl2rr1q2SpK5du2rgwIHGUmkAAGS21O0rSbpy5Yry5cunkJAQ7dixQ//973/Vp08fNWvWTAkJCTp48KAkAnwAgKxnbyO9/vrrqlq1qqZMmXJb4C/17HOz2awnn3xSY8aMkbu7O3UXkMMR9AOyKZPJpD179uizzz7TmDFjdPr06TQdo4MHD1aZMmW0cuVKbdy4kcAfAMBh7PWTj4+PEhISFBsbK+lmAzQoKEiPPfaYrly5ojVr1hiBP7PZbDRQAQDIbPYO0OvXr0uScufOrfz58yssLExffvmlevfurZYtW0qSDh8+rF27dikyMtJh+QUA5FypB0e++OKLqlmzphH4S05ONs6zWCz66quv9Mknn6hAgQLy9/d3VJYBZCP0sgDZ1LFjx/Thhx/K29tbZrNZZ8+e1U8//WR0pErSkCFDVLhwYW3atImZEgCALHNrnWMP3AUHB+vUqVPasmWLUlJSjA5WDw8PVa5cWb6+vtq+fbvi4uIkMXsCAJC11q1bp59++kmS5O/vr927d+vzzz9Xr169jIBfUlKSfv75ZyUkJBj7zgIAkBVSt7PuFPjbs2ePLBaLbDabZs+erR07dmjgwIHy9PR0VLYBZDMmm31tCwDZxoULF7Rjxw65ubmpXbt2kqRZs2bpyJEjqlmzph599FF5eXkZ50dERDCaBwCQJaxWqxHk+/333xUTE6OUlBTVrVtX3t7eWrlypWbPnq0ePXooNDRU+fLl09SpUxUSEqIyZcro3Xff1bvvvqsyZco4uCQAgJxm0aJFWr58uSZPniwfHx+FhYXp888/V8eOHVWuXDl5eHho8eLFiomJ0fvvvy8XFxfZbDYGqQAAMoW9bRUXF2f086Vub936ePLkydq9e7eef/55HTp0SBs3btT48eMVFBTkkPwDyJ4I+gHZzOXLlzVlyhRduHBBXbp0UZs2bYxjs2bN0uHDh1W7dm21atVKuXPndmBOAQA52ezZs7Vt2zZ5e3srKSlJCQkJevHFF1WlShWtXr1aP/30kywWi9zd3ZUrVy69//77ioqK0oQJE/TKK6+oRIkSji4CAOAhZe/msAfr7B2mFotFEyZMUGBgoHr16iVXV1dt3LhRS5YsUWxsrAoVKiQfHx+9+uqrcnV1va3jFQCAjHb+/Hm988476tixozp06CDpnwN/X331lTZt2iR3d3eNGzeOgB+A27g6OgMA0sqfP79CQ0N15coV7d69W02aNFGuXLkkSU8//bS+++47bdiwQa6urmrfvj2jTgEAWW7r1q3atGmTRo0apfz588tsNmvq1Kn67LPPNGLECLVp00YVK1ZUXFycEhMTFRoaKrPZrFWrVslkMilv3ryOLgIA4CF2axsp9T6yZcuW1YEDB2SxWOTq6qomTZqoatWqSkxMlJubm/z8/GQymZSSkiIXFxcHlQAAkBNYrVZt2LBBsbGxWrlypSwWi7p06WIs7WkP9KV+/MILLyhv3ryqX7++AgMDHVsAANkSQ9YAB7t1sq2Li4s6d+6s1q1b6/r165ozZ46x95EkPfXUU6pXr57q1KlDwA8A4BDXrl1TqVKlFBgYKC8vL3l5eWnYsGEqW7asvv76a1ksFhUvXlxly5ZV5cqV9ddff+k///mPNm3apKFDhxL0AwBkiu+++05HjhwxHq9fv14TJ07UpUuXlJCQILPZrHbt2unixYtaunSpcZ6vr68KFiwof39/mUwmWa1WAn4AgExnNpsVHBysAgUKqHHjxtq0aZMWL15sHLt1j7+UlBRJUq9evQj4Abgjgn6AA9n3hzh69KgWL16sRYsWaefOnXJxcVG7du1Ut25dnTp1SnPnzk0T+OvZs6cCAgIcmHMAQE5248YNnTt3TtLNxmdycrIkqW3btoqPj1d4eLhxrn2mhLu7u0aPHk3jFACQKc6fP6/Y2Fhjz1j74Mr4+HiNHTtW06dP1549e5Q7d2517dpVp06d0vnz59O9F0t6AgAyg81mM+onewCvXr168vPzU3h4uJo2bapff/1VS5YskXR74I8BKQDuBt9kAQcymUzavn27JkyYoD///FN79+7Vxx9/rG+++UbJycnq0KGDatSoobNnz2r69OmKj493dJYBADlM6kamXYMGDeTm5qbvvvtOkuTm5mb87+bmlmYmuouLi0qUKKHnnnuOffwAAJmmaNGiGjRokFxcXLR161bt379fzZo10/jx4/XEE0/IZDLpww8/1LRp03ThwgWFh4cbA1gAAMhsVqtVJpPJ6NtLHcB79NFH5ebmpurVq6tZs2ZavXq1MSP91sAfAPwb9vQDHCg8PFyzZ89W79691apVK1mtVu3fv18ff/yxTCaTnnvuOXXo0EFJSUk6ceKEEhMT5enp6ehsAwBygGPHjikwMFDu7u63bSQfEBCgRo0aac+ePZo6daq6deummJgYLV26VPny5VPBggVvu5+rK187AQCZy2azKTo6Wj/99JN8fX2VnJysmjVrqnnz5mratKkaNWqkX375RXFxcbp48aI2b96sRx55xNHZBgDkAGazWRcuXNDo0aNVo0YNNWjQQCVKlJCPj4+Cg4M1Z84cVa9eXY8//rhMJpNWr14tk8mkjh07MgMdwD2h9wXIImvXrlWJEiVUpkwZYwZEQkKCXFxcVKFCBeO8qlWr6uWXX9YHH3ygGjVqqFq1aurWrZtu3LihPHnyOCr7AIAcJDw8XFOnTlWBAgX0yiuvyM3NzQj82Ww25cqVS61bt5aHh4fWr1+vF154QQULFpSXl5fGjh1728bzAABkBZPJJF9fXz3//POaN2+efv31V0lSzZo1ZTabFRoaqsDAQMXExGjLli16/PHHHZxjAMDDzt4uslqtWrt2rWJiYrRjxw65urpq2rRp6tWrl0JDQ/Xkk09q7dq1qlKlipo1ayaz2ayFCxfK1dVVbdu2dXQxADgRgn5AFrDZbFq0aJE8PT01ZMgQBQcHy2QyyWQyKTw8XNeuXVOxYsWMcytUqKBixYrp8uXLkm6OBiLgBwDIKn5+fmrdurU2bdqkyZMna8iQIWlm/FmtVuXOnVuPPfaY2rRpo9OnT8vFxUWBgYHGBvPsNwEAyGypB5ik/rl06dLq0aOH5s6dq19//VVms1nVq1eXJHl5eSl37tzq3r27JMlisTAbHQCQacxmsy5fvixPT0+1bdtWNptNGzduVGBgoIKDg7Vo0SKtWrVKrq6uunHjhi5fvqygoCA1adJErq6uRv0FAHeL4ddAJrPZbDKZTPriiy/k5uamr776SidPnlRKSoqKFy+u+vXra9GiRTpx4oTMZrNMJpPc3d3l4eHBDAkAQJaz2Wxyc3NTkyZN1KxZM125ckVffPGFkpKSjICevX6KiYnRL7/8ouLFiys4ONgICBLwAwBkttRBvjVr1ujbb7/V559/rh07dig+Pl5lypTRk08+qaSkJK1Zs0Z79uyRpNvaWAT8AACZKSkpSV999ZWmT5+ufPnyqUWLFnrkkUc0Z84clS5dWu+8844effRRXbt2TadPn9a1a9ckSf7+/mrXrp0KFy7s4BIAcDZEFIBMZjKZlJycLFdXV40bN05JSUmaM2eOTp06JUlq1qyZvL29NW3aNO3atUvHjh3TvHnzdPnyZVWpUsXBuQcA5DQmk8kI/DVs2FAtW7ZME/hzcXEx9kz6+OOPtXXrVrm7uxvXM2AFAJAV7PXNnDlztGDBAnl5eSkxMVFLly7VokWLFBcXlybw9+OPP+rYsWMOzjUAIKdxdXVVYGCgLly4oKSkJBUtWlTt27dXjRo1NHr0aJ06dUo1a9bUuHHj9Mknn6hmzZqy2WySaFsBuD8mm/2vCIBMYZ/pFxYWpoMHD+rChQs6dOiQAgMDNXDgQAUFBenQoUPauHGjtmzZokKFCslkMunFF19UUFCQo7MPAMih7PVXcnKytmzZol9//VUFChTQSy+9JJvNpvHjx+v69euaNGmSXF1d2cMPAJDpbq1rNm7cqB9//FEvv/yygoODtXv3bk2aNEnFihVTxYoV1aNHD3l5eenw4cP67bff1LdvX+oqAECWsbepoqKi9PLLL6tt27Z64oknJEkXL17UkiVLtGvXLg0bNkxVqlQxgn0mk8mR2Qbg5Aj6AVng8OHDmjBhgvr166fixYsrJSVFX3/9tcxmc5rg3uXLl+Xi4iIPDw/28AMAONytgb+1a9fK19dXMTExunHjhhHwYw8/AEBWiIiIkL+/v6xWqyRp/fr1ioyMVNeuXbVz505NmTJFXbt2VUREhNavX68mTZqoS5cuyp07t3EPBqkAALKSvc767rvv9Ndff+mll16Sr6+vpP8F/vbu3avBgweratWqjssogIcG33SBLHDy5EmVLFlSjRo1UpkyZVSuXDlNnDjRCP4dP35cKSkpKliwoPLnz0/ADwCQJewN0FulHmF661Kfp0+fVkJCAgE/AECWOnPmjAYNGqTt27fLbDbLbDarXr16atmypSIiIrRw4UJ16dJFjz32mB577DG5ubnpt99+0/r16yWJpdIAAJnK3rZKSEhQUlKSkWavs2rUqKHDhw8b2/1IUuHChdWlSxeVL19e3377rRITE8X8HAAPih2rgUxknyERFxenuLg4Y5P4pKQkeXl56ZlnntF7772nqVOnatCgQQoODnZwjgEAOUXqmQ5nz56Vm5ub/P395eHhYQT7TCZTmsBfgwYNlDdvXlWtWlVms5mAHwAgy/j6+qp58+b6z3/+IxcXF9WqVUu5cuUylu+Mj49XtWrVJEnR0dEqW7asKleurGbNmkliqTQAQOYym826evWqPvjgAxUvXlzt27dX8eLFjTZXaGio6tatq2XLlikkJMSYhV6oUCH16tVL7u7u8vDwcGQRADwkGOIGZCJ7w7Ju3bqKiIjQkiVLJEnu7u6Sbm7mW6NGDbm6usrb29th+QQA5Dz2xuf333+vjz76SMOHD9e3336rffv2SfrfLL/UP7u5ual69eoym82yWq0E/AAAWcbX11fdunVTy5Yt9dFHH2nXrl1pZu25u7tr9+7dOn/+vBYsWKBcuXKpefPmRp0FAEBmSF3H+Pv7q2LFirp+/bpGjBihr7/+Wps2bTKO16lTR1euXNGVK1ckSRaLRZJUsGBB+fn5ZW3GATy02NMPyED2WRFnzpzR33//raJFi6pAgQLKkyePFi9erA0bNqhp06bq0qWLEhIStGTJEiUmJuqpp56i4xQAkCVSz/DbvXu3Zs2apeeee06RkZHatGmTXF1d1bJlS9WuXVvS/+o2AACy2rVr1+Tu7p5m+4OoqCgtXrxYv/zyi1577TXVqlVL8fHx+u6773TgwAElJiYqX758GjdunFxdXanHAACZxt62Cg8P1969exUaGqqiRYsqJSVFW7Zs0c6dO/Xnn3+qVKlSqlevnpo0aaJ3331Xfn5+evnllx2dfQAPKYJ+QAbbsWOHvvrqK/n4+OjGjRtq0KCB2rZtq7x582r16tVasmSJcufOrVy5cikiIkLvvPOOgoKCHJ1tAEAOs3//fu3evVuFChXSY489JunmHrQLFy6UxWJRq1atCPwBABxm+/bt+u9//ys/Pz81b95cefPmVYMGDSTdnBnx3XffafXq1Xr55ZdVp04dJSQk6NKlS4qPj1fZsmVZhhoAkKnsAb+zZ8/q448/VvHixdWkSRPVrFnTOCcuLk5Xr17V/PnzdfHiRSUlJalQoUI6deqURo4cqdKlSzuwBAAeVgT9gAxg7wy9evWqpk2bpho1aqhhw4bauHGjtmzZooCAAHXr1k2FChXSpUuXtHv3bnl5ealChQoqVKiQo7MPAMhhLl26pA8++EBXr15VmzZt1KtXL+OYPfCXkpKixo0bGx2sAABkFYvFopkzZ2rz5s3y8PBQkSJFdOXKFXl6eqpw4cJq3bq1TCaTDhw4oCVLluitt95S1apV09wj9cx2AAAyw/nz5/X222+rZcuWatOmjfz9/dM9Lzk5WdeuXdOvv/6q3377TYmJiZo0adIdzweAB0HQD8ggJ06c0ObNmxUREaEBAwbIx8dHkrRp0yb9+uuvCggIUMeOHVWyZEkH5xQAkNPYB6eknrG3f/9+zZs3TyaTSb169VLFihWN80+dOqXp06erdOnS6tu3r4NyDQDIyaKiorR06VKFh4erWLFiateunXbu3Kl9+/bpr7/+MmZLHDt2TFarVe+9956Cg4MdnW0AQA6RlJSkL774Qnnz5tWzzz5rpFssFkVHRysxMVFFihSRlHbllHPnzil37tzy9fV1RLYB5ACujs4A8LDYv3+/wsLC5OLiori4OCPo17hxY0nShg0bNH/+fPXq1UvFihVzZFYBADlI6pkOSUlJcnNzk8lkUuXKlWW1WrVw4UL98ssvMpvNKl++vCQpODhYgwYNUuHChR2ZdQBADubr66sOHTpoyZIl+vPPP+Xv7682bdqoRYsWOn/+vKKiorRx40ZZLBZdv36dwZUAgCzl4uKi6OhoVahQwUjbt2+f9u3bpw0bNihPnjwqWLCg3n77bZlMJmPJafoEAWQ2ZvoBGWj16tVauXKlqlSpoo4dO6pAgQLGsbVr12rnzp0aOHAg0/cBAFkidcBv+fLl+vPPP5WSkiI/Pz/169dPXl5e2rdvnxYuXKh8+fLpscceU7ly5e54DwAAslpkZKSWLFmiEydOqGbNmurSpYtx7NaZ7OzhBwDIKnFxcRo5cqTKlSun9u3ba8eOHdq0aZOKFy+u8uXLK1euXFq6dKlq1qypPn36ODq7AHIQgn7AfbA3KhMTE2Wz2ZQrVy7j2NKlS/Xbb7+pQoUKatu2rfLnz28ci4uLk5eXlyOyDADIwebNm6e1a9eqXbt2iomJ0YEDB3Tjxg29/fbbKlKkiPbs2aMlS5bI3d1dTz31lAIDAx2dZQAADFFRUVq8eLFOnjypWrVqqVOnTpKUJsjHIBUAQFY7cOCAJkyYIH9/f8XGxqp3796qVKmSChUqJIvFog8++EC+vr4aPHiwo7MKIAdheU/gHtkDfnv27NG6dev0999/q3bt2qpQoYKqV6+uTp06yWazafv27XJxcVGrVq0UEBAgSQT8AABZ7vLly9qxY4cGDRqkmjVrSpKio6M1efJkvffee/rss89UvXp1paSkaO/evSpRooSDcwwAQFq+vr7q0qWLFi9erN9//10JCQnq0aNHmll9BPwAAFktNDRUkydPVkxMjPLnz29s9SPdrJc8PT2VL18+2efc2Pf1A4DMxLdi4B6ZTCbt3r1bn376qYoXL6727dvr9OnT+vHHH7V161ZJUufOnVWvXj399ttvWr9+vVJSUhycawBATvDOO+9o586dadLi4uIUGRlpDECxWq3KmzevBgwYIElat26dJKlWrVoaMGCAzGazrFZr1mYcAIB/YQ/8FSxYUNHR0WLRIgBAdpA/f34FBwenCfhZLBb98MMPOnr0qBo3biyTyUTAD0CWYaYfcI8uXLigefPmqU+fPmrZsqWSkpK0YMEC5c6dW6tWrZLZbFa9evXUsWNHubi4qHbt2uwrAQDIEg0bNlS1atXSpBUvXlx+fn7atm2bSpQoYcyE8PHxkYeHh+Li4m67D7MlAADZka+vr/r27SsvL680e/kBAJBdbN68WSdPnlRYWJhGjBihwoULOzpLAHIYenSAO7jTyFF3d3dVr15ddevW1bVr1/Tqq6+qTp06eumllxQdHa2ffvpJ69evlyS1a9fOmFkBAEBma9mypdzc3LR48WKtXr3aSK9Zs6YOHz6stWvXGmmurq7y8PCQh4eHI7IKAMB9yZ07tzErnYAfACA7uXDhgjZs2KBr165p9OjRCgoKcnSWAORAzPQD0mHfBP769euKjo6W1Wo19jjy9/dX+/btlTt3bs2dO1dlypRRr1695OnpqTJlyujIkSPavXu36tSpI09PTxqiAIBMZ6+37OLi4rRgwQK5ubmpefPmatu2raKiorRmzRrt2bNHISEh2rt3rxISEtSqVSsH5hwAgPvDrHQAQHZTpEgRDRs2TG5ubvLy8nJ0dgDkUAT9gFvYO07Pnj2rKVOmKCYmRpJUuXJlPf/88zKbzcY63RcuXFBwcLA8PT0lSZ6enmrXrp3q169P5Q4AyBKpA35Xr16Vv7+/evfuLS8vL02dOlVWq1UtW7bUU089pV27diksLEwHDx5UwYIFNWrUKLm4uNwWNAQAAAAA3Lu8efM6OgsAcjiCfkAq9k7PM2fOaNSoUWrZsqVq1Kih7du3a926dQoKClKrVq1ktVqVnJys/Pnz68KFC1q7dq0uXbqk33//XU888YR8fX0dXRQAQA6QOli3aNEiXbhwQc2aNVNoaKi6dOkiq9Wqb7/9VtLNpT9btGihFi1ayGKxyNX15tfAlJQU9p4FAAAAAAB4CBD0A1Ixm826dOmSRo4cqfbt26tHjx6SpAIFCmjdunW6dOmScZ6Hh4caNmyolStX6qeffpK7u7vefPNN+fv7O7IIAIAcxB7w+/7777VhwwY9//zzKlasmHH8iSeekNVq1fTp0+Xi4qKmTZvKZDIZAT+bzUbADwAAAAAA4CFB0A9IxWq1av369fL09FSePHmM9G3btiklJUWXLl3SypUrlTt3btWtW1dVqlRRxYoVFRsbm2bZTwAAssrevXsVFhamUaNGKTAwUFarVdHR0Tp//rxCQkLUrVs3SdJ///tf+fj4qGbNmsa17DsLAAAAAADw8CDoB6RiNpvVpk0bJSUlKSwsTG5uboqPj9eyZcvUuXNnBQYGauvWrbp27ZrmzZunIkWK6LHHHkvTgQoAQGay2WxpgnUpKSny9vaWv7+/zp8/r61bt2rz5s2yWq3KkyePJkyYoG7duikgIEDVqlVzYM4BAAAAAACQmUw2m83m6EwA2U1UVJQWL16s/fv36/Llyxo5cqRCQ0Ml/W/vo9WrV+vUqVPq0KFDmqXUAADILKn38IuKipKPj48OHz6sGTNmKE+ePDp37pyqVaum0qVLq0iRIpo8ebIGDRqkqlWrGvdgDz8AAAAAAICHEzP9gHT4+vqqS5cuMplMOnTokE6fPm0E/exx8jZt2tBxCgDIMqkDfj/++KPCw8PVunVrVaxYUY8//rguXryo1q1bq0KFCvLx8VFERITy5s0rDw+PNPeh3gIAAAAAAHg4EfQD7sDX11edO3eWzWbT9u3blZKSok6dOsnV1dUI9tFxCgDIKvaA3/fff69Nmzapb9++8vX1lSTVrVvXOC8lJUXXr1/X1KlTlStXLpUtW9YR2QUAAAAAAEAWY3lP4F/Yl/o8ffq0KlWqpG7dujk6SwCAHGr37t369ttv9eabbyowMFCSFBMTo6tXr6pw4cLy9PTUsmXLdODAAV2/fl3jx4+Xq6trmlmCAAAAAAAAeDgx0w/4F/alPufOnaujR4/q+vXrypMnj6OzBQDIgSwWiwoUKKCAgACdO3dO27dv14YNG+Tm5qZ8+fLpzTffVKFChWS1WtW+fXu5uLiwFDUAAAAAAEAOwUw/4C5FRUVJkrGUGgAAmSm92Xk7d+7UtGnTVKpUKZ08eVKVKlVSSEiIvL29NW/ePA0bNkylS5f+x3sAAAAAAADg4cRMP+AuEewDAGSV1MG6S5cu6caNGypatKhq164tk8mko0ePqn79+qpYsaJ8fX0VEREhT09PpaSkpLkPAT8AAAAAAICcg6AfAABANmKz2Yxg3bx587R7925FRUWpUKFCKlu2rB5//HHVqlVL0s3gYFxcnKZOnSovLy+VKVPGkVkHAAAAAACAAzH8GwAAIBsxmUySpGXLlmn9+vV6+umnNW3aNOXLl09btmzR+fPnJUnJyclasmSJPv30U0VFRWnUqFEym82yWq2OzD4AAAAAAAAchJl+AAAA2YDNZpPJZJLValViYqL+/PNP9ejRQ5UrV9a+ffu0b98+9enTRyEhIbJYLHJzc1PRokWVnJysrl27ysXFRSkpKXJxcXF0UQAAAAAAAOAABP0AAAAcLPUefgkJCcqVK5eSk5NVvnx57du3T5988ol69+6tFi1aKDk5WZs2bVJgYKDq1KmjOnXqGPcg4AcAAAAAAJBzEfQDAABwoNR7+P33v/9VZGSkhg0bJpvNpsmTJ+vixYvq27evmjVrJkmKjo7Wtm3b5ObmptKlSxv3sd8DAAAAAAAAORO9QwAAAA5k38MvIiJC58+fV7t27ZQrVy717dtXcXFxKlq0qJo1ayaLxaK4uDh98803slqtatiwoYNzDgAAAAAAgOzEZLPZbI7OBAAAQE62YsUK7d27V3ny5NELL7wgd3d3JSUlKSwsTDNmzFChQoXk5eUli8WixMRETZw4Ua6urmmWBQUAAAAAAEDOxvKeAAAAWSx1sC4xMVEWi0Vnz56Vn5+f3N3dJUnu7u5q1KiRypUrp7Vr18rNzU3+/v5q3ry5zGazUlJS2MMPAAAAAAAABmb6AQAAOEhiYqI8PDwUFRWl7du3a9asWWrbtq169+4tSXcM7DHDDwAAAAAAALeitwgAACCLWK1W4+ewsDC98MILio6Olq+vr+rVq6fevXtr7dq1mj9/viTJxcVFKSkpso/Rsv9PwA8AAAAAAAC3oscIAAAgC6SenRcWFqYrV64oNjZW77//vqKiouTj46OGDRuqW7duWrNmjRYsWCDpZuDPZDJJkvE/AAAAAAAAcCuCfgAAAFnAHvD7/vvv9f3338tkMqlZs2aKjY3V6NGjjcBfgwYN1LVrVy1evFhr1651cK4BAAAAAADgLNjTDwAAIIv8/fffevfdd/X888+revXqkqTTp09r6tSpiouL09ixY+Xr66uoqCgdPnxYtWvXTndPPwAAAAAAAOBWzPQDAADIIvHx8YqLi1OhQoWMtJIlS+rpp59WZGSkPvjgA12/fl2+vr5GwC8lJcWBOQYAAAAAAICzIOgHAACQCdJbTCEwMFD58+fX5s2bjTSz2awSJUqoePHiunTpkkaNGiWLxWLM8GOmHwAAAAAAAO4GQT8AAIAMZrVaZTKZJEmxsbGKiopScnKy3N3dVbt2bR04cEBr1qwxzjeZTMqfP79efPFFubi4aOnSpQ7KOQAAAAAAAJyVq6MzAAAA8DCx2Wwym2+Oq1q4cKGOHDmiU6dOqVatWqpSpYoef/xxRUREaMOGDfrzzz9VoUIFhYWFSZJCQ0Pl7e2tiIgIRxYBAAAAAAAAToiZfgAAABnIPsPvhx9+0OrVq/Xoo49q+PDhunr1qmbPnq3ExET17t1bzZo1U0xMjMLCwpQ3b16NGjVK7u7u8vb2lq+vr2w2W7pLhAIAAAAAAADpYaYfAABABrt69ar++OMPvfTSS6pSpYoOHDig48eP65lnnlGePHkkSS1btlTLli2VlJQkd3d3SdL333+v48ePq0+fPkbwEAAAAAAAALgbBP0AAAAymNls1o0bN1SyZEnt3LlTX3zxhZ566ik1a9ZMSUlJCgsLU+nSpVWsWDG5u7vr7NmzWrFihQ4dOqSRI0eqcOHCji4CAAAAAAAAnAxBPwAAgAdw9uxZxcbGymazqWLFipIki8UiFxcXrVixQuvWrVOvXr3UqlUrSdKFCxe0c+dOFShQQMWKFZMklShRQvXq1VPXrl1VoEABh5UFAAAAAAAAzougHwAAwH3auHGjlixZooSEBJnNZlWqVEkvvPCCAgICVL9+fS1YsEBt2rRR69atJUkJCQmaP3++UlJSVL58eUmS1WqV2WxW1apVHVgSAAAAAAAAODuCfgAAAPfh119/1YwZMzRw4ECVKFFC69at09q1a1W5cmU1aNBAbdu2VUREhFavXq2UlBRZLBZdvnxZMTEx+uCDD2Q2m42AHwAAAAAAAPCgCPoBAADco507d+rbb7/V8OHDVbNmTUlS48aNtWbNGkVEREiSPDw89Nxzz6lYsWI6ePCgzGazypcvr8cff1wuLi5KSUmRi4uLI4sBAAAAAACAhwhBPwAAgHuQnJysP/74QwEBAQoPDzfSly1bJkk6deqUvv/+e/n4+KhZs2Zq06aN2rRpk+YeVquVgB8AAAAAAAAylMlms9kcnQkAAABnEhkZqZ9++knHjx9XvXr1dPToUV24cEHt27dXwYIFtXnzZp09e1ZXrlxRrly59Nxzz6lSpUqOzjYAAAAAAAAeYgT9AAAA7kNUVJQWL16s33//XfHx8froo4/k7+8vScZefZs3b1Z4eLg6d+7MzD4AAAAAAABkKoJ+AAAA9ykqKkpLlizR0aNHVa9ePXXo0EGSZLFY5OqadhV1eyAQAAAAAAAAyAwE/QAAAB6AfcbfyZMnVatWLXXq1EkSQT4AAAAAAABkLYJ+AAAAD8ge+Dt9+rQqVqyoHj16ODpLAAAAAAAAyGEYfg4AAPCAfH191aVLFxUsWFDR0dFiTBUAAAAAAACyGjP9AAAAMkhsbKy8vLxkNptls9lkMpkcnSUAAAAAAADkEAT9AAAAMhj7+QEAAAAAACCrEfQDAAAAAAAAAAAAnBxD0AEAAAAAAAAAAAAnR9APAAAAAAAAAAAAcHIE/QAAAAAAAAAAAAAnR9APAAAAAAAAAAAAcHIE/QAAAAAAAAAAAAAnR9APAAAAAAAAAAAAcHIE/QAAAAAAAAAAAAAnR9APAAAAAAAAAAAAcHIE/QAAAAAAAAAAAAAnR9APAAAAAAAAAAAAcHIE/QAAAAAAAAAAAAAnR9APAAAAAAAAAAAAcHIE/QAAAAAAAAAAAAAnR9APAAAAAAAAAAAAcHIE/QAAAAAAAAAAAAAnR9APAAAAAAAAAAAAcHIE/QAAAAAAAAAAAAAnR9APAAAAAAAAAAAAcHIE/QAAAAAAAAAAAAAnR9APAAAAAAAAAAAAcHIE/QAAAAAAAAAAAAAnR9APAAAAAAAAAAAAcHIE/QAAAAAAAAAAAAAnR9APAAAAAAAAAAAAcHIE/QAAAAAAAAAAAAAnR9APAAAAAAAAAAAAcHIE/QAAAAAAAAAAAAAnR9APAAAAAAAAAAAAcHIE/QAAAAAAAAAAAAAnR9APAAAAAAAAAAAAcHIE/QAAAAAAAAAAAAAnR9APAAAAAAAAAAAAcHIE/QAAAAAAAAAAAAAnR9APAAAAAAAAAAAAcHIE/QAAAAAAAAAAAAAnR9APAAAAAAAAAAAAcHIE/QAAAAAAAAAAAAAnR9APAAAAAAAAAAAAcHIE/QAAAAAAAAAgG9m4caNMJpPx78yZM8axvn37GulNmjRxWB4BANkPQT8AgFMKDQ1N0wAqXLiwLBaLo7MFAAAAAHCAW4Nk9n8uLi7y9fVV9erV9cYbb+jSpUuOzioAAJmGoB8AwOns2rVLBw8eTJN26dIlrV692kE5AgAAAABkR1arVdHR0dq7d68+/PBDVatWTX///bejswUAQKYg6AcAcDozZ868p3RnExMT4+gsAAAAAIBT6969uyZNmqRRo0apUqVKRvqlS5f06aefOjBnAABkHoJ+AACnkpiYqHnz5hmPQ0JCjJ+XL1+ua9eupXvdkSNHNHjwYFWoUEG5c+eWl5eXgoOD1aNHD+3evTvNuTabTYsWLVKHDh1UtGhReXh4yN/fX9WqVdMrr7yipKQkSdKZM2fSLBuzcePGNPdp0qSJcaxv375GenrXTZs2TdWrV5enp6caNWokSTp9+rSGDRumhg0bqnjx4vL29paHh4eKFi2q9u3ba/ny5Xf8Pe3atUvPPPOMSpcuLS8vL+XOnVshISF65plndPLkSVmtVgUHBxt5GDFixG33GD58uHG8QoUKd3wuAAAAAMhu2rRpo9dee03jxo3Tli1b5O7ubhw7dOjQbedv2bJFPXr0UIkSJeTh4SEfHx/VrVtXX375pZKTk9N9jmvXrmn8+PGqU6eO/Pz8jPZa69attWDBAuO8iIgIvf7662revLkCAwOVJ08eubu7q2DBgmrZsqW+++472Wy2jP8lAAByHFdHZwAAgHvx008/KTIy0ng8a9YsNWrUSMnJyUpKStLcuXP14osvprlm2rRpeuGFF4xgnd3p06d1+vRp1alTRzVr1pQkJSQk6IknntDKlSvTnJuUlKTIyEjt27dP77zzTpoG44N65513tGXLltvSDx48qM8///y29AsXLujChQtasWKFxo4dq3feeSfN8XHjxmnMmDG3NRqPHz+u48ePq2PHjipVqpReeOEFDR8+XNLN3+P48ePl4uJinL9w4ULj52eeeeaByggAAAAAjpI3b17lzp1bERERkqT8+fOnOT5y5EhNnDgxTVpSUpK2b9+u7du3a8GCBVq1apW8vb2N47t27VKHDh1u2yPQ3l7z9PRU9+7djbRJkybdlq/w8HCtXbtWa9eu1YYNGzR9+vQMKS8AIOci6AcAcCqpl/CsXr266tSpoxYtWmjVqlXG8dRBv+3bt2vAgAGyWq2SJFdXV3Xt2lXlypXTuXPnbtsH8NVXX00T8CtevLg6d+6svHnz6uDBg1qxYkWGl2nLli0qWbKkHn/8cXl5eSk8PNzIa9WqVVWzZk0VKFBAPj4+unHjhrZt26YNGzZIksaPH69nn31WRYsWlXQzUDd69Gjj3l5eXurRo4dKliyp06dPp5kd+Oyzz2r06NGKi4vThQsXtHLlSnXo0EGStHPnTv31119GPp566qkMLzcAAAAAZLaYmBjNnDnTCPhJUrdu3Yyf58+fnybg17p1a9WvX1+XL1/WrFmzFBsbqy1btujll1/W1KlTJUnXr1+/LeDXrFkz1a9fXzExMdq6dWuaPJjNZpUvX161a9dWoUKF5Ovrq4SEBO3du1fLly+XzWbTjBkzNHDgQNWuXTuzfhUAgByAoB8AwGlcvHhRa9asMR737NnT+N8e9NuzZ4/+/PNPY8+GSZMmGQE/s9ms9evXq2HDhsY9kpKSjCBbZGSk0YiTpGrVqmnz5s3KnTu3kfb333+nGd2ZEYKCgrRnzx75+vqmSW/Tpo3atGmjY8eOae/evbpy5Yrc3Nz02GOPaceOHYqLi5PFYtH69euNoNz7779vXO/t7a09e/akWQL1xo0bunHjhiTJz89PvXr10jfffCNJ+vbbb42g3w8//GBc8+ijj6pQoUIZWmYAAAAAyEzPPPPMbSuWeHl5aezYsUa7R5I+/PBD4+c+ffpo1qxZxuPGjRsbAcIZM2bo/fffl7+/v2bOnJkm4DdhwoTbtkw4deqU8XOFChV06NAhnT17Vrt27dKlS5fk5uamhg0b6vfff9f58+clSb/88gtBPwDAAyHoBwBwGt99951SUlIkSSaTyVgqpVOnTsqVK5cSEhIk3WyMffLJJ5KUZoRl69at0wT8JMnd3V3FihWTdHNWoMViMY69+eabaQJ+0s2Zfxlt8ODBtwX8pJt7//Xq1UthYWH/eP25c+ckSXFxcdq7d6+R3qdPnzQBP+lmIDB10PLFF180gn4///yzLly4oCJFimjRokXGOSztCQAAAOBh0LlzZw0cONB4HBcXp3379hmPZ8+erdmzZ6d7rcVi0c6dO9WmTZs07cw8efLojTfeuO384OBg4+dr167p6aefvm0biVvZ23YAANwvs6MzAADA3Uq9tGe9evWMAFyePHnUtm1b49icOXOM4F3qJVyCgoL+8f6pz72b82916x56iYmJd3VduXLl0k3v1KnTvwb8Uj9PZGRkmjzcTf4rVaqkJk2aSJJSUlI0Y8YM7dixw1jas0CBAmrXrt2/3gcAAAAAspPu3btr4sSJadozc+bMUceOHY12061tqH9z5coVSWnbjsWLF0+zN3p6nn322X8N+El334YEAOBOmOkHAHAKO3bs0OHDh43H27Ztk8lkSvfc8PBw/fzzz+rQoYP8/f2N5TtPnz79j8/h7++f5vHp06dVq1atO55vNqcdOxMfH2/8bLVadfLkyX98Prv0lgs9evSo/vjjD+Pxk08+qQ8//FBFihSRyWRSQECA0eC08/Pzk8lkMhqt/1ZeuxdffFEbN26UJE2fPl3Xrl0zjvXu3Vtubm53dR8AAAAAyC7atGmjvn37SpIGDhyo//73v5Kk9evX6/vvv9dTTz1124orHTp0uG11mNSqV68uKW3b8e+//1ZKSsodA383btxIszd88+bNNXXqVJUsWVIuLi6qXbu2du3adT9FBADgNsz0AwA4hdSz/O7l/AYNGhhpa9as0bZt29KcZ7FYjP0T6tSpI1fX/42H+eCDDxQXF5fm/AsXLig5OVmSbmsgbt++3fj5m2++uS0ody9SB94k6YknnlDRokVlMpm0cePGdO/t5eWlatWqGY+/++47nThxIs058fHxRhDUrmPHjipRooSkm/tOTJkyxTjWr1+/+y4DAAAAAGQH77//vvLmzWs8HjdunFJS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wIED1aNHDyUlJWnGjBm5hne5//771bZtW7Vu3ZoACId36dIl1ahRQ8HBwfL09JSnp6eee+451alTR19//bVMJpMqV66sOnXqqFGjRjp16pQ+//xzbdq0Sc8++ywBEHe8n3/+WX/88Yf18fr16/Xf//5X0dHRSk9Pl9FoVJ8+fXT+/HktWrTIup2/v7/KlSungIAAGQwGmc1mwh8citls1oYNG5ScnKzly5drwYIFknIP9XLt4yeeeEL9+vUjAALIhbwH3BoyH3BzZD6g4Mh7sGd0+pVwFotFBoNBR44c0YIFCzR//nxFRETIyclJffr0UZs2bXTixAnNnDkzVxAcMWKEAgMDbVg5YB9SUlJ05swZSVcOxDmT6t5zzz1KS0tTTEyMdducK9ZcXV01fvx4BQcH26JkoNicPXtWycnJqlWrlqS/f3RMS0vThAkT9N1332n37t3y9vbW0KFDdeLEiRvOecLwLnA0RqNR1atXV9myZdWhQwdt2rTppkEwOztbkjRy5EiOLwCsyHvArSPzATdG5gMKh7wHe8acfneAHTt26KuvvlKNGjWUmZmp48ePq2vXrnrggQfk4uKiRYsWae/evQoMDNTDDz/M5KBwWHmNK3/69Gl99NFHCg0N1f33329d/scff2jq1Kl69dVXVb58+VzPyRnOAnAkW7dulY+Pjxo3bixJWrdunY4cOaLNmzerW7duMhgM2rdvn0aMGKFWrVrZuFqg+F09B8rVwxqNGzdOpUuXVnBwsFavXq3u3btr4MCBkvI+LgHAtch7QP6R+YDCI/MBN0beQ0nCGUwJFxMTo59++kn33XefunfvLrPZrH379umjjz6SwWDQI488on79+lnDYUZGBiEQDufo0aMKDg6Wq6vrdQfcwMBA3X333dq9e7emTZumYcOGKTExUYsWLVLp0qVVrly56/ZH+IMjsVgsSkhI0OLFi+Xv76+srCyFhoaqS5cu6tSpk+6++26tXr1aqampOn/+vDZv3kwAhMO5dhL3q4c16tWrl/bs2aNmzZopKytLq1atksFg0IABA66b8wEArkXeA/KHzAcUHpkPuDnyHkoazmJKkLVr16pKlSqqVauWdW6G9PR0OTk5qX79+tbtmjRpoueff16TJk1S8+bN1bRpUw0bNkwpKSny8fGxVfmATcTExGjatGkqW7as/vOf/8jFxcV6wLVY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fOXaCxcu6J133lGHDh1Urlw5ubq6ysvLSw0aNNDDDz+slStXymKxFPj9AADsk7OtCwAAoDjMmjVLn332WZHt79SpU2rfvr3OnDmTa3lsbKxiY2P1xx9/aNGiRWrcuLEqV65cZK8LAAAAAI7EbDYrISFBe/bs0Z49e/TTTz8pIiLiupxlMpn0wgsv6PPPP79uHzExMYqJidGGDRs0adIkzZgxQ927d79uu8uXL2v06NFatGjRdesuXbqkrVu3auvWrdq0aVOBLx79+eefZTKZci1bunTp/7F33/FRVPv/x9+72XRIo0MuBAhICb0poFIUUQEBpanXgiIgWFARRbmAioodlYvX61cBlSaCVAHpvQtIB6VITUIq6cnu7w9+mZslCSRhk90lr+fjkcdj58yZ2TObOTv7mc/MGcXExCgkJKRQ6yqof//733r55ZeVmppqV56RkaGDBw/q4MGD+vbbb3XixAmFhYUVSxsAACWLpB8AwK3169dPLVu2zFUeERGRq6xSpUpq0aKFgoKCNGPGjBt631GjRhkJP4vFoj59+qhBgway2Wz666+/tHnzZh09evSG3qM4ZGVlKS0tTX5+fs5uCgAAAADkKzvWS0hI0C+//KI//vhD0pU75j799FN98skndvWfe+45ffXVV8Z01apV1bdvX5UvX15//PGH5s6dq6ysLEVHR6t79+5avXq12rVrZ9RPSkpSly5dtHPnTqOscuXK6tmzp6pXr67ExETt3r1bq1atKtL2TJs2LVdZenq6ZsyYoeHDhxdpndfywQcfaNSoUca0h4eH7r//frVo0UImk0nHjx/X8uXLdfHiRYe/NwDAeUj6AQDcWteuXfMc6uRq7733nj777DNJV4aNudGk34oVK4zXb775psaOHZurzqFDh+Tr65urPDMzU9OnT9esWbO0d+9excbGKjAwULVr19a9996ba11Hjx7Vp59+qtWrVxvDhYaGhqpjx44aMWKE6tWrZ1f/iSeeMALKO++8U9OnT9cbb7yhFStWKCoqSvPmzVPPnj0lXRnqZdKkSVq6dKn+/PNPZWRkKDQ0VPfcc49GjRql6tWr39DnBAAAAABFkTPWe/nll1WxYkWlp6dLkg4ePGhXd/PmzXYJv+bNm2vNmjUKCAgwylavXq27775bVqtV6enpGjx4sPbt2yez+crTj9555x27hN8DDzygGTNm5Lpg8ty5c1q0aFGhtmXHjh06cOCAMV23bl3jItGpU6c6POl38OBBjR492piuWLGili1bpmbNmtnVy8jI0NSpU7koFABuIjzTDwBQKuSVfLsROYdlOXz4sNLS0nLVqV+/fq4hUmJiYtS2bVs99dRT+u233xQZGamMjAxFR0dr27Zt+vTTT+3q//TTT2rSpIm++uorHT16VCkpKUpJSdGxY8f09ddfq2nTppo1a1a+7Tx37pzatGmjH374QZGRkXbPatiyZYsiIiL03nvvae/evbp8+bLS0tL0559/6t///rcaN26sDRs2FPETAgAAAADHCAwMVJkyZYzp8uXL283/+uuv7aY/+OADu4SfJHXq1En9+vUzpg8cOGDEOxkZGZo8ebIxr3Llyvrxxx/zTIZVrVpVgwcPLlT7v/vuO+N1aGioPvjgA2N6165dxl2MjvLFF18oKyvLmJ4yZUquhJ8keXp6atCgQapYsaJD3x8A4Dzc6QcAcGvLli1TdHR0rvJ+/foV67P0mjdvrnXr1kmSZs2apaVLl+q2225T8+bN1aZNG3Xq1Elly5bNtdw///lP7dixw5iuX7++7rvvPnl7e+v333/Xtm3bjHnHjx/XP//5TyOhWK5cOT3++OMymUyaNm2aoqOjlZaWpscff1wtWrRQnTp1cr3fsWPHJEm9e/dWkyZNdOrUKQUGBiohIUE9e/Y0PrsaNWqoX79+8vX11dy5c3XgwAHFx8frwQcf1LFjxxQYGOi4Dw8AAAAACighIUFTp05VTEyMUda3b1+7OjkvVgwODlbnzp3zXFe/fv00c+ZMu+XuvPNO7dixQ4mJiXb1/P39HdL+tLQ0uws1+/btq3vvvVdBQUGKi4uTdOVuv48//tgh7yfJbgjS4OBgY6QXAMDNj6QfAMCtzZ49W7Nnz85V3rJly2JN+n3wwQe6/fbbjeFlEhIStHz5ci1fvlyS5OPjo2eeeUbvvfeecXXoH3/8oaVLlxrruO+++/TLL7/I09PTKPvrr7+M119++aWR8DObzVq7dq3xrMInnnhCTZo0MYammTx5sjF86dU+++wzvfDCC3Zln3/+uSIjIyVdCQJ3795tPDx+5MiRqlmzpqKiohQVFaVp06bp+eefL/JnBQAAAACF9eSTT+rJJ5+0K/Pz89P48ePVo0cPu/Lz588br2vUqJHvOq+el73c2bNn7cqvfoTCjViwYIFiY2ON6QEDBsjLy0u9e/fWt99+K0n68ccfNXHiRFksjjlVm3N76tatawxhCgC4+fGNDwBAEbRu3Vrbtm3TAw88YJe0y5aamqrPP/9czz77rFG2ceNGuzpjx47NtWytWrWM11u2bDFet2jRwkj4SVJERIRatGiRZ92cgoODNWzYsFzlmzZtMl7HxsaqXLlyMplMMplMKlOmjKKiooz5mzdvznPdAAAAAFCSevXqpSFDhji7GYUydepU43V4eLhatmwpSerfv79RfvHiRbsLRAEAKCqSfgAAt/bdd9/JZrPl+uvQoUOxv3fTpk31yy+/KC4uTmvWrNF7772X632nTZtmDEOTczgaSapZs+Y115+zfqVKlXLNz1mW88rRnGrXrp3n1aJXt+VaciYAAQAAAKAk9OvXT++++666detmlP3444964IEH7J5VLklVqlQxXp8+fTrfdZ46dSrP5apVq2ZXfvjw4SK3O6dz585pxYoVxnTOZwp26tTJ7ll6OZODkuziuNTU1FzrTklJsZv28vIyXufcnqNHj+b6vAAANy+SfgAA3CA/Pz916NBBr732mtasWaO33nrLbn72c/Wyh8/MduLEiWuuN2f9ixcv5pqfsyw4ODjPdeT3HIqc665SpYo+/PDDfP+eeeaZa7YTAAAAAByta9euev3117Vo0SINHjzYKF+9erV++OEHu7q333678TomJkarV6/Oc51z5szJc7lWrVrZPZN9zpw5Sk5OvuFt+P7775WVlWVMT5gwwRhhxWKxGI9ckKQlS5bo0qVLxnSFChWM13nFjjkfDXF1/ZzPNIyNjdWCBQtubEMAAG6DpB8AAEXw3HPPae3atXleMVmmTBm76aCgIElS+/bt7crffvttZWZm2pXlvPK0bdu2xutdu3bpwIEDxvT+/fu1a9euPOsWRM76UVFR6tKli1555RW7v5dffllNmzZV69atC7VuAAAAAHCk999/X4GBgcb0W2+9ZZdMu/pCxVGjRikxMdGubO3atXbPg2/QoIGR9PP09LR7NMP58+f1z3/+M9fddNKVu/e+/vrrArX76rv3riU9PV0//vijMd2mTRvj9fbt2/Xbb78Z06dOndL3339vTJcrV07h4eHG9PDhw+Xh4WFMDx06VHv37s31nhkZGfrmm2/sko8AAPdmsnF/NwDAjaxdu1YdO3Y0pr/77js98cQT111uxYoVxrAqf//9t90Vnn379tU//vEPSVKXLl3UpUuX664vLCxMp06dUtWqVXXnnXeqTp068vLy0pEjRzR79mylp6dLujKE559//imTySRJuv/+++2e1dCgQQPdd9998vHx0YEDB7R+/XpFR0dLko4fP66IiAilpaVJuhLIPf744zKZTJo2bZpRz8vLSwcOHDCCvCeeeELTpk2TJN15551au3ZtrvbHx8crPDzcWEeZMmXUp08fhYeHKy0tTUeOHNHatWt18eJFrVmzpkSGSwUAAABQel0v1nvjjTf07rvvGtM//vijHn74YWN6yJAh+s9//mNMV6tWTX379lX58uX1xx9/aO7cucZFl15eXlq9erXatWtn1L98+bLuvPNO7d692yirUqWKevXqpdDQUCUmJmr37t1atWqV2rVrl2ecldPWrVt12223GdNt2rRRWFhYrnqrVq0y4rKmTZvq999/lyT99ttvdrGp2WxWRESE/Pz8tG/fPrs7Ed944w298847dut97733NHr0aGPaYrGoW7duatasmUwmk44fP67ly5fr4sWLOnHiRJ5tAwC4IRsAAG5kzZo1NknG33fffVeg5caOHWu3XH5/Y8eOLdD6atSocd11+fj42FatWmW3XHR0tK1Vq1b5LhMYGGhXf86cOTYfH59863t7e9tmzpxpt8zjjz9uzL/zzjvz3YZNmzbZypcvf93tWLNmTYE+EwAAAAAoquvFepGRkTY/Pz9jfsOGDW1Wq9WYn5GRYRs+fPh145ty5crZli9fnmcboqOjbd26dbvuOq4VZ2UbPHiwUd9sNttOnTqVZ70xY8bYrXvv3r3GvH/961/Xbcs999xjS0tLy3PdkyZNsnl7e193HSdOnLju9gAA3APDewIAUATLly/Xl19+qd69eysiIkIVK1aUxWKRv7+/GjRooGHDhumPP/5Qp06d7JYrV66cNm3apG+++UZ33XWXKlSoIIvFouDgYLVo0UIvvviiXf0+ffpoz549GjJkiMLDw+Xj4yMfHx/Vrl1bgwYN0u+//67+/fsXaRvatm2rAwcOaMyYMWrRooUCAgLk4eGhoKAgtWjRQsOHD9dvv/2mO+64o6gfEwAAAAA4RIUKFfT0008b0wcOHND8+fONaYvFoi+++EK///67hg4dqgYNGqhs2bKyWCyq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",
|
||
"text/plain": [
|
||
"<Figure size 1800x1400 with 5 Axes>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
}
|
||
],
|
||
"source": [
|
||
"# Créer la visualisation\n",
|
||
"display_metrics_subplot(results_df)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "u83ZVCLJWxlQ"
|
||
},
|
||
"source": [
|
||
"### Identifier le meilleur modèle selon `Precision`"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "eHr3Z6btZm2E"
|
||
},
|
||
"source": [
|
||
"Le contexte métier est le suivant : on souhaite éviter à tout prix qu'un tweet qui serait reçu négativement soit à tort prédit comme positif. La variable \"precision\" (basée sur la modalité 1 = tweet positif) est donc la plus pertinente."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/"
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 5,
|
||
"status": "ok",
|
||
"timestamp": 1751740006356,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "f07BiYp_ZgDh",
|
||
"outputId": "d30f2935-f9a5-4df3-8fe9-082caf759620"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"\n",
|
||
"Meilleur modèle (selon la précision): Random Forest avec BoW\n",
|
||
"Precision: 0.7798\n",
|
||
"F1 Score: 0.7687\n",
|
||
"ROC AUC: 0.8515\n",
|
||
"Meilleurs paramètres: {'max_depth': 'None', 'min_samples_split': '5', 'n_estimators': '200'}\n",
|
||
"\n",
|
||
"Run ID du meilleur modèle: 7d52e808227f468da7f733265280fc02\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"# Identifier le meilleur modèle selon la précision\n",
|
||
"best_model_row = results_df.loc[results_df['Precision'].idxmax()]\n",
|
||
"best_model_name = best_model_row['Modèle'].replace(\" \", \"_\")\n",
|
||
"best_vectorizer = best_model_row['Vectorisation']\n",
|
||
"\n",
|
||
"print(f\"\\nMeilleur modèle (selon la précision): {best_model_row['Modèle']} avec {best_vectorizer}\")\n",
|
||
"print(f\"Precision: {best_model_row['Precision']:.4f}\")\n",
|
||
"print(f\"F1 Score: {best_model_row['F1 Score']:.4f}\")\n",
|
||
"print(f\"ROC AUC: {best_model_row['ROC AUC']:.4f}\")\n",
|
||
"print(f\"Meilleurs paramètres: {best_model_row['Meilleurs paramètres']}\")\n",
|
||
"print(f\"\\nRun ID du meilleur modèle: {best_model_row['Run ID']}\")\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "lv6SEBguWxlQ"
|
||
},
|
||
"source": [
|
||
"## Charger le meilleur modèle et son vectoriseur depuis MLflow"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"id": "4n3rWdQ4WxlQ"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def load_and_save_best_model(run_id, folder_path=\"content/simple-model/best\"):\n",
|
||
" \"\"\"\n",
|
||
" Charge le meilleur modèle et son vectoriseur depuis MLflow et les sauvegarde localement\n",
|
||
"\n",
|
||
" Parameters:\n",
|
||
" -----------\n",
|
||
" run_id : str\n",
|
||
" L'identifiant du run MLflow contenant le meilleur modèle\n",
|
||
" folder_path : str, optional\n",
|
||
" Le chemin où sauvegarder le modèle et le vectoriseur\n",
|
||
"\n",
|
||
" Returns:\n",
|
||
" --------\n",
|
||
" tuple\n",
|
||
" (modèle chargé, vectoriseur chargé)\n",
|
||
" \"\"\"\n",
|
||
" # Créer le dossier cible s'il n'existe pas\n",
|
||
" try:\n",
|
||
" os.makedirs(folder_path, exist_ok=True)\n",
|
||
" except PermissionError:\n",
|
||
" print(f\"Erreur de permission pour le dossier {folder_path}\")\n",
|
||
" print(\"Tentative avec un dossier temporaire...\")\n",
|
||
" import tempfile\n",
|
||
" temp_dir = tempfile.mkdtemp()\n",
|
||
" print(f\"Utilisation du dossier temporaire : {temp_dir}\")\n",
|
||
" folder_path = temp_dir\n",
|
||
"\n",
|
||
" # Créer un client MLflow\n",
|
||
" client = MlflowClient()\n",
|
||
"\n",
|
||
" print(f\"Chargement du modèle depuis le run {run_id}...\")\n",
|
||
"\n",
|
||
" # Charger le modèle depuis MLflow\n",
|
||
" best_model = mlflow.sklearn.load_model(f\"runs:/{run_id}/model\")\n",
|
||
"\n",
|
||
" print(f\"Modèle chargé avec succès : {type(best_model).__name__}\")\n",
|
||
"\n",
|
||
" # Récupérer les paramètres du run pour vérifier le type de vectoriseur\n",
|
||
" run = client.get_run(run_id)\n",
|
||
" vectorizer_type = run.data.params.get(\"vectorizer_type\", \"\").lower()\n",
|
||
"\n",
|
||
" print(f\"Type de vectoriseur utilisé dans ce run : {vectorizer_type}\")\n",
|
||
"\n",
|
||
" # Récupérer les artefacts du run\n",
|
||
" artifacts = client.list_artifacts(run_id)\n",
|
||
"\n",
|
||
" # Chercher le vectoriseur en privilégiant BoW ou CountVectorizer\n",
|
||
" vectorizer_path = None\n",
|
||
"\n",
|
||
" # Afficher les artefacts disponibles\n",
|
||
" print(\"Artefacts disponibles :\")\n",
|
||
" for artifact in artifacts:\n",
|
||
" print(f\" - {artifact.path}\")\n",
|
||
"\n",
|
||
" # Priorité 1: Chercher un vectoriseur correspondant au type attendu (BoW ou CountVectorizer)\n",
|
||
" for artifact in artifacts:\n",
|
||
" path_lower = artifact.path.lower()\n",
|
||
" if \"vectorizer\" in path_lower and (\"bow\" in path_lower or \"countvectorizer\" in path_lower):\n",
|
||
" vectorizer_path = artifact.path\n",
|
||
" print(f\"Vectoriseur de type BoW/CountVectorizer trouvé : {artifact.path}\")\n",
|
||
" break\n",
|
||
"\n",
|
||
" # Priorité 2: Chercher n'importe quel vectoriseur\n",
|
||
" if not vectorizer_path:\n",
|
||
" for artifact in artifacts:\n",
|
||
" if \"vectorizer\" in artifact.path.lower():\n",
|
||
" vectorizer_path = artifact.path\n",
|
||
" print(f\"Vectoriseur générique trouvé : {artifact.path}\")\n",
|
||
" break\n",
|
||
"\n",
|
||
" # Télécharger et charger le vectoriseur\n",
|
||
" if vectorizer_path:\n",
|
||
" local_path = client.download_artifacts(run_id, vectorizer_path)\n",
|
||
" print(f\"Vectoriseur téléchargé dans : {local_path}\")\n",
|
||
"\n",
|
||
" # Charger le vectoriseur depuis le fichier local\n",
|
||
" with open(local_path, \"rb\") as f:\n",
|
||
" vectorizer = pickle.load(f)\n",
|
||
"\n",
|
||
" print(f\"Vectoriseur chargé avec succès : {type(vectorizer).__name__}\")\n",
|
||
" else:\n",
|
||
" print(\"Aucun fichier vectoriseur trouvé dans les artefacts, tentative de chargement direct...\")\n",
|
||
"\n",
|
||
" # Tenter de charger le vectoriseur directement depuis MLflow\n",
|
||
" try:\n",
|
||
" vectorizer = mlflow.sklearn.load_model(f\"runs:/{run_id}/vectorizer\")\n",
|
||
" print(f\"Vectoriseur chargé directement depuis MLflow : {type(vectorizer).__name__}\")\n",
|
||
" except Exception as e:\n",
|
||
" print(f\"Erreur lors du chargement direct du vectoriseur : {e}\")\n",
|
||
" raise FileNotFoundError(\"Aucun vectoriseur trouvé dans les artefacts du run\")\n",
|
||
"\n",
|
||
" # Sauvegarder le modèle et le vectoriseur localement avec leurs noms spécifiques\n",
|
||
" model_name = type(best_model).__name__\n",
|
||
" vectorizer_name = type(vectorizer).__name__\n",
|
||
" model_save_path = os.path.join(folder_path, f\"{model_name}_model.pkl\")\n",
|
||
" vectorizer_save_path = os.path.join(folder_path, f\"{vectorizer_name}_vectorizer.pkl\")\n",
|
||
"\n",
|
||
" # Sauvegarder le modèle\n",
|
||
" with open(model_save_path, \"wb\") as f:\n",
|
||
" pickle.dump(best_model, f)\n",
|
||
"\n",
|
||
" # Sauvegarder le vectoriseur\n",
|
||
" with open(vectorizer_save_path, \"wb\") as f:\n",
|
||
" pickle.dump(vectorizer, f)\n",
|
||
"\n",
|
||
" print(f\"Modèle et vectoriseur sauvegardés avec succès dans {folder_path}\")\n",
|
||
" print(f\"Chemins des fichiers :\")\n",
|
||
" print(f\" - Modèle : {os.path.abspath(model_save_path)}\")\n",
|
||
" print(f\" - Vectoriseur : {os.path.abspath(vectorizer_save_path)}\")\n",
|
||
"\n",
|
||
" return best_model, vectorizer"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/",
|
||
"height": 494,
|
||
"referenced_widgets": [
|
||
"91504476b2b34a9eb462a30da59a2b19",
|
||
"88ae9e2307804694bc546afb10a362f7",
|
||
"9897c186c00947c280a7eae2fc9a315c",
|
||
"9572601035c34a5eb88f81f6514f872d",
|
||
"8e7128400e4c4eff96b67db314ccaff1",
|
||
"727814859996469da84c76c1a3f15bef",
|
||
"6f6c8fc42ef846a4ac56ffe69bcbbe0f",
|
||
"d5f9951d6c094fcfb03e166af93cfea5",
|
||
"6efad0330efc4790a1eac95fcc96de17",
|
||
"b08959c4edfa465588e03c99d00ad586",
|
||
"8b25983eb05344928535625c726939d8",
|
||
"9ecc775347df487bb63a5e1b2dcc68b7",
|
||
"073bf36ff26d455ca01956dee8d1f1a2",
|
||
"ce14528df1ed4f1abb72ccb9a3c66443",
|
||
"6d712f894c5d4d19a478fa1d1a2b2c62",
|
||
"b0c4432101b948979653cd43bcd3fc4b",
|
||
"8ddc3f81d9094d06b680908375077c62",
|
||
"0e157319861c42049d63bd43b797987e",
|
||
"b7d70f2ce66f40ea8f606256cb654540",
|
||
"d112b0758b97447ab47470e826e94687",
|
||
"6c04e4ad7c5f49c3bd9658ccab659890",
|
||
"acbe4e7d94f04dfe9e797ab54d3102ad",
|
||
"91b8f1667ff54011bd98fd748a0a91c6",
|
||
"3a1f9f8dff4e49fe8a94cd71fcfd3699",
|
||
"6baff5e484754cdaa400a6adeab6958c",
|
||
"2d7826d641614256a9f135515160958c",
|
||
"6050e4a9af9e4c46aa4b38d407b7bab9",
|
||
"0e61cbeda1f4421398f9456ad9e492e0",
|
||
"974da4c9934842ff8286f10a78790410",
|
||
"8beb625411f6459c97243979b6cb3664",
|
||
"b23315ac058141fd9bf35c49276544d0",
|
||
"e7775e44c82b472181e4f8ee6e7d918e",
|
||
"074c0860e74d41ff9562fb72d395b28d"
|
||
]
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 141544,
|
||
"status": "ok",
|
||
"timestamp": 1751740147902,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "aGDo4_KJWxlR",
|
||
"outputId": "0e69eea7-8493-4f2a-cd16-2154f4aee16f"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Charger et sauvegarder le meilleur modèle et son vectoriseur\n",
|
||
"best_model, vectorizer = load_and_save_best_model(run_id=best_model_row['Run ID'])"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "Psby_wbGWxlR"
|
||
},
|
||
"source": [
|
||
"## Fonction de prédiction pour l'API\n",
|
||
"\n",
|
||
"Cette fonction constitue **le cœur de notre solution d'analyse de sentiment**. Elle prend **un tweet en entrée**, le prétraite, le vectorise et utilise notre modèle pour **prédire son sentiment**. Elle retourne un dictionnaire contenant le résultat (positif/négatif), un score de confiance et des métadonnées sur le modèle utilisé, **prêt à être exposé via l'API RESTful**."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"id": "7wl2v3XLWxlR"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def predict_sentiment(text, model=best_model, vect=vectorizer):\n",
|
||
" \"\"\"\n",
|
||
" Fonction qui prend un texte en entrée et retourne la prédiction du sentiment\n",
|
||
" Cette fonction pourra être utilisée dans l'API\n",
|
||
" \"\"\"\n",
|
||
" # Prétraiter le texte\n",
|
||
" processed_text = preprocess_tweet(text)\n",
|
||
"\n",
|
||
" # Vectoriser\n",
|
||
" text_vectorized = vect.transform([processed_text])\n",
|
||
"\n",
|
||
" # Prédire\n",
|
||
" prediction = model.predict(text_vectorized)[0]\n",
|
||
"\n",
|
||
" # Récupérer la probabilité si le modèle le permet\n",
|
||
" if hasattr(model, 'predict_proba'):\n",
|
||
" probas = model.predict_proba(text_vectorized)[0]\n",
|
||
" confidence = probas[1] if prediction == 1 else probas[0]\n",
|
||
" else:\n",
|
||
" # Pour les modèles sans predict_proba, comme SVM\n",
|
||
" decision = model.decision_function(text_vectorized)[0] if hasattr(model, 'decision_function') else 0\n",
|
||
" confidence = abs(decision) / 2 # Normaliser d'une certaine façon\n",
|
||
"\n",
|
||
" return {\n",
|
||
" 'sentiment': 'positif' if prediction == 1 else 'négatif',\n",
|
||
" 'score': float(confidence),\n",
|
||
" 'model': best_model_name,\n",
|
||
" 'vectorizer': best_vectorizer\n",
|
||
" }"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "HUpwhmfIWxlR"
|
||
},
|
||
"source": [
|
||
"## Test de la fonction de prédiction sur quelques exemples\n",
|
||
"\n",
|
||
"Nous avons constitué un **ensemble diversifié de tweets tests** incluant différentes caractéristiques linguistiques des réseaux sociaux pour évaluer notre modèle de détection de sentiment. Les résultats sont présentés dans un **DataFrame** avec des indicateurs visuels (💚/❌) permettant d'identifier rapidement les prédictions et leur **niveau de confiance**, validant ainsi l'efficacité de notre solution pour **anticiper les bad buzz**."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"id": "b86qIdD3WxlR"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Liste améliorée de tweets pour tester le modèle\n",
|
||
"test_tweets_improved = [\n",
|
||
" # Tweets positifs avec différentes caractéristiques\n",
|
||
" \"I absolutely love flying with @AirParadis! Their service is amazing and their staff is so helpful :) #bestairline #travel\",\n",
|
||
" \"Just landed after a wonderful flight... The crew was totally awesome and the food was perfect!!! Can't wait to fly with them again :D\",\n",
|
||
" \"OMG! You really have to try @AirParadis. Best. Flight. Ever. Their new seats are extremely comfortable. http://airparadis.com/newseats #travel #comfort\",\n",
|
||
" \"We had a very pleasant experience with our flight today. The staff completely exceeded our expectations ;) #happy #AirParadis\",\n",
|
||
" \"My first time flying business class and I'm absolutely amazed!!! The service is 100% worth it... @AirParadis never disappoints :)\",\n",
|
||
"\n",
|
||
" # Tweets négatifs avec différentes caractéristiques\n",
|
||
" \"I hate how @AirParadis always delays their flights... This is the third time this month!!! :( #disappointed #travel\",\n",
|
||
" \"The worst flight experience of my life? Definitely today with @AirParadis. Their customer service won't even respond to my complaints... #terrible\",\n",
|
||
" \"Really @AirParadis??? Flight cancelled and no compensation??? That's how you treat your customers? SMH :(\",\n",
|
||
" \"Our baggage was lost and nobody at @AirParadis seems to care! Don't they understand that we can't enjoy our vacation without our stuff??? http://badservice.com/complaint :-(\",\n",
|
||
" \"Food was terrible, seats were uncomfortable, and the staff was not helpful at all... Never flying with @AirParadis again! #worstairline\",\n",
|
||
"\n",
|
||
" # Tweets mixtes et nuancés\n",
|
||
" \"The flight was good but the food wasn't really what I expected... @AirParadis can do better! #mixedfeelings\",\n",
|
||
" \"IDK what to think about my @AirParadis experience? The crew was nice but the flight was delayed for 2 hours... #confused\",\n",
|
||
" \"My husband loved the flight but I didn't... Too bad they can't make everyone happy :-) #AirParadis\",\n",
|
||
" \"TBH, @AirParadis has improved their service since last year! Not perfect yet, but they're trying... #progress\",\n",
|
||
" \"We were so excited for our trip but then our flight got delayed... at least the staff was very apologetic and gave us free drinks! @AirParadis\",\n",
|
||
"\n",
|
||
" # Tweets spécifiquement pour tester les caractéristiques spéciales\n",
|
||
" \"This is a tweet with many!!! exclamation!!! marks!!! to test how they affect sentiment analysis :)\",\n",
|
||
" \"How does the model handle multiple??? question??? marks??? in a single tweet? @AirParadis\",\n",
|
||
" \"Testing ellipses... many... many... ellipses... in... one... tweet... @AirParadis #test\",\n",
|
||
" \"#many #hashtags #in #one #tweet #to #see #how #they #affect #the #analysis #AirParadis\",\n",
|
||
" \"@mention1 @mention2 @mention3 @mention4 @mention5 multiple mentions in one tweet\",\n",
|
||
" \"Multiple URLs in one tweet: http://example1.com http://example2.com http://example3.com @AirParadis\",\n",
|
||
" \"Let's try all emoticons :) :( :D ;) :-) :-( :-D ;-) in a single tweet to see the impact\"\n",
|
||
"]"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/"
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 6284,
|
||
"status": "ok",
|
||
"timestamp": 1751740154190,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "HYemSzp2WxlR",
|
||
"outputId": "a3f850c7-8ae3-4daf-9296-d94ef357c74f"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"\n",
|
||
"Test du modèle sur les exemples:\n",
|
||
"==================================================\n",
|
||
"Résumé: 22 tweets analysés\n",
|
||
"Tweets positifs: 13 (59.1%)\n",
|
||
"Tweets négatifs: 9 (40.9%)\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"def test_model_on_examples(model, vectorizer, test_tweets):\n",
|
||
" \"\"\"\n",
|
||
" Teste le modèle sur une liste de tweets et retourne un DataFrame avec les résultats des prédictions.\n",
|
||
" \"\"\"\n",
|
||
"\n",
|
||
" results = {\n",
|
||
" \"positif\": 0,\n",
|
||
" \"négatif\": 0\n",
|
||
" }\n",
|
||
"\n",
|
||
" # Créer un DataFrame pour stocker les résultats\n",
|
||
" predictions_data = []\n",
|
||
"\n",
|
||
" for i, tweet in enumerate(test_tweets):\n",
|
||
" result = predict_sentiment(tweet, model, vectorizer)\n",
|
||
"\n",
|
||
" # Ajouter l'emoji approprié pour le sentiment\n",
|
||
" emoji = \"💚\" if result['sentiment'] == \"positif\" else \"❌\"\n",
|
||
"\n",
|
||
" # Ajouter les données au DataFrame\n",
|
||
" predictions_data.append({\n",
|
||
" \"Tweet\": tweet,\n",
|
||
" \"Sentiment\": result['sentiment'],\n",
|
||
" \"Emoji\": emoji,\n",
|
||
" \"Score de confiance\": result['score'],\n",
|
||
" \"Index\": i+1\n",
|
||
" })\n",
|
||
"\n",
|
||
" # Comptage des résultats\n",
|
||
" results[result['sentiment']] += 1\n",
|
||
"\n",
|
||
" # Créer le DataFrame\n",
|
||
" df_predictions = pd.DataFrame(predictions_data)\n",
|
||
"\n",
|
||
" # Afficher un résumé\n",
|
||
" print(\"\\nTest du modèle sur les exemples:\")\n",
|
||
" print(\"=\"*50)\n",
|
||
" print(f\"Résumé: {len(test_tweets)} tweets analysés\")\n",
|
||
" print(f\"Tweets positifs: {results['positif']} ({(results['positif']/len(test_tweets)*100):.1f}%)\")\n",
|
||
" print(f\"Tweets négatifs: {results['négatif']} ({(results['négatif']/len(test_tweets)*100):.1f}%)\")\n",
|
||
"\n",
|
||
" # Retourner le DataFrame\n",
|
||
" return df_predictions\n",
|
||
"\n",
|
||
"# Exemple d'utilisation:\n",
|
||
"if best_model is not None and vectorizer is not None:\n",
|
||
" # Obtenir le DataFrame des prédictions\n",
|
||
" df_results = test_model_on_examples(best_model, vectorizer, test_tweets_improved)\n",
|
||
" # Optionnel: sauvegarder les résultats dans un fichier CSV\n",
|
||
" df_results.to_csv(\"content/simple-model/best/predictions_results.csv\", index=False)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/",
|
||
"height": 739
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 41,
|
||
"status": "ok",
|
||
"timestamp": 1751740154234,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "P40YQzXDWxlR",
|
||
"outputId": "911ca8cf-e1dd-4082-f249-f09869a0f7d0"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"application/vnd.google.colaboratory.intrinsic+json": {
|
||
"summary": "{\n \"name\": \"df_results\",\n \"rows\": 22,\n \"fields\": [\n {\n \"column\": \"Tweet\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 22,\n \"samples\": [\n \"I absolutely love flying with @AirParadis! Their service is amazing and their staff is so helpful :) #bestairline #travel\",\n \"TBH, @AirParadis has improved their service since last year! Not perfect yet, but they're trying... #progress\",\n \"Our baggage was lost and nobody at @AirParadis seems to care! Don't they understand that we can't enjoy our vacation without our stuff??? http://badservice.com/complaint :-(\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Sentiment\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"n\\u00e9gatif\",\n \"positif\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Emoji\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"\\u274c\",\n \"\\ud83d\\udc9a\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Score de confiance\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.13093384858249077,\n \"min\": 0.5325674603174603,\n \"max\": 0.9620695325915914,\n \"num_unique_values\": 22,\n \"samples\": [\n 0.9620695325915914,\n 0.5618869047619047\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Index\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 6,\n \"min\": 1,\n \"max\": 22,\n \"num_unique_values\": 22,\n \"samples\": [\n 1,\n 14\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}",
|
||
"type": "dataframe",
|
||
"variable_name": "df_results"
|
||
},
|
||
"text/html": [
|
||
"\n",
|
||
" <div id=\"df-2800f6ef-518b-4319-bd85-13e48c6d3b36\" class=\"colab-df-container\">\n",
|
||
" <div>\n",
|
||
"<style scoped>\n",
|
||
" .dataframe tbody tr th:only-of-type {\n",
|
||
" vertical-align: middle;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe tbody tr th {\n",
|
||
" vertical-align: top;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .dataframe thead th {\n",
|
||
" text-align: right;\n",
|
||
" }\n",
|
||
"</style>\n",
|
||
"<table border=\"1\" class=\"dataframe\">\n",
|
||
" <thead>\n",
|
||
" <tr style=\"text-align: right;\">\n",
|
||
" <th></th>\n",
|
||
" <th>Tweet</th>\n",
|
||
" <th>Sentiment</th>\n",
|
||
" <th>Emoji</th>\n",
|
||
" <th>Score de confiance</th>\n",
|
||
" <th>Index</th>\n",
|
||
" </tr>\n",
|
||
" </thead>\n",
|
||
" <tbody>\n",
|
||
" <tr>\n",
|
||
" <th>0</th>\n",
|
||
" <td>I absolutely love flying with @AirParadis! The...</td>\n",
|
||
" <td>positif</td>\n",
|
||
" <td>💚</td>\n",
|
||
" <td>0.962070</td>\n",
|
||
" <td>1</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>1</th>\n",
|
||
" <td>Just landed after a wonderful flight... The cr...</td>\n",
|
||
" <td>positif</td>\n",
|
||
" <td>💚</td>\n",
|
||
" <td>0.874403</td>\n",
|
||
" <td>2</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>2</th>\n",
|
||
" <td>OMG! You really have to try @AirParadis. Best....</td>\n",
|
||
" <td>positif</td>\n",
|
||
" <td>💚</td>\n",
|
||
" <td>0.767187</td>\n",
|
||
" <td>3</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>3</th>\n",
|
||
" <td>We had a very pleasant experience with our fli...</td>\n",
|
||
" <td>positif</td>\n",
|
||
" <td>💚</td>\n",
|
||
" <td>0.877798</td>\n",
|
||
" <td>4</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>4</th>\n",
|
||
" <td>My first time flying business class and I'm ab...</td>\n",
|
||
" <td>positif</td>\n",
|
||
" <td>💚</td>\n",
|
||
" <td>0.608684</td>\n",
|
||
" <td>5</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>5</th>\n",
|
||
" <td>I hate how @AirParadis always delays their fli...</td>\n",
|
||
" <td>négatif</td>\n",
|
||
" <td>❌</td>\n",
|
||
" <td>0.868094</td>\n",
|
||
" <td>6</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>6</th>\n",
|
||
" <td>The worst flight experience of my life? Defini...</td>\n",
|
||
" <td>négatif</td>\n",
|
||
" <td>❌</td>\n",
|
||
" <td>0.781381</td>\n",
|
||
" <td>7</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>7</th>\n",
|
||
" <td>Really @AirParadis??? Flight cancelled and no ...</td>\n",
|
||
" <td>négatif</td>\n",
|
||
" <td>❌</td>\n",
|
||
" <td>0.705216</td>\n",
|
||
" <td>8</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>8</th>\n",
|
||
" <td>Our baggage was lost and nobody at @AirParadis...</td>\n",
|
||
" <td>négatif</td>\n",
|
||
" <td>❌</td>\n",
|
||
" <td>0.673389</td>\n",
|
||
" <td>9</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>9</th>\n",
|
||
" <td>Food was terrible, seats were uncomfortable, a...</td>\n",
|
||
" <td>négatif</td>\n",
|
||
" <td>❌</td>\n",
|
||
" <td>0.815938</td>\n",
|
||
" <td>10</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>10</th>\n",
|
||
" <td>The flight was good but the food wasn't really...</td>\n",
|
||
" <td>positif</td>\n",
|
||
" <td>💚</td>\n",
|
||
" <td>0.590071</td>\n",
|
||
" <td>11</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>11</th>\n",
|
||
" <td>IDK what to think about my @AirParadis experie...</td>\n",
|
||
" <td>positif</td>\n",
|
||
" <td>💚</td>\n",
|
||
" <td>0.677984</td>\n",
|
||
" <td>12</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>12</th>\n",
|
||
" <td>My husband loved the flight but I didn't... To...</td>\n",
|
||
" <td>négatif</td>\n",
|
||
" <td>❌</td>\n",
|
||
" <td>0.751300</td>\n",
|
||
" <td>13</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>13</th>\n",
|
||
" <td>TBH, @AirParadis has improved their service si...</td>\n",
|
||
" <td>négatif</td>\n",
|
||
" <td>❌</td>\n",
|
||
" <td>0.561887</td>\n",
|
||
" <td>14</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>14</th>\n",
|
||
" <td>We were so excited for our trip but then our f...</td>\n",
|
||
" <td>positif</td>\n",
|
||
" <td>💚</td>\n",
|
||
" <td>0.532567</td>\n",
|
||
" <td>15</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>15</th>\n",
|
||
" <td>This is a tweet with many!!! exclamation!!! ma...</td>\n",
|
||
" <td>négatif</td>\n",
|
||
" <td>❌</td>\n",
|
||
" <td>0.715387</td>\n",
|
||
" <td>16</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>16</th>\n",
|
||
" <td>How does the model handle multiple??? question...</td>\n",
|
||
" <td>positif</td>\n",
|
||
" <td>💚</td>\n",
|
||
" <td>0.555274</td>\n",
|
||
" <td>17</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>17</th>\n",
|
||
" <td>Testing ellipses... many... many... ellipses.....</td>\n",
|
||
" <td>positif</td>\n",
|
||
" <td>💚</td>\n",
|
||
" <td>0.802591</td>\n",
|
||
" <td>18</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>18</th>\n",
|
||
" <td>#many #hashtags #in #one #tweet #to #see #how ...</td>\n",
|
||
" <td>négatif</td>\n",
|
||
" <td>❌</td>\n",
|
||
" <td>0.562698</td>\n",
|
||
" <td>19</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>19</th>\n",
|
||
" <td>@mention1 @mention2 @mention3 @mention4 @menti...</td>\n",
|
||
" <td>positif</td>\n",
|
||
" <td>💚</td>\n",
|
||
" <td>0.834694</td>\n",
|
||
" <td>20</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>20</th>\n",
|
||
" <td>Multiple URLs in one tweet: http://example1.co...</td>\n",
|
||
" <td>positif</td>\n",
|
||
" <td>💚</td>\n",
|
||
" <td>0.937625</td>\n",
|
||
" <td>21</td>\n",
|
||
" </tr>\n",
|
||
" <tr>\n",
|
||
" <th>21</th>\n",
|
||
" <td>Let's try all emoticons :) :( :D ;) :-) :-( :-...</td>\n",
|
||
" <td>positif</td>\n",
|
||
" <td>💚</td>\n",
|
||
" <td>0.649427</td>\n",
|
||
" <td>22</td>\n",
|
||
" </tr>\n",
|
||
" </tbody>\n",
|
||
"</table>\n",
|
||
"</div>\n",
|
||
" <div class=\"colab-df-buttons\">\n",
|
||
"\n",
|
||
" <div class=\"colab-df-container\">\n",
|
||
" <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-2800f6ef-518b-4319-bd85-13e48c6d3b36')\"\n",
|
||
" title=\"Convert this dataframe to an interactive table.\"\n",
|
||
" style=\"display:none;\">\n",
|
||
"\n",
|
||
" <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n",
|
||
" <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n",
|
||
" </svg>\n",
|
||
" </button>\n",
|
||
"\n",
|
||
" <style>\n",
|
||
" .colab-df-container {\n",
|
||
" display:flex;\n",
|
||
" gap: 12px;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-convert {\n",
|
||
" background-color: #E8F0FE;\n",
|
||
" border: none;\n",
|
||
" border-radius: 50%;\n",
|
||
" cursor: pointer;\n",
|
||
" display: none;\n",
|
||
" fill: #1967D2;\n",
|
||
" height: 32px;\n",
|
||
" padding: 0 0 0 0;\n",
|
||
" width: 32px;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-convert:hover {\n",
|
||
" background-color: #E2EBFA;\n",
|
||
" box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
|
||
" fill: #174EA6;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-buttons div {\n",
|
||
" margin-bottom: 4px;\n",
|
||
" }\n",
|
||
"\n",
|
||
" [theme=dark] .colab-df-convert {\n",
|
||
" background-color: #3B4455;\n",
|
||
" fill: #D2E3FC;\n",
|
||
" }\n",
|
||
"\n",
|
||
" [theme=dark] .colab-df-convert:hover {\n",
|
||
" background-color: #434B5C;\n",
|
||
" box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
|
||
" filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
|
||
" fill: #FFFFFF;\n",
|
||
" }\n",
|
||
" </style>\n",
|
||
"\n",
|
||
" <script>\n",
|
||
" const buttonEl =\n",
|
||
" document.querySelector('#df-2800f6ef-518b-4319-bd85-13e48c6d3b36 button.colab-df-convert');\n",
|
||
" buttonEl.style.display =\n",
|
||
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
|
||
"\n",
|
||
" async function convertToInteractive(key) {\n",
|
||
" const element = document.querySelector('#df-2800f6ef-518b-4319-bd85-13e48c6d3b36');\n",
|
||
" const dataTable =\n",
|
||
" await google.colab.kernel.invokeFunction('convertToInteractive',\n",
|
||
" [key], {});\n",
|
||
" if (!dataTable) return;\n",
|
||
"\n",
|
||
" const docLinkHtml = 'Like what you see? Visit the ' +\n",
|
||
" '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
|
||
" + ' to learn more about interactive tables.';\n",
|
||
" element.innerHTML = '';\n",
|
||
" dataTable['output_type'] = 'display_data';\n",
|
||
" await google.colab.output.renderOutput(dataTable, element);\n",
|
||
" const docLink = document.createElement('div');\n",
|
||
" docLink.innerHTML = docLinkHtml;\n",
|
||
" element.appendChild(docLink);\n",
|
||
" }\n",
|
||
" </script>\n",
|
||
" </div>\n",
|
||
"\n",
|
||
"\n",
|
||
" <div id=\"df-181ed6a7-4635-458e-acb1-210c50c72f46\">\n",
|
||
" <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-181ed6a7-4635-458e-acb1-210c50c72f46')\"\n",
|
||
" title=\"Suggest charts\"\n",
|
||
" style=\"display:none;\">\n",
|
||
"\n",
|
||
"<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
|
||
" width=\"24px\">\n",
|
||
" <g>\n",
|
||
" <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n",
|
||
" </g>\n",
|
||
"</svg>\n",
|
||
" </button>\n",
|
||
"\n",
|
||
"<style>\n",
|
||
" .colab-df-quickchart {\n",
|
||
" --bg-color: #E8F0FE;\n",
|
||
" --fill-color: #1967D2;\n",
|
||
" --hover-bg-color: #E2EBFA;\n",
|
||
" --hover-fill-color: #174EA6;\n",
|
||
" --disabled-fill-color: #AAA;\n",
|
||
" --disabled-bg-color: #DDD;\n",
|
||
" }\n",
|
||
"\n",
|
||
" [theme=dark] .colab-df-quickchart {\n",
|
||
" --bg-color: #3B4455;\n",
|
||
" --fill-color: #D2E3FC;\n",
|
||
" --hover-bg-color: #434B5C;\n",
|
||
" --hover-fill-color: #FFFFFF;\n",
|
||
" --disabled-bg-color: #3B4455;\n",
|
||
" --disabled-fill-color: #666;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-quickchart {\n",
|
||
" background-color: var(--bg-color);\n",
|
||
" border: none;\n",
|
||
" border-radius: 50%;\n",
|
||
" cursor: pointer;\n",
|
||
" display: none;\n",
|
||
" fill: var(--fill-color);\n",
|
||
" height: 32px;\n",
|
||
" padding: 0;\n",
|
||
" width: 32px;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-quickchart:hover {\n",
|
||
" background-color: var(--hover-bg-color);\n",
|
||
" box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
|
||
" fill: var(--button-hover-fill-color);\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-quickchart-complete:disabled,\n",
|
||
" .colab-df-quickchart-complete:disabled:hover {\n",
|
||
" background-color: var(--disabled-bg-color);\n",
|
||
" fill: var(--disabled-fill-color);\n",
|
||
" box-shadow: none;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-spinner {\n",
|
||
" border: 2px solid var(--fill-color);\n",
|
||
" border-color: transparent;\n",
|
||
" border-bottom-color: var(--fill-color);\n",
|
||
" animation:\n",
|
||
" spin 1s steps(1) infinite;\n",
|
||
" }\n",
|
||
"\n",
|
||
" @keyframes spin {\n",
|
||
" 0% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-bottom-color: var(--fill-color);\n",
|
||
" border-left-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 20% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-left-color: var(--fill-color);\n",
|
||
" border-top-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 30% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-left-color: var(--fill-color);\n",
|
||
" border-top-color: var(--fill-color);\n",
|
||
" border-right-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 40% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-right-color: var(--fill-color);\n",
|
||
" border-top-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 60% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-right-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 80% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-right-color: var(--fill-color);\n",
|
||
" border-bottom-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" 90% {\n",
|
||
" border-color: transparent;\n",
|
||
" border-bottom-color: var(--fill-color);\n",
|
||
" }\n",
|
||
" }\n",
|
||
"</style>\n",
|
||
"\n",
|
||
" <script>\n",
|
||
" async function quickchart(key) {\n",
|
||
" const quickchartButtonEl =\n",
|
||
" document.querySelector('#' + key + ' button');\n",
|
||
" quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n",
|
||
" quickchartButtonEl.classList.add('colab-df-spinner');\n",
|
||
" try {\n",
|
||
" const charts = await google.colab.kernel.invokeFunction(\n",
|
||
" 'suggestCharts', [key], {});\n",
|
||
" } catch (error) {\n",
|
||
" console.error('Error during call to suggestCharts:', error);\n",
|
||
" }\n",
|
||
" quickchartButtonEl.classList.remove('colab-df-spinner');\n",
|
||
" quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n",
|
||
" }\n",
|
||
" (() => {\n",
|
||
" let quickchartButtonEl =\n",
|
||
" document.querySelector('#df-181ed6a7-4635-458e-acb1-210c50c72f46 button');\n",
|
||
" quickchartButtonEl.style.display =\n",
|
||
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
|
||
" })();\n",
|
||
" </script>\n",
|
||
" </div>\n",
|
||
"\n",
|
||
" <div id=\"id_ef9aa32c-1bd5-4918-94e5-04bd07129897\">\n",
|
||
" <style>\n",
|
||
" .colab-df-generate {\n",
|
||
" background-color: #E8F0FE;\n",
|
||
" border: none;\n",
|
||
" border-radius: 50%;\n",
|
||
" cursor: pointer;\n",
|
||
" display: none;\n",
|
||
" fill: #1967D2;\n",
|
||
" height: 32px;\n",
|
||
" padding: 0 0 0 0;\n",
|
||
" width: 32px;\n",
|
||
" }\n",
|
||
"\n",
|
||
" .colab-df-generate:hover {\n",
|
||
" background-color: #E2EBFA;\n",
|
||
" box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
|
||
" fill: #174EA6;\n",
|
||
" }\n",
|
||
"\n",
|
||
" [theme=dark] .colab-df-generate {\n",
|
||
" background-color: #3B4455;\n",
|
||
" fill: #D2E3FC;\n",
|
||
" }\n",
|
||
"\n",
|
||
" [theme=dark] .colab-df-generate:hover {\n",
|
||
" background-color: #434B5C;\n",
|
||
" box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
|
||
" filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
|
||
" fill: #FFFFFF;\n",
|
||
" }\n",
|
||
" </style>\n",
|
||
" <button class=\"colab-df-generate\" onclick=\"generateWithVariable('df_results')\"\n",
|
||
" title=\"Generate code using this dataframe.\"\n",
|
||
" style=\"display:none;\">\n",
|
||
"\n",
|
||
" <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
|
||
" width=\"24px\">\n",
|
||
" <path d=\"M7,19H8.4L18.45,9,17,7.55,7,17.6ZM5,21V16.75L18.45,3.32a2,2,0,0,1,2.83,0l1.4,1.43a1.91,1.91,0,0,1,.58,1.4,1.91,1.91,0,0,1-.58,1.4L9.25,21ZM18.45,9,17,7.55Zm-12,3A5.31,5.31,0,0,0,4.9,8.1,5.31,5.31,0,0,0,1,6.5,5.31,5.31,0,0,0,4.9,4.9,5.31,5.31,0,0,0,6.5,1,5.31,5.31,0,0,0,8.1,4.9,5.31,5.31,0,0,0,12,6.5,5.46,5.46,0,0,0,6.5,12Z\"/>\n",
|
||
" </svg>\n",
|
||
" </button>\n",
|
||
" <script>\n",
|
||
" (() => {\n",
|
||
" const buttonEl =\n",
|
||
" document.querySelector('#id_ef9aa32c-1bd5-4918-94e5-04bd07129897 button.colab-df-generate');\n",
|
||
" buttonEl.style.display =\n",
|
||
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
|
||
"\n",
|
||
" buttonEl.onclick = () => {\n",
|
||
" google.colab.notebook.generateWithVariable('df_results');\n",
|
||
" }\n",
|
||
" })();\n",
|
||
" </script>\n",
|
||
" </div>\n",
|
||
"\n",
|
||
" </div>\n",
|
||
" </div>\n"
|
||
],
|
||
"text/plain": [
|
||
" Tweet Sentiment Emoji \\\n",
|
||
"0 I absolutely love flying with @AirParadis! The... positif 💚 \n",
|
||
"1 Just landed after a wonderful flight... The cr... positif 💚 \n",
|
||
"2 OMG! You really have to try @AirParadis. Best.... positif 💚 \n",
|
||
"3 We had a very pleasant experience with our fli... positif 💚 \n",
|
||
"4 My first time flying business class and I'm ab... positif 💚 \n",
|
||
"5 I hate how @AirParadis always delays their fli... négatif ❌ \n",
|
||
"6 The worst flight experience of my life? Defini... négatif ❌ \n",
|
||
"7 Really @AirParadis??? Flight cancelled and no ... négatif ❌ \n",
|
||
"8 Our baggage was lost and nobody at @AirParadis... négatif ❌ \n",
|
||
"9 Food was terrible, seats were uncomfortable, a... négatif ❌ \n",
|
||
"10 The flight was good but the food wasn't really... positif 💚 \n",
|
||
"11 IDK what to think about my @AirParadis experie... positif 💚 \n",
|
||
"12 My husband loved the flight but I didn't... To... négatif ❌ \n",
|
||
"13 TBH, @AirParadis has improved their service si... négatif ❌ \n",
|
||
"14 We were so excited for our trip but then our f... positif 💚 \n",
|
||
"15 This is a tweet with many!!! exclamation!!! ma... négatif ❌ \n",
|
||
"16 How does the model handle multiple??? question... positif 💚 \n",
|
||
"17 Testing ellipses... many... many... ellipses..... positif 💚 \n",
|
||
"18 #many #hashtags #in #one #tweet #to #see #how ... négatif ❌ \n",
|
||
"19 @mention1 @mention2 @mention3 @mention4 @menti... positif 💚 \n",
|
||
"20 Multiple URLs in one tweet: http://example1.co... positif 💚 \n",
|
||
"21 Let's try all emoticons :) :( :D ;) :-) :-( :-... positif 💚 \n",
|
||
"\n",
|
||
" Score de confiance Index \n",
|
||
"0 0.962070 1 \n",
|
||
"1 0.874403 2 \n",
|
||
"2 0.767187 3 \n",
|
||
"3 0.877798 4 \n",
|
||
"4 0.608684 5 \n",
|
||
"5 0.868094 6 \n",
|
||
"6 0.781381 7 \n",
|
||
"7 0.705216 8 \n",
|
||
"8 0.673389 9 \n",
|
||
"9 0.815938 10 \n",
|
||
"10 0.590071 11 \n",
|
||
"11 0.677984 12 \n",
|
||
"12 0.751300 13 \n",
|
||
"13 0.561887 14 \n",
|
||
"14 0.532567 15 \n",
|
||
"15 0.715387 16 \n",
|
||
"16 0.555274 17 \n",
|
||
"17 0.802591 18 \n",
|
||
"18 0.562698 19 \n",
|
||
"19 0.834694 20 \n",
|
||
"20 0.937625 21 \n",
|
||
"21 0.649427 22 "
|
||
]
|
||
},
|
||
"execution_count": 39,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"df_results"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"colab": {
|
||
"base_uri": "https://localhost:8080/"
|
||
},
|
||
"executionInfo": {
|
||
"elapsed": 6,
|
||
"status": "ok",
|
||
"timestamp": 1751740154241,
|
||
"user": {
|
||
"displayName": "Grégoire",
|
||
"userId": "01249298206117462766"
|
||
},
|
||
"user_tz": -120
|
||
},
|
||
"id": "5g5IagpMWxlR",
|
||
"outputId": "379e77cb-1b6e-412e-a483-4510c1f22b90"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"Index(['Tweet', 'Sentiment', 'Emoji', 'Score de confiance', 'Index'], dtype='object')"
|
||
]
|
||
},
|
||
"execution_count": 40,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"df_results.columns"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "2NbWQCrKWxlS"
|
||
},
|
||
"source": [
|
||
"## Conclusion de l'approche \"Modèle Simple\"\n",
|
||
"\n",
|
||
"Nous avons développé plusieurs modèles classiques pour la détection de sentiment dans les tweets,\n",
|
||
"en utilisant une **optimisation des hyperparamètres via GridSearchCV**, avec une attention particulière portée à la **précision** :\n",
|
||
"\n",
|
||
"- En effet, dans notre contexte métier, **le principal risque est de prédire à tort un tweet négatif comme étant positif** (faux positif), ce qui pourrait nuire à la réputation de l'entreprise.\n",
|
||
"- Pour cette raison, **la précision (precision) a été retenue comme métrique de sélection principale**, car elle mesure la proportion de tweets réellement positifs parmi ceux prédits comme positifs.\n",
|
||
"\n",
|
||
"Les modèles testés sont :\n",
|
||
"\n",
|
||
"1. Régression Logistique \n",
|
||
"2. SVM Linéaire \n",
|
||
"3. Random Forest \n",
|
||
"4. Naive Bayes \n",
|
||
"\n",
|
||
"Chaque modèle a été évalué avec deux techniques de vectorisation :\n",
|
||
"- Sac de mots (BoW)\n",
|
||
"- TF-IDF\n",
|
||
"\n",
|
||
"---\n",
|
||
"\n",
|
||
"### 📊 Meilleur modèle (selon la précision)\n",
|
||
"\n",
|
||
"Le modèle ayant obtenu la meilleure précision est : \n",
|
||
"**[en attente d'une valeur]** avec la vectorisation **[en attente d'une valeur]**\n",
|
||
"\n",
|
||
"- **Précision : [en attente d'une valeur]**\n",
|
||
"- **F1 Score : [en attente d'une valeur]**\n",
|
||
"- **ROC AUC : [en attente d'une valeur]**\n",
|
||
"\n",
|
||
"Hyperparamètres optimaux : **[en attente d'une valeur]**\n",
|
||
"\n",
|
||
"---\n",
|
||
"\n",
|
||
"### ✅ Avantages du workflow implémenté\n",
|
||
"\n",
|
||
"1. **Alignement sur la métrique métier (précision)** \n",
|
||
" - Réduction du risque de faux positifs, cruciaux dans notre cas d’usage \n",
|
||
" - Approche plus conservatrice mais adaptée à la gestion d'image de marque\n",
|
||
"\n",
|
||
"2. **Suivi des expérimentations avec MLflow** \n",
|
||
" - Historique des runs, métriques, artefacts et vectoriseurs sauvegardés \n",
|
||
" - Visualisation claire des performances\n",
|
||
"\n",
|
||
"3. **Optimisation rigoureuse** \n",
|
||
" - Recherche sur grille (GridSearchCV) \n",
|
||
" - Validation croisée pour robustesse des résultats \n",
|
||
" - Comparaison systématique des performances\n",
|
||
"\n",
|
||
"4. **Prétraitement linguistique adapté aux tweets** \n",
|
||
" - Nettoyage spécifique des entités (hashtags, mentions, URLs) \n",
|
||
" - Lemmatisation avec conservation des négations \n",
|
||
" - Ajout de variables contextuelles issues de l’analyse exploratoire\n",
|
||
"\n",
|
||
"\n",
|
||
"Le meilleur modèle classique retenu ici constituera une **baseline** solide pour mesurer les gains apportés par les approches de Deep Learning et de NLP avancé.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "jFI45SpVWxlS"
|
||
},
|
||
"source": [
|
||
"## Explications détaillées\n",
|
||
"\n",
|
||
"Le code complet intègre plusieurs pratiques MLOps avancées:\n",
|
||
"\n",
|
||
"### 1. Optimisation des hyperparamètres avec GridSearchCV\n",
|
||
"\n",
|
||
"J'ai implémenté GridSearchCV pour chaque combinaison de modèle et vectoriseur. Cela permet d'explorer systématiquement l'espace des hyperparamètres pour trouver la configuration optimale. Pour chaque modèle, j'ai défini une grille de paramètres pertinents:\n",
|
||
"\n",
|
||
"- **Régression Logistique**: différentes valeurs de régularisation (C), types de solveurs\n",
|
||
"- **SVM**: différentes valeurs de C, options de dualité\n",
|
||
"- **Random Forest**: nombre d'arbres, profondeur maximale, critères de division\n",
|
||
"- **Naive Bayes**: différentes valeurs pour le paramètre de lissage alpha\n",
|
||
"\n",
|
||
"L'optimisation est effectuée avec validation croisée à 5 plis (5-fold) pour garantir la robustesse des résultats.\n",
|
||
"\n",
|
||
"### 2. Tracking complet avec MLflow\n",
|
||
"\n",
|
||
"Pour chaque expérience, j'enregistre dans MLflow:\n",
|
||
"\n",
|
||
"- **Paramètres**: tous les hyperparamètres utilisés, y compris les meilleurs trouvés par GridSearchCV\n",
|
||
"- **Métriques**: accuracy, precision, recall, F1 score, ROC AUC, temps d'entraînement\n",
|
||
"- **Artifacts**:\n",
|
||
" - Le modèle optimisé avec sa signature d'entrée/sortie\n",
|
||
" - Le vectoriseur utilisé (nouveauté demandée)\n",
|
||
" - La matrice de confusion et la courbe ROC\n",
|
||
" - Les résultats détaillés de la validation croisée\n",
|
||
" - Les features les plus importantes (pour les modèles qui le permettent)\n",
|
||
" - Des graphiques d'analyse de l'influence des hyperparamètres\n",
|
||
"\n",
|
||
"### 3. Sauvegarde et utilisation du meilleur modèle\n",
|
||
"\n",
|
||
"J'ai implémenté une méthode pour:\n",
|
||
"\n",
|
||
"1. Identifier le meilleur modèle dans l'historique MLflow\n",
|
||
"2. Le récupérer avec son vectoriseur\n",
|
||
"3. Sauvegarder les deux dans un dossier local spécifié (\"content/simple-model/best\")\n",
|
||
"4. Créer une fonction de prédiction prête pour l'API\n",
|
||
"\n",
|
||
"### 4. Visualisations avancées\n",
|
||
"\n",
|
||
"Pour faciliter l'analyse:\n",
|
||
"\n",
|
||
"- Matrices de confusion pour chaque modèle\n",
|
||
"- Courbes ROC avec AUC calculé\n",
|
||
"- Graphiques des features les plus importantes\n",
|
||
"- Graphiques d'évolution des scores en fonction des hyperparamètres"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "hJSt92gut0Vu"
|
||
},
|
||
"source": [
|
||
"# Enregistrement de dépendances"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"id": "LeieF6LStjLc"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"!pip freeze > requirements_modele_simple.txt"
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"colab": {
|
||
"provenance": []
|
||
},
|
||
"kernelspec": {
|
||
"display_name": "Python 3",
|
||
"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.10.12"
|
||
},
|
||
"widgets": {
|
||
"application/vnd.jupyter.widget-state+json": {
|
||
"073bf36ff26d455ca01956dee8d1f1a2": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "HTMLModel",
|
||
"state": {
|
||
"_dom_classes": [],
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "HTMLModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/controls",
|
||
"_view_module_version": "1.5.0",
|
||
"_view_name": "HTMLView",
|
||
"description": "",
|
||
"description_tooltip": null,
|
||
"layout": "IPY_MODEL_8ddc3f81d9094d06b680908375077c62",
|
||
"placeholder": "",
|
||
"style": "IPY_MODEL_0e157319861c42049d63bd43b797987e",
|
||
"value": "Downloading artifacts: 100%"
|
||
}
|
||
},
|
||
"074c0860e74d41ff9562fb72d395b28d": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "DescriptionStyleModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "DescriptionStyleModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "StyleView",
|
||
"description_width": ""
|
||
}
|
||
},
|
||
"0e157319861c42049d63bd43b797987e": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "DescriptionStyleModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "DescriptionStyleModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "StyleView",
|
||
"description_width": ""
|
||
}
|
||
},
|
||
"0e61cbeda1f4421398f9456ad9e492e0": {
|
||
"model_module": "@jupyter-widgets/base",
|
||
"model_module_version": "1.2.0",
|
||
"model_name": "LayoutModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/base",
|
||
"_model_module_version": "1.2.0",
|
||
"_model_name": "LayoutModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "LayoutView",
|
||
"align_content": null,
|
||
"align_items": null,
|
||
"align_self": null,
|
||
"border": null,
|
||
"bottom": null,
|
||
"display": null,
|
||
"flex": null,
|
||
"flex_flow": null,
|
||
"grid_area": null,
|
||
"grid_auto_columns": null,
|
||
"grid_auto_flow": null,
|
||
"grid_auto_rows": null,
|
||
"grid_column": null,
|
||
"grid_gap": null,
|
||
"grid_row": null,
|
||
"grid_template_areas": null,
|
||
"grid_template_columns": null,
|
||
"grid_template_rows": null,
|
||
"height": null,
|
||
"justify_content": null,
|
||
"justify_items": null,
|
||
"left": null,
|
||
"margin": null,
|
||
"max_height": null,
|
||
"max_width": null,
|
||
"min_height": null,
|
||
"min_width": null,
|
||
"object_fit": null,
|
||
"object_position": null,
|
||
"order": null,
|
||
"overflow": null,
|
||
"overflow_x": null,
|
||
"overflow_y": null,
|
||
"padding": null,
|
||
"right": null,
|
||
"top": null,
|
||
"visibility": null,
|
||
"width": null
|
||
}
|
||
},
|
||
"2d7826d641614256a9f135515160958c": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "HTMLModel",
|
||
"state": {
|
||
"_dom_classes": [],
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "HTMLModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/controls",
|
||
"_view_module_version": "1.5.0",
|
||
"_view_name": "HTMLView",
|
||
"description": "",
|
||
"description_tooltip": null,
|
||
"layout": "IPY_MODEL_e7775e44c82b472181e4f8ee6e7d918e",
|
||
"placeholder": "",
|
||
"style": "IPY_MODEL_074c0860e74d41ff9562fb72d395b28d",
|
||
"value": " 1/1 [00:00<00:00, 1.13it/s]"
|
||
}
|
||
},
|
||
"3a1f9f8dff4e49fe8a94cd71fcfd3699": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "HTMLModel",
|
||
"state": {
|
||
"_dom_classes": [],
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "HTMLModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/controls",
|
||
"_view_module_version": "1.5.0",
|
||
"_view_name": "HTMLView",
|
||
"description": "",
|
||
"description_tooltip": null,
|
||
"layout": "IPY_MODEL_0e61cbeda1f4421398f9456ad9e492e0",
|
||
"placeholder": "",
|
||
"style": "IPY_MODEL_974da4c9934842ff8286f10a78790410",
|
||
"value": "Downloading artifacts: 100%"
|
||
}
|
||
},
|
||
"6050e4a9af9e4c46aa4b38d407b7bab9": {
|
||
"model_module": "@jupyter-widgets/base",
|
||
"model_module_version": "1.2.0",
|
||
"model_name": "LayoutModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/base",
|
||
"_model_module_version": "1.2.0",
|
||
"_model_name": "LayoutModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "LayoutView",
|
||
"align_content": null,
|
||
"align_items": null,
|
||
"align_self": null,
|
||
"border": null,
|
||
"bottom": null,
|
||
"display": null,
|
||
"flex": null,
|
||
"flex_flow": null,
|
||
"grid_area": null,
|
||
"grid_auto_columns": null,
|
||
"grid_auto_flow": null,
|
||
"grid_auto_rows": null,
|
||
"grid_column": null,
|
||
"grid_gap": null,
|
||
"grid_row": null,
|
||
"grid_template_areas": null,
|
||
"grid_template_columns": null,
|
||
"grid_template_rows": null,
|
||
"height": null,
|
||
"justify_content": null,
|
||
"justify_items": null,
|
||
"left": null,
|
||
"margin": null,
|
||
"max_height": null,
|
||
"max_width": null,
|
||
"min_height": null,
|
||
"min_width": null,
|
||
"object_fit": null,
|
||
"object_position": null,
|
||
"order": null,
|
||
"overflow": null,
|
||
"overflow_x": null,
|
||
"overflow_y": null,
|
||
"padding": null,
|
||
"right": null,
|
||
"top": null,
|
||
"visibility": null,
|
||
"width": null
|
||
}
|
||
},
|
||
"6baff5e484754cdaa400a6adeab6958c": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "FloatProgressModel",
|
||
"state": {
|
||
"_dom_classes": [],
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "FloatProgressModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/controls",
|
||
"_view_module_version": "1.5.0",
|
||
"_view_name": "ProgressView",
|
||
"bar_style": "success",
|
||
"description": "",
|
||
"description_tooltip": null,
|
||
"layout": "IPY_MODEL_8beb625411f6459c97243979b6cb3664",
|
||
"max": 1,
|
||
"min": 0,
|
||
"orientation": "horizontal",
|
||
"style": "IPY_MODEL_b23315ac058141fd9bf35c49276544d0",
|
||
"value": 1
|
||
}
|
||
},
|
||
"6c04e4ad7c5f49c3bd9658ccab659890": {
|
||
"model_module": "@jupyter-widgets/base",
|
||
"model_module_version": "1.2.0",
|
||
"model_name": "LayoutModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/base",
|
||
"_model_module_version": "1.2.0",
|
||
"_model_name": "LayoutModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "LayoutView",
|
||
"align_content": null,
|
||
"align_items": null,
|
||
"align_self": null,
|
||
"border": null,
|
||
"bottom": null,
|
||
"display": null,
|
||
"flex": null,
|
||
"flex_flow": null,
|
||
"grid_area": null,
|
||
"grid_auto_columns": null,
|
||
"grid_auto_flow": null,
|
||
"grid_auto_rows": null,
|
||
"grid_column": null,
|
||
"grid_gap": null,
|
||
"grid_row": null,
|
||
"grid_template_areas": null,
|
||
"grid_template_columns": null,
|
||
"grid_template_rows": null,
|
||
"height": null,
|
||
"justify_content": null,
|
||
"justify_items": null,
|
||
"left": null,
|
||
"margin": null,
|
||
"max_height": null,
|
||
"max_width": null,
|
||
"min_height": null,
|
||
"min_width": null,
|
||
"object_fit": null,
|
||
"object_position": null,
|
||
"order": null,
|
||
"overflow": null,
|
||
"overflow_x": null,
|
||
"overflow_y": null,
|
||
"padding": null,
|
||
"right": null,
|
||
"top": null,
|
||
"visibility": null,
|
||
"width": null
|
||
}
|
||
},
|
||
"6d712f894c5d4d19a478fa1d1a2b2c62": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "HTMLModel",
|
||
"state": {
|
||
"_dom_classes": [],
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "HTMLModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/controls",
|
||
"_view_module_version": "1.5.0",
|
||
"_view_name": "HTMLView",
|
||
"description": "",
|
||
"description_tooltip": null,
|
||
"layout": "IPY_MODEL_6c04e4ad7c5f49c3bd9658ccab659890",
|
||
"placeholder": "",
|
||
"style": "IPY_MODEL_acbe4e7d94f04dfe9e797ab54d3102ad",
|
||
"value": " 5/5 [01:56<00:00, 32.51s/it]"
|
||
}
|
||
},
|
||
"6efad0330efc4790a1eac95fcc96de17": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "ProgressStyleModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "ProgressStyleModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "StyleView",
|
||
"bar_color": null,
|
||
"description_width": ""
|
||
}
|
||
},
|
||
"6f6c8fc42ef846a4ac56ffe69bcbbe0f": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "DescriptionStyleModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "DescriptionStyleModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "StyleView",
|
||
"description_width": ""
|
||
}
|
||
},
|
||
"727814859996469da84c76c1a3f15bef": {
|
||
"model_module": "@jupyter-widgets/base",
|
||
"model_module_version": "1.2.0",
|
||
"model_name": "LayoutModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/base",
|
||
"_model_module_version": "1.2.0",
|
||
"_model_name": "LayoutModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "LayoutView",
|
||
"align_content": null,
|
||
"align_items": null,
|
||
"align_self": null,
|
||
"border": null,
|
||
"bottom": null,
|
||
"display": null,
|
||
"flex": null,
|
||
"flex_flow": null,
|
||
"grid_area": null,
|
||
"grid_auto_columns": null,
|
||
"grid_auto_flow": null,
|
||
"grid_auto_rows": null,
|
||
"grid_column": null,
|
||
"grid_gap": null,
|
||
"grid_row": null,
|
||
"grid_template_areas": null,
|
||
"grid_template_columns": null,
|
||
"grid_template_rows": null,
|
||
"height": null,
|
||
"justify_content": null,
|
||
"justify_items": null,
|
||
"left": null,
|
||
"margin": null,
|
||
"max_height": null,
|
||
"max_width": null,
|
||
"min_height": null,
|
||
"min_width": null,
|
||
"object_fit": null,
|
||
"object_position": null,
|
||
"order": null,
|
||
"overflow": null,
|
||
"overflow_x": null,
|
||
"overflow_y": null,
|
||
"padding": null,
|
||
"right": null,
|
||
"top": null,
|
||
"visibility": null,
|
||
"width": null
|
||
}
|
||
},
|
||
"88ae9e2307804694bc546afb10a362f7": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "HTMLModel",
|
||
"state": {
|
||
"_dom_classes": [],
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "HTMLModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/controls",
|
||
"_view_module_version": "1.5.0",
|
||
"_view_name": "HTMLView",
|
||
"description": "",
|
||
"description_tooltip": null,
|
||
"layout": "IPY_MODEL_727814859996469da84c76c1a3f15bef",
|
||
"placeholder": "",
|
||
"style": "IPY_MODEL_6f6c8fc42ef846a4ac56ffe69bcbbe0f",
|
||
"value": "Downloading artifacts: 0%"
|
||
}
|
||
},
|
||
"8b25983eb05344928535625c726939d8": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "DescriptionStyleModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "DescriptionStyleModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "StyleView",
|
||
"description_width": ""
|
||
}
|
||
},
|
||
"8beb625411f6459c97243979b6cb3664": {
|
||
"model_module": "@jupyter-widgets/base",
|
||
"model_module_version": "1.2.0",
|
||
"model_name": "LayoutModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/base",
|
||
"_model_module_version": "1.2.0",
|
||
"_model_name": "LayoutModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "LayoutView",
|
||
"align_content": null,
|
||
"align_items": null,
|
||
"align_self": null,
|
||
"border": null,
|
||
"bottom": null,
|
||
"display": null,
|
||
"flex": null,
|
||
"flex_flow": null,
|
||
"grid_area": null,
|
||
"grid_auto_columns": null,
|
||
"grid_auto_flow": null,
|
||
"grid_auto_rows": null,
|
||
"grid_column": null,
|
||
"grid_gap": null,
|
||
"grid_row": null,
|
||
"grid_template_areas": null,
|
||
"grid_template_columns": null,
|
||
"grid_template_rows": null,
|
||
"height": null,
|
||
"justify_content": null,
|
||
"justify_items": null,
|
||
"left": null,
|
||
"margin": null,
|
||
"max_height": null,
|
||
"max_width": null,
|
||
"min_height": null,
|
||
"min_width": null,
|
||
"object_fit": null,
|
||
"object_position": null,
|
||
"order": null,
|
||
"overflow": null,
|
||
"overflow_x": null,
|
||
"overflow_y": null,
|
||
"padding": null,
|
||
"right": null,
|
||
"top": null,
|
||
"visibility": null,
|
||
"width": null
|
||
}
|
||
},
|
||
"8ddc3f81d9094d06b680908375077c62": {
|
||
"model_module": "@jupyter-widgets/base",
|
||
"model_module_version": "1.2.0",
|
||
"model_name": "LayoutModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/base",
|
||
"_model_module_version": "1.2.0",
|
||
"_model_name": "LayoutModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "LayoutView",
|
||
"align_content": null,
|
||
"align_items": null,
|
||
"align_self": null,
|
||
"border": null,
|
||
"bottom": null,
|
||
"display": null,
|
||
"flex": null,
|
||
"flex_flow": null,
|
||
"grid_area": null,
|
||
"grid_auto_columns": null,
|
||
"grid_auto_flow": null,
|
||
"grid_auto_rows": null,
|
||
"grid_column": null,
|
||
"grid_gap": null,
|
||
"grid_row": null,
|
||
"grid_template_areas": null,
|
||
"grid_template_columns": null,
|
||
"grid_template_rows": null,
|
||
"height": null,
|
||
"justify_content": null,
|
||
"justify_items": null,
|
||
"left": null,
|
||
"margin": null,
|
||
"max_height": null,
|
||
"max_width": null,
|
||
"min_height": null,
|
||
"min_width": null,
|
||
"object_fit": null,
|
||
"object_position": null,
|
||
"order": null,
|
||
"overflow": null,
|
||
"overflow_x": null,
|
||
"overflow_y": null,
|
||
"padding": null,
|
||
"right": null,
|
||
"top": null,
|
||
"visibility": null,
|
||
"width": null
|
||
}
|
||
},
|
||
"8e7128400e4c4eff96b67db314ccaff1": {
|
||
"model_module": "@jupyter-widgets/base",
|
||
"model_module_version": "1.2.0",
|
||
"model_name": "LayoutModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/base",
|
||
"_model_module_version": "1.2.0",
|
||
"_model_name": "LayoutModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "LayoutView",
|
||
"align_content": null,
|
||
"align_items": null,
|
||
"align_self": null,
|
||
"border": null,
|
||
"bottom": null,
|
||
"display": null,
|
||
"flex": null,
|
||
"flex_flow": null,
|
||
"grid_area": null,
|
||
"grid_auto_columns": null,
|
||
"grid_auto_flow": null,
|
||
"grid_auto_rows": null,
|
||
"grid_column": null,
|
||
"grid_gap": null,
|
||
"grid_row": null,
|
||
"grid_template_areas": null,
|
||
"grid_template_columns": null,
|
||
"grid_template_rows": null,
|
||
"height": null,
|
||
"justify_content": null,
|
||
"justify_items": null,
|
||
"left": null,
|
||
"margin": null,
|
||
"max_height": null,
|
||
"max_width": null,
|
||
"min_height": null,
|
||
"min_width": null,
|
||
"object_fit": null,
|
||
"object_position": null,
|
||
"order": null,
|
||
"overflow": null,
|
||
"overflow_x": null,
|
||
"overflow_y": null,
|
||
"padding": null,
|
||
"right": null,
|
||
"top": null,
|
||
"visibility": null,
|
||
"width": null
|
||
}
|
||
},
|
||
"91504476b2b34a9eb462a30da59a2b19": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "HBoxModel",
|
||
"state": {
|
||
"_dom_classes": [],
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "HBoxModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/controls",
|
||
"_view_module_version": "1.5.0",
|
||
"_view_name": "HBoxView",
|
||
"box_style": "",
|
||
"children": [
|
||
"IPY_MODEL_88ae9e2307804694bc546afb10a362f7",
|
||
"IPY_MODEL_9897c186c00947c280a7eae2fc9a315c",
|
||
"IPY_MODEL_9572601035c34a5eb88f81f6514f872d"
|
||
],
|
||
"layout": "IPY_MODEL_8e7128400e4c4eff96b67db314ccaff1"
|
||
}
|
||
},
|
||
"91b8f1667ff54011bd98fd748a0a91c6": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "HBoxModel",
|
||
"state": {
|
||
"_dom_classes": [],
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "HBoxModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/controls",
|
||
"_view_module_version": "1.5.0",
|
||
"_view_name": "HBoxView",
|
||
"box_style": "",
|
||
"children": [
|
||
"IPY_MODEL_3a1f9f8dff4e49fe8a94cd71fcfd3699",
|
||
"IPY_MODEL_6baff5e484754cdaa400a6adeab6958c",
|
||
"IPY_MODEL_2d7826d641614256a9f135515160958c"
|
||
],
|
||
"layout": "IPY_MODEL_6050e4a9af9e4c46aa4b38d407b7bab9"
|
||
}
|
||
},
|
||
"9572601035c34a5eb88f81f6514f872d": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "HTMLModel",
|
||
"state": {
|
||
"_dom_classes": [],
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "HTMLModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/controls",
|
||
"_view_module_version": "1.5.0",
|
||
"_view_name": "HTMLView",
|
||
"description": "",
|
||
"description_tooltip": null,
|
||
"layout": "IPY_MODEL_b08959c4edfa465588e03c99d00ad586",
|
||
"placeholder": "",
|
||
"style": "IPY_MODEL_8b25983eb05344928535625c726939d8",
|
||
"value": " 0/1 [00:00<?, ?it/s]"
|
||
}
|
||
},
|
||
"974da4c9934842ff8286f10a78790410": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "DescriptionStyleModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "DescriptionStyleModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "StyleView",
|
||
"description_width": ""
|
||
}
|
||
},
|
||
"9897c186c00947c280a7eae2fc9a315c": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "FloatProgressModel",
|
||
"state": {
|
||
"_dom_classes": [],
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "FloatProgressModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/controls",
|
||
"_view_module_version": "1.5.0",
|
||
"_view_name": "ProgressView",
|
||
"bar_style": "danger",
|
||
"description": "",
|
||
"description_tooltip": null,
|
||
"layout": "IPY_MODEL_d5f9951d6c094fcfb03e166af93cfea5",
|
||
"max": 1,
|
||
"min": 0,
|
||
"orientation": "horizontal",
|
||
"style": "IPY_MODEL_6efad0330efc4790a1eac95fcc96de17",
|
||
"value": 0
|
||
}
|
||
},
|
||
"9ecc775347df487bb63a5e1b2dcc68b7": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "HBoxModel",
|
||
"state": {
|
||
"_dom_classes": [],
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "HBoxModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/controls",
|
||
"_view_module_version": "1.5.0",
|
||
"_view_name": "HBoxView",
|
||
"box_style": "",
|
||
"children": [
|
||
"IPY_MODEL_073bf36ff26d455ca01956dee8d1f1a2",
|
||
"IPY_MODEL_ce14528df1ed4f1abb72ccb9a3c66443",
|
||
"IPY_MODEL_6d712f894c5d4d19a478fa1d1a2b2c62"
|
||
],
|
||
"layout": "IPY_MODEL_b0c4432101b948979653cd43bcd3fc4b"
|
||
}
|
||
},
|
||
"acbe4e7d94f04dfe9e797ab54d3102ad": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "DescriptionStyleModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "DescriptionStyleModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "StyleView",
|
||
"description_width": ""
|
||
}
|
||
},
|
||
"b08959c4edfa465588e03c99d00ad586": {
|
||
"model_module": "@jupyter-widgets/base",
|
||
"model_module_version": "1.2.0",
|
||
"model_name": "LayoutModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/base",
|
||
"_model_module_version": "1.2.0",
|
||
"_model_name": "LayoutModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "LayoutView",
|
||
"align_content": null,
|
||
"align_items": null,
|
||
"align_self": null,
|
||
"border": null,
|
||
"bottom": null,
|
||
"display": null,
|
||
"flex": null,
|
||
"flex_flow": null,
|
||
"grid_area": null,
|
||
"grid_auto_columns": null,
|
||
"grid_auto_flow": null,
|
||
"grid_auto_rows": null,
|
||
"grid_column": null,
|
||
"grid_gap": null,
|
||
"grid_row": null,
|
||
"grid_template_areas": null,
|
||
"grid_template_columns": null,
|
||
"grid_template_rows": null,
|
||
"height": null,
|
||
"justify_content": null,
|
||
"justify_items": null,
|
||
"left": null,
|
||
"margin": null,
|
||
"max_height": null,
|
||
"max_width": null,
|
||
"min_height": null,
|
||
"min_width": null,
|
||
"object_fit": null,
|
||
"object_position": null,
|
||
"order": null,
|
||
"overflow": null,
|
||
"overflow_x": null,
|
||
"overflow_y": null,
|
||
"padding": null,
|
||
"right": null,
|
||
"top": null,
|
||
"visibility": null,
|
||
"width": null
|
||
}
|
||
},
|
||
"b0c4432101b948979653cd43bcd3fc4b": {
|
||
"model_module": "@jupyter-widgets/base",
|
||
"model_module_version": "1.2.0",
|
||
"model_name": "LayoutModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/base",
|
||
"_model_module_version": "1.2.0",
|
||
"_model_name": "LayoutModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "LayoutView",
|
||
"align_content": null,
|
||
"align_items": null,
|
||
"align_self": null,
|
||
"border": null,
|
||
"bottom": null,
|
||
"display": null,
|
||
"flex": null,
|
||
"flex_flow": null,
|
||
"grid_area": null,
|
||
"grid_auto_columns": null,
|
||
"grid_auto_flow": null,
|
||
"grid_auto_rows": null,
|
||
"grid_column": null,
|
||
"grid_gap": null,
|
||
"grid_row": null,
|
||
"grid_template_areas": null,
|
||
"grid_template_columns": null,
|
||
"grid_template_rows": null,
|
||
"height": null,
|
||
"justify_content": null,
|
||
"justify_items": null,
|
||
"left": null,
|
||
"margin": null,
|
||
"max_height": null,
|
||
"max_width": null,
|
||
"min_height": null,
|
||
"min_width": null,
|
||
"object_fit": null,
|
||
"object_position": null,
|
||
"order": null,
|
||
"overflow": null,
|
||
"overflow_x": null,
|
||
"overflow_y": null,
|
||
"padding": null,
|
||
"right": null,
|
||
"top": null,
|
||
"visibility": null,
|
||
"width": null
|
||
}
|
||
},
|
||
"b23315ac058141fd9bf35c49276544d0": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "ProgressStyleModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "ProgressStyleModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "StyleView",
|
||
"bar_color": null,
|
||
"description_width": ""
|
||
}
|
||
},
|
||
"b7d70f2ce66f40ea8f606256cb654540": {
|
||
"model_module": "@jupyter-widgets/base",
|
||
"model_module_version": "1.2.0",
|
||
"model_name": "LayoutModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/base",
|
||
"_model_module_version": "1.2.0",
|
||
"_model_name": "LayoutModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "LayoutView",
|
||
"align_content": null,
|
||
"align_items": null,
|
||
"align_self": null,
|
||
"border": null,
|
||
"bottom": null,
|
||
"display": null,
|
||
"flex": null,
|
||
"flex_flow": null,
|
||
"grid_area": null,
|
||
"grid_auto_columns": null,
|
||
"grid_auto_flow": null,
|
||
"grid_auto_rows": null,
|
||
"grid_column": null,
|
||
"grid_gap": null,
|
||
"grid_row": null,
|
||
"grid_template_areas": null,
|
||
"grid_template_columns": null,
|
||
"grid_template_rows": null,
|
||
"height": null,
|
||
"justify_content": null,
|
||
"justify_items": null,
|
||
"left": null,
|
||
"margin": null,
|
||
"max_height": null,
|
||
"max_width": null,
|
||
"min_height": null,
|
||
"min_width": null,
|
||
"object_fit": null,
|
||
"object_position": null,
|
||
"order": null,
|
||
"overflow": null,
|
||
"overflow_x": null,
|
||
"overflow_y": null,
|
||
"padding": null,
|
||
"right": null,
|
||
"top": null,
|
||
"visibility": null,
|
||
"width": null
|
||
}
|
||
},
|
||
"ce14528df1ed4f1abb72ccb9a3c66443": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "FloatProgressModel",
|
||
"state": {
|
||
"_dom_classes": [],
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "FloatProgressModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/controls",
|
||
"_view_module_version": "1.5.0",
|
||
"_view_name": "ProgressView",
|
||
"bar_style": "success",
|
||
"description": "",
|
||
"description_tooltip": null,
|
||
"layout": "IPY_MODEL_b7d70f2ce66f40ea8f606256cb654540",
|
||
"max": 5,
|
||
"min": 0,
|
||
"orientation": "horizontal",
|
||
"style": "IPY_MODEL_d112b0758b97447ab47470e826e94687",
|
||
"value": 5
|
||
}
|
||
},
|
||
"d112b0758b97447ab47470e826e94687": {
|
||
"model_module": "@jupyter-widgets/controls",
|
||
"model_module_version": "1.5.0",
|
||
"model_name": "ProgressStyleModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/controls",
|
||
"_model_module_version": "1.5.0",
|
||
"_model_name": "ProgressStyleModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "StyleView",
|
||
"bar_color": null,
|
||
"description_width": ""
|
||
}
|
||
},
|
||
"d5f9951d6c094fcfb03e166af93cfea5": {
|
||
"model_module": "@jupyter-widgets/base",
|
||
"model_module_version": "1.2.0",
|
||
"model_name": "LayoutModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/base",
|
||
"_model_module_version": "1.2.0",
|
||
"_model_name": "LayoutModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "LayoutView",
|
||
"align_content": null,
|
||
"align_items": null,
|
||
"align_self": null,
|
||
"border": null,
|
||
"bottom": null,
|
||
"display": null,
|
||
"flex": null,
|
||
"flex_flow": null,
|
||
"grid_area": null,
|
||
"grid_auto_columns": null,
|
||
"grid_auto_flow": null,
|
||
"grid_auto_rows": null,
|
||
"grid_column": null,
|
||
"grid_gap": null,
|
||
"grid_row": null,
|
||
"grid_template_areas": null,
|
||
"grid_template_columns": null,
|
||
"grid_template_rows": null,
|
||
"height": null,
|
||
"justify_content": null,
|
||
"justify_items": null,
|
||
"left": null,
|
||
"margin": null,
|
||
"max_height": null,
|
||
"max_width": null,
|
||
"min_height": null,
|
||
"min_width": null,
|
||
"object_fit": null,
|
||
"object_position": null,
|
||
"order": null,
|
||
"overflow": null,
|
||
"overflow_x": null,
|
||
"overflow_y": null,
|
||
"padding": null,
|
||
"right": null,
|
||
"top": null,
|
||
"visibility": null,
|
||
"width": null
|
||
}
|
||
},
|
||
"e7775e44c82b472181e4f8ee6e7d918e": {
|
||
"model_module": "@jupyter-widgets/base",
|
||
"model_module_version": "1.2.0",
|
||
"model_name": "LayoutModel",
|
||
"state": {
|
||
"_model_module": "@jupyter-widgets/base",
|
||
"_model_module_version": "1.2.0",
|
||
"_model_name": "LayoutModel",
|
||
"_view_count": null,
|
||
"_view_module": "@jupyter-widgets/base",
|
||
"_view_module_version": "1.2.0",
|
||
"_view_name": "LayoutView",
|
||
"align_content": null,
|
||
"align_items": null,
|
||
"align_self": null,
|
||
"border": null,
|
||
"bottom": null,
|
||
"display": null,
|
||
"flex": null,
|
||
"flex_flow": null,
|
||
"grid_area": null,
|
||
"grid_auto_columns": null,
|
||
"grid_auto_flow": null,
|
||
"grid_auto_rows": null,
|
||
"grid_column": null,
|
||
"grid_gap": null,
|
||
"grid_row": null,
|
||
"grid_template_areas": null,
|
||
"grid_template_columns": null,
|
||
"grid_template_rows": null,
|
||
"height": null,
|
||
"justify_content": null,
|
||
"justify_items": null,
|
||
"left": null,
|
||
"margin": null,
|
||
"max_height": null,
|
||
"max_width": null,
|
||
"min_height": null,
|
||
"min_width": null,
|
||
"object_fit": null,
|
||
"object_position": null,
|
||
"order": null,
|
||
"overflow": null,
|
||
"overflow_x": null,
|
||
"overflow_y": null,
|
||
"padding": null,
|
||
"right": null,
|
||
"top": null,
|
||
"visibility": null,
|
||
"width": null
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 0
|
||
}
|