{ "cells": [ { "cell_type": "markdown", "id": "f739280c-1c48-437e-b8f6-beef3fc13def", "metadata": {}, "source": [ "# 13 septembre 2023 : classification avec la méthode des moindres carrés\n", "\n", "Inspiration :\n", "\n", "- S. Boyd et L. Vandenberghe, *Introduction to \n", "Applied Linear Algebra: Vectors, Matrices, and Least Squares*, Cambridge University Press, 2018." ] }, { "cell_type": "markdown", "id": "b3b2cd32-0136-41c4-a014-c976af5ea7b2", "metadata": {}, "source": [ "## Classification\n", "Lorsqu'on fait de la classification booléenne (ou à deux classes), l'output du classificateur $\\hat f$ est en général soit $+1$ (True) soit $-1$ (False). \n", "\n", "Pour tester les performances du classificateur, on utilise un jeu de données *qui n'a pas été utilisé pour construire celui-ci* (on l'appelle parfois *validation set*). On compare alors les labels réels $y$ du jeu de données à ceux prédits par le classificateur, $\\hat y$. Il y a quatre options possibles :\n", "\n", "- Vrai positif : $y=+1$ et $\\hat y = -1$\n", "- Vrai négatif : $y=-1$ et $\\hat y = -1$\n", "- Faux positif : $y=-1$ et $\\hat y = +1$\n", "- Faux négatif : $y=+1$ et $\\hat y = -1$\n", "\n", "On peut alors regarder, pour le jeu de données de validation, combien de vrais positifs, vrais négatifs, faux positifs et faux négatifs on a obtenu. Sur cette base, on construit la *matrice de confusion*.\n", "\n", "### Exercice 1 : construire une matrice de confusion\n", "Écris une fonction `build_confusion_matrix` qui prend en entrée un vecteur `y` contenant les labels réels des données et un vecteur `yhat` qui contient les labels prédits par le classificateur. Cette fonction renvoie la matrice de confusion `C`." ] }, { "cell_type": "code", "execution_count": 1, "id": "45a17a5e-29b8-448d-bea3-0a1a4091ebb9", "metadata": {}, "outputs": [], "source": [ "def build_confusion_matrix(y, yhat):\n", " ..." ] }, { "cell_type": "markdown", "id": "28f11fae-a0d5-4e17-be47-9ed1d7cce262", "metadata": {}, "source": [ "Écris une fonction `compute_error_rate` qui prend la matrice de confusion `C` comme argument d'entrée et qui renvoie le taux d'erreur associé, `e`. Tu peux éventuellement écrire d'autres fonctions qui calculent \n", "\n", "- le taux de vrais positifs (aussi appelé sensibilité) ;\n", "- le taux de faux positifs (aussi appelé taux de fausse alerte) ;\n", "- le taux de vrais négatifs ;\n", "- la précision.\n", "\n", "En fonction de l'application, on s'intéressera plus à l'une ou l'autre d'entre elles." ] }, { "cell_type": "code", "execution_count": null, "id": "fcccc517-1142-4429-9e81-77a35355ec8b", "metadata": {}, "outputs": [], "source": [ "def compute_error_rate(C):\n", " ..." ] }, { "cell_type": "markdown", "id": "e9a7ffd3-5b10-4e02-8a20-8167fecc216b", "metadata": {}, "source": [ "## Le jeu de données : les fleurs d'iris\n", "Ce jeu de données contient 150 observations réalisées sur trois espèces d’iris (l’*iris setosa*, l’*iris versicolor* et l’*iris virginica*). Chaque observation correspond à un vecteur à quatre composantes : largeur et longueur du pétale ainsi que largeur et longueur du sépale. Dans ce notebook, nous allons construire un classificateur qui permet de distinguer l'espèce *iris virginica* des deux autres espèces.\n", "\n", "Puisque la classification est un apprentissage *supervisé*, on utilisera les *targets* (labels) présents pour chaque observation du jeu de données. \n", "\n", "\"Iris\n", "\n", "### Exercice 2 : visualisation des données\n", "Le jeu de données est téléchargé ci-dessous. Visualise sur une figure les 150 observations sur base de la taille des pétales (longueur des pétales en abscisses et largeur des pétales en ordonnées).\n", "Affiche les *iris setosa* et *iris versicolor* dans la même couleur et les *iris virginica* dans une autre couleur." ] }, { "cell_type": "code", "execution_count": 3, "id": "6695aad5", "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import pandas\n", "import sklearn\n", "from sklearn import datasets\n", "\n", "iris = datasets.load_iris()\n", "data = pandas.DataFrame(iris.data)\n", "data.columns = ['Sepal_Length','Sepal_Width','Petal_Length','Petal_Width']\n", "y = pandas.DataFrame(iris.target)\n", "y.columns = ['Targets']\n", "\n", "# Visualisation des données\n", "fig = plt.figure(figsize=(10, 6))\n", "ax1 = plt.subplot(1,1,1)\n", "\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "da0109b3-716c-4ef5-b5db-fe499ee35dd7", "metadata": {}, "source": [ "## Classification\n", "Dans ce notebook, on propose une méthode simple basée sur les moindres carrés. D'autres méthodes plus sophistiquées (et avec de meilleures performances) existent comme la régression logistique ou le *support vector machine*. \n", "\n", "Dans notre cas, on utilise un classificateur basé sur les moindres carrés qui fait intervenir un modèle de régression,\n", "$$\\hat f (x) = \\text{sign}(x^\\top \\beta + v),$$\n", "où la fonction $\\text{sign}$ permet d'avoir un output valant $-1$ ou $+1$. \n", "\n", "Si $\\beta_2$ est négatif et que $x_2$ est beaucoup plus grand que les autres entrées du vecteur $x$, quelle sera probablement la sortie du classificateur ?" ] }, { "cell_type": "markdown", "id": "2db82c0a-c010-4891-87a6-2e7a4acee778", "metadata": {}, "source": [ "..." ] }, { "cell_type": "markdown", "id": "695da9c1-ffeb-4577-bc79-199166609116", "metadata": {}, "source": [ "### Exercice 3 : créer un set d'entraînement et un set de validation\n", "Écris une fonction `create_sets` qui permet de séparer aléatoirement le jeu de données en deux jeux distincts : un contenant `N` observations et utilisé pour construire le classificateur et un autre contenant le restant des observations et utilisé pour quantifier ses performances. Les inputs de la fonction sont le jeu de données `data`, les labels `y` et l'entier `N`. La fonction renvoie les deux jeux de données `training_data` et `validation_data` ainsi que les deux vecteurs de labels `training_labels` et `validation_labels`." ] }, { "cell_type": "code", "execution_count": 9, "id": "e4a48714-e5f7-4658-95e0-bd39b3a6233d", "metadata": {}, "outputs": [], "source": [ "def create_sets(data, N):\n", " ...\n", " return training_data, validation_data, training_labels, validation_labels" ] }, { "cell_type": "markdown", "id": "91220cbd-d4f5-42f5-809c-6a09e2e3a659", "metadata": {}, "source": [ "### Exercice 4 : résoudre l'estimation au sens des moindres carrés\n", "On va commencer par essayer de trouver les cinq paramètres du modèle de régression (les quatre composantes de $\\beta$ ainsi $v$). On souhaite trouver les paramètres qui minimisent la somme des erreurs mises au carré entre les labels prédits par le modèle et les vrais labels,\n", "$$\\text{arg\\,min} \\sum_{i=1}^N [y_{\\text{t},i} - (x_i^\\top\\beta + v)]^2 = \\text{arg\\,min} \\| y_t - A \\theta\\|^2,$$\n", "où $A$ est une matrice de taille $N\\times 5$ contenant les observations du set d'entraînement (et une colonne de $1$) et où $\\theta = \\begin{pmatrix} \\beta^\\top & v \\end{pmatrix}^\\top$.\n", "\n", "Commence par écrire la matrice $A$." ] }, { "cell_type": "code", "execution_count": null, "id": "05a97cb8-2df7-42a4-880c-b6256940e7b6", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "2115803f-c682-46c2-bf3d-8072b773b34e", "metadata": {}, "source": [ "En utilisant la fonction `np.linalg.lstsq`, résouds le problème de minimisation. Tu as obtenu de cette façon les cinq paramètres de ton modèle !" ] }, { "cell_type": "code", "execution_count": null, "id": "505d8f38-c017-4d22-86b6-fdb8a15c9ff7", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "10927e54-4e74-465d-8c8b-db9bed2fdaea", "metadata": {}, "source": [ "### Exercice 5 : construire le classificateur\n", "Écris la fonction `fhat` qui représente ton classificateur. Elle prend en entrée les paramètres du modèle `beta` (un vecteur) et `v` (un scalaire), un vecteur de données à classifier `data` et elle renvoie en sortie `yhat`, un vecteur de la même longueur que `data` contenant les labels estimés." ] }, { "cell_type": "code", "execution_count": null, "id": "bd9cb19a-81ee-4d63-8534-93c278357a82", "metadata": {}, "outputs": [], "source": [ "def fhat(beta, v, data):\n", " ..." ] }, { "cell_type": "markdown", "id": "6a08d519", "metadata": {}, "source": [ "### Exercice 6 : estimer les performances du classificateur \n", "À présent, teste ton classificateur sur le set de validation. Quelle est la matrice de confusion obtenue ? Comment l'interpréter ? Quel est le taux d'erreur ?" ] }, { "cell_type": "code", "execution_count": null, "id": "4d706c57-1e8e-4b3e-be11-9c368558ca74", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "293d4ad5-76a0-4ab2-b377-d56e79977751", "metadata": {}, "source": [ "Finalement, visualise les données comme à l'exercice 2 mais uniquement pour le set de validation. Affiche les vrais labels et les labels prédits, dans deux couleurs différentes." ] }, { "cell_type": "code", "execution_count": 19, "id": "f577b81a", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.7" }, "vscode": { "interpreter": { "hash": "4a2701644a567983fe4c710d2a706eee629c52060847d7c704aa57db76d57a44" } } }, "nbformat": 4, "nbformat_minor": 5 }