{ "cells": [ { "cell_type": "raw", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-2cac5e96b3dd6263", "locked": true, "schema_version": 1, "solution": false } }, "source": [ "---\n", "metadata: true\n", "section: \"Practical task\"\n", "goal: \"Practice the content that was covered in this chapter, in Python.\"\n", "time: \"60 min\"\n", "prerequisites: \"Chapter 1 - Numerical data\"\n", "level: \"Advanced\"\n", "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Practical task" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-07aa1282a4242acf", "locked": true, "schema_version": 1, "solution": false } }, "source": [ "You will now have the possibility to practice all we have seen in this chapter, on a new dataset.\n", "\n", "The dataset is called \"Wine quality\" and has been found and downloaded here: http://archive.ics.uci.edu/ml/datasets/Wine+Quality.\n", "\n", "It contains the characteristics of 6497 wines, and their ``quality``, a grade between 0 and 10 given by 3 wine experts. On the website, the data is separated between white and red wine, but we have grouped them together for the purpose of the exercise. We added an additionnal attribute ``type``, containing the type of wine (red or white).\n", "\n", "For the purpose of the exercise, and to train with missing values, some values have been deleted or modified from the original dataset." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-db9152c02e6a6a46", "locked": true, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "# Import the functions for machine learning\n", "\n", "%run 1-functions.ipynb" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-dc735286646a1d0b", "locked": true, "schema_version": 1, "solution": false } }, "source": [ "## 1. Import the dataset\n", "\n", "+ Import the dataset called ``wine.csv`` into the variable ``data`` __(2 points)__." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-26fdede1ae78cb6b", "locked": false, "schema_version": 1, "solution": true } }, "outputs": [], "source": [ "# import dataset\n", "\n", "import pandas as pd\n", "\n", "# Begin answer\n", "data = pd.read_csv('wine.csv')\n", "# End answer" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "nbgrader": { "grade": true, "grade_id": "cell-88a57b85550b20eb", "locked": true, "points": 1, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "### BEGIN HIDDEN TESTS\n", "assert not data.empty\n", "### END HIDDEN TESTS" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "nbgrader": { "grade": true, "grade_id": "cell-aabb6fbb6ec0272c", "locked": true, "points": 1, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "### BEGIN HIDDEN TESTS\n", "assert not data['fixed acidity'].empty\n", "### END HIDDEN TESTS" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-7759c198372eea8d", "locked": true, "schema_version": 1, "solution": false } }, "source": [ "## 2. Get to know the dataset\n", "\n", "Understand the dataset: how it looks like, the different attributes, their distribution. Plot the distribution of the attributes.\n", "\n", "+ Place the head of the dataset in the variable ``head`` __(1 point)__.\n", "+ Place the description of the numerical attributes in the variable ``description`` __(1 point)__.\n", "+ How many unique values does the attribute ``type`` contain? Place this number in the variable ``unique_type`` __(1 point)__." ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-7c72618014610d14", "locked": false, "schema_version": 1, "solution": true } }, "outputs": [], "source": [ "# examine dataset\n", "\n", "# Begin answer\n", "head = data.head()\n", "description = data.describe()\n", "unique_type = len(data['type'].unique())\n", "# End answer" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "nbgrader": { "grade": true, "grade_id": "cell-3b9c5213d0cbd728", "locked": true, "points": 1, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "### BEGIN HIDDEN TESTS\n", "assert head.equals(data.head())\n", "### END HIDDEN TESTS" ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "nbgrader": { "grade": true, "grade_id": "cell-3ea91df14bffdc06", "locked": true, "points": 1, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "### BEGIN HIDDEN TESTS\n", "assert description.equals(data.describe())\n", "### END HIDDEN TESTS" ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "nbgrader": { "grade": true, "grade_id": "cell-1e8906f68a281ea3", "locked": true, "points": 1, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "### BEGIN HIDDEN TESTS\n", "assert unique_type == len(data['type'].unique())\n", "### END HIDDEN TESTS" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-6f2dc5d93c7efab4", "locked": true, "schema_version": 1, "solution": false } }, "source": [ "## 3. Detect the missing values\n", "\n", "+ There is only one attribute which contains missing values. Place the number of missing values for this attribute in the variable ``missing_nb`` __(1 point)__.\n", "\n", "Think about how to deal with the missing values." ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-55048960dbe4093a", "locked": false, "schema_version": 1, "solution": true } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "RangeIndex: 6497 entries, 0 to 6496\n", "Data columns (total 13 columns):\n", "fixed acidity 6497 non-null float64\n", "volatile acidity 6497 non-null float64\n", "citric acid 6497 non-null float64\n", "residual sugar 6497 non-null float64\n", "chlorides 6497 non-null float64\n", "free sulfur dioxide 6497 non-null float64\n", "total sulfur dioxide 6497 non-null float64\n", "density 5235 non-null float64\n", "pH 6497 non-null float64\n", "sulphates 6497 non-null float64\n", "alcohol 6497 non-null float64\n", "quality 6497 non-null int64\n", "type 6497 non-null object\n", "dtypes: float64(11), int64(1), object(1)\n", "memory usage: 659.9+ KB\n" ] } ], "source": [ "# detect missing values\n", "\n", "# Begin answer\n", "missing_nb = data['density'].isna().sum()\n", "# End answer" ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "nbgrader": { "grade": true, "grade_id": "cell-dde860e67e8cf85b", "locked": true, "points": 1, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "### BEGIN HIDDEN TESTS\n", "assert missing_nb == data['density'].isna().sum()\n", "### END HIDDEN TESTS" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-c045b19897dd6ef0", "locked": true, "schema_version": 1, "solution": false } }, "source": [ "+ The attribute containing the missing values can be recovered with a reasonable accuracy using the attributes ``residual sugar`` and ``alcohol``. Use this formula to recover the attribute: ``attribute = -0.0014 * alcohol + 0.0002 * residual sugar + 1.0082`` __(2 points)__." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-cebfe2b317f53083", "locked": false, "schema_version": 1, "solution": true } }, "outputs": [], "source": [ "# recover the missing values\n", "\n", "# Begin answer\n", "data.loc[data['density'].isna(), 'density'] = -0.0014 * data['alcohol'] + 0.0002 * data['residual sugar'] + 1.0082\n", "# End answer" ] }, { "cell_type": "code", "execution_count": 53, "metadata": { "nbgrader": { "grade": true, "grade_id": "cell-4cd52ff887bf9ac6", "locked": true, "points": 2, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "### BEGIN HIDDEN TESTS\n", "assert data.loc[data['density'].isna()].empty\n", "assert data.iloc[6]['density'] == -0.0014 * data.iloc[6]['alcohol'] + 0.0002 * data.iloc[6]['residual sugar'] + 1.0082\n", "### END HIDDEN TESTS" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-3ec36a7efd0c17d4", "locked": true, "schema_version": 1, "solution": false } }, "source": [ "## 4. Build the regression model\n", "\n", "+ Use the dataset with all the attributes to predict the attribute ``quality`` with a regression model (you can use the functions we used along the chapter).\n", "+ Place the right attributes in the variables ``x`` and ``y`` __(2 points)__.\n", "+ Place the MAE in the variable ``mae_regression`` __(1 point)__." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-2cba9ee11b8b0f1d", "locked": false, "schema_version": 1, "solution": true } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "MAE: 0.6105846153846155\n" ] } ], "source": [ "# predict 'quality' with regression\n", "\n", "from sklearn.metrics import mean_absolute_error\n", "\n", "# Begin answer\n", "x = ['fixed acidity', 'volatile acidity', 'citric acid', 'residual sugar', 'chlorides', 'free sulfur dioxide',\n", " 'density', 'pH', 'sulphates', 'alcohol']\n", "y = ['quality']\n", "\n", "predictions, ytest = knn_regression(data, x, y)\n", "mae_regression = mean_absolute_error(predictions, ytest)\n", "print('MAE: ' + str(mae_regression))\n", "# End answer" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "nbgrader": { "grade": true, "grade_id": "cell-828f5d428ebfee4e", "locked": true, "points": 1, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "### BEGIN HIDDEN TESTS\n", "assert x == ['fixed acidity', 'volatile acidity', 'citric acid', 'residual sugar', 'chlorides', 'free sulfur dioxide',\n", " 'density', 'pH', 'sulphates', 'alcohol']\n", "### END HIDDEN TESTS" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "nbgrader": { "grade": true, "grade_id": "cell-ea568e14c06da526", "locked": true, "points": 1, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "### BEGIN HIDDEN TESTS\n", "assert y == ['quality']\n", "### END HIDDEN TESTS" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "nbgrader": { "grade": true, "grade_id": "cell-dc4056afc81274cf", "locked": true, "points": 1, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "### BEGIN HIDDEN TESTS\n", "assert mae_regression > 0.6 and mae_regression < 0.7\n", "### END HIDDEN TESTS" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 5. Visualize the predictions\n", "\n", "+ Plot the graph predictions vs. true labels." ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-968ecfa6e236ae54", "locked": false, "schema_version": 1, "solution": true } }, "outputs": [ { "data": { "text/plain": [ "Text(0.5, 1.0, 'Prediction vs. true label')" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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ERGRS7J+/Xr69OnD999/T1hYGOPGjeOaa67xdVgiRU4VZREREfHIqVOnGDBgAHfddRcXLlxg1apVzJgxQ0mylFlKlEVERKRQS5cupXnz5kyZMoVnnnmGb7/9lq5du/o6LBGv0tELERERydexY8d49tln+fjjjwkKCiI2NpbbbrvN12GJFAtVlEVEROQi1lrmzZtHUFAQn376Kf/5z3/Yvn27kmQpV1RRFhERERdHjhzhqaee4ssvv6Rt27asWrWK4OBgX4clUuxUURYREREgu4ocGRlJUFAQy5cv56233mLTpk1KkqXcUkVZREREOHAsUIbnAAAgAElEQVTgAOHh4axZs4a77rqLGTNm0LhxY1+HJeJTqiiLiIiUY5mZmbzzzjvceuutbNmyhalTp7JmzRolySKooiwiIlJu7d69m7CwMOLi4ggNDWXq1KnUr1/f12GJlBiqKIuIiJQz58+f59VXX6VVq1bs37+fOXPmsGjRIiXJInmooiwiIlKObNmyhbCwML799lseeeQRJkyYQN26dX0dlkiJpIqyiIhIOXD27FleeOEFbrvtNk6cOMHChQuZO3eukmSRAqiiLCIiUsbFxMQQHh7O/v376du3L2+++SYBAQG+DkukxFNFWUREpIxKSUmhf//+dOnSBWsta9asYdq0aUqSRTykRFlERKQMWrx4Mc2aNSMiIoLnnnuO+Ph4unTp4uuwREoVJcoiIiJlSHJyMj179uSvf/0rNWvWZNOmTYwbN44qVar4OjSRUkeJsoiISBlgreWTTz4hKCiI+fPn88orr7Bt2zbat2/v69BESi29mE9ERKSUO3z4ME8++SSLFy+mffv2REZG0rx5c1+HJVLqqaIsIiJSSmVlZTF9+nSaNWvG6tWrGT9+PLGxsUqSRYqIKsoiIiKl0P79+wkPDycmJoYuXboQERFBYGCgr8MSKVNUURYRESlFLly4wLhx47j11lvZvn07ERERrF69WkmyiBeooiwiIlJKfPvtt4SFhbFlyxbuv/9+3n//fa6//npfhyVSZqmiLCIiUsKlp6fz8ssv07p1a5KSkvj000/573//qyRZxMtUURYRESnB4uLiCAsLY/fu3fTq1Yt33nmHOnXq+DoskXJBFWUREZESKDU1lcGDB9OxY0dSUlJYvHgxH330kZJkkWKkirKIiEgJs3r1asLDw/nhhx948sknGTt2LDVq1PB1WCLljirKIiIiJcRvv/1GeHg43bp1w9/fn5iYGN5//30lySI+okRZRESkBPjyyy8JCgrigw8+4MUXXyQ+Pp677rrL12GJlGtKlEVERHzo119/5eGHH6ZHjx7UrVuXuLg43njjDa6++mpfhyZS7ilRFhER8QFrLR9//DFNmzYlKiqK1157ja1bt9K2bVtfhyYiOfRiPhERkWJ26NAh+vfvz5IlS7jtttuIjIwkKCjI12GJSB6qKIuIiBSTrKwspkyZQlBQEDExMbz77rts3LhRSbJICaWKsoiISDHYt28fffr0YcOGDXTr1o3p06dz4403+josESmAKsoiIiJedOHCBd58801atGhBfHw8kZGRrFixQkmySCmgirKIiIiX7Ny5k969e7N9+3Z69OjB5MmTqVevnq/DEhEPqaIsIiJSxNLT0xkxYgRt27bl8OHDfP755yxYsEBJskgpo4qyiIhIEdq0aRNhYWF89913PP7444wfP57atWv7OiwRuQyqKIuIiBSBM2fO8K9//Yvbb7+d1NRUli5dyqxZs5Qki5RiqiiLiIhcoZUrV9K3b1+SkpIYMGAAY8aMoXr16r4OS0SukCrKIiIil+nkyZP07t2b7t27c9VVV7F+/XomTZqkJFmkjFCiLCIichmioqIICgpi9uzZDB06lJ07d9KpUydfhyUiRUhHL0RERC7Bzz//zMCBA5k/fz4tW7YkOjqa1q1b+zosEfECVZRFREQ8YK1l1qxZBAUFsWjRIkaPHs3mzZuVJIuUYaooi4iIFOLHH3+kX79+LF++nJCQECIjI2nSpImvwxIRL1NFWUREJB9ZWVlMmjSJZs2asXHjRiZOnMiGDRuUJIuUE6ooi4iIuLF3717CwsL46quv6N69O9OmTaNRo0a+DktEipEqyiIiIk4yMjIYM2YMLVq0YM+ePcycOZNly5YpSRYph1RRFhERybFjxw569+7NN998w9///ncmTpzIdddd5+uwRMRHVFEWEZFyLy0tjaFDh9KuXTuOHj3KF198weeff64kWaScU0VZRETKtY0bNxIWFsa+ffv45z//ydtvv03NmjV9HZaIlACqKIuISLl0+vRpnn76aTp16kR6ejrLly/ngw8+UJIsIrmUKIuISLmzfPlymjdvzvvvv8+gQYPYtWsX3bt393VYIlLCKFEWEZFy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2Yr4wyk+X3NT4gke7dAg910vRj0YTPXK/lSvXMGlrV5AZWpVrUh4p+xX54d3CsTPZFf+Vj3XGSD3ErjoT+QOe53eKcCR7DgnPY7jF87HMNz1c8zvvI67fgW15VXU819J24XTx0le8DrHFr7JDTfcQPw3O7im06OYChXdjnMce3A+/nAl/fK7j5wfP8fxix8KmT/yifYul44jDeC6ZxzHL5yPYTiOXzgfw3A8JhX8jEtsjmMTedes4Jfd17mtVtWKXF3Rz2U/Gy7ez+7mq1LRj6v8jcvz4yp/Q5WKfrn9/tz8j9kV5eNngezn333Bf+S+4D8W688BkaLgtaMXl0NHL0REyi9rLZGRkTz//POkp6fz+uuv869//YsKFfQhsiJStDw9eqGfPiIi4nOJiYmEh4ezdu1a7rrrLmbMmEHjxo19HZaIlHP6CGsREfGZzMxMxo8fz6233sq2bduYNm0aa9asUZIsIiWCKsoiIuITu3btIiwsjM2bN3PfffcxZcoU6tev7+uwRERyqaIsIiLF6vz587zyyiu0bt2aAwcOMHfuXBYuXKgkWURKHFWURUSk2GzevJmwsDB27dpFz549effdd6lbt66vwxIRcUsVZRER8bqzZ8/y/PPP07FjR06ePMmiRYuYM2eOkmQRKdFUURYREa9au3Ytffr04cCBA/Tr14833niDgIAAX4clIlIoVZRFRMQrUlJS6NevH3fffTfGGNauXcvUqVOVJItIqaFEWUREityiRYsICgpixowZPP/888THx9O5c2dfhyUickmUKIuISJFJTk6mZ8+e3H///dSuXZuvv/6at956iypVqvg6NBGRS6ZEWURErpi1lrlz59K0aVPmz5/Pq6++ytatW2nXrp2vQxMRuWz5vpjPGFOjoIHW2lNFH46IiJQ2hw8fpn///kRHR9OhQwciIyNp1qyZr8MSEbliBb3rxW7AAsapzXHdAg29GJeIiJRwWVlZRERE8MILL5CZmck777zDwIED8ff393VoIiJFIt9E2VrboDgDERGR0uP7778nPDycdevWcffddxMREcFNN93k67BERIqUR2eUjTEPG2OG5Xxd3xjTxrthiYhISXThwgXGjRtHcHAw33zzDTNmzGDVqlVKkkWkTCo0UTbGTAK6AI/lNJ0FpnozKBERKXni4+Pp2LEjL7zwAn/+85/Zs2cPYWFhGGMKHywiUgp5UlEOsdb2A9IArLUngKu8GpWIiJQY6enp/Oc//6FNmzYcPHiQefPmERUVRb169XwdmoiIV3nyEdYZxhg/sl/AhzGmNpDl1ahERKRE+PrrrwkLC2PPnj089thjvPPOO9SuXdvXYYmIFAtPKsqTgS+AusaYV4CNwBtejUpERHwqNTWVZ599lpCQEE6fPs2SJUuYPXu2kmQRKVcKrShba2cbY7YB3XKa/s9au8u7YYmIiK+sXr2a8PBwfvjhB5566inGjBlDjRoFvrW+iEiZ5Okn8/kDGcD5SxgjIiKlyG+//UafPn3o1q0bFSpUYN26dUyePFlJsoiUW56868Vw4BOgHlAfmGuMGertwEREpPh8+eWXBAUFMXPmTF566SV27tzJnXfe6euwRER8ypMX8/UC2lhrzwIYY0YB24Ax3gxMRES875dffmHQoEHMmzePFi1asGjRItq00Vvli4iAZ8cofsQ1oa4AHPBOOCIiUhystXz00UcEBQXx3//+l1GjRrFlyxYlySIiTvKtKBtj3iH7LeHOAruNMctzrncn+50vRESkFDp48CD9+/dn6dKldOzYkcjISJo2berrsERESpyCjl443tliNxDt1P6198IRERFvycrKYurUqbz00ktYa3nvvfd46qmn8Pf393VoIiIlUr6JsrU2sjgDERER79m3bx99+vRhw4YN/OlPf2L69Ok0atTI12GJiJRonrzrRaAx5lNjTLwxZp/jX3EEJyIiV+bChQu88cYbBAcH8+233/Lhhx+yfPlyJckiIh7w5F0vZgKvA+OAe4F/oo+wFhEp8Xbu3Env3r3Zvn07f/vb35g8eTLXXXedr8MSESk1PHnXiyrW2uUA1tpEa+2/gS7eDUtERC5XWloa//73v2nbti0//fQT8+fP54svvlCSLCJyiTypKKcbYwyQaIzpD/wE/MG7YYmIyOWIjY0lLCyMhIQE/vGPfzB+/Hhq1arl67BEREolTyrKzwLVgEHA7UA40NubQYmIyKU5c+YMgwYN4o477uDs2bMsW7aMmTNnKkkWEbkChVaUrbVxOV+eBh7zbjgiInKpVqxYQd++fTl48CADBgxg9OjRVK9e3ddhiYiUegV94EgU2R8w4pa19m9eiUhERDxy8uRJBg8ezMyZM7nllltYv349d9xxh6/DEhEpMwqqKE8qtihEROSS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oSQDAOADTJSBKio7O1tut1t5eXl65plnNHLkSDVq1MjpWAAAVBtMlIEq5pdfftEbb7yhtm3bav/+/frss880bdo0SjIAAD7GRBmoQpYvX67IyEht27ZNUVFRGjZsmOrVq+d0LAAAqiUmykAV8PPPP6tHjx66//77VVhYqCVLliguLo6SDACAH1GUgUouJSVFwcHBiouL06uvvqr169frgQcecDoWAADVHkUZqKT279+vbt26qWvXrqpXr54yMjI0fPhw1a5d2+loAAAEBIoyUMlYa/Xxxx8rKChIn376qf79738rJydHbdu2dToaAAABhRfzAZXId999px49emjOnDlq06aNEhMTFRIS4nQsAAACEhNloBKw1io+Pl4ul0uLFy/W8OHDlZGRQUkGAMBBTJQBh23fvl1RUVFatmyZOnbsqPj4eDVr1szpWAAABDwmyoBDCgoK9P777+vOO+/UmjVrFBcXpyVLllCSAQCoJJgoAw7YsGGD3G63srKy9Ic//EFjxozRjTfe6HQsAABwDibKQAU6efKk3nnnHbVq1Upff/21Pv74Y3322WeUZAAAKiEmykAFycrKktvt1oYNG/Tcc89pxIgRatiwodOxAADARTBRBvzsl19+0Wuvvaa7775bhw4dUnJysqZMmUJJBgCgkmOiDPjRsmXLFBkZqR07duiVV17Ru+++q2uuucbpWAAAwAtMlAE/yM/PV3R0tB544AFdccUVSk1N1ZgxYyjJAABUIRRlwMfmzJkjl8ulxMREvf7668rNzdV9993ndCwAAHCZKMqAj+zbt0/PPvusHn/8cTVo0ECZmZkaOnSoateu7XQ0AABQBhRloJystZo6daqCgoI0a9YsDRgwQNnZ2QoPD3c6GgAAKAdezAeUw+7du9WjRw+lpKSoXbt2SkxMlMvlcjoWAADwASbKQBkUFhZq7NixCg4O1rJlyzRixAilp6dTkgEAqEaYKAOX6auvvlJUVJSWL1+uTp06KS4uTrfeeqvTsQAAgI8xUQa8dPr0aQ0bNkyhoaFat26dEhMTtWjRIkoyAADVFBNlwAt5eXlyu93Kzs7WE088odGjR+uGG25wOhYAAPAjJsrAJZw4cUL/+7//q9atW2vXrl369NNPlZSUREkGACAAMFEGLuKLL76Q2+3Wpk2b9Pzzz+v9999XgwYNnI4FAAAqCBNl4DxH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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "# plot predictions vs. true labels\n", "\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "\n", "# Begin answer\n", "plt.figure(figsize = (12, 8))\n", "\n", "pred = []\n", "for element in predictions:\n", " pred.append(element[0])\n", "plt.plot(pred, ytest, 'x')\n", "\n", "x = np.linspace(3, 8, 10)\n", "plt.plot(x, x, color = 'black')\n", "\n", "plt.xlabel('Prediction')\n", "plt.ylabel('True label')\n", "plt.title('Prediction vs. true label')\n", "# End answer" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-6dfc842b21b8e30a", "locked": true, "schema_version": 1, "solution": false } }, "source": [ "## 6. Attributes selection\n", "\n", "+ Build other models with different attributes.\n", "+ Place the combination of attributes which gives the worst performance in the variable ``worst_comb``, it contains only one attribute __(1 point)__.\n", "+ Place the combination of attributes which gives the best performance in the variable ``best_comb``, it contains 5 attributes (including ``fixed acidity`` and ``volatile acidity``) __(1 point)__." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-d56cfc2fd1e3fe09", "locked": false, "schema_version": 1, "solution": true } }, "outputs": [], "source": [ "# find best and worst attribute combinations\n", "\n", "# Begin answer\n", "worst_comb = ['sulphates']\n", "best_comb = ['fixed acidity', 'volatile acidity', 'pH', 'sulphates', 'alcohol']\n", "# End answer" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "nbgrader": { "grade": true, "grade_id": "cell-ed52d85a6f6c2e6c", "locked": true, "points": 1, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "### BEGIN HIDDEN TESTS\n", "assert worst_comb == ['sulphates']\n", "### END HIDDEN TESTS" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "nbgrader": { "grade": true, "grade_id": "cell-38d8c692f587abe4", "locked": true, "points": 1, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "### BEGIN HIDDEN TESTS\n", "assert best_comb == ['fixed acidity', 'volatile acidity', 'pH', 'sulphates', 'alcohol']\n", "### END HIDDEN TESTS" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-5e32c18ea6502bdd", "locked": true, "schema_version": 1, "solution": false } }, "source": [ "## 7. Classification model\n", "\n", "+ Predict the attribute ``quality`` with a classification model, with all the attributes.\n", "+ Place the MAE in the variable ``mae_classification`` __(1 point)__.\n", "+ Plot the results.\n", "\n", "Think about which model is the best to use: regression or classification? Why? Look at the values of the variable ``quality``." ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-a26417b6406b3c68", "locked": false, "schema_version": 1, "solution": true } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "MAE: 0.5884615384615385\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "C:\\Users\\Anna\\Anaconda3\\lib\\site-packages\\ipykernel_launcher.py:14: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", " \n" ] } ], "source": [ "# predict 'quality' with classification\n", "\n", "from sklearn.metrics import mean_absolute_error\n", "\n", "# Begin answer\n", "x = ['fixed acidity', 'volatile acidity', 'citric acid', 'residual sugar', 'chlorides', 'free sulfur dioxide',\n", " 'density', 'pH', 'sulphates', 'alcohol']\n", "y = ['quality']\n", "\n", "predictions, ytest = knn_classification(data, x, y)\n", "mae_classification = mean_absolute_error(predictions, ytest)\n", "print('MAE: ' + str(mae_classification))\n", "# End answer" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "nbgrader": { "grade": true, "grade_id": "cell-66ed9f7945846479", "locked": true, "points": 1, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "### BEGIN HIDDEN TESTS\n", "assert mae_classification > 0.5 and mae_classification < 0.6\n", "### END HIDDEN TESTS" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-0aa2aa02b138e423", "locked": true, "schema_version": 1, "solution": false } }, "source": [ "## 8. Split the dataset\n", "\n", "+ Split the dataset on a well chosen attribute, and predict the attribute ``quality`` with the new datasets and the chosen type of task (classification or regression).\n", "+ Place the two MAEs in the variables ``mae_1`` and ``mae_2`` __(2 points)__." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-71f62bcc37745c91", "locked": false, "schema_version": 1, "solution": true } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "MAE 1: 0.6642857142857143\n", "MAE 2: 0.49375\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "C:\\Users\\Anna\\Anaconda3\\lib\\site-packages\\ipykernel_launcher.py:14: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", " \n", "C:\\Users\\Anna\\Anaconda3\\lib\\site-packages\\ipykernel_launcher.py:14: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", " \n" ] } ], "source": [ "# split the dataset and make predictions\n", "\n", "from sklearn.metrics import mean_absolute_error\n", "\n", "# Begin answer\n", "x = ['fixed acidity', 'volatile acidity', 'citric acid', 'residual sugar', 'chlorides', 'free sulfur dioxide',\n", " 'density', 'pH', 'sulphates', 'alcohol']\n", "y = ['quality']\n", "\n", "white_wine = data.loc[data['type'] == 'white']\n", "predictions, ytest = knn_classification(white_wine, x, y)\n", "mae_1 = mean_absolute_error(predictions, ytest)\n", "print('MAE 1: ' + str(mae_1))\n", "\n", "red_wine = data.loc[data['type'] == 'red']\n", "predictions, ytest = knn_classification(red_wine, x, y)\n", "mae_2 = mean_absolute_error(predictions, ytest)\n", "print('MAE 2: ' + str(mae_2))\n", "# End answer" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "nbgrader": { "grade": true, "grade_id": "cell-8deeea4ce465d4a5", "locked": true, "points": 1, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "### BEGIN HIDDEN TESTS\n", "assert (mae_1 > 0.6 and mae_1 < 0.7) or (mae_2 > 0.6 and mae_2 < 0.7)\n", "### END HIDDEN TESTS" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "nbgrader": { "grade": true, "grade_id": "cell-3edbec12c2157f83", "locked": true, "points": 1, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "### BEGIN HIDDEN TESTS\n", "assert (mae_1 > 0.4 and mae_1 < 0.5) or (mae_2 > 0.4 and mae_2 < 0.5)\n", "### END HIDDEN TESTS" ] } ], "metadata": { "celltoolbar": "Create Assignment", "kernelspec": { "display_name": "Python 3", "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.7.1" }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false } }, "nbformat": 4, "nbformat_minor": 2 }