Skip to content

Instantly share code, notes, and snippets.

@WassimBenzarti
Created May 16, 2020 15:55
Show Gist options
  • Save WassimBenzarti/4b65253832ea4e5a0d4e17c74cf355f6 to your computer and use it in GitHub Desktop.
Save WassimBenzarti/4b65253832ea4e5a0d4e17c74cf355f6 to your computer and use it in GitHub Desktop.
Data Mining TP3
Display the source blob
Display the rendered blob
Raw
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"name": "Data Mining TP3",
"provenance": [],
"collapsed_sections": [],
"include_colab_link": true
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
}
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "view-in-github",
"colab_type": "text"
},
"source": [
"<a href=\"https://colab.research.google.com/gist/WassimBenzarti/4b65253832ea4e5a0d4e17c74cf355f6/data-mining-tp3.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "nFEGHDEZdfa3",
"colab_type": "text"
},
"source": [
"### Loading data"
]
},
{
"cell_type": "code",
"metadata": {
"id": "iQgvKD-eYFqF",
"colab_type": "code",
"outputId": "24c215fe-0905-449b-a06a-9063ea36a927",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
}
},
"source": [
"from sklearn import datasets\n",
"# Load the dataset\n",
"irisData = datasets.load_iris()\n",
"# Display the data\n",
"print (irisData.data)\n",
"print (irisData.target)\n",
"# Show the dimensions of the dataset\n",
"irisData.data.shape, irisData.target.shape\n",
"# Show the description\n",
"print(irisData.DESCR)\n",
"\n",
"# Uppercase letters -> Vectors\n",
"# Lowercase letters -> Scalars\n",
"X = irisData.data\n",
"y = irisData.target"
],
"execution_count": 1,
"outputs": [
{
"output_type": "stream",
"text": [
"[[5.1 3.5 1.4 0.2]\n",
" [4.9 3. 1.4 0.2]\n",
" [4.7 3.2 1.3 0.2]\n",
" [4.6 3.1 1.5 0.2]\n",
" [5. 3.6 1.4 0.2]\n",
" [5.4 3.9 1.7 0.4]\n",
" [4.6 3.4 1.4 0.3]\n",
" [5. 3.4 1.5 0.2]\n",
" [4.4 2.9 1.4 0.2]\n",
" [4.9 3.1 1.5 0.1]\n",
" [5.4 3.7 1.5 0.2]\n",
" [4.8 3.4 1.6 0.2]\n",
" [4.8 3. 1.4 0.1]\n",
" [4.3 3. 1.1 0.1]\n",
" [5.8 4. 1.2 0.2]\n",
" [5.7 4.4 1.5 0.4]\n",
" [5.4 3.9 1.3 0.4]\n",
" [5.1 3.5 1.4 0.3]\n",
" [5.7 3.8 1.7 0.3]\n",
" [5.1 3.8 1.5 0.3]\n",
" [5.4 3.4 1.7 0.2]\n",
" [5.1 3.7 1.5 0.4]\n",
" [4.6 3.6 1. 0.2]\n",
" [5.1 3.3 1.7 0.5]\n",
" [4.8 3.4 1.9 0.2]\n",
" [5. 3. 1.6 0.2]\n",
" [5. 3.4 1.6 0.4]\n",
" [5.2 3.5 1.5 0.2]\n",
" [5.2 3.4 1.4 0.2]\n",
" [4.7 3.2 1.6 0.2]\n",
" [4.8 3.1 1.6 0.2]\n",
" [5.4 3.4 1.5 0.4]\n",
" [5.2 4.1 1.5 0.1]\n",
" [5.5 4.2 1.4 0.2]\n",
" [4.9 3.1 1.5 0.2]\n",
" [5. 3.2 1.2 0.2]\n",
" [5.5 3.5 1.3 0.2]\n",
" [4.9 3.6 1.4 0.1]\n",
" [4.4 3. 1.3 0.2]\n",
" [5.1 3.4 1.5 0.2]\n",
" [5. 3.5 1.3 0.3]\n",
" [4.5 2.3 1.3 0.3]\n",
" [4.4 3.2 1.3 0.2]\n",
" [5. 3.5 1.6 0.6]\n",
" [5.1 3.8 1.9 0.4]\n",
" [4.8 3. 1.4 0.3]\n",
" [5.1 3.8 1.6 0.2]\n",
" [4.6 3.2 1.4 0.2]\n",
" [5.3 3.7 1.5 0.2]\n",
" [5. 3.3 1.4 0.2]\n",
" [7. 3.2 4.7 1.4]\n",
" [6.4 3.2 4.5 1.5]\n",
" [6.9 3.1 4.9 1.5]\n",
" [5.5 2.3 4. 1.3]\n",
" [6.5 2.8 4.6 1.5]\n",
" [5.7 2.8 4.5 1.3]\n",
" [6.3 3.3 4.7 1.6]\n",
" [4.9 2.4 3.3 1. ]\n",
" [6.6 2.9 4.6 1.3]\n",
" [5.2 2.7 3.9 1.4]\n",
" [5. 2. 3.5 1. ]\n",
" [5.9 3. 4.2 1.5]\n",
" [6. 2.2 4. 1. ]\n",
" [6.1 2.9 4.7 1.4]\n",
" [5.6 2.9 3.6 1.3]\n",
" [6.7 3.1 4.4 1.4]\n",
" [5.6 3. 4.5 1.5]\n",
" [5.8 2.7 4.1 1. ]\n",
" [6.2 2.2 4.5 1.5]\n",
" [5.6 2.5 3.9 1.1]\n",
" [5.9 3.2 4.8 1.8]\n",
" [6.1 2.8 4. 1.3]\n",
" [6.3 2.5 4.9 1.5]\n",
" [6.1 2.8 4.7 1.2]\n",
" [6.4 2.9 4.3 1.3]\n",
" [6.6 3. 4.4 1.4]\n",
" [6.8 2.8 4.8 1.4]\n",
" [6.7 3. 5. 1.7]\n",
" [6. 2.9 4.5 1.5]\n",
" [5.7 2.6 3.5 1. ]\n",
" [5.5 2.4 3.8 1.1]\n",
" [5.5 2.4 3.7 1. ]\n",
" [5.8 2.7 3.9 1.2]\n",
" [6. 2.7 5.1 1.6]\n",
" [5.4 3. 4.5 1.5]\n",
" [6. 3.4 4.5 1.6]\n",
" [6.7 3.1 4.7 1.5]\n",
" [6.3 2.3 4.4 1.3]\n",
" [5.6 3. 4.1 1.3]\n",
" [5.5 2.5 4. 1.3]\n",
" [5.5 2.6 4.4 1.2]\n",
" [6.1 3. 4.6 1.4]\n",
" [5.8 2.6 4. 1.2]\n",
" [5. 2.3 3.3 1. ]\n",
" [5.6 2.7 4.2 1.3]\n",
" [5.7 3. 4.2 1.2]\n",
" [5.7 2.9 4.2 1.3]\n",
" [6.2 2.9 4.3 1.3]\n",
" [5.1 2.5 3. 1.1]\n",
" [5.7 2.8 4.1 1.3]\n",
" [6.3 3.3 6. 2.5]\n",
" [5.8 2.7 5.1 1.9]\n",
" [7.1 3. 5.9 2.1]\n",
" [6.3 2.9 5.6 1.8]\n",
" [6.5 3. 5.8 2.2]\n",
" [7.6 3. 6.6 2.1]\n",
" [4.9 2.5 4.5 1.7]\n",
" [7.3 2.9 6.3 1.8]\n",
" [6.7 2.5 5.8 1.8]\n",
" [7.2 3.6 6.1 2.5]\n",
" [6.5 3.2 5.1 2. ]\n",
" [6.4 2.7 5.3 1.9]\n",
" [6.8 3. 5.5 2.1]\n",
" [5.7 2.5 5. 2. ]\n",
" [5.8 2.8 5.1 2.4]\n",
" [6.4 3.2 5.3 2.3]\n",
" [6.5 3. 5.5 1.8]\n",
" [7.7 3.8 6.7 2.2]\n",
" [7.7 2.6 6.9 2.3]\n",
" [6. 2.2 5. 1.5]\n",
" [6.9 3.2 5.7 2.3]\n",
" [5.6 2.8 4.9 2. ]\n",
" [7.7 2.8 6.7 2. ]\n",
" [6.3 2.7 4.9 1.8]\n",
" [6.7 3.3 5.7 2.1]\n",
" [7.2 3.2 6. 1.8]\n",
" [6.2 2.8 4.8 1.8]\n",
" [6.1 3. 4.9 1.8]\n",
" [6.4 2.8 5.6 2.1]\n",
" [7.2 3. 5.8 1.6]\n",
" [7.4 2.8 6.1 1.9]\n",
" [7.9 3.8 6.4 2. ]\n",
" [6.4 2.8 5.6 2.2]\n",
" [6.3 2.8 5.1 1.5]\n",
" [6.1 2.6 5.6 1.4]\n",
" [7.7 3. 6.1 2.3]\n",
" [6.3 3.4 5.6 2.4]\n",
" [6.4 3.1 5.5 1.8]\n",
" [6. 3. 4.8 1.8]\n",
" [6.9 3.1 5.4 2.1]\n",
" [6.7 3.1 5.6 2.4]\n",
" [6.9 3.1 5.1 2.3]\n",
" [5.8 2.7 5.1 1.9]\n",
" [6.8 3.2 5.9 2.3]\n",
" [6.7 3.3 5.7 2.5]\n",
" [6.7 3. 5.2 2.3]\n",
" [6.3 2.5 5. 1.9]\n",
" [6.5 3. 5.2 2. ]\n",
" [6.2 3.4 5.4 2.3]\n",
" [5.9 3. 5.1 1.8]]\n",
"[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n",
" 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\n",
" 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2\n",
" 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2\n",
" 2 2]\n",
".. _iris_dataset:\n",
"\n",
"Iris plants dataset\n",
"--------------------\n",
"\n",
"**Data Set Characteristics:**\n",
"\n",
" :Number of Instances: 150 (50 in each of three classes)\n",
" :Number of Attributes: 4 numeric, predictive attributes and the class\n",
" :Attribute Information:\n",
" - sepal length in cm\n",
" - sepal width in cm\n",
" - petal length in cm\n",
" - petal width in cm\n",
" - class:\n",
" - Iris-Setosa\n",
" - Iris-Versicolour\n",
" - Iris-Virginica\n",
" \n",
" :Summary Statistics:\n",
"\n",
" ============== ==== ==== ======= ===== ====================\n",
" Min Max Mean SD Class Correlation\n",
" ============== ==== ==== ======= ===== ====================\n",
" sepal length: 4.3 7.9 5.84 0.83 0.7826\n",
" sepal width: 2.0 4.4 3.05 0.43 -0.4194\n",
" petal length: 1.0 6.9 3.76 1.76 0.9490 (high!)\n",
" petal width: 0.1 2.5 1.20 0.76 0.9565 (high!)\n",
" ============== ==== ==== ======= ===== ====================\n",
"\n",
" :Missing Attribute Values: None\n",
" :Class Distribution: 33.3% for each of 3 classes.\n",
" :Creator: R.A. Fisher\n",
" :Donor: Michael Marshall (MARSHALL%PLU@io.arc.nasa.gov)\n",
" :Date: July, 1988\n",
"\n",
"The famous Iris database, first used by Sir R.A. Fisher. The dataset is taken\n",
"from Fisher's paper. Note that it's the same as in R, but not as in the UCI\n",
"Machine Learning Repository, which has two wrong data points.\n",
"\n",
"This is perhaps the best known database to be found in the\n",
"pattern recognition literature. Fisher's paper is a classic in the field and\n",
"is referenced frequently to this day. (See Duda & Hart, for example.) The\n",
"data set contains 3 classes of 50 instances each, where each class refers to a\n",
"type of iris plant. One class is linearly separable from the other 2; the\n",
"latter are NOT linearly separable from each other.\n",
"\n",
".. topic:: References\n",
"\n",
" - Fisher, R.A. \"The use of multiple measurements in taxonomic problems\"\n",
" Annual Eugenics, 7, Part II, 179-188 (1936); also in \"Contributions to\n",
" Mathematical Statistics\" (John Wiley, NY, 1950).\n",
" - Duda, R.O., & Hart, P.E. (1973) Pattern Classification and Scene Analysis.\n",
" (Q327.D83) John Wiley & Sons. ISBN 0-471-22361-1. See page 218.\n",
" - Dasarathy, B.V. (1980) \"Nosing Around the Neighborhood: A New System\n",
" Structure and Classification Rule for Recognition in Partially Exposed\n",
" Environments\". IEEE Transactions on Pattern Analysis and Machine\n",
" Intelligence, Vol. PAMI-2, No. 1, 67-71.\n",
" - Gates, G.W. (1972) \"The Reduced Nearest Neighbor Rule\". IEEE Transactions\n",
" on Information Theory, May 1972, 431-433.\n",
" - See also: 1988 MLC Proceedings, 54-64. Cheeseman et al\"s AUTOCLASS II\n",
" conceptual clustering system finds 3 classes in the data.\n",
" - Many, many more ...\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "e7F8m4ytdVdd",
"colab_type": "text"
},
"source": [
"### 1. Comment sont réparties les données dans les tableaux ?\n",
"Les données sont répartis dans un tableau de 150 instances segmenter en 2 parties, input et output. En input, chaque instance a 4 colonnes (features) numériques: \n",
"- sepal length in cm\n",
"- sepal width in cm\n",
"- petal length in cm\n",
"- petal width in cm\n",
"\n",
"En output, on a une seul valeur numérique pour chaque instance qui désigne le type d'Iris:\n",
"- 0: Iris-Setosa\n",
"- 1: Iris-Versicolour\n",
"- 2: Iris-Virginica"
]
},
{
"cell_type": "code",
"metadata": {
"id": "Cnb8D2cdeT9k",
"colab_type": "code",
"outputId": "467e6e0a-e954-4987-f690-3a442772327f",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
}
},
"source": [
"# Show for each class, the number of instances in it\n",
"# We used the vector selection to filter\n",
"# the data\n",
"X[y==0].shape,X[y==1].shape,X[y==2].shape"
],
"execution_count": 2,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"((50, 4), (50, 4), (50, 4))"
]
},
"metadata": {
"tags": []
},
"execution_count": 2
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "H7SSVm-eeTZv",
"colab_type": "text"
},
"source": [
"#### Combien y a-t-il de données dans chaque classe ?\n",
"Chaque classe contient 50 instances."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "1qEDWYSEemKo",
"colab_type": "text"
},
"source": [
"### Quels sont les attributs et la classe du 32ème élément de l'échantillon ?\n",
"\n",
"|Sepal length|Sepal width|Petal length|Petal width|Classe|\n",
"|-|-|-|-|-|\n",
"|5.4 | 3.4| 1.5| 0.4|0|"
]
},
{
"cell_type": "code",
"metadata": {
"id": "hF8HHpWUeV6w",
"colab_type": "code",
"outputId": "449e5902-375c-43c3-c816-cb9184014cb5",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
}
},
"source": [
"X[31], y[31]"
],
"execution_count": 3,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"(array([5.4, 3.4, 1.5, 0.4]), 0)"
]
},
"metadata": {
"tags": []
},
"execution_count": 3
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Fc-qEuxkex5d",
"colab_type": "text"
},
"source": [
"### Comprendre, commenter et programmer le code source suivant"
]
},
{
"cell_type": "code",
"metadata": {
"id": "wWPHCm3dexVN",
"colab_type": "code",
"outputId": "f1a261ce-aba7-42e6-8c7d-378552a1ea6c",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 765
}
},
"source": [
"# Inclure les dépendances matplotlib, cycle et pylab\n",
"from itertools import cycle\n",
"import matplotlib\n",
"import pylab as pl\n",
"\n",
"# Visualiser le nuage des points de tous les classes\n",
"def plot_2D(data, target, target_names):\n",
" colors = cycle('rgbcmykw') # cycle de couleurs: (r) rouge, (g) vert, (b) bleu, (c) cyan, (m) magenta, (y) jaune, (k) noir, (w) blanc\n",
" target_ids = range(len(target_names))\n",
" pl.figure()\n",
" # Itérer sur les classes et dans chaque itération, on utilise une couleur unique\n",
" for i, c, label in zip(target_ids, colors, target_names):\n",
" # Choisir Sepal length et Sepal width seulement comme deux axes \n",
" pl.scatter(data[target == i, 0], data[target == i, 1], c=c, label=label)\n",
" pl.legend()\n",
" pl.show()\n",
"\n",
"# Appeler la fonction plot_2D en passant en entré les données, la classe de chaque instance\n",
"# et les différents noms des classes\n",
"plot_2D(irisData.data, irisData.target, [\"Iris-Setosa\", \"Iris-Versicolour\", \"Iris-Virginica\"])"
],
"execution_count": 4,
"outputs": [
{
"output_type": "display_data",
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"tags": [],
"needs_background": "light"
}
},
{
"output_type": "display_data",
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"tags": [],
"needs_background": "light"
}
},
{
"output_type": "display_data",
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAXcAAAD4CAYAAAAXUaZHAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+j8jraAAAdPElEQVR4nO3dfZRcVbnn8e8v3cHQEEVJX18I6Wati9eXjHlrMbzcGA14QVmIyIhZbS7gjT2TuDRe9eooVxFGXOPS5WI5GrDFNXBNXyEqYEZFiTPJkAwS7IQEJeAbpNtoHJrwdrEHJi/P/HGq051Kddep7qquOqd/n7VqVZ1du/d5dp3iyeHsU3srIjAzs3yZVu8AzMys+pzczcxyyMndzCyHnNzNzHLIyd3MLIea67XjWbNmRXt7e712b2aWSdu3b38iIlrL1atbcm9vb6e3t7deuzczyyRJfWnq+bKMmVkOObmbmeWQk7uZWQ7V7Zp7KQcOHGDv3r08//zz9Q5lypoxYwazZ89m+vTp9Q7FzCagoZL73r17mTlzJu3t7UiqdzhTTkSwf/9+9u7dy2mnnVbvcMxsAspelpE0Q9L9knZJekjSNSXqzJG0SdIDkh6U9PbxBPP8889z8sknO7HXiSROPvlk/5+TGdDTA+3tMG1a8tzT05htjibNmfsLwFsj4jlJ04Gtku6KiPtG1PlnYH1E3CDpdcCPgfbxBOTEXl/+/M2SpNvVBYODyXZfX7IN0NnZOG2OpeyZeySeK2xOLzyK5wkO4MWF1y8B/lS1CM3MJtlVVw0n4SGDg0l5I7U5llR3y0hqkrQTeBzYGBHbiqp8DnifpL0kZ+0fGqWdLkm9knoHBgYmEHbtnHjiiaO+d9ZZZ6Vq48orr+Qb3/jGUWV33nknF1xwAb29vXz4wx+uOK40+165ciW7d++uuG0zO1p/f2Xl9WpzLKmSe0Qcioj5wGzgDElzi6osB26OiNnA24FvSzqm7YjojoiOiOhobS3769mGcfDgQQDuvffeVPWXL1/OrbfeelTZrbfeyvLly+no6OCrX/3qqPsYTZp933TTTbzuda9LFaOZjW7OnMrK69XmWCq6zz0ingY2AecXvfUPwPpCnZ8DM4BZ1QhwLLUcnNi8eTN/+7d/y0UXXXQkYQ6d1e/bt48lS5Ywf/585s6dy5YtW47622XLlvHII4+wb98+AP7yl7/ws5/9jIsvvpjNmzdz4YUXAvC5z32OFStWcPbZZ7NixQoGBgY477zzeP3rX8/KlStpa2vjiSeeOGrfmzdvZunSpVx66aW85jWvobOzk6HVtJYuXXpkSoef/OQnLFy4kHnz5rFs2TIA7r//fs4880wWLFjAWWedxa9//evqfWBmOXLdddDScnRZS0tS3khtjikixnwArcBJhdfHA1uAC4vq3AVcUXj9WpJr7hqr3UWLFkWx3bt3H1M2mnXrIlpaImD40dKSlE/ECSecEBERmzZtipaWlnj00UePee/LX/5yfP7zn4+IiIMHD8azzz57TDsf/OAH4/rrr4+IiO985zvx7ne/+0i773jHOyIi4uqrr46FCxfG4ODgkb/5whe+EBERd911VwAxMDBwTFwvfvGL4w9/+EMcOnQoFi9eHFu2bImIiDe/+c3xi1/8Ih5//PGYPXv2kdj3798fERHPPPNMHDhwICIiNm7cGJdccknJz6CS42CWV+vWRbS1RUjJ80RzS7XaBHqjTN6OiFR3y7wSuEVSE8mZ/vqI+KGkaws72QB8DPimpH8kGVy9ohBEzYw1OFGtkeczzjij5P3eb3zjG3n/+9/PgQMHuPjii5k/f/4xdZYvX87HP/5x1qxZw6233sqKFStK7uOiiy7i+OOPB2Dr1q3ccccdAJx//vm89KUvHTWu2bNnAzB//nz27NnDOeecc+T9++67jyVLlhyJ/WUvexkAzzzzDJdffjm//e1vkcSBAwfSfhRmU05nZ/XvYqlFm6Mpm9wj4kFgQYnyz454vRs4u7qhjW0yBidOOOGEkuVLlizhnnvu4Uc/+hFXXHEFH/3oR5k5cybXXJP8BOCmm27irLPOYt++fezatYt77733mGvw5fYxlhe96EVHXjc1NZW9Xj/kM5/5DG95y1u444472LNnD0uXLq1432aWDZmdW2ayBydG6uvr4+Uvfzkf+MAHWLlyJTt27OBd73oXO3fuZOfOnXR0dCCJyy67jMsvv5wLLriAGTNmlG337LPPZv369QDcfffdPPXUU+OKb/Hixdxzzz089thjADz55JNAcuZ+yimnAHDzzTePq20zy4bMJvdJH5wYYfPmzcybN48FCxZw2223sWbNmpL1li9fzq5du1i+fHmqdq+++mruvvtu5s6dy3e/+11e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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"tags": [],
"needs_background": "light"
}
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "jsgwd__WeqMd",
"colab_type": "text"
},
"source": [
"On peut également modifier les attributs utilisé en modifiant cette ligne\n",
"```python\n",
"pl.scatter(data[target == i, 0], data[target == i, 1], c=c, label=label)\n",
"```\n",
"**Example**\n",
"Pour choisir les attributs 'Petal length' et 'Petal width', la modification sera comme suit:\n",
"```python\n",
"pl.scatter(data[target == i, 2], data[target == i, 3], c=c, label=label)\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Vt8Pmfwou3hT",
"colab_type": "text"
},
"source": [
"### Recherche d'une droite permettant de séparer les examples d'une classe des exemples des deux autres classes\n",
"Pour ce faire, on va superposer les nuages des points pour visualiser la distance entre les points de chaque classe."
]
},
{
"cell_type": "code",
"metadata": {
"id": "3ddlcmdCdZu2",
"colab_type": "code",
"outputId": "1837d836-edf7-4bbb-e45c-1f0c8b882c4c",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 268
}
},
"source": [
"# Inclure les dépendances matplotlib, cycle et pylab\n",
"from itertools import cycle\n",
"import matplotlib\n",
"import numpy as np\n",
"import pylab as pl\n",
"\n",
"line_x= np.linspace(4.5,6.5,1000)\n",
"\n",
"# Visualiser le nuage des points de tous les classes\n",
"def plot_2D(data, target, target_names):\n",
" colors = cycle('rgbcmykw') # cycle de couleurs\n",
" target_ids = range(len(target_names))\n",
" pl.figure()\n",
" ax = pl.subplot(111)\n",
" ax.plot(line_x,(line_x*1)-2.3)\n",
" # Itérer sur les classes et dans chaque itération, on utilise une couleur unique\n",
" for i, c, label in zip(target_ids, colors, target_names):\n",
" # Choisir Sepal length et Sepal width seulement comme deux axes \n",
" ax.scatter(data[target == i, 0], data[target == i, 1], c=c, label=label)\n",
" ax.legend()\n",
" ax.figure.show()\n",
"\n",
"# Appeler la fonction plot_2D en passant en entré les données, la classe de chaque instance\n",
"# et les différents noms des classes\n",
"plot_2D(irisData.data, irisData.target, [\"Iris-Setosa\", \"Iris-Versicolour\", \"Iris-Virginica\"])"
],
"execution_count": 5,
"outputs": [
{
"output_type": "display_data",
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAXUAAAD7CAYAAACVMATUAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+j8jraAAAgAElEQVR4nO3deXgUVdb48e/NwhJAFsmgsiSMOwQSICQoiowRd3EdFoOKClFwd15ExXGAEXV+46uO77gFXFDCojgugCMKgoCyGPbNhZ0ISggQlggk6fP7o0PI3tVJpbq6cz7P0w/p6upbpyuVQ/WtU/caEUEppVRoCAt0AEoppeyjSV0ppUKIJnWllAohmtSVUiqEaFJXSqkQokldKaVCiOWkbowJN8asNMbMrOC1wcaYbGPMqqLHEHvDVEopZUWEH+s+BGwETqnk9Wkicn/NQ1JKKVVdlpK6MaYNcA0wDnjUjg23bNlSYmNj7WhKKaXqjOXLl+8VkejKXrd6pv4y8BjQpIp1bjbG9AJ+Ah4RkZ1VNRgbG0tmZqbFzSullAIwxmyv6nWfferGmGuBPSKyvIrVZgCxItIZ+AqYWElbacaYTGNMZnZ2tq9NK6WU8pOVC6U9gb7GmG3AVOBSY8ykkiuISI6IHCt6OgHoVlFDIpIuIokikhgdXem3B6WUUtXkM6mLyBMi0kZEYoEBwNciMqjkOsaY00s87Yv3gqpSSimH+VP9UooxZiyQKSKfAQ8aY/oCBcA+YLA94Sml7JKfn09WVhZHjx4NdCjKggYNGtCmTRsiIyP9ep8J1NC7iYmJohdKlXLO1q1badKkCaeeeirGmECHo6ogIuTk5HDo0CHat29f6jVjzHIRSazsvXpHqXKHjAyIjYWwMO+/GRmBjijkHD16VBN6kDDGcOqpp1brW1W1u1+Usk1GBqSlQV6e9/n27d7nAKmpgYsrBGlCDx7V/V3pmboKvFGjTib0E/LyvMuVUn7RpK4Cb8cO/5aroNW4ceNKX7vwwgstt5OXl0dqaiqdOnUiLi6Oiy66iMOHD1f5nmeffdZy+8FMk7oKvHbt/FuuQkpBQQEA3333neX3/Otf/6JVq1asXbuWdevW8dZbb/msEtGkrpRTxo2DqKjSy6KivMtV4NTixev58+dz8cUX07dvXzp06ACcPIvfvXs3vXr1IiEhgbi4OBYuXFju/bt376Z169bFz88991zq168PwKRJk0hKSiIhIYF77rmHwsJCHn/8cX7//XcSEhJILbpO8+KLLxIXF0dcXBwvv/wyAEeOHOGaa64hPj6euLg4pk2bBsDYsWPp3r07cXFxpKWlEaiqQUtEJCCPbt26iVLFJk0SiYkRMcb776RJgY4o5GzYsMH6ypMmiURFicDJR1RUjX8vjRo1EhGRefPmSVRUlGzZsqXcay+88II888wzIiJSUFAgBw8eLNfOypUrJTo6Wnr06CGjRo2Sn376SUS8n/Haa6+V48ePi4jIsGHDZOLEiaXaFxHJzMyUuLg4OXz4sBw6dEg6dOggK1askOnTp8uQIUOK1ztw4ICIiOTk5BQvGzRokHz22Wc12g9WVfQ7w3t/UKW5Vc/UlTukpsK2beDxeP/VqpfAcuDidVJSUrkabIDu3bvzzjvvMHr0aNauXUuTJuXHEUxISGDLli2MGDGCffv20b17dzZu3MjcuXNZvnw53bt3JyEhgblz57Jly5Zy71+0aBE33ngjjRo1onHjxtx0000sXLiQTp068dVXXzFy5EgWLlxI06ZNAZg3bx7Jycl06tSJr7/+mvXr19u2H+ymJY1KqfIcuHjdqFGjCpf36tWLBQsWMGvWLAYPHsyjjz5KkyZNGDNmDAATJkwgMTGxOBnfdNNNhIWF8fnnn1OvXj3uuOMOnnvuuWrFdM4557BixQo+//xznnrqKVJSUnjssccYPnw4mZmZtG3bltGjR7v6rlw9U1dKlRfAi9fbt2+nVatWDB06lCFDhrBixQpuvPFGVq1axapVq0hMTOTbb79l//79ABw/fpwNGzYQExNDSkoK06dPZ8+ePQDs27eP7du9I9VGRkaSn58PwMUXX8wnn3xCXl4eR44c4eOPP+biiy9m165dREVFMWjQIEaMGMGKFSuKE3jLli05fPgw06dPr/V9UBN6pq6UKm/cuNI3hIFjF6/nz5/PP//5TyIjI2ncuDHvvfdeuXU2b97MsGHDEBE8Hg/XXHMNN998M8YYnnnmGS6//HI8Hg+RkZG8+uqrxMTEkJaWRufOnenatSsZGRkMHjyYpKQkAIYMGUKXLl2YPXs2I0aMICwsjMjISF5//XWaNWvG0KFDiYuL47TTTqN79+61vg9qQsd+UaqO2LhxI+eff771N2RkePvQd+zwnqGPG6fXOhxW0e/M19gveqaulKpYaqom8SCkfepKKRVCNKkrpVQI0aSulFIhRJO6UkqFEE3qquZ0ggulXEOTuqqZExNcbN/uHSHkxAQXmthrLGt/nu+VgowdQ+/eeeedvPnmm6WWffLJJ1x11VU1ii0zM5MHH3ywWu+NjY1l7969Ndq+XTSpq5rRCS5qxYSFW7j0hW9YtfNAoEOpdf4OvTtw4ECmTp1aatnUqVMZOHCgX9srKzExkVdeecVSG7Wlstj8oUld1YxOcGG71+dv5plZG0k5/w90OP2UgMWRsTaD2JdjCRsTRuzLsWSsdcfQuykpKfzwww/s3r0b8A6XO2fOHG644QaWL1/OJZdcQrdu3bjiiiuK1+nduzcPP/wwiYmJ/Otf/+LDDz8kLi6O+Ph4evXqVRzTtddeC8Dhw4e588476dSpE507d+ajjz4CYMqUKcUTc4wcObLCz1bRkL7btm0jLi6ueJ0XXniB0aNHVxhbTenNR6pm2rXzdrlUtFz57ZW5P/PiVz/RN/4MXuwXT0R4YM67MtZmkDYjjbx877ew7bnbSZvhnTc2tZM9NyStWLGCdevWlRupcfLkyVxxxRWMGjWKwsJC8sp8EwwPD+fmm2/mgw8+4KGHHmLGjBn07t2bhg0b8sADD/Dpp58SHR3NtGnTGDVqFG+//TbgHSPmxF3snTp1Yvbs2bRu3ZoDB8p/G/r73/9O06ZNWbt2LQD79+9n165djBw5kuXLl9O8eXMuv/xyPvnkE2644Ybi9y1fvpx33nmHpUuXIiIkJydzySWX0Lx58yr3RcnYakrP1FXN6AQXthARXpj9Iy9+9RM3d23DS/0TApbQAUbNHVWc0E/Iy89j1Fx3DL1bsgvmRNfLjz/+yLp16+jTpw8JCQk888wzZGVlFb+nf//+xT/37NmTwYMHM378eAoLC8u1P2fOHO67777i582bN+f777+nd+/eREdHExERQWpqKgsWLCj1vsqG9PWlZGw1pUld1UxqKqSnQ0wMGOP9Nz1dby/3g4jw3H9/4N/zNjGge1v+eUtnwsOqN5O8XXbkVtx9Vtny6vA19G7r1q0ZPHgw7733Hh9//DEJCQkkJCSQmZnJhRdeyO7du1m9ejXfffcd11xzDSJCx44di0dzXLt2LV9++WWF23vjjTd45pln2LlzJ926dSMnJ8e2z1WRiIgIPB5P8fOyQ/dWti+qQ5O6qjmd4KLaRIQxMzaQvmALt/WI4dkbOxEW4IQO0K5pxd1nlS23k5Whd40x9O/fnzvuuIOrrrqKBg0acO6555Kdnc3ixYsByM/Pr3Qyi82bN5OcnMzYsWOJjo5m586dpV7v06cPr776avHz/fv3k5SUxDfffMPevXspLCxkypQpXHLJJaXeV9mQvq1atWLPnj3k5ORw7NgxZs6cafNeO0mTeqjTGnLX8niEpz5Zx7vfbePui9oz9vqOrkjoAONSxhEVWbpbLSoyinEpzgy9Gx8fT5cuXZg2bRoPPfRQhesNHDiQ1atXF1e91KtXj+nTpzNy5Eji4+NJSEiotKJmxIgRxRc8L7zwQuLj40u9/tRTT7F///7ii6nz5s3j9NNP5/nnn+dPf/oT8fHxdOvWjeuvv77U+7p27Vo8pG9ycnLxkL6RkZE8/fTTJCUl0adPH8477zwb9lTFdOjdUHaihrzsmNjaPRJwhR7hif+s4YPMLIb1PpPHrjgXY2o3ofs79G7G2gxGzR3FjtwdtGvajnEp42y7SKqs0aF3VWlV1ZBrUg+YgkIPI6av4eOVv/BQytk8fNnZtZ7QqyO1U6om8SCkST2UaQ256+QXenh42ipmrdnN/1x+DvdfenagQ1IhRvvUQ1kA55lU5R0v8HD/5BXMWrObJ68+TxO6qhWa1EOZ1pC7xtH8QoZNWs7s9b/xt+s6kNbrzECHpEKUJvVQpjXkrnA0v5Ch72Uy94c9jLsxjjt7lr/hRim7WO5TN8aEA5nALyJybZnX6gPvAd2AHKC/iGyzMU5VXTrPZEDlHS/g7nczWbI1h/93S2f6JbYNdEgqxPlzpv4QsLGS1+4G9ovIWcBLwD9qGphSpQRhvf3hYwUMfvt7lm7N4cV+8ZrQqf2hd6s7fK6VbQ8ZMoQNGzb43bbjRMTnA2gDzAUuBWZW8Pps4IKinyOAvRTVwFf26NatmyhlyaRJIlFRIt4R272PqCjvcpfK/f243PDqIvnjE7Pks1W/BDocERHZsGFDoEOQRo0alVuWn5/vVxuzZ8+W3r17l1rWv39/mThxYqXv8XcbblHR7wzIlCpyq9Uz9ZeBxwBPJa+3BnYW/SdRAOQCp1bnPxmlygmyMdsP5B1n0ISlrPsll1dv7cp18WcEOqRqqc0vR7U19G7J4XNHjx7NbbfdRs+ePbntttvIzs6mT58+dOzYkSFDhhATE1M8scWJbc+fP5/evXtzyy23cN5555GamnrixJXevXsXj6T4xRdf0LVrV+Lj40lJSQFg2bJlXHDBBXTp0oULL7yQH3/80b4d5gefferGmGuBPSKy3BjTuyYbM8akAWkA7bSsTlkVRPX2+454E/qmPYd5Y1A3Us5vFeiQqqXszcgnJrQC+y7R2D307imnlB97fsOGDSxatIiGDRty//33c+mll/LEE0/wxRdf8NZbb1UY18qVK1m/fj1nnHEGPXv25Ntvv+Wiiy4qfj07O5uhQ4eyYMEC2rdvz759+wA477zzWLhwIREREcyZM4cnn3yyeBx2J1k5U+8J9DXGbAOmApcaYyaVWecXoC2AMSYCaIr3gmkpIpIuIokikhgdHV2jwFUdEiT19tmHjjEgfTGbsw8z/o7EoE3o4MyXI7uH3q1I3759adiwIeAdFnfAgAEAXHnllZWOcZ6UlESbNm0ICwsjISGBbdu2lXp9yZIl9OrVqzj2Fi1aAJCbm8uf//xn4uLieOSRRyodTKy2+UzqIvKEiLQRkVhgAPC1iAwqs9pnwB1FP99StE5gBpVRoScI6u1/O3iUAemL2bnvd94Z3J1LzgnukxYnvhzZPfSuP9uoSv369Yt/Dg8PtzzF3F//+lf+9Kc/sW7dOmbMmFFueF2nVLtO3Rgz1hjTt+jpW8CpxphNwKPA43YEpxTg+nr7XQd+p/+bi/k19ygT70riwrNaBjqkGgvkl6PqDr3rS8+ePfnggw8A+PLLL9m/f3+14uvRowcLFixg69atAMXdL7m5ubRu3RqAd999t1pt28GvpC4i86WoRl1EnhaRz4p+PioifxaRs0QkSUS21Eawqg5z6ZjtO/fl0T99MTmHj/Pe3ckktW8R6JBsEcgvR9UdeteXv/3tb3z55ZfExcXx4Ycfctppp1XYteNLdHQ06enp3HTTTcTHxxfPWvTYY4/xxBNP0KVLF1smkK62qkpjavOhJY1BYtgwkfBwbxlheLj3uRIRka3Zh+WCZ+dI59GzZfXO/YEOxyd/SxonTRKJiRExxvuviytILTl69GhxaeN3330n8fHxAY7It+qUNOoojapyw4fD66+ffF5YePL5a68FJiaX2LTnMKkTlnC8wMPkocl0PKNpoEOyXajdjLxjxw769euHx+OhXr16jB8/PtAh1QpN6qpy6emVL6/DSf2n3w5x6/ilgDA17QLOPc3/r/DKeWeffTYrV64MdBi1Tgf0UpWrYJb1KpfXARt2HWRA+hLCDEGZ0EWL0oJGdX9XmtRV5cLD/Vse4tZm5TJw/BLqR4Qx7Z4LOOsPlY9j4kYNGjQgJydHE3sQEBFycnIsVfWUpd0vqnJpaaX71Esur2NW7NjPHW8vo2nDSKYM7UHbFlG+3+Qybdq0ISsri+zs7ECHoixo0KABbdq08ft9mtRV5U70m6ene7tcwsO9Cb2O9ad/v20fg99eRssm9Zk8tAetmzUMdEjVEhkZWeEdnCq0aFJXVXvttTqXxEtavDmHu979ntObNWDykB6c1tT/r8NKOUmTulKVWPhzNkPfy6Rt8ygyhibzhyaa0JX76YXSYHbZZd7b5k88Lrss0BFVn8smwZj3wx7unphJ+5aNmZrWQxO6suUQdeQwr+rOpNp86B2lNZSSUnrSiBOPlJRAR+Y/l02C8cW63XLWk7Pk2lcWyv4jxwISg3IXOw5Ruw5zfNxRaiRA5U2JiYlyYsB5VQ3GVP5asJWsxcZ6B+wuKybGO86Lg2at2c1DU1cS17opE+9KomnDSEe3r9zJjkPUrsPcGLNcRBIre127X1TguWQSjE9W/sIDU1bQpV0z3r9bE7o6yY5D1KnDXJO6CjwXTILxYeZOHvlgFcntT+XdO5No0kATujrJjkPUqcNck3qwKpoX0fJyNwvwJBiTl+5gxPQ1XHRWS94e3J1G9bUoTJVmxyHq2GFeVYd7bT70QqkNyl4sDcaLpCcEaJzXd7/dKjEjZ8rgt5fK78cLHNmmCk52HKJ2tIFeKFWqYuMXbGHc5xvp06EV/761C/Uj6uaYNiq46IXSUOZE4azL6sft8uq8TYz7fCPXdDqd11K7akJXIUM7D4NVRoZ3HJYTU75v335yoC2rMxv4asOObbiMiPCvuT/z8pyfuSHhDF74czwR4Xpuo0KHdr8EKycKZ11UP24HEeGfs3/ktfmbuaVbG/5xc2fCw6qo91fKhXx1v+iZerByonDWJfXjdhARxs3ayIRFWxmY1I5xN8QRpgldhSD93hmsnCicdUH9uB1EhNGfrWfCoq3ccUEMz96oCV2FLk3qwcqJwtkA14/bweMRnvx4HRMXb2foxe0Z3bcjpqohFpQKcprUg1VqqnfyipgY7zgwMTHe5/5cwPTVhh3bCKBCj/DYR2uYsmwH9/3pTJ68+nxN6Crk6YVSFZIKCj385cPVfLpqF49cdg4PppylCV2FBK1Trw4narOtbCNEa8RrW36hh4emruLTVbsYccW5PHTZ2ZrQXUwPc5tVdbtpbT5cO0yAE2N7W9mGy8YYDxZH8wtkyMTvJWbkTBm/YHOgw1E+6GHuP3SYAD85UZttZRshViPuhKP5hQybtJx5P2Yzpm9H7rgwNtAhKR/0MPefr+4XTeplhYVVPMmEMeDxOLcNJ+IIIb8fLyTt/UwWbdrLuBs6cWtycJVd1lV6mPtP+9T95URttpVthEiNuBOOHCvgzneXsWjTXv7fzZ01oQcRPcztp0m9LCdqs61sIwRqxJ1w6Gg+d7y9jGVb9/FSvwT+nNg20CEpP+hhXguq6nCvzYdrL5SKODO2t5VtBGiM8WBxIO+4XP/vRXLmE7Nk5updgQ5HVZMe5v5BL5SqUHQg7zi3vbWMH349yKu3duXyjqcFOiSlHFHjPnVjTANjzDJjzGpjzHpjzJgK1hlsjMk2xqwqegypaeAKGD4cIiK8V40iIrzP/Xkd3FNzb6Ocw8cYkL6EH387RPptiZrQlSqpqtP4orN4AzQu+jkSWAr0KLPOYODfvtqSYOl+cYNhw0oX7554DBtm7XUR99Tc2+i3g7/LZf87X84Z9bks+GlPrWxDKTfDzu4XY0wUsAgYJiJLSywfDCSKyP1W29LuFx8iIqCwsPzy8HAoKPD9Orin5t4mv+Ye5dbxS9ide5S3Bidy4ZktbW1fqWBgS0mjMSbcGLMK2AN8VTKhl3CzMWaNMWa6MabCEgRjTJoxJtMYk5mdnW3pA9RZFSXskst9vQ7OjIfu0Jjrvxz4nf7pi9lz6Bjv3Z2kCV2pSlhK6iJSKCIJQBsgyRgTV2aVGUCsiHQGvgImVtJOuogkikhidHR0TeIOfeGVzJl5Yrmv18E9Nfc1tHNfHv3fXMy+I8d5/+4kuse2sK1tpUKNX3XqInIAmAdcWWZ5jogcK3o6AehmT3h12Im5QCtb7ut1cE/NfQ1s3XuEfm8u5vCxAiYP6UGXds1taVepkFVVh3tRf3s00Kzo54bAQuDaMuucXuLnG4ElvtrVC6UWDBsmEh7uvfgYHl76IqiV10XcU3NfDT//dlC6P/OVdBn7paz/JdeWNpUKdtT0QqkxpjPe7pRwvGf2H4jIWGPM2KLGPzPGPAf0BQqAfXgvpP5QVbt6oVRV5cdfD5E6YQlgmDw0mXNaNQl0SEq5gg7opYLO+l25DJqwlHoRYUwe2oMzoxsHOiSlXEMH9KoOO26msXJjUE3bcGKiDTs+hx/WZB3g1vFLaRgZzrS0C2xN6BlrM4h9OZawMWHEvhxLxlr/f686t4lyvar6Zmrz4do+dTtuprFyY1BN23Biog07PocfMrftk7inv5Cez8+VHTlHbG170ppJEjUuShhN8SNqXJRMWmP996pzmyg3QMd+8ZMdN9NYuTGopm04MdGGHZ/DoqVbcrjr3e+JblKfyUN7cEazhra2H/tyLNtzy++LmKYxbHt4m7U2YnVuExV42qfuLztG7a9qPkyr+9tXG05MtGHH57Dgu017uXtiJmc0a8DkoT1odUoD29o+IWxMGEL5mA0Gz9+s/V51bhPlBtqn7i87bqaxcmNQTdtwYqINOz6HD9/8lM2d735PuxZRTE27oFYSOkC7phV/5sqWV7iuzm2igoAm9bLsuJnGyo1BNW3DiYk27PgcVZi78TeGTszkzOjGTEnrQXST+ra0W5FxKeOIiiy9L6IioxiXYv33qnObqKBQVYd7bT5ce6FUxJ6baazcGFTTNpyYaMOOz1GB/67dLWc9OUuu+7+Fsv/IMVva9GXSmkkS81KMmNFGYl6K8esiaXEbOreJCjD0Qqlymxmrd/HwtFV0btOUiXclcUqDyECHpFTQ0D71YOar4DkIC6I/XpnFQ1NX0q1dc96/OzkkE/rw5xcR0SILYzxEtMhi+POLnI/B2dsLlJtUdRpfmw9Xd7+4ga+C5yAsiJ62bIfEPj5TBqYvliPH8gMdTq0Y9txCIfJw6dL+yMMy7LmFzsXg7O0FymFo90uQ8lXwHGQF0ZOWbOepT9bR65xo0m/rRoNI+ypo3CSiRRaF+9uUWx7ePIuCfeWX10oMzt1eoAJAu1+Cla/JJxyanMIO73y7lac+WUfKeX8I6YQOULj/DL+W10oMFuZPUaFLk7pb+Sp4DpKC6PQFmxkzYwNXdGzF64NCO6EDhDff5dfyWomh9m8vUC6mSd2tfBU8B0FB9L+//plnP/+Bazufzr9v7Uq9iNA/3NIe2waRR0ovjDziXe5UDLV7e4Fyu6o63GvzoRdKLfBV8OzSgmiPxyP/++WPEjNypjwydaXkFxQGOiRHDXtuoYQ33ylQKOHNdzp6kbQ4htq5vUC5AHqhVDlJRPjHFz/yxjeb6ZfYhudu6kx4WBVjyCil/FL3LpTaUbvtqw2nioCDrA5dRPj7zI288c1mUpPb8bzDCd2O8dKd4KuO3alfux23QTg1Rr3yQ1Wn8bX5qJXuFztqt3214VQRcJDVoRcWeuSpj9dKzMiZ8rdP14nH43F0+3aMl+4EX3XsTv3a7bgNwqkx6lVp1KnuFztqt3214VQRcBDVoXs8wpMfr2Xq9zu5p9cfefyq8zBVDdtbC+wYL90JvurYnfq123EbhFNj1KvS6tZ46nYMZu2rDYfGGA+WgbkLPcJj09fw0YosHrj0LB7tc47jCR3sGS/dCcZ4qLjX04NImGO/dl/bsTR2vENj1KvS6lafuh21277acKoIOAjq0AsKPTwybRUfrcji0T7n8JfLzw1IQgd7xkt3gq86dqd+7XbcBuHUGPXKP6GV1O2o3fbVhlNFwC6vQ88v9PDAlJV8tnoXI688jwdTzg5oPHaMl+4EX3XsTv3a7bgNwqkx6pWfqupwr81HrdWp21G77asNp4qAXVqHfjS/QO5+93uJGTlTxi/YHOhwitkxXroTfNWxO/Vrt+M2CKfGqFcnUaculKpadzS/kHsnLWf+j9n8/fqO3HZBbKBDUqpOqVt96nYJpVp3G/1+vJAhEzP55qdsnr+pkyb0anKiLvuy/3kb02w7xngwzbZz2f+87X8b/X/AhBdgjGDCC7is/w/2B6rsV9VpfG0+XDtMQCjVutvo8NF86ffGd9L+8ZkyPXNnoMMJWk7UZaf85a0Ka+FT/vKW9Tb6bRTwlDlEPZLSb6N9gapqQbtf/BRKte42OXQ0n8HvfM+qnQd4sV881ye0DnRIQcuJumzTbDvkxpR/oel25EAFyytqI7wAPBHlXwgrQAorWK4c46v7RX87ZdkxTrmvNoJowOvcvHxuf2cZ63/J5d8Du3BVp9MDHVJQc2QY/Ny2/i2viKeSEt3KlivX0D71skKp1r2G9h85zq0TlrBx10FeH9RNE7oNHKnLbrrTv+UVCavkBKOy5co1NKmXFUq17jWw9/AxBo5fws97DvPm7d3o06FVoEMKCU7UZacMmVthLXzKkLnW27hlE5S7W1SKlitXq6rDvTYfrr1QKhJate7V8Fvu75Lyv/Pl3Kc+l4U/ZQc6nJDjRF12yl/eEppuEygUmm7z6yJpcRv9Ngph+d4LpmH5epHUJdALpcofu3N/59bxS/nt4FHeHtydHn88NdAhKaVKqHGdujGmgTFmmTFmtTFmvTFmTAXr1DfGTDPGbDLGLDXGxNYsbBUIWfvz6P/mErIPHeO9u5I0oSsVhKz0qR8DLhWReCABuNIY06PMOncD+0XkLOAl4B/2hlnE0qj9Lhlx39fNRS77LDtyvAn9QN5xJg1JJjG2hTcEGyZBGD5rOBFjIzBjDBFjIxg+q/yNVrZsx4bJJ3y14YTLLvMeNicel11WfsI21ukAABX8SURBVB1f+8vK53Di8HLZYV6pYInTkqr6Zso+gChgBZBcZvls4IKinyOAvRQN61vZw+8+dUuj9rtkxH1fNxe57LNs3nNIksfNkfgxs2Vt1oGTIdgwCcKwmcNKvf/EY9jMk9cQbNmODZNP+GrDCSkpFR86KSkn1/G1v6x8DicOL5cd5kEf5wnY0adujAkHlgNnAa+KyMgyr68DrhSRrKLnm4sS/97K2vS7T93SqP0W1nGCr5uLXPRZNu05xMDxS/F4hElDkjn/9FOKX7NjEoSIsREUSvl9EW7CKXi6wL7t2DD5hK82nGBluH5f+8vK53Di8HLRYV6lYInzBFsnyTDGNAM+Bh4QkXUllltK6saYNCANoF27dt22V7SXKmNp1H6XjLjv6y/TJZ/lh18Pkjp+KWFhhslDkjm7VZNSr9sxCYIZU/m+kL+JfduxYfIJX204wUpS97W/rHwOJ/5UXHKY+xQscZ7cpo0DeonIAWAecGWZl34B2hZtMAJoCuRU8P50EUkUkcTo6Gh/Nm1x1H6XjLjv6+YiF3yWdb/kMjB9CZHhYUxL61EuoYM9kyCEm4r3RcnltmzHhsknfLXhFr72l5XP4cSfigsOc0uCJU6rrFS/RBedoWOMaQj0AcoO1/YZcEfRz7cAX4s/XwGssDRqv0tG3Pd1c1GAP8uqnQe4dfwSoupFMO2eHvwxunGF69kxCUJat4r3RcnltmzHhsknfLXhhJQU38t97S8rn8OJP5Vg+ZMNljgtq6rDvSgvdwZWAmuAdcDTRcvHAn2Lfm4AfAhsApYBf/TVbrVuPrI0ar9LRtz3dXNRgD5L5rYc6fj0F3LRP+bKzn1HfK5vxyQIw2YOk/Ax4cJoJHxMeKmLpLZux4bJJ3y14YSyF0tLXiQ9wdf+svI5nPhTCZY/2WCJU0RvPlIlLN2Sw53vfk+rUxoweWgypzdtGOiQlFJ+qnuTZARNMamzvt20lzveWcYZzRoyLa2HowndSg26HXXqTsRhqQ0fh6Adn9WJ/eUW+iftn9A6U8/I8PZb5+WdXBYVBenpkJpq77aCyPwf93DP+8tp37IRk4Yk07Jxfce2nbE2g7QZaeTln/ydREVGkX5dOqmdUi2v44Y4LLXh4xC047M6sb/cQv+ky7O1pNFOtZLU3VRM6hJzNvzG8IwVnN2qMZPuTqZ5o3qObt9KDboddepOxGGpjdiqD0E7PqsT+8st9E+6vLrV/eLIDATB479rd3PvpOWcf3oTJg/p4XhCB9iRW/G+L7ncyjpuiMNSGz4OQTs+qxP7yy30T9p/oZXUg6mYtJZ9tnoX909ZSXzbZrw/JJmmUZEBicNKDboddepOxGGpDR+HoB2f1Yn95Rb6J+2/0ErqQVVMWns+Wp7Fw1NX0i2mORPvSuKUBoFJ6GCtBt2OOnUn4rDUho9D0I7P6sT+cgv9k66Gquoda/NRa5NkuKWYNECmLtsusY/PlFvHL5Yjx/IDHY6IWKtBt6NO3Yk4LLXh4xC047M6sb/coo7/SZeD1qnXHe8v3sZfP13PJedE8+Zt3WgQ6a45T5VSNVe3LpTWYW8t2spfP13PZef/gfTb3ZXQLY1j7mPMdadqle2Iw9c6Pofad6gGPZRq3d0yNrwrVHUaX5sPV89RGmRen79JYkbOlHvfz5Rj+YWBDqcUS+OY+xhz3amxrO2Iw9c6Pofat2FseSuc2o4T3DI2vFPQ7pfQ9srcn3nxq5+4Lv4MXuoXT0S4u758WRrH3MeY607VKtsRh691fA6171ANeijVurtlbHin+Op+iXAyGGUfEeHFr37i/77exE1dW/PPW+IJD6tiMO4AsVJnXFEiLbncqVplO+LwtU5FCb3kcqdq0EOp1t2J4yOY6uXddVqnLBERnv/vD/zf15sY0L0tL7g0oYPFccx9jLnuVK2yHXH4WsfnUPsO1aCHUq27W8aGdwtN6kFGRBg7cwNvLtjCoB7tePbGToS5NKGDxXHMfYy57lStsh1x+FrH51D7DtWgh1Ktu1vGhneNqjrca/OhF0r9V1jokVEfr5GYkTNlzGfrxePxBDokSyyNY+5jzHWnapXtiMPXOj6H2neoBj2Uat3dMja8E9ALpaGh0CM8+Z+1TMvcyb2XnMnIK8/FVDWhpVIqJGmdeggoKPQw4sPVTMvcyYOXnuVXQndDLbIdMXS8Zj4mrABjBBNWQMdr5gckDkvb8TWeerDUO6vgVNVpfG0+tPvFmuMFhXJfxnKJGTlTXpnzk1/vdUMtsh0xdLh6noCnTG23RzpcPc/ROCxtx0c9s5vqnVVwQrtfgtfxAg8PTlnJF+t/5YmrzuOeS8706/1uqEW2IwYTVgBSQfWtKUA81qpyHav/jvUxnrqP15XyRevUg9SxgkLuy1jBnI17ePraDtx1UXu/23BDLbItMUgldYCVLa+tOKxsx9d46kFU76yCk/apu9DR/EKGvrecORv38MwNcdVK6OCOWmRbYjCV3LFT2fLaisPKdnyNpx5E9c4qOGlSd5m84wXc9e73LPw5m/93c2cG9YipdltuqEW2I4YOVy0CynYTStFy5+KwtB1f46kHU72zCk5VdbjX5kMvlJZ36Gi+/Pn176T94zPlo+U7bWnTDbXIdsTQ4ep5gsn3XjA1+X5dJLUzDkvb8TWeukvqnVVwQi+UBoeDR/MZ/PYyVmfl8nL/BK6LPyPQISmlXEjr1INAbl4+t01Yytpfcnn11i5Bl9DtqP/21YZbasxV3RUsx4ZWvwTYviPHGTRhKZv2HOaNQd1IOb9VoEPyS8baDNJmpJGXnwfA9tztpM3wDmSS2inVljbs2IalODK8Y7DkeTfD9u0nx2RJtW8zKggF07Gh3S8BlH3oGIMmLGVbzhHSb0/kknOiAx2S3+yo//bVhltqzFXd5aZjQ+vUXWrPwaMMHL+EXw78ztuDu9PzrJaBDqla7Kj/9tWGW2rMVd0VTMeG9qkHwO7c3+mfvoRfc48y8c6koE3oYE/9t6823FJjruquYDo2NKk7bOe+PPq9uZi9h47x3t3JJP/x1ECHVCN21H/7asMtNeaq7gqmY0OTuoO25xxhQPoScvPymTQkmW4xzQMdUo2ldkol/bp0YprGYDDENI0h/bp0vy5g+mrDjm1YiiMV0tO9/aTGeP9NT3ffhTDlvGA6NvRCqUM2Zx/m1vFLOF7g4f27k4lr3TTQISmlglCN69SNMW2NMfOMMRuMMeuNMQ9VsE5vY0yuMWZV0ePpmgYeSn7+7RD931xCoUeYktZDE7pSqtZY6X4pAP4iIh2AHsB9xpgOFay3UEQSih5jbY0yiG3cfZAB6UsIMzA1rQfnnXYKYM+NDG6YAMNKHFbiDJYbO6wY/vwiIlpkYYyHiBZZDH/e+hg1dgml/an8VNUYAhU9gE+BPmWW9QZm+tNOXRj7ZW3WAYkfM1t6PDtHtmQfLl5ux0QJbpgAw0ocVuIMpYkjhj23UIg8XHpCj8jDMuy5hY7FEEr7U5WHnWO/GGNigQVAnIgcLLG8N/ARkAXsAv5HRNZX1Vao96mv3LGf299exikNIpma1oO2LU5eOrfjRgY3TIBhJQ4rcbrpxo6aimiRReH+NuWWhzfPomBf+eW1IZT2pyrPtpuPjDGN8Sbuh0sm9CIrgBgROWyMuRr4BDi7gjbSgDSAdm4s8LRJ5rZ9DH7ne1o0qsfkocm0aV66FsqOGxncMAGGlTisxBlMN3b4Uri/4nF7KlteG0Jpfyr/WSppNMZE4k3oGSLyn7Kvi8hBETlc9PPnQKQxptwdNSKSLiKJIpIYHR18t8RbsXhzDre/vYw/NKnPB/dcUC6hgz03MrhhAgwrcViJM5hu7PAlvPkuv5bXhlDan8p/VqpfDPAWsFFEXqxkndOK1sMYk1TUbo6dgQaDRT/v5c53l9G6WUOm3tOD05o2qHA9O25kcMMEGFbisBJnMN3Y4UvaY9sg8kjphZFHvMsdEkr7U1VDVR3uRf3tF+GddmYNsKrocTVwL3Bv0Tr3A+uB1cAS4EJf7YbahdKvN/4mZ4/6XK546RvZe+ioz/XtmCjBDRNgWInDSpyhNHHEsOcWSnjznQKFEt58p6MXSU8Ipf2pSkMnyah9X67/lfsmr+Dc05rw/l3JNG9UL9AhKaVClE6SUcs+X7ub4Rkr6HBGUzKG9LCc0N1SY26H4bOGEzE2AjPGEDE2guGzhgc6JKXqLB16twY+XfULj36wmi5tm/HOnd1p0iDS0vucmvTBCcNnDef1zNeLnxdKYfHz1655LVBhKVVn6Zl6NU1fnsXD01bRPbY5E+9KspzQAUbNHVWc0E/Iy89j1NxRdodZ69KXp/u1XClVu/RMvRqmLNvBkx+vpeeZLRl/eyIN64X79X631JjboVAK/VqulKpdeqbup/cWb+OJ/6zlknOimXCH/wkd3FNjbodwU/Hnr2y5Uqp2aVL3w4SFW3j60/X06dCKN2/rRoPI6iUut9SY2yGtW5pfy5VStUuTukWvzd/EM7M2cnWn03gttSv1I6p/JurUpA9OeO2a1xiWOKz4zDzchDMscZheJFUqQLRO3QcR4ZW5m3hpzk9cn3AG//vneCLC9f9CpVRgaJ16WX4MNC0ivPDlj7w05ydu7tqGF/slOJrQg6WWPVjidIruDxVIdav6JSMD0tIgr6iccPt273MoN9mgiPDs5xsZv3ArA5PaMu6GToSFGedCDZJa9mCJ0ym6P1Sg1a3uF4sDTYsIY2Zs4N3vtnH7BTGMvq6jowkd3DNeui/BEqdTdH+o2mbbeOohwcJA0x6P8NSn65i8dAdDLmrPqGvOp2gASkcFSy17sMTpFN0fKtDqVp+6j4GmCz3CyI/WMHnpDob3PjNgCR2Cp5Y9WOJ0iu4PFWh1K6lXMdB0QaGHv3ywig+XZ/FQytmMuOLcgCV0CJ5a9mCJ0ym6P1Sg1a2knpoK6enePnRjvP+mp5M/YCAPTVvFJ6t2MeKKc3mkzzkBTegQPLXswRKnU3R/qECrWxdKK3C8wMMDU1Ywe/1vjLr6fIb2+mOgQ1JKqUppnXoVjuYXcu+k5cxe/xujr+ugCT3EDX9+EREtsjDGQ0SLLIY/v8jvNrQGXbld3ap+KeH344WkvZ/Jwp/38uyNnbg1WS9khbLhzy/i9ae7QH4jAAr3t+H1p5sDi3jt8YsstaE16CoY1Mnul7zjBdz9biZLtubwj5s70y+xbUDiUM6JaJFF4f425ZaHN8+iYF/55RXRGnTlBlqnXoG3Fm5l6dYcXuwXz41drP1Bq+BWuP8Mv5ZXRGvQVTCok0n93t5nkvzHU0lq3yLQoSiHhDffVcmZ+i7A2n/s7Zq2q/BMXWvQlZvUyQulkeFhmtDrmLTHtkHkkdILI494l1ukNegqGNTJpK7qntcev4hhY1cS3jwL8BDePIthY1davkgKWoOugkOdvFCqlFLBSuvUlVKqDtGkrpRSIUSTulJKhRBN6kopFUI0qSulVAjRpK6UUiFEk7pSSoUQTepKKRVCfCZ1Y0xbY8w8Y8wGY8x6Y8xDFaxjjDGvGGM2GWPWGGO61k64SimlqmLlTL0A+IuIdAB6APcZYzqUWecq4OyiRxrwuq1R1lE6IYNSyl8+R2kUkd3A7qKfDxljNgKtgQ0lVrseeE+8Yw4sMcY0M8acXvReVQ06IYNSqjr86lM3xsQCXYClZV5qDews8TyraJmqplFzRxUn9BPy8vMYNXdUgCJSSgUDy0ndGNMY+Ah4WEQOVmdjxpg0Y0ymMSYzOzu7Ok3UGTohg1KqOiwldWNMJN6EniEi/6lglV+AknPCtSlaVoqIpItIoogkRkdHVyfeOqOyiRd0QgalVFWsVL8Y4C1go4i8WMlqnwG3F1XB9ABytT+9ZnRCBqVUdViZzq4ncBuw1hizqmjZk0A7ABF5A/gcuBrYBOQBd9ofat1y4mLoqLmj2JG7g3ZN2zEuZZxeJFVKVUknyVBKqSCik2QopVQdokldKaVCiCZ1pZQKIZrUlVIqhGhSV0qpEBKw6hdjTDawPSAb92oJ7A3g9v0RLLFqnPYKljgheGINhThjRKTSuzcDltQDzRiTWVVZkJsES6wap72CJU4InljrQpza/aKUUiFEk7pSSoWQupzU0wMdgB+CJVaN017BEicET6whH2ed7VNXSqlQVJfP1JVSKuTUiaRujAk3xqw0xsys4LXBxphsY8yqoseQAMW4zRiztiiGciOduWlybwux9jbG5JbYp08HKM5mxpjpxpgfjDEbjTEXlHndFfvUQpxu2Z/nlohhlTHmoDHm4TLrBHyfWozTLfv0EWPMemPMOmPMFGNMgzKv1zfGTCvan0uLZp+rmoiE/AN4FJgMzKzgtcHAv10Q4zagZRWvXw38FzB4JwBf6uJYe1e0rwMQ50RgSNHP9YBmbtynFuJ0xf4sE1M48CvemmnX7VMLcQZ8n+Kd8nMr0LDo+QfA4DLrDAfeKPp5ADDNV7shf6ZujGkDXANMCHQsNVQ8ubeILAGaGWNOD3RQbmWMaQr0wjvBCyJyXEQOlFkt4PvUYpxulAJsFpGyNxAGfJ+WUVmcbhEBNDTGRABRwK4yr1+P9z99gOlAStHERZUK+aQOvAw8BniqWOfmoq+K040xbatYrzYJ8KUxZrkxJq2C1900ubevWAEuMMasNsb81xjT0cngirQHsoF3irreJhhjGpVZxw371EqcEPj9WdYAYEoFy92wT0uqLE4I8D4VkV+AF4AdwG68M8Z9WWa14v0pIgVALnBqVe2GdFI3xlwL7BGR5VWsNgOIFZHOwFec/F/RaReJSFfgKuA+Y0yvAMVhha9YV+D9uhsP/B/widMB4j0D6gq8LiJdgCPA4wGIwxcrcbphfxYzxtQD+gIfBjIOX3zEGfB9aoxpjvdMvD1wBtDIGDOopu2GdFLHOxVfX2PMNmAqcKkxZlLJFUQkR0SOFT2dAHRzNsTiOH4p+ncP8DGQVGYVS5N7O8FXrCJyUEQOF/38ORBpjGnpcJhZQJaILC16Ph1v8izJDfvUZ5wu2Z8lXQWsEJHfKnjNDfv0hErjdMk+vQzYKiLZIpIP/Ae4sMw6xfuzqIumKZBTVaMhndRF5AkRaSMisXi/hn0tIqX+JyzT39cX2OhgiCdiaGSMaXLiZ+ByYF2Z1VwxubeVWI0xp53o9zPGJOE9zqo8EO0mIr8CO40x5xYtSgE2lFkt4PvUSpxu2J9lDKTyLo2A79MSKo3TJft0B9DDGBNVFEsK5fPPZ8AdRT/fgjeHVXlzkZWJp0OOMWYskCkinwEPGmP6AgXAPrzVME5rBXxcdIxFAJNF5AtjzL3gusm9rcR6CzDMGFMA/A4M8HUg1pIHgIyir+FbgDtduk99xemW/XniP/I+wD0llrlun1qIM+D7VESWGmOm4+0KKgBWAull8tNbwPvGmE1489MAX+3qHaVKKRVCQrr7RSml6hpN6kopFUI0qSulVAjRpK6UUiFEk7pSSoUQTepKKRVCNKkrpVQI0aSulFIh5P8Djd61cCwkiTMAAAAASUVORK5CYII=\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"tags": [],
"needs_background": "light"
}
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Py56ReH5wfKB",
"colab_type": "text"
},
"source": [
"Il est clair qu'il y a une droite qui sépare la classe `Iris-Setosa` des autres classes.\n",
"L'équation de cette droite est:\n",
"$$\n",
"y = x - 2.3\n",
"$$"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "owons9o4zgGx",
"colab_type": "text"
},
"source": [
"## Un premier apprentissage de classifieur"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "VTsoJj873w1T",
"colab_type": "text"
},
"source": [
"### Naïve Bayes\n",
"L'example ci-dessous permet de:\n",
"1. Initialiser le classifieur Naïve Bayes Multinomial\n",
"2. Lancer l'apprentissage sur tout l'ensemble de données sauf la dérniére instance\n",
"3. Lancer la prédiction:\n",
" - sur le 32éme élement\n",
" - sur le dérnier élement\n",
" - sur tout l'ensemble de données\n",
"\n",
"##### **Conclusion**\n",
"La précision du classifieur est 96.6% sur les données d'apprentissage (train dataset) sauf la dernière instance. Ce score peut être biaisé car il ne reflète pas des prédictions sur des nouvelles instances."
]
},
{
"cell_type": "code",
"metadata": {
"id": "qDu5K6FZzeaL",
"colab_type": "code",
"outputId": "d893b12f-94ee-422a-ce21-44763bea8fbb",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 199
}
},
"source": [
"from sklearn import naive_bayes\n",
"# Initialiser le classifieur\n",
"nb = naive_bayes.MultinomialNB(fit_prior=True)# un algo d'apprentissage\n",
"# Charger les données\n",
"irisData = datasets.load_iris()\n",
"\n",
"# Lancer la phase d'apprentissage\n",
"nb.fit(irisData.data[:-1], irisData.target[:-1])\n",
"\n",
"# Lancer la prédiction\n",
"p31 = nb.predict([irisData.data[31]])\n",
"#print(irisData.target[31], p31)\n",
"\n",
"plast = nb.predict([irisData.data[-1]])\n",
"#print(plast)\n",
"predicted_results = nb.predict(irisData.data[:])\n",
"\n",
"print(\"Prediction results\", predicted_results)\n",
"print(\"Actual results\", irisData.target)\n"
],
"execution_count": 6,
"outputs": [
{
"output_type": "stream",
"text": [
"Prediction results [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n",
" 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\n",
" 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2\n",
" 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 2 1 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2\n",
" 2 2]\n",
"Actual results [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n",
" 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\n",
" 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2\n",
" 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2\n",
" 2 2]\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "HhVae88W9Gl9",
"colab_type": "text"
},
"source": [
"#### b- Deuxième programme\n",
"Cet algorithme divise des données en deux: les données d'apprentissage et les données de test."
]
},
{
"cell_type": "code",
"metadata": {
"id": "58xVzW769J4m",
"colab_type": "code",
"outputId": "195edc24-ea43-42bc-c330-95f08db67a5d",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 90
}
},
"source": [
"from sklearn import naive_bayes\n",
"\n",
"nb = naive_bayes.MultinomialNB(fit_prior=True)\n",
"\n",
"nb.fit(irisData.data[:99], irisData.target[:99])\n",
"\n",
"# Prédire sur les données restantes\n",
"prediction_result = nb.predict(irisData.data[100:149])\n",
"\n",
"print(\"Prediction results\", prediction_result)\n",
"print(\"Actual results\", irisData.target[100:149])"
],
"execution_count": 7,
"outputs": [
{
"output_type": "stream",
"text": [
"Prediction results [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\n",
" 1 1 1 1 1 1 1 1 1 1 1 1]\n",
"Actual results [2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2\n",
" 2 2 2 2 2 2 2 2 2 2 2 2]\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "8kqI4h_MTHIM",
"colab_type": "text"
},
"source": [
"##### **Conclusion**\n",
"Les résultats sont incohérents. Le problème c'est que notre dataset n'est pas équilibré aprés la division. En effet le modèle n'a jamais vu le 3éme type 'Iris-Virginica'. Pour remédier à ce problème, il faut mélanger le dataset avant la division (Train & Test).\n",
"\n",
"\n",
"Ci-dessous le même algorithme avec le mélange avant la division en utilisant la fonction `shuffle` de sklearn"
]
},
{
"cell_type": "code",
"metadata": {
"id": "vKfk_de_prA6",
"colab_type": "code",
"outputId": "6c577745-c1a4-4c58-e296-7b2eaa5fa2d1",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 74
}
},
"source": [
"from sklearn import naive_bayes\n",
"from random import shuffle\n",
"\n",
"nb = naive_bayes.MultinomialNB(fit_prior=True)\n",
"data = list(zip(irisData.data, irisData.target))\n",
"\n",
"shuffle(data)\n",
"X, y = list(zip(*data))\n",
"\n",
"nb.fit(X[:99], y[:99])\n",
"\n",
"# Prédire sur les données restantes\n",
"prediction_result = nb.predict(X[100:149])\n",
"\n",
"print(\"Prediction \", list(prediction_result))\n",
"print(\"Actual \", list(y[100:149]))"
],
"execution_count": 8,
"outputs": [
{
"output_type": "stream",
"text": [
"Prediction [2, 1, 0, 2, 0, 1, 1, 2, 2, 2, 2, 0, 0, 1, 1, 2, 2, 1, 2, 2, 2, 0, 0, 2, 2, 2, 2, 1, 1, 1, 0, 0, 2, 1, 2, 0, 0, 2, 2, 1, 2, 0, 0, 1, 2, 0, 0, 2, 2]\n",
"Actual [1, 1, 0, 2, 0, 1, 1, 2, 2, 1, 1, 0, 0, 1, 1, 2, 1, 1, 1, 1, 2, 0, 0, 2, 2, 1, 2, 1, 1, 1, 0, 0, 2, 1, 2, 0, 0, 2, 2, 1, 2, 0, 0, 1, 2, 0, 0, 2, 2]\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "_yYTEpZbV_pG",
"colab_type": "text"
},
"source": [
"## III- Evaluer les performances d'un classifieur"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "ympqHUKH-Keh",
"colab_type": "text"
},
"source": [
"### Performances sur l'ensemble d'apprentissage"
]
},
{
"cell_type": "code",
"metadata": {
"id": "l44ua0BqWDab",
"colab_type": "code",
"outputId": "69d61d05-38f3-456c-d785-b60ad3e981be",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
}
},
"source": [
"nb.fit(irisData.data, irisData.target)\n",
"prediction_result = nb.predict(irisData.data)\n",
"\n",
"# Calculer l'erreur en faisant la somme des inégalité\n",
"def calculate_error(P, Y):\n",
" ea = 0\n",
" for i in range(len(irisData.target)):\n",
" if (P[i] != Y[i]):\n",
" ea = ea+1\n",
" return (ea/len(Y))\n",
"\n",
"calculate_error(prediction_result, irisData.target)"
],
"execution_count": 9,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"0.04666666666666667"
]
},
"metadata": {
"tags": []
},
"execution_count": 9
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "PKoaw_bPuk0l",
"colab_type": "text"
},
"source": [
"Les opérateurs sur les tableaux permet d'effectuer ce comptage en une seule instruction. \n",
"\n",
"Les valeurs non nulles représente les erreurs commises par le modéle. Donc on peut utiliser la fonction `count_nonzero()` du package `numpy`."
]
},
{
"cell_type": "code",
"metadata": {
"id": "3bceMW0Vl6hS",
"colab_type": "code",
"outputId": "a2d4e68d-ab2c-4081-a6d0-fda4f522d4c7",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
}
},
"source": [
"diff = prediction_result - irisData.target\n",
"np.count_nonzero(diff)/len(irisData.target)"
],
"execution_count": 10,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"0.04666666666666667"
]
},
"metadata": {
"tags": []
},
"execution_count": 10
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "5-9SCdUW7P0g",
"colab_type": "text"
},
"source": [
"On peut aussi calculer le taux de bonne classification du\n",
"modèle et le taux d'erreur en utilisant la méthode `.score()`"
]
},
{
"cell_type": "code",
"metadata": {
"id": "-Ae_EgV17Erj",
"colab_type": "code",
"outputId": "8228985e-77d9-4933-d9be-d45db8f06a31",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 54
}
},
"source": [
"print(f\"Accuracy = {nb.score(irisData.data, irisData.target)}\")\n",
"print(f\"Taux d'erreur = {1-nb.score(irisData.data, irisData.target)}\")"
],
"execution_count": 11,
"outputs": [
{
"output_type": "stream",
"text": [
"Accuracy = 0.9533333333333334\n",
"Taux d'erreur = 0.046666666666666634\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "O8lYa_p8-ycf",
"colab_type": "text"
},
"source": [
"### Performances en généralisation"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "XjRZajoDZCUt",
"colab_type": "text"
},
"source": [
"La fonction `split(S)` permet de séléctionner les indexes qui vont être présent dans le Set `S2`. Puis, charger les listes `dataS1`, `targetS1`, `dataS2` et `targetS2` suivant l'index (si il fait partie des indexes `S2`, on l'ajoute à la liste `S2` sinon dans `S1`."
]
},
{
"cell_type": "code",
"metadata": {
"id": "IsO1sd11-ztg",
"colab_type": "code",
"outputId": "6d4aa013-8bd2-4bde-e616-e6b1aea81fe6",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 54
}
},
"source": [
"from random import sample\n",
"S = list(zip(irisData.data, irisData.target))\n",
"def split(S):\n",
" s2_size = len(S)*0.33\n",
" s2_indexes = sample(range(len(S)),k=round(s2_size))\n",
"\n",
" dataS1 = []\n",
" targetS1 = []\n",
" dataS2 = []\n",
" targetS2 = []\n",
" for i in range(len(S)):\n",
" if i in s2_indexes:\n",
" dataS2.append(S[i][0])\n",
" targetS2.append(S[i][1])\n",
" else:\n",
" dataS1.append(S[i][0])\n",
" targetS1.append(S[i][1])\n",
" return [dataS1, targetS1, dataS2, targetS2]\n",
"\n",
"\n",
"[dataS1, targetS1, dataS2, targetS2] = split(S)\n",
"print(f\"dataS1 = {len(dataS1)} targetS1 = {len(targetS1)}\")\n",
"print(f\"dataS2 = {len(dataS2)} targetS2 = {len(targetS2)}\")"
],
"execution_count": 20,
"outputs": [
{
"output_type": "stream",
"text": [
"dataS1 = 100 targetS1 = 100\n",
"dataS2 = 50 targetS2 = 50\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "EjIEbA0rsgw5",
"colab_type": "text"
},
"source": [
"Pour tester la fonction `split()`, on va créer une fonction `test` qui va effectuer l'apprentissage et le calcule d'erreur."
]
},
{
"cell_type": "code",
"metadata": {
"id": "WEsNxkd8ZrNZ",
"colab_type": "code",
"outputId": "557f7a64-7535-4d03-c0a1-a1f131f04676",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
}
},
"source": [
"def test(S, clf):\n",
" '''\n",
" - S is the list containing (X,y) pairs\n",
" - clf is the sklearn model\n",
" '''\n",
" [dataS1, targetS1, dataS2, targetS2] = split(S)\n",
" clf.fit(dataS1, targetS1)\n",
" return 1-clf.score(dataS2, targetS2)\n",
"\n",
"test(S,nb)\n"
],
"execution_count": 25,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"0.1333333333333333"
]
},
"metadata": {
"tags": []
},
"execution_count": 25
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "E7bZawE7c46Z",
"colab_type": "text"
},
"source": [
"**L'erreur estimée est-elle plus petite que l'erreur apparente précédemment calculée ?**\n",
"- Non, elle est supérieure à celle calculée précédemment.\n",
"\n",
"**Obtient-on toujours la même estimation pour l'erreur réelle ?**\n",
"- Pour chaque execution, on obtient une estimation différente de l'erreur réelle\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "AVW6c2_bdofz",
"colab_type": "code",
"outputId": "56c4c548-bf88-48e8-d53e-9fd34c4db441",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 126
}
},
"source": [
"# Cette fonction permet d'effectuer le test t fois et retourner la moyenne\n",
"# du taux d'erreur\n",
"def repeat_test(S,nb, t):\n",
" result = 0\n",
" for i in range(t):\n",
" result += test(S,nb)\n",
" return result / t\n",
"\n",
"# Pour chaque t on va effectuer le test et afficher la moyenne du taux d'erreur\n",
"for t in [10,50,100,200,500,1000]:\n",
" print(f\"t = {t} | moyenne = {repeat_test(S,nb, t)}\")\n"
],
"execution_count": 22,
"outputs": [
{
"output_type": "stream",
"text": [
"t = 10 | moyenne = 0.24\n",
"t = 50 | moyenne = 0.20159999999999997\n",
"t = 100 | moyenne = 0.19619999999999993\n",
"t = 200 | moyenne = 0.19640000000000005\n",
"t = 500 | moyenne = 0.2028000000000002\n",
"t = 1000 | moyenne = 0.20078000000000007\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "E3f2BB_Mi5rg",
"colab_type": "code",
"outputId": "88f65b75-cb8b-41ab-d712-293491ea3c43",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 126
}
},
"source": [
"# Pour chaque t on va répeter le test 20 fois \n",
"# et afficher la moyenne du taux d'erreur\n",
"for t in [10,50,100,200,500,1000]:\n",
" moy = 0\n",
" for i in range(20):\n",
" moy += repeat_test(S,nb, t)\n",
" print(f\"t = {t} | 20 fois | moyenne = {moy/20}\")"
],
"execution_count": 15,
"outputs": [
{
"output_type": "stream",
"text": [
"t = 10 | 20 fois | moyenne = 0.18760000000000004\n",
"t = 50 | 20 fois | moyenne = 0.19938000000000003\n",
"t = 100 | 20 fois | moyenne = 0.20166999999999993\n",
"t = 200 | 20 fois | moyenne = 0.19890499999999997\n",
"t = 500 | 20 fois | moyenne = 0.20429200000000014\n",
"t = 1000 | 20 fois | moyenne = 0.2014140000000002\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "TDD57gy1joAF",
"colab_type": "text"
},
"source": [
"**Est-ce que l'erreur moyenne est stable ou non?**\n",
"- L'erreur moyenne est plus en plus stable à chaque itération.\n",
"\n",
"**Pouvez-vous interpréter ce résultat?**\n",
"- On peut conclure que les taux d'erreur obtenus sont des estimations d'un même l'estimateur (théorique). Plus l'ensemble de données est grand, plus les taux d'erreur converge vers le taux réel d'erreur."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "_lt8Witzkw-H",
"colab_type": "text"
},
"source": [
"**Est-ce que l'erreur estimée (dans sa version stable), dans le cas d'un échantillon de test qui ne prend que le 10ème de l'échantillon initial, est la même qu'avec la proportion d'1/3 ?**\n",
"\n",
"Pour réaliser cette comparaison, on a besoin de modifier la fonction `split(S)`\n",
"- L'erreur avec la proportion d'1/3 est `0.20`\n",
"- L'erreur avec le 10éme de l'échantillon initial est `0.13`"
]
},
{
"cell_type": "code",
"metadata": {
"id": "8qlTT9AulF7s",
"colab_type": "code",
"colab": {}
},
"source": [
"def split(S):\n",
" s2_size = len(S)*0.1 # Le 10éme de l'échantillon initial\n",
" s2_indexes = sample(range(len(S)),k=round(s2_size))\n",
"\n",
" dataS1 = []\n",
" targetS1 = []\n",
" dataS2 = []\n",
" targetS2 = []\n",
" for i in range(len(S)):\n",
" if i in s2_indexes:\n",
" dataS2.append(S[i][0])\n",
" targetS2.append(S[i][1])\n",
" else:\n",
" dataS1.append(S[i][0])\n",
" targetS1.append(S[i][1])\n",
" return [dataS1, targetS1, dataS2, targetS2]"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "9Pb1zMufymFi",
"colab_type": "text"
},
"source": [
"En utilisant la fonction `train_test_split`, on va tester différent test sizes."
]
},
{
"cell_type": "code",
"metadata": {
"id": "PJp5CtmzyuHz",
"colab_type": "code",
"outputId": "7f5bc246-3ceb-4a9b-c049-9550b7629b7e",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 217
}
},
"source": [
"from sklearn.model_selection import train_test_split\n",
"from numpy import arange\n",
"\n",
"def test_it(test_size=.33):\n",
" X_train, X_test, y_train, y_test = train_test_split(irisData.data, irisData.target,test_size=test_size)\n",
" nb.fit(X_train, y_train)\n",
" print(f\"Test size= {test_size} Accuracy = {nb.score(X_test, y_test)} Taux d'erreur = {1-nb.score(X_test, y_test)}\")\n",
" return 1-nb.score(X_test, y_test)\n",
"\n",
"min_error_test_size = None\n",
"min_error = None\n",
"avg_error = 0\n",
"test_sizes = arange(.05, 0.5, .05)\n",
"for test_size in test_sizes:\n",
" error = test_it(test_size)\n",
" avg_error += error\n",
" if (min_error_test_size is None):\n",
" min_error_test_size = test_size\n",
" min_error = error\n",
" else:\n",
" if error < min_error:\n",
" min_error = error\n",
" min_error_test_size = test_size\n",
"\n",
"print(f\"min_error is {min_error} with test_size = {min_error_test_size}\")\n",
"print(f\"Erreur moyenne = {avg_error/ len(test_sizes)}\")"
],
"execution_count": 17,
"outputs": [
{
"output_type": "stream",
"text": [
"Test size= 0.05 Accuracy = 1.0 Taux d'erreur = 0.0\n",
"Test size= 0.1 Accuracy = 0.8 Taux d'erreur = 0.19999999999999996\n",
"Test size= 0.15000000000000002 Accuracy = 0.8695652173913043 Taux d'erreur = 0.13043478260869568\n",
"Test size= 0.2 Accuracy = 0.7333333333333333 Taux d'erreur = 0.2666666666666667\n",
"Test size= 0.25 Accuracy = 0.8947368421052632 Taux d'erreur = 0.10526315789473684\n",
"Test size= 0.3 Accuracy = 0.8222222222222222 Taux d'erreur = 0.1777777777777778\n",
"Test size= 0.35000000000000003 Accuracy = 0.9622641509433962 Taux d'erreur = 0.037735849056603765\n",
"Test size= 0.4 Accuracy = 0.75 Taux d'erreur = 0.25\n",
"Test size= 0.45 Accuracy = 0.8676470588235294 Taux d'erreur = 0.13235294117647056\n",
"min_error is 0.0 with test_size = 0.05\n",
"Erreur moyenne = 0.14447013057566124\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "6R-sZBQS-iM_",
"colab_type": "text"
},
"source": [
"### 2.2 Estimer l'erreur réelle par validation croisée"
]
},
{
"cell_type": "code",
"metadata": {
"id": "YqsE5aGx8tUD",
"colab_type": "code",
"outputId": "ff6f5a2a-9473-49d4-9559-37694ff62381",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 108
}
},
"source": [
"from sklearn.model_selection import cross_val_score\n",
"\n",
"def test_fold(fold):\n",
" error_rate = 1 - cross_val_score(nb, irisData.data, irisData.target, cv=fold)\n",
" return 1-error_rate\n",
"def test_it(params,fn):\n",
" for param in params:\n",
" scores = fn(param)\n",
" print(\"K= %d folds | Taux d'erreur: %0.4f (+/- %0.2f)\" % (param,1-scores.mean(), scores.std() * 2))\n",
"\n",
"test_it([10,2,3,5,8],test_fold)\n"
],
"execution_count": 18,
"outputs": [
{
"output_type": "stream",
"text": [
"K= 10 folds | Taux d'erreur: 0.0467 (+/- 0.13)\n",
"K= 2 folds | Taux d'erreur: 0.0467 (+/- 0.01)\n",
"K= 3 folds | Taux d'erreur: 0.0533 (+/- 0.04)\n",
"K= 5 folds | Taux d'erreur: 0.0467 (+/- 0.09)\n",
"K= 8 folds | Taux d'erreur: 0.0526 (+/- 0.12)\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "XNl0NaKbIQcs",
"colab_type": "text"
},
"source": [
"# Génération du tableau des erreurs obtenues"
]
},
{
"cell_type": "code",
"metadata": {
"id": "7fhi6YlcISO_",
"colab_type": "code",
"outputId": "0b053f72-3eca-4be3-90cf-1520a10b51ba",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 145
}
},
"source": [
"from sklearn.naive_bayes import MultinomialNB\n",
"from sklearn.tree import DecisionTreeClassifier\n",
"from sklearn.ensemble import RandomForestClassifier\n",
"from sklearn.svm import SVC\n",
"from sklearn.neighbors import KNeighborsClassifier\n",
"\n",
"# Performances sur l'ensemble d'apprentissage\n",
"def performance_method1(clf, X, y):\n",
" clf.fit(X,y)\n",
" return 1 - clf.score(X,y)\n",
"# Par division de l'échantillon d'apprentissage\n",
"def performance_method2(clf, X, y):\n",
" X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=.33)\n",
" clf.fit(X_train, y_train)\n",
" return 1 - clf.score(X_test, y_test)\n",
"# Par la validation croisée\n",
"def performance_method3(clf, X, y):\n",
" error_rate = 1 - cross_val_score(clf, X, y).mean()\n",
" return error_rate\n",
"\n",
"performances = {\n",
" \"Performances sur l'ensemble d'apprentissage\": performance_method1,\n",
" \"Par division de l'échantillon d'apprentissage\": performance_method2,\n",
" \"Par la validation croisée\":performance_method3\n",
"}\n",
"\n",
"classifiers = {\n",
" \"Naive Bayes\": MultinomialNB(fit_prior=True),\n",
" \"Arbre de décision\": DecisionTreeClassifier(),\n",
" \"Random forest\": RandomForestClassifier(),\n",
" \"SVM Classifier\": SVC(),\n",
" \"KNN\": KNeighborsClassifier(),\n",
"}\n",
"\n",
"def generate_markdown_report(X, y):\n",
" print(\"| |\"+\"|\".join([perf_label for perf_label in performances])+\"|\")\n",
" print(\"|-|\"+\"|\".join([\"-\" for temp in performances])+\"|\")\n",
" for clf_label, clf in classifiers.items():\n",
" print(\"|\", clf_label, end=\"|\")\n",
" for perf_label, performance_fn in performances.items():\n",
" print(\"%.4f\"%performance_fn(clf, X, y), end=\"|\")\n",
" print()\n",
"\n",
"generate_markdown_report(irisData.data, irisData.target)\n"
],
"execution_count": 19,
"outputs": [
{
"output_type": "stream",
"text": [
"| |Performances sur l'ensemble d'apprentissage|Par division de l'échantillon d'apprentissage|Par la validation croisée|\n",
"|-|-|-|-|\n",
"| Naive Bayes|0.0467|0.4600|0.0467|\n",
"| Arbre de décision|0.0000|0.0800|0.0333|\n",
"| Random forest|0.0000|0.0400|0.0400|\n",
"| SVM Classifier|0.0267|0.0000|0.0333|\n",
"| KNN|0.0333|0.0600|0.0267|\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "hQUK4dAZOhG0",
"colab_type": "text"
},
"source": [
"##### **tableau recapitulatif des taux d'erreurs**\n",
"| |Performances sur l'ensemble d'apprentissage|Par division de l'échantillon d'apprentissage|Par la validation croisée|\n",
"|-|-|-|-|\n",
"| Naive Bayes|0.0467|**0.0000**|0.0467|\n",
"| Arbre de décision|**0.0000**|0.0600|0.0400|\n",
"| Random forest|**0.0000**|0.0400|0.0400|\n",
"| SVM Classifier|0.0267|0.0800|0.0333|\n",
"| KNN|0.0333|0.0600|**0.0267**|"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "hGsyhwBnRWlj",
"colab_type": "text"
},
"source": [
"**Est-ce que les erreurs obtenues par la méthode naïve Bayes et par la méthode arbre de décision, vous permettent d'indiquer si une méthode de classification est meilleure qu'une autre ?**\n",
"- On ne peut pas considérer qu'une méthode de classification est meilleure qu'une autre seulement par la comparaison de taux d'erreur. Cela dépend fortement à la nature du dataset. Certains algorithmes sont plus adapté à certains problèmes que d'autres."
]
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment