{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "EDdA-Classification_CNN_Conv1D-EGC.ipynb",
      "provenance": [],
      "collapsed_sections": []
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0yFsoHXX8Iyy"
      },
      "source": [
        "# Deep learning for EDdA classification"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "tFlUCDL2778i"
      },
      "source": [
        "## Setup colab environment"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Sp8d_Uus7SHJ",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "976ed0dd-7aeb-4f64-e34b-117733abf38c"
      },
      "source": [
        "from google.colab import drive\n",
        "drive.mount('/content/drive')"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Mounted at /content/drive\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jQBu-p6hBU-j"
      },
      "source": [
        "### Install packages"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "bTIXsF6kBUdh"
      },
      "source": [
        "#!pip install zeugma\n",
        "#!pip install plot_model"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "56-04SNF8BMx"
      },
      "source": [
        "### Import librairies"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "HwWkSznz7SEv"
      },
      "source": [
        "import pandas as pd\n",
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "import pickle\n",
        "import os\n",
        "\n",
        "from tqdm import tqdm\n",
        "import requests, zipfile, io\n",
        "import codecs\n",
        "\n",
        "from sklearn import preprocessing # LabelEncoder\n",
        "from sklearn.metrics import classification_report\n",
        "from sklearn.metrics import confusion_matrix\n",
        "\n",
        "from keras.preprocessing import sequence\n",
        "from keras.preprocessing.text import Tokenizer\n",
        "\n",
        "from keras.layers import BatchNormalization, Input, Reshape, Conv1D, MaxPool1D, Conv2D, MaxPool2D, Concatenate\n",
        "from keras.layers import Embedding, Dropout, Flatten, Dense\n",
        "from keras.models import Model, load_model\n",
        "from keras.callbacks import ModelCheckpoint\n"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xrekV6W978l4"
      },
      "source": [
        "### Utils functions"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "4LJ5blQR7PUe"
      },
      "source": [
        "\n",
        "def resample_classes(df, classColumnName, numberOfInstances):\n",
        "  #random numberOfInstances elements\n",
        "  replace = False  # with replacement\n",
        "  fn = lambda obj: obj.loc[np.random.choice(obj.index, numberOfInstances if len(obj) > numberOfInstances else len(obj), replace),:]\n",
        "  return df.groupby(classColumnName, as_index=False).apply(fn)\n",
        "    \n"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MtLr35eM753e"
      },
      "source": [
        "## Load Data"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "FnbNT4NF7zal",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "c2a72d94-c7ae-4e6a-b962-ec4677053555"
      },
      "source": [
        "!wget https://projet.liris.cnrs.fr/geode/EDdA-Classification/datasets/training_set.tsv\n",
        "!wget https://projet.liris.cnrs.fr/geode/EDdA-Classification/datasets/test_set.tsv"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "--2022-02-17 19:08:55--  https://projet.liris.cnrs.fr/geode/EDdA-Classification/datasets/training_set.tsv\n",
            "Resolving projet.liris.cnrs.fr (projet.liris.cnrs.fr)... 134.214.142.28\n",
            "Connecting to projet.liris.cnrs.fr (projet.liris.cnrs.fr)|134.214.142.28|:443... connected.\n",
            "HTTP request sent, awaiting response... 200 OK\n",
            "Length: 175634219 (167M) [text/tab-separated-values]\n",
            "Saving to: ‘training_set.tsv’\n",
            "\n",
            "training_set.tsv    100%[===================>] 167.50M  28.2MB/s    in 6.5s    \n",
            "\n",
            "2022-02-17 19:09:02 (25.7 MB/s) - ‘training_set.tsv’ saved [175634219/175634219]\n",
            "\n",
            "--2022-02-17 19:09:02--  https://projet.liris.cnrs.fr/geode/EDdA-Classification/datasets/test_set.tsv\n",
            "Resolving projet.liris.cnrs.fr (projet.liris.cnrs.fr)... 134.214.142.28\n",
            "Connecting to projet.liris.cnrs.fr (projet.liris.cnrs.fr)|134.214.142.28|:443... connected.\n",
            "HTTP request sent, awaiting response... 200 OK\n",
            "Length: 42730598 (41M) [text/tab-separated-values]\n",
            "Saving to: ‘test_set.tsv’\n",
            "\n",
            "test_set.tsv        100%[===================>]  40.75M  19.7MB/s    in 2.1s    \n",
            "\n",
            "2022-02-17 19:09:05 (19.7 MB/s) - ‘test_set.tsv’ saved [42730598/42730598]\n",
            "\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Loading dataset"
      ],
      "metadata": {
        "id": "UHushJ1XfUj9"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "train_path = 'training_set.tsv'\n",
        "test_path =  'test_set.tsv'"
      ],
      "metadata": {
        "id": "Q4te2c0bfvaJ"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "nRLaQUO97zcq"
      },
      "source": [
        "df_train = pd.read_csv(train_path, sep=\"\\t\")\n"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "df_train.sample(5)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 548
        },
        "id": "2MvHEc7zVK1N",
        "outputId": "a934bbce-4ebe-4d5a-eb4e-18db1ce10532"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "\n",
              "  <div id=\"df-24c25d4d-881e-4c52-8629-da71863f5656\">\n",
              "    <div 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>volume</th>\n",
              "      <th>numero</th>\n",
              "      <th>head</th>\n",
              "      <th>normClass</th>\n",
              "      <th>classEDdA</th>\n",
              "      <th>author</th>\n",
              "      <th>id_enccre</th>\n",
              "      <th>domaine_enccre</th>\n",
              "      <th>ensemble_domaine_enccre</th>\n",
              "      <th>content</th>\n",
              "      <th>contentWithoutClass</th>\n",
              "      <th>firstParagraph</th>\n",
              "      <th>nb_words</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>17253</th>\n",
              "      <td>1</td>\n",
              "      <td>4938</td>\n",
              "      <td>Auge</td>\n",
              "      <td>Verrerie</td>\n",
              "      <td>dans les Verreries</td>\n",
              "      <td>unsigned</td>\n",
              "      <td>v1-3613-9</td>\n",
              "      <td>verrerie</td>\n",
              "      <td>Métiers</td>\n",
              "      <td>Auge, dans les Verreries, ce sont de gros hêtr...</td>\n",
              "      <td>auge gros hêtre \\n creusés tient plein eau ser...</td>\n",
              "      <td>auge gros hêtre \\n creusés tient plein eau ser...</td>\n",
              "      <td>70</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>16170</th>\n",
              "      <td>9</td>\n",
              "      <td>2017</td>\n",
              "      <td>Lettres de reprise</td>\n",
              "      <td>unclassified</td>\n",
              "      <td>unclassified</td>\n",
              "      <td>Boucher d'Argis</td>\n",
              "      <td>v9-1324-120</td>\n",
              "      <td>jurisprudence</td>\n",
              "      <td>Droit - Jurisprudence</td>\n",
              "      <td>Lettres de reprise, sont une commission que\\nl...</td>\n",
              "      <td>lettre reprise commission \\n prend chancelleri...</td>\n",
              "      <td>lettre reprise commission \\n prend chancelleri...</td>\n",
              "      <td>36</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>12041</th>\n",
              "      <td>16</td>\n",
              "      <td>1213</td>\n",
              "      <td>THOLUS</td>\n",
              "      <td>Architecture romaine</td>\n",
              "      <td>Archit. rom.</td>\n",
              "      <td>Jaucourt</td>\n",
              "      <td>v16-709-0</td>\n",
              "      <td>architecture</td>\n",
              "      <td>Architecture</td>\n",
              "      <td>THOLUS, s. m. (Archit. rom.) Vitruve nomme\\nth...</td>\n",
              "      <td>tholus s. m.   vitruve nomme \\n tholus coupe d...</td>\n",
              "      <td>tholus s. m.   vitruve nomme \\n tholus coupe d...</td>\n",
              "      <td>95</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>20046</th>\n",
              "      <td>9</td>\n",
              "      <td>4327</td>\n",
              "      <td>MALLIENS, les</td>\n",
              "      <td>Géographie ancienne</td>\n",
              "      <td>Geog. anc.</td>\n",
              "      <td>Jaucourt</td>\n",
              "      <td>v9-2589-0</td>\n",
              "      <td>géographie</td>\n",
              "      <td>Géographie</td>\n",
              "      <td>MALLIENS, les, (Géog. anc.) en latin Malli ;\\n...</td>\n",
              "      <td>malliens géog anc latin malli \\n ancien peuple...</td>\n",
              "      <td>malliens géog anc latin malli \\n ancien peuple...</td>\n",
              "      <td>71</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>35783</th>\n",
              "      <td>9</td>\n",
              "      <td>3883</td>\n",
              "      <td>MAGDOLOS</td>\n",
              "      <td>Géographie ancienne</td>\n",
              "      <td>Geog. anc.</td>\n",
              "      <td>Jaucourt</td>\n",
              "      <td>v9-2377-0</td>\n",
              "      <td>géographie</td>\n",
              "      <td>Géographie</td>\n",
              "      <td>MAGDOLOS, (Géog. anc.) ville d'Egypte dont\\npa...</td>\n",
              "      <td>magdolos géog anc ville egypte \\n parlent jéré...</td>\n",
              "      <td>magdolos géog anc ville egypte \\n parlent jéré...</td>\n",
              "      <td>50</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>\n",
              "      <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-24c25d4d-881e-4c52-8629-da71863f5656')\"\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 0 24 24\"\n",
              "       width=\"24px\">\n",
              "    <path d=\"M0 0h24v24H0V0z\" fill=\"none\"/>\n",
              "    <path d=\"M18.56 5.44l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94zm-11 1L8.5 8.5l.94-2.06 2.06-.94-2.06-.94L8.5 2.5l-.94 2.06-2.06.94zm10 10l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94z\"/><path d=\"M17.41 7.96l-1.37-1.37c-.4-.4-.92-.59-1.43-.59-.52 0-1.04.2-1.43.59L10.3 9.45l-7.72 7.72c-.78.78-.78 2.05 0 2.83L4 21.41c.39.39.9.59 1.41.59.51 0 1.02-.2 1.41-.59l7.78-7.78 2.81-2.81c.8-.78.8-2.07 0-2.86zM5.41 20L4 18.59l7.72-7.72 1.47 1.35L5.41 20z\"/>\n",
              "  </svg>\n",
              "      </button>\n",
              "      \n",
              "  <style>\n",
              "    .colab-df-container {\n",
              "      display:flex;\n",
              "      flex-wrap:wrap;\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",
              "    [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-24c25d4d-881e-4c52-8629-da71863f5656 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-24c25d4d-881e-4c52-8629-da71863f5656');\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",
              "  </div>\n",
              "  "
            ],
            "text/plain": [
              "       volume  ...  nb_words\n",
              "17253       1  ...        70\n",
              "16170       9  ...        36\n",
              "12041      16  ...        95\n",
              "20046       9  ...        71\n",
              "35783       9  ...        50\n",
              "\n",
              "[5 rows x 13 columns]"
            ]
          },
          "metadata": {},
          "execution_count": 7
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Configuration\n"
      ],
      "metadata": {
        "id": "-63bh_cKfN4p"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "columnText = 'contentWithoutClass'\n",
        "columnClass = 'ensemble_domaine_enccre'\n",
        "\n",
        "maxOfInstancePerClass = 10000\n",
        "\n",
        "batch_size = 64\n",
        "validation_split = 0.20\n",
        "max_nb_words = 20000        # taille du vocabulaire\n",
        "max_sequence_length = 512   # taille max du 'document' \n",
        "epochs = 10\n",
        "\n",
        "#embedding_name = \"fasttext\" \n",
        "#embedding_dim = 300 \n",
        "\n",
        "embedding_name = \"glove.6B.100d\"\n",
        "embedding_dim = 100 \n",
        "\n",
        "path = \"drive/MyDrive/Classification-EDdA/\"\n",
        "encoder_filename = \"label_encoder.pkl\"\n",
        "tokenizer_filename = \"tokenizer_keras.pkl\""
      ],
      "metadata": {
        "id": "nsRuyzYUfOBg"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Preprocessing\n"
      ],
      "metadata": {
        "id": "ZDz-Y1LCfQt0"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "if maxOfInstancePerClass != 10000:\n",
        "  df_train = resample_classes(df_train, columnClass, maxOfInstancePerClass)"
      ],
      "metadata": {
        "id": "cP5e7DvRvwxh"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "vGWAgBH87ze8"
      },
      "source": [
        "labels  = df_train[columnClass]\n",
        "numberOfClasses = labels.nunique()\n",
        "\n",
        "if os.path.isfile(path+encoder_filename):    \n",
        "    # load existing encoder \n",
        "    with open(path+encoder_filename, 'rb') as file:\n",
        "      encoder = pickle.load(file)\n",
        "\n",
        "else:\n",
        "  encoder = preprocessing.LabelEncoder()\n",
        "  encoder.fit(labels)\n",
        "\n",
        "  with open(path+encoder_filename, 'wb') as file:\n",
        "      pickle.dump(encoder, file)\n",
        "\n",
        "\n",
        "labels = encoder.transform(labels)"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "encoder.classes_"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "SME4vvVhW9Sn",
        "outputId": "8b577b93-69a5-47e3-ea3b-6a2e1d144914"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "array(['Agriculture - Economie rustique', 'Anatomie', 'Antiquité',\n",
              "       'Architecture', 'Arts et métiers', 'Beaux-arts',\n",
              "       'Belles-lettres - Poésie', 'Blason', 'Caractères', 'Chasse',\n",
              "       'Chimie', 'Commerce', 'Droit - Jurisprudence',\n",
              "       'Economie domestique', 'Grammaire', 'Géographie', 'Histoire',\n",
              "       'Histoire naturelle', 'Jeu', 'Marine', 'Maréchage - Manège',\n",
              "       'Mathématiques', 'Mesure', 'Militaire (Art) - Guerre - Arme',\n",
              "       'Minéralogie', 'Monnaie', 'Musique', 'Médailles',\n",
              "       'Médecine - Chirurgie', 'Métiers', 'Pharmacie', 'Philosophie',\n",
              "       'Physique - [Sciences physico-mathématiques]', 'Politique',\n",
              "       'Pêche', 'Religion', 'Spectacle', 'Superstition'], dtype=object)"
            ]
          },
          "metadata": {},
          "execution_count": 13
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "labels_index = dict(zip(list(encoder.classes_), encoder.transform(list(encoder.classes_))))"
      ],
      "metadata": {
        "id": "nIzWQ2VbW_UO"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "labels_index"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "4e7ggEGiXC_W",
        "outputId": "8a22e814-c63c-4e0d-adb9-899c11a1dc9b"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "{'Agriculture - Economie rustique': 0,\n",
              " 'Anatomie': 1,\n",
              " 'Antiquité': 2,\n",
              " 'Architecture': 3,\n",
              " 'Arts et métiers': 4,\n",
              " 'Beaux-arts': 5,\n",
              " 'Belles-lettres - Poésie': 6,\n",
              " 'Blason': 7,\n",
              " 'Caractères': 8,\n",
              " 'Chasse': 9,\n",
              " 'Chimie': 10,\n",
              " 'Commerce': 11,\n",
              " 'Droit - Jurisprudence': 12,\n",
              " 'Economie domestique': 13,\n",
              " 'Grammaire': 14,\n",
              " 'Géographie': 15,\n",
              " 'Histoire': 16,\n",
              " 'Histoire naturelle': 17,\n",
              " 'Jeu': 18,\n",
              " 'Marine': 19,\n",
              " 'Maréchage - Manège': 20,\n",
              " 'Mathématiques': 21,\n",
              " 'Mesure': 22,\n",
              " 'Militaire (Art) - Guerre - Arme': 23,\n",
              " 'Minéralogie': 24,\n",
              " 'Monnaie': 25,\n",
              " 'Musique': 26,\n",
              " 'Médailles': 27,\n",
              " 'Médecine - Chirurgie': 28,\n",
              " 'Métiers': 29,\n",
              " 'Pharmacie': 30,\n",
              " 'Philosophie': 31,\n",
              " 'Physique - [Sciences physico-mathématiques]': 32,\n",
              " 'Politique': 33,\n",
              " 'Pêche': 34,\n",
              " 'Religion': 35,\n",
              " 'Spectacle': 36,\n",
              " 'Superstition': 37}"
            ]
          },
          "metadata": {},
          "execution_count": 15
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Loading pre-trained embeddings"
      ],
      "metadata": {
        "id": "CoQSwXfNEOOx"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "#### FastText"
      ],
      "metadata": {
        "id": "PUn9G_LYEYvM"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# download FastText (prend trop de place pour le laisser sur le drive)\n",
        "zip_file_url = \"https://dl.fbaipublicfiles.com/fasttext/vectors-english/crawl-300d-2M.vec.zip\"\n",
        "r = requests.get(zip_file_url)\n",
        "z = zipfile.ZipFile(io.BytesIO(r.content))\n",
        "z.extractall()"
      ],
      "metadata": {
        "id": "qKQFmUs0EY5E"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "print('loading word embeddings FastText...')\n",
        "\n",
        "embeddings_index = {}\n",
        "f = codecs.open('crawl-300d-2M.vec', encoding='utf-8')\n",
        "\n",
        "for line in tqdm(f):\n",
        "    values = line.rstrip().rsplit(' ')\n",
        "    word = values[0]\n",
        "    coefs = np.asarray(values[1:], dtype='float32')\n",
        "    embeddings_index[word] = coefs\n",
        "f.close()\n",
        "\n",
        "print('found %s word vectors' % len(embeddings_index))"
      ],
      "metadata": {
        "id": "x0C0XwhwEY7Z"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "#### GLOVE"
      ],
      "metadata": {
        "id": "q81MEgYrEWsj"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# download Glove\n",
        "#zip_file_url = \"https://nlp.stanford.edu/data/glove.6B.zip\"\n",
        "#r = requests.get(zip_file_url)\n",
        "#z = zipfile.ZipFile(io.BytesIO(r.content))\n",
        "#z.extractall()"
      ],
      "metadata": {
        "id": "qTHuXs2EEV-M"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "print('loading word embeddings GLOVE...')\n",
        "\n",
        "embeddings_index = {}\n",
        "f = open(path+\"embeddings/\"+embedding_name+\".txt\", encoding='utf-8')\n",
        "for line in tqdm(f):\n",
        "    values = line.split()\n",
        "    word = values[0]\n",
        "    coefs = np.asarray(values[1:], dtype='float32')\n",
        "    embeddings_index[word] = coefs\n",
        "f.close()\n",
        "\n",
        "print('Found %s word vectors.' % len(embeddings_index))"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "U0hwICJzEOVL",
        "outputId": "be478f5b-6c4a-48ee-e05d-49b2e7fdd285"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "loading word embeddings GLOVE...\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "400000it [00:12, 31570.08it/s]"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Found 400000 word vectors.\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HuUVfklf-dSR"
      },
      "source": [
        "## Training models"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "NTNh6kMTp_eU",
        "outputId": "fba63a44-73c5-4928-ad7e-7356b17af073"
      },
      "source": [
        "\n",
        "raw_docs_train = df_train[columnText].tolist()\n",
        "\n",
        "\n",
        "print(\"pre-processing train data...\")\n",
        "\n",
        "if os.path.isfile(path+tokenizer_filename):\n",
        "  with open(path+tokenizer_filename, 'rb') as file:\n",
        "      tokenizer = pickle.load(file)\n",
        "else:\n",
        "  tokenizer = Tokenizer(num_words = max_nb_words)\n",
        "  tokenizer.fit_on_texts(raw_docs_train) \n",
        "\n",
        "  with open(path+tokenizer_filename, 'wb') as file:\n",
        "        pickle.dump(tokenizer, file)\n",
        "\n",
        "sequences = tokenizer.texts_to_sequences(raw_docs_train)\n",
        "\n",
        "word_index = tokenizer.word_index\n",
        "print(\"dictionary size: \", len(word_index))\n",
        "\n",
        "#pad sequences\n",
        "data = sequence.pad_sequences(sequences, maxlen=max_sequence_length)\n",
        "\n",
        "print('Shape of data tensor:', data.shape)\n",
        "print('Shape of label tensor:', labels.shape)\n",
        "#print(labels)"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "pre-processing train data...\n",
            "dictionary size:  190508\n",
            "Shape of data tensor: (46807, 512)\n",
            "Shape of label tensor: (46807,)\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# split the data into a training set and a validation set\n",
        "\n",
        "indices = np.arange(data.shape[0])\n",
        "np.random.shuffle(indices)\n",
        "data = data[indices]\n",
        "labels = labels[indices]\n",
        "\n",
        "nb_validation_samples = int(validation_split * data.shape[0])\n",
        "\n",
        "x_train = data[:-nb_validation_samples]\n",
        "y_train = labels[:-nb_validation_samples]\n",
        "x_val = data[-nb_validation_samples:]\n",
        "y_val = labels[-nb_validation_samples:]\n"
      ],
      "metadata": {
        "id": "sHYJ4P-YDfFb"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "wGjQI0YgpQAS",
        "outputId": "ab38f7a8-8c10-471f-88e6-10a62ae1776c"
      },
      "source": [
        "#embedding matrix\n",
        "\n",
        "print('preparing embedding matrix...')\n",
        "\n",
        "embedding_matrix = np.zeros((len(word_index)+1, embedding_dim))\n",
        "\n",
        "for word, i in word_index.items():\n",
        "    embedding_vector = embeddings_index.get(word)\n",
        "    if embedding_vector is not None : \n",
        "        embedding_matrix[i] = embedding_vector\n"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "preparing embedding matrix...\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "\n",
        "#filter_sizes = [2,  3, 5]\n",
        "#drop = 0.5\n",
        "\n",
        "embedding_layer = Embedding(len(word_index)+1, embedding_dim, input_length = max_sequence_length,\n",
        "                    weights=[embedding_matrix], trainable=False)\n",
        "inputs = Input(shape=(max_sequence_length), dtype='int32')\n",
        "embedding = embedding_layer(inputs)\n",
        "\n",
        "print(embedding.shape)\n",
        "#reshape = Reshape((max_sequence_length, embedding_dim, 1))(embedding)\n",
        "#print(reshape.shape)\n",
        "\n",
        "# architecture testée par Khaled\n",
        "\n",
        "conv_0 = Conv1D(64, 5, activation='relu')(embedding)\n",
        "#conv_1 = Conv1D(128, 5, activation='relu')(embedding)\n",
        "#conv_2 = Conv1D(128, 5, activation='relu')(embedding)\n",
        "\n",
        "maxpool_0 = MaxPool1D(pool_size=(max_sequence_length - 5 + 1))(conv_0)\n",
        "#maxpool_1 = MaxPool1D(5)(conv_1)\n",
        "#maxpool_2 = MaxPool1D(35)(conv_2)\n",
        "\n",
        "#concatenated_tensor = Concatenate(axis=1)([maxpool_0, maxpool_1, maxpool_2])\n",
        "flatten = Flatten()(maxpool_0)\n",
        "#dropout = Dropout(drop)(flatten)\n",
        "output = Dense(len(labels_index), activation='softmax')(flatten)\n",
        "\n",
        "# this creates a model that includes\n",
        "model = Model(inputs=inputs, outputs=output)\n",
        "\n",
        "checkpoint = ModelCheckpoint('weights_cnn_sentece.hdf5', monitor='val_acc', verbose=1, save_best_only=True, mode='auto')\n",
        "#adam = Adam(lr=1e-4, beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.0)\n",
        "\n",
        "model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['acc'])\n",
        "model.summary()"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "OUphqlYJCC9n",
        "outputId": "7b8a479d-ba34-4ea7-b714-107b9c7166b3"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "(None, 512, 100)\n",
            "Model: \"model\"\n",
            "_________________________________________________________________\n",
            " Layer (type)                Output Shape              Param #   \n",
            "=================================================================\n",
            " input_1 (InputLayer)        [(None, 512)]             0         \n",
            "                                                                 \n",
            " embedding (Embedding)       (None, 512, 100)          19050900  \n",
            "                                                                 \n",
            " conv1d (Conv1D)             (None, 508, 64)           32064     \n",
            "                                                                 \n",
            " max_pooling1d (MaxPooling1D  (None, 1, 64)            0         \n",
            " )                                                               \n",
            "                                                                 \n",
            " flatten (Flatten)           (None, 64)                0         \n",
            "                                                                 \n",
            " dense (Dense)               (None, 38)                2470      \n",
            "                                                                 \n",
            "=================================================================\n",
            "Total params: 19,085,434\n",
            "Trainable params: 34,534\n",
            "Non-trainable params: 19,050,900\n",
            "_________________________________________________________________\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "history = model.fit(x_train, y_train, \n",
        "                    batch_size=batch_size, \n",
        "                    epochs=epochs, \n",
        "                    verbose=1,\n",
        "                    callbacks=[checkpoint],\n",
        "                    validation_data=(x_val, y_val))"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "3aUBdLdNCEGK",
        "outputId": "591e58dc-c403-445a-dab6-3d902f0f6465"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Epoch 1/10\n",
            "585/586 [============================>.] - ETA: 0s - loss: 2.0486 - acc: 0.4831\n",
            "Epoch 1: val_acc improved from -inf to 0.56832, saving model to weights_cnn_sentece.hdf5\n",
            "586/586 [==============================] - 93s 157ms/step - loss: 2.0484 - acc: 0.4831 - val_loss: 1.6547 - val_acc: 0.5683\n",
            "Epoch 2/10\n",
            "585/586 [============================>.] - ETA: 0s - loss: 1.4558 - acc: 0.6155\n",
            "Epoch 2: val_acc improved from 0.56832 to 0.61949, saving model to weights_cnn_sentece.hdf5\n",
            "586/586 [==============================] - 85s 145ms/step - loss: 1.4557 - acc: 0.6156 - val_loss: 1.4356 - val_acc: 0.6195\n",
            "Epoch 3/10\n",
            "585/586 [============================>.] - ETA: 0s - loss: 1.2437 - acc: 0.6631\n",
            "Epoch 3: val_acc improved from 0.61949 to 0.63829, saving model to weights_cnn_sentece.hdf5\n",
            "586/586 [==============================] - 84s 143ms/step - loss: 1.2439 - acc: 0.6631 - val_loss: 1.3358 - val_acc: 0.6383\n",
            "Epoch 4/10\n",
            "585/586 [============================>.] - ETA: 0s - loss: 1.1175 - acc: 0.6942\n",
            "Epoch 4: val_acc improved from 0.63829 to 0.65111, saving model to weights_cnn_sentece.hdf5\n",
            "586/586 [==============================] - 84s 143ms/step - loss: 1.1176 - acc: 0.6941 - val_loss: 1.2895 - val_acc: 0.6511\n",
            "Epoch 5/10\n",
            "585/586 [============================>.] - ETA: 0s - loss: 1.0243 - acc: 0.7172\n",
            "Epoch 5: val_acc improved from 0.65111 to 0.65356, saving model to weights_cnn_sentece.hdf5\n",
            "586/586 [==============================] - 84s 143ms/step - loss: 1.0242 - acc: 0.7172 - val_loss: 1.2751 - val_acc: 0.6536\n",
            "Epoch 6/10\n",
            "585/586 [============================>.] - ETA: 0s - loss: 0.9492 - acc: 0.7371\n",
            "Epoch 6: val_acc improved from 0.65356 to 0.65987, saving model to weights_cnn_sentece.hdf5\n",
            "586/586 [==============================] - 92s 158ms/step - loss: 0.9491 - acc: 0.7371 - val_loss: 1.2598 - val_acc: 0.6599\n",
            "Epoch 7/10\n",
            "585/586 [============================>.] - ETA: 0s - loss: 0.8892 - acc: 0.7536\n",
            "Epoch 7: val_acc did not improve from 0.65987\n",
            "586/586 [==============================] - 86s 147ms/step - loss: 0.8892 - acc: 0.7536 - val_loss: 1.2598 - val_acc: 0.6557\n",
            "Epoch 8/10\n",
            "585/586 [============================>.] - ETA: 0s - loss: 0.8387 - acc: 0.7659\n",
            "Epoch 8: val_acc improved from 0.65987 to 0.66179, saving model to weights_cnn_sentece.hdf5\n",
            "586/586 [==============================] - 85s 145ms/step - loss: 0.8387 - acc: 0.7659 - val_loss: 1.2452 - val_acc: 0.6618\n",
            "Epoch 9/10\n",
            "585/586 [============================>.] - ETA: 0s - loss: 0.7950 - acc: 0.7780\n",
            "Epoch 9: val_acc improved from 0.66179 to 0.66275, saving model to weights_cnn_sentece.hdf5\n",
            "586/586 [==============================] - 83s 142ms/step - loss: 0.7950 - acc: 0.7780 - val_loss: 1.2593 - val_acc: 0.6627\n",
            "Epoch 10/10\n",
            "585/586 [============================>.] - ETA: 0s - loss: 0.7575 - acc: 0.7873\n",
            "Epoch 10: val_acc improved from 0.66275 to 0.66286, saving model to weights_cnn_sentece.hdf5\n",
            "586/586 [==============================] - 83s 141ms/step - loss: 0.7575 - acc: 0.7873 - val_loss: 1.2646 - val_acc: 0.6629\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        ""
      ],
      "metadata": {
        "id": "ZcYbQsQEJKLq"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "\n",
        "plt.plot(history.history['acc'])\n",
        "plt.plot(history.history['val_acc'])\n",
        "plt.title('model accuracy')\n",
        "plt.ylabel('accuracy')\n",
        "plt.xlabel('epoch')\n",
        "plt.legend(['train', 'validation'], loc='lower right')\n",
        "plt.show()\n",
        "\n",
        "# summarize history for loss\n",
        "plt.plot(history.history['loss'])\n",
        "plt.plot(history.history['val_loss'])\n",
        "plt.title('model loss')\n",
        "plt.ylabel('loss')\n",
        "plt.xlabel('epoch')\n",
        "plt.legend(['train', 'validation'], loc='upper right')\n",
        "plt.show()\n",
        "\n"
      ],
      "metadata": {
        "id": "Job-3uMvJKN_",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 573
        },
        "outputId": "612f25b7-e9ad-43c6-e084-041e2a5f3b64"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "<Figure size 432x288 with 1 Axes>"
            ]
          },
          "metadata": {
            "needs_background": "light"
          }
        },
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "<Figure size 432x288 with 1 Axes>"
            ]
          },
          "metadata": {
            "needs_background": "light"
          }
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Uw6YR76p_AF0"
      },
      "source": [
        "## Saving models"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "name = \"cnn_conv1D_egc_\"+embedding_name+\"_s\"+str(maxOfInstancePerClass)"
      ],
      "metadata": {
        "id": "irB4mATeeUcw"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "ykTp9lyRaAma"
      },
      "source": [
        "model.save(path+name+\".h5\")\n"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "5J4xDoqRUSfS"
      },
      "source": [
        "# save embeddings\n",
        "\n",
        "# saving embeddings index \n"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HHlEtipG_Cp0"
      },
      "source": [
        "## Loading models"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "fKt8ft1t_Cxx"
      },
      "source": [
        "model = load_model(path+name+\".h5\")\n",
        "\n",
        "with open(path+tokenizer_filename, 'rb') as file:\n",
        "  tokenizer = pickle.load(file)\n",
        "\n",
        "with open(path+encoder_filename, 'rb') as file:\n",
        "  encoder = pickle.load(file)\n"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zbS4poso-3k7"
      },
      "source": [
        "## Evaluation"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "df_test = pd.read_csv(test_path, sep=\"\\t\")\n"
      ],
      "metadata": {
        "id": "KWORvsadvBbr"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "test_texts = df_test[columnText].tolist()\n",
        "test_labels  = df_test[columnClass].tolist()\n",
        "\n",
        "test_sequences = tokenizer.texts_to_sequences(test_texts)\n",
        "test_input = sequence.pad_sequences(test_sequences, maxlen=max_sequence_length)\n",
        "\n",
        "# Get predictions\n",
        "test_predictions_probas = model.predict(test_input)\n",
        "test_predictions = test_predictions_probas.argmax(axis=-1)"
      ],
      "metadata": {
        "id": "Xr0o-0i5t38G"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "\n",
        "\n",
        "\n",
        "test_intent_predictions = encoder.inverse_transform(test_predictions)\n",
        "#test_intent_original = encoder.inverse_transform(test_labels)\n",
        "\n",
        "print('accuracy: ', sum(test_intent_predictions == test_labels) / len(test_labels))\n",
        "print(\"Precision, Recall and F1-Score:\\n\\n\", classification_report(test_labels, test_intent_predictions))\n",
        "\n"
      ],
      "metadata": {
        "id": "lSn8yZ0gt3-d",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "b8077e36-fa15-467d-9bf8-0877982c6f80"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "accuracy:  0.6617672192787558\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "/usr/local/lib/python3.7/dist-packages/sklearn/metrics/_classification.py:1318: UndefinedMetricWarning: Precision and F-score are ill-defined and being set to 0.0 in labels with no predicted samples. Use `zero_division` parameter to control this behavior.\n",
            "  _warn_prf(average, modifier, msg_start, len(result))\n",
            "/usr/local/lib/python3.7/dist-packages/sklearn/metrics/_classification.py:1318: UndefinedMetricWarning: Precision and F-score are ill-defined and being set to 0.0 in labels with no predicted samples. Use `zero_division` parameter to control this behavior.\n",
            "  _warn_prf(average, modifier, msg_start, len(result))\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Precision, Recall and F1-Score:\n",
            "\n",
            "                                              precision    recall  f1-score   support\n",
            "\n",
            "            Agriculture - Economie rustique       0.40      0.28      0.33       233\n",
            "                                   Anatomie       0.79      0.53      0.63       215\n",
            "                                  Antiquité       0.47      0.50      0.48       272\n",
            "                               Architecture       0.54      0.47      0.51       278\n",
            "                            Arts et métiers       0.37      0.13      0.20       112\n",
            "                                 Beaux-arts       0.49      0.30      0.37        86\n",
            "                    Belles-lettres - Poésie       0.31      0.22      0.26       206\n",
            "                                     Blason       0.59      0.48      0.53       108\n",
            "                                 Caractères       1.00      0.09      0.16        23\n",
            "                                     Chasse       0.66      0.53      0.58       116\n",
            "                                     Chimie       0.40      0.31      0.35       104\n",
            "                                   Commerce       0.48      0.54      0.51       376\n",
            "                      Droit - Jurisprudence       0.79      0.76      0.77      1284\n",
            "                        Economie domestique       0.20      0.04      0.06        27\n",
            "                                  Grammaire       0.43      0.38      0.40       452\n",
            "                                 Géographie       0.95      0.94      0.95      2621\n",
            "                                   Histoire       0.39      0.53      0.45       616\n",
            "                         Histoire naturelle       0.77      0.82      0.79       963\n",
            "                                        Jeu       0.63      0.64      0.64        56\n",
            "                                     Marine       0.65      0.71      0.68       415\n",
            "                         Maréchage - Manège       0.85      0.72      0.78       105\n",
            "                              Mathématiques       0.56      0.61      0.58       140\n",
            "                                     Mesure       0.33      0.05      0.09        37\n",
            "            Militaire (Art) - Guerre - Arme       0.57      0.63      0.60       258\n",
            "                                Minéralogie       0.10      0.05      0.06        22\n",
            "                                    Monnaie       0.27      0.13      0.17        63\n",
            "                                    Musique       0.73      0.53      0.61       137\n",
            "                                  Médailles       0.86      0.26      0.40        23\n",
            "                       Médecine - Chirurgie       0.51      0.64      0.57       455\n",
            "                                    Métiers       0.53      0.67      0.59      1051\n",
            "                                  Pharmacie       0.39      0.14      0.20        65\n",
            "                                Philosophie       0.41      0.27      0.32        94\n",
            "Physique - [Sciences physico-mathématiques]       0.52      0.56      0.54       265\n",
            "                                  Politique       0.50      0.04      0.08        23\n",
            "                                      Pêche       0.75      0.43      0.55        42\n",
            "                                   Religion       0.54      0.55      0.55       328\n",
            "                                  Spectacle       0.00      0.00      0.00         9\n",
            "                               Superstition       0.86      0.27      0.41        22\n",
            "\n",
            "                                   accuracy                           0.66     11702\n",
            "                                  macro avg       0.54      0.41      0.44     11702\n",
            "                               weighted avg       0.66      0.66      0.66     11702\n",
            "\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "/usr/local/lib/python3.7/dist-packages/sklearn/metrics/_classification.py:1318: UndefinedMetricWarning: Precision and F-score are ill-defined and being set to 0.0 in labels with no predicted samples. Use `zero_division` parameter to control this behavior.\n",
            "  _warn_prf(average, modifier, msg_start, len(result))\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "name = \"test_\"+ name\n",
        "\n",
        "#classesName = encoder.classes_\n",
        "#classes = [str(e) for e in encoder.transform(encoder.classes_)]\n",
        "\n",
        "report = classification_report(test_labels, test_intent_predictions, output_dict = True)\n",
        "\n",
        "precision = []\n",
        "recall = []\n",
        "f1 = []\n",
        "support = []\n",
        "dff = pd.DataFrame(columns= ['className', 'precision', 'recall', 'f1-score', 'support', 'FP', 'FN', 'TP', 'TN'])\n",
        "for c in encoder.classes_:\n",
        "  precision.append(report[c]['precision'])\n",
        "  recall.append(report[c]['recall'])\n",
        "  f1.append(report[c]['f1-score'])\n",
        "  support.append(report[c]['support'])\n",
        "\n",
        "accuracy = report['accuracy']\n",
        "weighted_avg = report['weighted avg']\n",
        "\n",
        "\n",
        "cnf_matrix = confusion_matrix(test_labels, test_intent_predictions)\n",
        "FP = cnf_matrix.sum(axis=0) - np.diag(cnf_matrix)\n",
        "FN = cnf_matrix.sum(axis=1) - np.diag(cnf_matrix)\n",
        "TP = np.diag(cnf_matrix)\n",
        "TN = cnf_matrix.sum() - (FP + FN + TP)\n",
        "\n",
        "dff['className'] = encoder.classes_\n",
        "dff['precision'] = precision\n",
        "dff['recall'] = recall\n",
        "dff['f1-score'] = f1\n",
        "dff['support'] = support\n",
        "dff['FP'] = FP\n",
        "dff['FN'] = FN\n",
        "dff['TP'] = TP\n",
        "dff['TN'] = TN\n",
        "\n",
        "\n",
        "\n",
        "      \n",
        "content = name + \"\\n\"\n",
        "print(name)\n",
        "content += str(weighted_avg) + \"\\n\"\n",
        "print(weighted_avg)\n",
        "print(accuracy)\n",
        "print(dff)\n",
        "\n",
        "dff.to_csv(path+\"reports/report_\"+name+\".csv\", index=False)\n",
        "\n",
        "# enregistrer les predictions\n",
        "pd.DataFrame({'labels': pd.Series(df_test[columnClass]), 'predictions': pd.Series(test_intent_predictions)}).to_csv(path+\"predictions/predictions_\"+name+\".csv\")\n",
        "\n",
        "with open(path+\"reports/report_\"+name+\".txt\", 'w') as f:\n",
        "  f.write(content)\n"
      ],
      "metadata": {
        "id": "RQ0LYGuOt4A4",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "bf597b6f-9c83-4fe3-c913-eed91c5610d6"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "/usr/local/lib/python3.7/dist-packages/sklearn/metrics/_classification.py:1318: UndefinedMetricWarning: Precision and F-score are ill-defined and being set to 0.0 in labels with no predicted samples. Use `zero_division` parameter to control this behavior.\n",
            "  _warn_prf(average, modifier, msg_start, len(result))\n",
            "/usr/local/lib/python3.7/dist-packages/sklearn/metrics/_classification.py:1318: UndefinedMetricWarning: Precision and F-score are ill-defined and being set to 0.0 in labels with no predicted samples. Use `zero_division` parameter to control this behavior.\n",
            "  _warn_prf(average, modifier, msg_start, len(result))\n",
            "/usr/local/lib/python3.7/dist-packages/sklearn/metrics/_classification.py:1318: UndefinedMetricWarning: Precision and F-score are ill-defined and being set to 0.0 in labels with no predicted samples. Use `zero_division` parameter to control this behavior.\n",
            "  _warn_prf(average, modifier, msg_start, len(result))\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "test_cnn_conv1D_egc_glove.6B.100d_s10000\n",
            "{'precision': 0.6623969961145181, 'recall': 0.6617672192787558, 'f1-score': 0.6552681646811063, 'support': 11702}\n",
            "0.6617672192787558\n",
            "                                      className  precision  ...    TP     TN\n",
            "0               Agriculture - Economie rustique   0.395210  ...    66  11368\n",
            "1                                      Anatomie   0.786207  ...   114  11456\n",
            "2                                     Antiquité   0.470383  ...   135  11278\n",
            "3                                  Architecture   0.543210  ...   132  11313\n",
            "4                               Arts et métiers   0.365854  ...    15  11564\n",
            "5                                    Beaux-arts   0.490566  ...    26  11589\n",
            "6                       Belles-lettres - Poésie   0.312500  ...    45  11397\n",
            "7                                        Blason   0.590909  ...    52  11558\n",
            "8                                    Caractères   1.000000  ...     2  11679\n",
            "9                                        Chasse   0.655914  ...    61  11554\n",
            "10                                       Chimie   0.400000  ...    32  11550\n",
            "11                                     Commerce   0.475410  ...   203  11102\n",
            "12                        Droit - Jurisprudence   0.785084  ...   979  10150\n",
            "13                          Economie domestique   0.200000  ...     1  11671\n",
            "14                                    Grammaire   0.434010  ...   171  11027\n",
            "15                                   Géographie   0.947469  ...  2471   8944\n",
            "16                                     Histoire   0.389087  ...   328  10571\n",
            "17                           Histoire naturelle   0.774162  ...   785  10510\n",
            "18                                          Jeu   0.631579  ...    36  11625\n",
            "19                                       Marine   0.647702  ...   296  11126\n",
            "20                           Maréchage - Manège   0.853933  ...    76  11584\n",
            "21                                Mathématiques   0.562914  ...    85  11496\n",
            "22                                       Mesure   0.333333  ...     2  11661\n",
            "23              Militaire (Art) - Guerre - Arme   0.569930  ...   163  11321\n",
            "24                                  Minéralogie   0.100000  ...     1  11671\n",
            "25                                      Monnaie   0.266667  ...     8  11617\n",
            "26                                      Musique   0.734694  ...    72  11539\n",
            "27                                    Médailles   0.857143  ...     6  11678\n",
            "28                         Médecine - Chirurgie   0.513228  ...   291  10971\n",
            "29                                      Métiers   0.527820  ...   702  10023\n",
            "30                                    Pharmacie   0.391304  ...     9  11623\n",
            "31                                  Philosophie   0.409836  ...    25  11572\n",
            "32  Physique - [Sciences physico-mathématiques]   0.522807  ...   149  11301\n",
            "33                                    Politique   0.500000  ...     1  11678\n",
            "34                                        Pêche   0.750000  ...    18  11654\n",
            "35                                     Religion   0.543807  ...   180  11223\n",
            "36                                    Spectacle   0.000000  ...     0  11693\n",
            "37                                 Superstition   0.857143  ...     6  11679\n",
            "\n",
            "[38 rows x 9 columns]\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        ""
      ],
      "metadata": {
        "id": "Lbwg2H8sJRe7"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        ""
      ],
      "metadata": {
        "id": "4mX5g55AJRhj"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        ""
      ],
      "metadata": {
        "id": "-D8Gj6kzJRjv"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        ""
      ],
      "metadata": {
        "id": "Lwz5cO2eJRmD"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        ""
      ],
      "metadata": {
        "id": "yr_UWq14JRoI"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        ""
      ],
      "metadata": {
        "id": "WJM6J6_EJRqx"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        ""
      ],
      "metadata": {
        "id": "CtYR7NTvJRs2"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        ""
      ],
      "metadata": {
        "id": "Qppm6jATJRvM"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        ""
      ],
      "metadata": {
        "id": "rK5nK4gyJRx0"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        ""
      ],
      "metadata": {
        "id": "vSjWwcQKJRz7"
      },
      "execution_count": null,
      "outputs": []
    }
  ]
}