diff --git a/HW 5/Iris_knn_W2025_template.ipynb b/HW 5/Iris_knn_W2025_template.ipynb new file mode 100644 index 0000000..929efcb --- /dev/null +++ b/HW 5/Iris_knn_W2025_template.ipynb @@ -0,0 +1,1771 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Q6ifg03dKPR4" + }, + "outputs": [], + "source": [ + "############################\n", + "# BLOCK 1: IMPORTS\n", + "############################\n", + "\n", + "# libraries!\n", + "import numpy as np # numpy is Python's \"array\" library\n", + "import pandas as pd # Pandas is Python's \"data\" library (\"dataframe\" == spreadsheet)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "0ghtg7ecRQ50" + }, + "outputs": [], + "source": [ + "#############################\n", + "# BLOCK 2: VARIABLES LISTING\n", + "#############################\n", + "\n", + "# for reference, as you work throughout, come back and list all the variable names\n", + "# here along with what that variable holds\n", + "\n", + "# Variable: Contents\n", + "# -------------------\n", + "# [FILL IN VARS BELOW]\n", + "#" + ] + }, + { + "cell_type": "code", + "source": [ + "####################################\n", + "from sklearn.datasets import load_iris\n", + "data = load_iris()\n", + "df = pd.DataFrame(data.data, columns=data.feature_names)\n", + "df" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 424 + }, + "id": "DjCaxH3BKJ_O", + "outputId": "ab33e45d-d332-412e-db2a-88cc4c9528f4" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " sepal length (cm) sepal width (cm) petal length (cm) petal width (cm)\n", + "0 5.1 3.5 1.4 0.2\n", + "1 4.9 3.0 1.4 0.2\n", + "2 4.7 3.2 1.3 0.2\n", + "3 4.6 3.1 1.5 0.2\n", + "4 5.0 3.6 1.4 0.2\n", + ".. ... ... ... ...\n", + "145 6.7 3.0 5.2 2.3\n", + "146 6.3 2.5 5.0 1.9\n", + "147 6.5 3.0 5.2 2.0\n", + "148 6.2 3.4 5.4 2.3\n", + "149 5.9 3.0 5.1 1.8\n", + "\n", + "[150 rows x 4 columns]" + ], + "text/html": [ + "\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sepal length (cm)sepal width (cm)petal length (cm)petal width (cm)
05.13.51.40.2
14.93.01.40.2
24.73.21.30.2
34.63.11.50.2
45.03.61.40.2
...............
1456.73.05.22.3
1466.32.55.01.9
1476.53.05.22.0
1486.23.45.42.3
1495.93.05.11.8
\n", + "

150 rows × 4 columns

\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "df", + "summary": "{\n \"name\": \"df\",\n \"rows\": 150,\n \"fields\": [\n {\n \"column\": \"sepal length (cm)\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.8280661279778629,\n \"min\": 4.3,\n \"max\": 7.9,\n \"num_unique_values\": 35,\n \"samples\": [\n 6.2,\n 4.5,\n 5.6\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"sepal width (cm)\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.435866284936698,\n \"min\": 2.0,\n \"max\": 4.4,\n \"num_unique_values\": 23,\n \"samples\": [\n 2.3,\n 4.0,\n 3.5\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"petal length (cm)\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1.7652982332594667,\n \"min\": 1.0,\n \"max\": 6.9,\n \"num_unique_values\": 43,\n \"samples\": [\n 6.7,\n 3.8,\n 3.7\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"petal width (cm)\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.7622376689603465,\n \"min\": 0.1,\n \"max\": 2.5,\n \"num_unique_values\": 22,\n \"samples\": [\n 0.2,\n 1.2,\n 1.3\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 9 + } + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ANJhDRNPKPR5" + }, + "outputs": [], + "source": [ + "#############################\n", + "# BLOCK 3: READING DATA\n", + "#############################\n", + "\n", + "# let's read in our flower data...\n", + "#\n", + "#filename = 'iris.csv'\n", + "#df = pd.read_csv(filename, header=0) # encoding=\"latin1\" et al.\n", + "#print(f\"{filename}: file read into a pandas DataFrame.\")\n", + "#df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8v3oVZYTKPR6", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 361 + }, + "outputId": "4110ac58-5c52-4cbf-a83f-16d9a7189ccb" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " sepal length (cm) sepal width (cm) petal length (cm) petal width (cm)\n", + "0 5.1 3.5 1.4 0.2\n", + "1 4.9 3.0 1.4 0.2\n", + "2 4.7 3.2 1.3 0.2\n", + "3 4.6 3.1 1.5 0.2\n", + ".. ... ... ... ...\n", + "146 6.3 2.5 5.0 1.9\n", + "147 6.5 3.0 5.2 2.0\n", + "148 6.2 3.4 5.4 2.3\n", + "149 5.9 3.0 5.1 1.8\n", + "\n", + "[150 rows x 4 columns]" + ], + "text/html": [ + "\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sepal length (cm)sepal width (cm)petal length (cm)petal width (cm)
05.13.51.40.2
14.93.01.40.2
24.73.21.30.2
34.63.11.50.2
...............
1466.32.55.01.9
1476.53.05.22.0
1486.23.45.42.3
1495.93.05.11.8
\n", + "

150 rows × 4 columns

\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "df", + "summary": "{\n \"name\": \"df\",\n \"rows\": 150,\n \"fields\": [\n {\n \"column\": \"sepal length (cm)\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.8280661279778629,\n \"min\": 4.3,\n \"max\": 7.9,\n \"num_unique_values\": 35,\n \"samples\": [\n 6.2,\n 4.5,\n 5.6\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"sepal width (cm)\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.435866284936698,\n \"min\": 2.0,\n \"max\": 4.4,\n \"num_unique_values\": 23,\n \"samples\": [\n 2.3,\n 4.0,\n 3.5\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"petal length (cm)\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1.7652982332594667,\n \"min\": 1.0,\n \"max\": 6.9,\n \"num_unique_values\": 43,\n \"samples\": [\n 6.7,\n 3.8,\n 3.7\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"petal width (cm)\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.7622376689603465,\n \"min\": 0.1,\n \"max\": 2.5,\n \"num_unique_values\": 22,\n \"samples\": [\n 0.2,\n 1.2,\n 1.3\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 10 + } + ], + "source": [ + "#############################\n", + "# BLOCK 4: SETTING OPTIONS\n", + "#############################\n", + "\n", + "#\n", + "# a dataframe is a \"spreadsheet in Python\"\n", + "# (this one seems to have an extra column!)\n", + "#\n", + "pd.set_option('display.max_rows', 8) # None for no limit; default: 10\n", + "pd.set_option('display.min_rows', 8) # None for no limit; default: 10\n", + "# let's view it!\n", + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "aksGQcJ8KPR6", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "4cbdedf5-cabe-4263-c06c-26bbb8f509b1" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\n", + "RangeIndex: 150 entries, 0 to 149\n", + "Data columns (total 4 columns):\n", + " # Column Non-Null Count Dtype \n", + "--- ------ -------------- ----- \n", + " 0 sepal length (cm) 150 non-null float64\n", + " 1 sepal width (cm) 150 non-null float64\n", + " 2 petal length (cm) 150 non-null float64\n", + " 3 petal width (cm) 150 non-null float64\n", + "dtypes: float64(4)\n", + "memory usage: 4.8 KB\n" + ] + } + ], + "source": [ + "##############################\n", + "# BLOCK 5: USING DF'S .info()\n", + "##############################\n", + "\n", + "#\n", + "# let's look at our pandas DataFrame's info (Aargh: that extra column!)\n", + "#\n", + "df.info()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ADWpUqeKKPR7", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "76ac8d2f-0d98-4721-e0f2-b79b48736b00" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\n", + "RangeIndex: 150 entries, 0 to 149\n", + "Data columns (total 4 columns):\n", + " # Column Non-Null Count Dtype \n", + "--- ------ -------------- ----- \n", + " 0 sepal length (cm) 150 non-null float64\n", + " 1 sepal width (cm) 150 non-null float64\n", + " 2 petal length (cm) 150 non-null float64\n", + " 3 petal width (cm) 150 non-null float64\n", + "dtypes: float64(4)\n", + "memory usage: 4.8 KB\n" + ] + } + ], + "source": [ + "#############################\n", + "# BLOCK 6: CLEANING DATA\n", + "#############################\n", + "\n", + "#\n", + "# let's drop that last column (dropping is usually by _name_):\n", + "#\n", + "# if you want a list of the column names use df.columns\n", + "#col5name = df.columns[5] # get column name at index 5\n", + "\n", + "df_clean = df # drop by name is typical, but what else is possible?\n", + "df_clean.info() # Is the bad last column gone?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "9RAydRsiKPR7", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "18ec37ec-3a95-4ef9-c111-847ac8f6ecec" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "FEATURES: Index(['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)',\n", + " 'petal width (cm)'],\n", + " dtype='object')\n", + "\n", + "First feature: sepal length (cm)\n", + "\n", + "feature_name_to_index: {'sepal length (cm)': 0, 'sepal width (cm)': 1, 'petal length (cm)': 2, 'petal width (cm)': 3}\n" + ] + } + ], + "source": [ + "##############################\n", + "# BLOCK 7: FEATURE NAMES DICT\n", + "##############################\n", + "\n", + "#\n", + "# let's keep our column names in variables, for reference;\n", + "# in machine learning contexts, these are referred to as \"features\"\n", + "#\n", + "features = df_clean.columns # \"list\" of columns\n", + "print(f\"FEATURES: {features}\\n\")\n", + " # It's a \"pandas\" list, called an Index\n", + " # use it just as a Python list of strings:\n", + "print(f\"First feature: {features[0]}\\n\")\n", + "\n", + "# let's create a dictionary to look up any column index by name\n", + "feature_name_to_index = {}\n", + "for i, name in enumerate(features):\n", + " feature_name_to_index[name] = i # using the name (as key), assign the value (i)\n", + "print(f\"feature_name_to_index: {feature_name_to_index}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "PWkPTOGnKPR8", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 1000 + }, + "outputId": "f6a46e8f-0169-4646-864f-1b3ed749f238" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\n", + "RangeIndex: 150 entries, 0 to 149\n", + "Data columns (total 4 columns):\n", + " # Column Non-Null Count Dtype \n", + "--- ------ -------------- ----- \n", + " 0 sepal length (cm) 150 non-null float64\n", + " 1 sepal width (cm) 150 non-null float64\n", + " 2 petal length (cm) 150 non-null float64\n", + " 3 petal width (cm) 150 non-null float64\n", + "dtypes: float64(4)\n", + "memory usage: 4.8 KB\n", + "======================================================================\n", + " sepal length (cm) sepal width (cm) petal length (cm) petal width (cm)\n", + "0 5.1 3.5 1.4 0.2\n", + "1 4.9 3.0 1.4 0.2\n", + "2 4.7 3.2 1.3 0.2\n", + "3 4.6 3.1 1.5 0.2\n", + ".. ... ... ... ...\n", + "146 6.3 2.5 5.0 1.9\n", + "147 6.5 3.0 5.2 2.0\n", + "148 6.2 3.4 5.4 2.3\n", + "149 5.9 3.0 5.1 1.8\n", + "\n", + "[150 rows x 4 columns]\n", + "======================================================================\n" + ] + }, + { + "output_type": "error", + "ename": "KeyError", + "evalue": "'irisname'", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/pandas/core/indexes/base.py\u001b[0m in \u001b[0;36mget_loc\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 3804\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 3805\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcasted_key\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3806\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32mindex.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", + "\u001b[0;32mindex.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", + "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", + "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", + "\u001b[0;31mKeyError\u001b[0m: 'irisname'", + "\nThe above exception was the direct cause of the following exception:\n", + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/tmp/ipykernel_6512/325098609.py\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;31m# or more to the point, grab that column and inspect:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 18\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"Irisname entries: {df_clean['irisname'].unique()}\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 19\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[0;31m# also note how the last two rows in the df have problems, among others...\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/pandas/core/frame.py\u001b[0m in \u001b[0;36m__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 4100\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnlevels\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4101\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_getitem_multilevel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 4102\u001b[0;31m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4103\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mis_integer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mindexer\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4104\u001b[0m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mindexer\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/pandas/core/indexes/base.py\u001b[0m in \u001b[0;36mget_loc\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 3810\u001b[0m ):\n\u001b[1;32m 3811\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mInvalidIndexError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 3812\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mKeyError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3813\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3814\u001b[0m \u001b[0;31m# If we have a listlike key, _check_indexing_error will raise\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mKeyError\u001b[0m: 'irisname'" + ] + } + ], + "source": [ + "##############################\n", + "# BLOCK 8: INSPECTING DATA\n", + "##############################\n", + "\n", + "#\n", + "# let's look at our cleaned-up dataframe...\n", + "#\n", + "df_clean.info()\n", + "print('=' * 70)\n", + "\n", + "#\n", + "# Notice that the non-null count is _different_ for irisname!\n", + "# Why? Show a table and inspect...\n", + "print(df_clean)\n", + "print('=' * 70)\n", + "\n", + "# or more to the point, grab that column and inspect:\n", + "print(f\"Irisname entries: {df_clean['irisname'].unique()}\")\n", + "\n", + "# also note how the last two rows in the df have problems, among others...\n" + ] + }, + { + "cell_type": "code", + "source": [ + "df.columns" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "4B2An3iML1ay", + "outputId": "5492db65-acd8-4c11-f669-742a79b6cb62" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "Index(['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)',\n", + " 'petal width (cm)'],\n", + " dtype='object')" + ] + }, + "metadata": {}, + "execution_count": 19 + } + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "xM22NWdqKPR-", + "scrolled": false + }, + "outputs": [], + "source": [ + "##############################\n", + "# BLOCK 9: USING DF'S dropna\n", + "##############################\n", + "\n", + "#\n", + "# typically, after dropping columns that we don't want,\n", + "# we drop rows with missing data (other approaches are possible, too)\n", + "#\n", + "df_clean = df_clean.dropna() # this removes all rows with nan items\n", + "df_clean.info()\n", + "print('=' * 70)\n", + "df_clean\n", + "\n", + "#\n", + "# notice that _all_ of the rows now have 144 non-null items\n", + "# also, the first and last rows (among others) aren't valid data...\n", + "# we'll handle that next" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "h0spkxGzKPR-" + }, + "outputs": [], + "source": [ + "################################\n", + "# BLOCK 10: REMOVING BOGUS DATA\n", + "################################\n", + "\n", + "# or more to the point, grab that column and inspect:\n", + "print(f\"Irisname entries: {df_clean['irisname'].unique()}\")\n", + "print(df_clean['irisname'] == 'alieniris') # what does this show?\n", + "print(df_clean['irisname'] != 'alieniris') # what does this show?\n", + "\n", + "# define a final version of the DataFrame by pulling out the\n", + "# bad alieniris data (remember that you can pass a boolean\n", + "# Series to select data that you want)\n", + "df_final = pass\n", + "# ^^^^ YOU NEED TO WRITE CODE HERE...\n", + "\n", + "print(df_final.shape)\n", + "df_final" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "EywtvRyMKPR-" + }, + "outputs": [], + "source": [ + "##########################################\n", + "# BLOCK 11: CONVERT SPECIES NAME TO INDEX\n", + "##########################################\n", + "\n", + "# all of scikit-learn's ML routines need numbers, not strings\n", + "# ... even for categories/classifications (like species!)\n", + "# so, we will convert the flower-species to numbers:\n", + "\n", + "species_names = df_final['irisname'].unique()\n", + "species_name_to_index = { species_names[i]:i for i in range(len(species_names))}\n", + "print(species_name_to_index)\n", + "print(type(species_name_to_index))\n", + "\n", + "def convertSpecies(species_name: str) -> int:\n", + " ''' return the species index (a unique integer/category) '''\n", + " #print(f\"converting {species_name}...\")\n", + " return species_name_to_index[species_name]\n", + "\n", + "# Let's try it out...\n", + "for name in species_names:\n", + " print(f\"{name} maps to {convertSpecies(name)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "NuKqemiiKPR_" + }, + "outputs": [], + "source": [ + "##########################################\n", + "# BLOCK 12: USING DF'S .apply\n", + "##########################################\n", + "\n", + "#\n", + "# we can \"apply\" our new convertSpecies function to a whole column\n", + "#\n", + "# (The following will issue a \"SettingWithCopyWarning\" here...)\n", + "# see https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + "#\n", + "# >>> ADD CODE HERE TO KEEP THE WARNING FROM HAPPENING <<<\n", + "df_final['irisname'] = df_final['irisname'].apply(convertSpecies)\n", + "\n", + "# Don't run this twice! Why?! What's \"KeyError: 0\"?\n", + "# (of course, you can always go back and re-establish definitions of df_final)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "tWoVKJBGKPR_" + }, + "outputs": [], + "source": [ + "##########################################\n", + "# BLOCK 13: CONFIRMING FINAL DATAFRAME\n", + "##########################################\n", + "\n", + "#\n", + "# let's see it! (this is safe to run many times...)\n", + "#\n", + "df_final # print(df_final.tostring()) # for _all_ rows..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "qxpBs7NnKPR_" + }, + "outputs": [], + "source": [ + "##########################################\n", + "# BLOCK 14: CONVERTING TO NUMPY FORMAT\n", + "##########################################\n", + "\n", + "#\n", + "# let's convert our dataframe to a numpy array, named A\n", + "# Our ML library, scikit-learn operates entirely on numpy arrays.\n", + "#\n", + "#A = df_final.values\n", + "A = df_final.to_numpy() # better -- self-documenting!\n", + "\n", + "print(f\"type of A: {type(A)}\")\n", + "print(df_final.head())\n", + "print(f\"A[0] = {A[0]}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "bblbBuIiKPSA" + }, + "outputs": [], + "source": [ + "##################################################\n", + "# BLOCK 15: CONVERTING NUMPY ARRAY TO ALL FLOATS\n", + "##################################################\n", + "\n", + "#\n", + "# let's convert to make sure it's all floating-point, so we can multiply and divide\n", + "#\n", + "A = A.astype('float64') # so many: www.tutorialspoint.com/numpy/numpy_data_types.htm\n", + "A" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wbns1qpJKPSA" + }, + "outputs": [], + "source": [ + "##########################################\n", + "# BLOCK 16: USING NUMPY'S .shape\n", + "##########################################\n", + "\n", + "#\n", + "# nice to have num_rows and num_cols variables handy...\n", + "#\n", + "num_rows, num_cols = A.shape\n", + "print(f\"\\nThe dataset has {num_rows} rows and {num_cols} cols\")\n", + "print(A)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ixiZhsuqKPSA", + "scrolled": true + }, + "outputs": [], + "source": [ + "##########################################\n", + "# BLOCK 17: PRINTING FLOWER INFO\n", + "##########################################\n", + "\n", + "# let's use all of our previously-defined variables, to reinforce names...\n", + "\n", + "# choose a row index (particular flower) arbitrarily:\n", + "flower = 132\n", + "print(f\"flower #{flower} data is {A[flower]}\")\n", + "\n", + "for i in range(len(features)):\n", + " col_name = features[i]\n", + " if col_name != 'irisname':\n", + " print(f\" Its {col_name} is {A[flower][i]}\")\n", + " else:\n", + " species_num = int(A[flower][i])\n", + " species_name = species_names[species_num]\n", + " print(f\" Its {col_name} is {species_name} ({species_num})\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "izGld2tSKPSA" + }, + "outputs": [], + "source": [ + "##########################################\n", + "# BLOCK 18: WRITING OUR OWN 1-NN FUNCTION\n", + "##########################################\n", + "\n", + "#\n", + "# We don't have to use scikit-learn to implement NN!\n", + "#\n", + "\n", + "#\n", + "# data-driven predictive model (1-nearest-neighbor)\n", + "#\n", + "\n", + "# Python functions are first-class objects!\n", + "dist = np.linalg.norm # built in to numpy... but what does norm do?\n", + "\n", + "num_rows, num_cols = A.shape # data size\n", + "\n", + "def predictiveModel( features: list[float] ) -> str:\n", + " \"\"\" input: a list of four features\n", + " [ sepallen, sepalwid, petallen, petalwid ]\n", + " output: the predicted species of iris, from\n", + " setosa (0), versicolor (1), virginica (2)\n", + " \"\"\"\n", + " our_features = np.asarray(features) # make a numpy array\n", + "\n", + " closest_flower = A[0]\n", + " closest_features = A[0,0:4]\n", + " closest_distance = dist(our_features - closest_features)\n", + "\n", + " for i in range(1, num_rows, 1):\n", + " current_flower = A[i]\n", + " current_features = A[i,0:4]\n", + " current_distance = dist(our_features - current_features)\n", + "\n", + " if current_distance < closest_distance:\n", + " closest_distance = current_distance # remember closest!\n", + " closest_flower = current_flower\n", + "\n", + " # done comparing with every flower in the dataset\n", + " predicted_species = int(round(closest_flower[4])) # what type is closest_flower?\n", + " name = species_names[predicted_species]\n", + " return f\"{name} ({predicted_species})\"\n", + "\n", + "#\n", + "# Try it!\n", + "#\n", + "# features = eval(input(\"Enter new features: \"))\n", + "#\n", + "features = [ 4.6, 3.6, 3.0, 1.2 ]\n", + "result = predictiveModel( features )\n", + "print(f\"I predict {result} from features {features}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "9nhDlGbRKPSB" + }, + "outputs": [], + "source": [ + "##########################################\n", + "# BLOCK 19: COMMENTS ON SCIKIT-LEARN kNN\n", + "##########################################\n", + "\n", + "#\n", + "# but, we don't have to write our own ... because\n", + "#\n", + "# we want knn for any k (not just k=1 as above)\n", + "# we want an already-debugged algorithm!\n", + "# we want to ask iris-related questions instead of implementation ones...\n", + "#" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "64kSAiCvKPSB" + }, + "outputs": [], + "source": [ + "################################################\n", + "# BLOCK 20: DEFINIING FEATURES & LABELS FOR kNN\n", + "################################################\n", + "\n", + "print(\"+++ Start of data definitions +++\\n\")\n", + "\n", + "X_all = A[:,0:4] # X (features) ... is all rows, columns 0, 1, 2, 3\n", + "y_all = A[:,4] # y (labels) ... is all rows, column 4 only\n", + " # (look back at slide 20)\n", + "print(f\"X_all (just features) is \\n {X_all}\")\n", + "print(f\"y_all (just labels) is \\n {y_all}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2ChEk2CDKPSC" + }, + "outputs": [], + "source": [ + "################################################\n", + "# BLOCK 21: REWEIGHTING FEATURES\n", + "################################################\n", + "\n", + "#\n", + "# we can re-weight different features here...\n", + "#\n", + "\n", + "col_weights = { # could be called feature weight...\n", + " 'sepallen':1.0,\n", + " 'sepalwid':1.0,\n", + " 'petallen':1.0,\n", + " 'petalwid':1.0,\n", + "}\n", + "\n", + "for col_name in col_weights:\n", + " i = feature_name_to_index[col_name] # get the column index, i, of the column name\n", + " weight = col_weights[col_name] # from the dictionary above\n", + " print(f\"Weighting {col_name} by {weight}\")\n", + " # weighting == \"multiplying\"\n", + " X_all[:,i] *= weight # multiply by the weight to give this column (\"feature\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "sTDi2mFnKPSC" + }, + "outputs": [], + "source": [ + "################################################\n", + "# BLOCK 22: PERMUTING THE DATA\n", + "################################################\n", + "\n", + "#\n", + "#\n", + "# we scramble the data, to give a different TRAIN/TEST split each time...\n", + "#\n", + "indices = np.random.permutation(len(y_all)) # indices is a permutation-list\n", + "\n", + "# we scramble both X and y, necessarily with the same permutation\n", + "X_labeled = X_all[indices] # we apply the _same_ permutation to each!\n", + "y_labeled = y_all[indices] # again...\n", + "print(X_labeled) # note that X_labeled and y_labeled are permuted identically\n", + "print(y_labeled)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_pD7IZR1KPSC" + }, + "outputs": [], + "source": [ + "################################################\n", + "# BLOCK 23: DEFINING TRAIN VS TEST SETS\n", + "################################################\n", + "\n", + "#\n", + "# We next separate into test data and training data ...\n", + "# + We will train on the training data...\n", + "# + We will _not_ look at the testing data when building the model\n", + "#\n", + "# Then, afterward, we will test on the testing data -- and see how well we do!\n", + "#\n", + "\n", + "#\n", + "# a common convention: train on 80%, test on 20% Let's define the TEST_PERCENT\n", + "#\n", + "num_rows = X_labeled.shape[0] # the number of labeled rows\n", + "test_percent = 0.20\n", + "test_size = int(test_percent * num_rows) # no harm in rounding down\n", + "\n", + "X_test = X_labeled[:test_size] # first section are for testing\n", + "y_test = y_labeled[:test_size]\n", + "\n", + "X_train = X_labeled[test_size:] # all the rest are for training\n", + "y_train = y_labeled[test_size:]\n", + "\n", + "num_train_rows = len(y_train)\n", + "num_test_rows = len(y_test)\n", + "print(f\"total rows: {num_rows}; training with {num_train_rows} rows; testing with {num_test_rows} rows\" )\n", + "print(f\"\\t(sanity check: {num_train_rows} + {num_test_rows} = {num_train_rows + num_test_rows})\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "jvJMYC3eKPSD" + }, + "outputs": [], + "source": [ + "#######################################################\n", + "# BLOCK 24: FIRST ATTEMPT TO BUILD & TRAIN A kNN MODEL\n", + "#######################################################\n", + "\n", + "#\n", + "# +++ This is the \"Model-building and Model-training Cell\"\n", + "#\n", + "# Create a kNN model and train it!\n", + "#\n", + "from sklearn.neighbors import KNeighborsClassifier\n", + "\n", + "k = 84 # we don't know what k to use, so we guess for now! (this will _not_ be a good value)\n", + "knn_model = KNeighborsClassifier(n_neighbors = k) # here, k is the \"k\" in kNN\n", + "\n", + "# we train the model (it's one line!)\n", + "knn_model.fit(X_train, y_train) # yay! trained!\n", + "print(\"Created and trained a knn classifier with k =\", k)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "d3cB0xryKPSD" + }, + "outputs": [], + "source": [ + "################################################\n", + "# BLOCK 25: TEST THE kNN MODEL\n", + "################################################\n", + "\n", + "#\n", + "# +++ This is the \"Model-testing Cell\"\n", + "#\n", + "# Now, let's see how well we did on our \"held-out data\" (the testing data)\n", + "#\n", + "\n", + "# We run our test set!\n", + "predicted_labels = knn_model.predict(X_test)\n", + "actual_labels = y_test\n", + "\n", + "# Let's print them so we can compare...\n", + "print(\"Predicted labels:\", predicted_labels)\n", + "print(\"Actual labels :\", actual_labels)\n", + "\n", + "# And, some overall results\n", + "num_correct = sum(predicted_labels == actual_labels)\n", + "total = len(actual_labels)\n", + "print(f\"\\nResults on test set: {num_correct} correct out of {total} total.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "liXBT5-IKPSD" + }, + "outputs": [], + "source": [ + "################################################\n", + "# BLOCK 26: PRETTY-PRINT PREDICTED LABELS\n", + "################################################\n", + "\n", + "#\n", + "# Let's print these more helpfully, in a vertical table\n", + "#\n", + "\n", + "def compareLabels(predicted_labels: np.ndarray, actual_labels: np.ndarray) -> int:\n", + " ''' a more neatly formatted comparison, returning the number correct '''\n", + " num_labels = len(predicted_labels)\n", + " num_correct = 0\n", + "\n", + " for i in range(num_labels):\n", + " predicted = int(round(predicted_labels[i])) # round-to-int protects from float imprecision\n", + " actual = int(round(actual_labels[i]))\n", + " result = \"incorrect\"\n", + " if predicted == actual: # if they match,\n", + " result = \"\" # no longer incorrect\n", + " num_correct += 1 # and we count a match!\n", + "\n", + " # note the justification formatting:\n", + " # :>3d right justifies integers (d) to width 3\n", + " # :<12s left justifies strings (s) to width 12\n", + " print(f\"row {i:>3d} : \", end = \"\")\n", + " print(f\"{species_names[predicted]:>12s} \", end = \"\")\n", + " print(f\"{species_names[actual]:<12s} {result}\")\n", + "\n", + " print()\n", + " print(f\"Correct: {num_correct} out of {num_labels}\")\n", + " return num_correct\n", + "\n", + "#\n", + "# let's try it out!\n", + "#\n", + "\n", + "compareLabels(predicted_labels,actual_labels)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "h_ZigXq2KPSE" + }, + "outputs": [], + "source": [ + "################################################\n", + "# BLOCK 27: USE THE FIRST-ATTEMPT kNN MODEL\n", + "################################################\n", + "\n", + "#\n", + "# Ok! We have our knn model, we could just use it...\n", + "#\n", + "\n", + "#\n", + "# data-driven predictive model (k-nearest-neighbor), using scikit-learn\n", + "#\n", + "\n", + "def predictiveModel( features: list[float] ) -> str:\n", + " ''' input: a list of four features\n", + " [ sepallen, sepalwid, petallen, petalwid ]\n", + " output: the predicted species of iris, from\n", + " setosa (0), versicolor (1), virginica (2)\n", + " '''\n", + " our_features = np.asarray([features]) # extra brackets needed\n", + " predicted_species = knn_model.predict(our_features)\n", + " print(f\"predicted_species = {predicted_species}\")\n", + "\n", + " predicted_species = int(round(predicted_species[0])) # unpack one element\n", + " name = species_names[predicted_species]\n", + " return f\"{name} ({predicted_species})\"\n", + "\n", + "#\n", + "# Try it!\n", + "#\n", + "# features = eval(input(\"Enter new features: \"))\n", + "#\n", + "features = [6.7,3.3,5.7,2.1] # [5.8,2.7,4.1,1.0] [4.6,3.6,3.0,2.2] [6.7,3.3,5.7,2.1]\n", + "result = predictiveModel( features )\n", + "print(f\"I predict {result} from features {features}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "kPByHBBnKPSE" + }, + "outputs": [], + "source": [ + "################################################\n", + "# BLOCK 28: COMMENTS ON CHOICE OF BEST k\n", + "################################################\n", + "\n", + "#\n", + "# Except, we didn't really explore whether this was the BEST model we could build!\n", + "#\n", + "#\n", + "# We used k = 84 (a neighborhood size of 84 flowers)\n", + "# In a dataset of only 140ish flowers, with three species, this seems like a bad idea!\n", + "#\n", + "# Perhaps we should try ALL the neighborhood sizes in their own TRAIN/TEST split\n", + "# and see which neighborhood size works the best, for irises, at least...\n", + "#" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ZUmotr7hKPSE" + }, + "outputs": [], + "source": [ + "################################################\n", + "# BLOCK 29: USING CROSS VALIDATION\n", + "################################################\n", + "\n", + "#\n", + "# to do this, we use \"cross validation\"\n", + "# (see slide 45)\n", + "#\n", + "\n", + "import seaborn as sns\n", + "import matplotlib.pyplot as plt\n", + "from sklearn.model_selection import cross_val_score\n", + "\n", + "#\n", + "# cross-validation splits the training set into two pieces:\n", + "# + model-building and model-validation. We'll use \"build\" and \"validate\"\n", + "#\n", + "\n", + "max_k = 85\n", + "all_accuracies = []\n", + "\n", + "for k in range(1, max_k, 1):\n", + " knn_cv_model = KNeighborsClassifier(n_neighbors = k) # build knn_model for every k!\n", + " cv_scores = cross_val_score( knn_cv_model, X_train, y_train, cv = 5 ) # 5 means 80/20 split\n", + " this_cv_accuracy = cv_scores.mean() # mean() is numpy's built-in average function\n", + " print(f\"k: {k:2d} cv accuracy: {this_cv_accuracy:7.4f}\")\n", + " all_accuracies.append(this_cv_accuracy)\n", + "\n", + "# assign best value of k to best_k\n", + "best_k = k # *** AT THE MOMENT THIS IS INCORRECT ***\n", + "# you'll need to modify the loop above to find and remember the real best_k\n", + "\n", + "print(f\"best_k = {best_k} yields the highest average cv accuracy.\") # print the best one\n", + "\n", + "plt.figure(figsize=(10, 6))\n", + "sns.lineplot(x=range(1,len(all_accuracies)+1), y=all_accuracies)\n", + "plt.xlabel(\"k value (index)\")\n", + "plt.ylabel(\"Cross-validated accuracy\")\n", + "plt.title(\"kNN Accuracy vs k Value\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "pJW6c8XdKPSF" + }, + "outputs": [], + "source": [ + "################################################\n", + "# BLOCK 30: RE-BUILD & RE-TRAIN USING BEST k\n", + "################################################\n", + "\n", + "#\n", + "# Now, we re-create and re-run the \"Model-building and -training Cell\"\n", + "#\n", + "# Now, using best_k instead of the original, randomly-guessed value How does it do?!\n", + "#\n", + "from sklearn.neighbors import KNeighborsClassifier\n", + "knn_model_tuned = KNeighborsClassifier(n_neighbors = best_k) # here, we use the best_k\n", + "\n", + "# we train the model (one line!)\n", + "knn_model_tuned.fit(X_train, y_train) # yay! trained!\n", + "print(f\"Created + trained a knn classifier, now tuned with a (best) k of {best_k}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "9h5-1TukKPSF" + }, + "outputs": [], + "source": [ + "################################################\n", + "# BLOCK 31: RE-TEST THE BEST-k MODEL\n", + "################################################\n", + "\n", + "#\n", + "# Re-create and re-run the \"Model-testing Cell\" How does it do with best_k?!\n", + "#\n", + "predicted_labels = knn_model_tuned.predict(X_test)\n", + "actual_labels = y_test\n", + "\n", + "# Let's print them so we can compare...\n", + "print(\"Predicted labels:\", predicted_labels)\n", + "print(\"Actual labels:\", actual_labels)\n", + "print()\n", + "# and, we'll print our nicer table...\n", + "compareLabels(predicted_labels,actual_labels)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8dIjchI0RQ57" + }, + "outputs": [], + "source": [ + "################################################\n", + "# BLOCK 32: TRYING DIFFERENT PERMUTATIONS\n", + "################################################\n", + "\n", + "#\n", + "# Before moving on, go back and choose a new permutation to give\n", + "# new testing and training sets, and go back through the steps\n", + "# for identifying the \"best\" k (starting at Block 22 and re-doing\n", + "# up through Block 31).\n", + "#\n", + "# Repeat this several times.\n", + "# Do you get the same value for k each time? Why or why not?\n", + "#" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "h1fhLBYSKPSF" + }, + "outputs": [], + "source": [ + "####################################################\n", + "# BLOCK 33: REBUILD & TRAIN USING BEST k & ALL DATA\n", + "####################################################\n", + "\n", + "# Ok! Now we have tuned knn to use the \"best\" value of k...\n", + "#\n", + "# And, we should really use ALL available data to train our final predictive model\n", + "# (not split into test and train as before)\n", + "#\n", + "\n", + "knn_model_final = KNeighborsClassifier(n_neighbors=best_k) # here, we use the best_k\n", + "knn_model_final.fit(X_all, y_all) # yay! trained!\n", + "print(f\"Created + trained a 'final' knn classifier, with a (best) k of {best_k}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "AsC4oa2qKPSG" + }, + "outputs": [], + "source": [ + "####################################################\n", + "# BLOCK 34: TRYING FINAL MODEL \"IN THE WILD\"\n", + "####################################################\n", + "\n", + "#\n", + "# final predictive model (k-nearest-neighbor), with tuned k + ALL data incorporated\n", + "#\n", + "\n", + "def predictiveModel( features: list[float] ) -> None:\n", + " ''' input: a list of four features\n", + " [ sepallen, sepalwid, petallen, petalwid ]\n", + " output: the predicted species of iris, from\n", + " setosa (0), versicolor (1), virginica (2)\n", + " '''\n", + " our_features = np.asarray([features]) # extra brackets needed\n", + " predicted_species = knn_model_final.predict(our_features)\n", + "\n", + " predicted_species = int(round(predicted_species[0])) # unpack one element\n", + " name = species_names[predicted_species]\n", + " return f\"{name} ({predicted_species})\"\n", + "\n", + "#\n", + "# Try it on several!\n", + "#\n", + "# features = eval(input(\"Enter new features: \"))\n", + "#\n", + "features = [6.7,3.3,5.7,2.1] # [5.8,2.7,4.1,1.0] [4.6,3.6,3.0,2.2] [6.7,3.3,5.7,2.1]\n", + "result = predictiveModel( features )\n", + "print(f\"I predict {result} from features {features}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "UHNILKXiRQ58" + }, + "outputs": [], + "source": [ + "################################################################\n", + "# BLOCK 35a: HOW DOES THE MODEL PERFORM ON MEAN OF EACH FLOWER?\n", + "################################################################\n", + "\n", + "# let's recall the species names and their order in the list\n", + "print(species_names)\n", + "print('=' * 70)\n", + "\n", + "# and let's recall what the final DataFrame looks like, noting that\n", + "# the irisname was converted to the corresponding index in species_names\n", + "print(df_final)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "MlnIrLPWRQ58" + }, + "outputs": [], + "source": [ + "################################################################\n", + "# BLOCK 35b: HOW DOES THE MODEL PERFORM ON MEAN OF EACH FLOWER?\n", + "################################################################\n", + "\n", + "# let's grab the data from df_final corresponding to versicolor\n", + "versicolor_data = df_final[ df_final['irisname'] == convertSpecies('versicolor') ]\n", + "print(versicolor_data)\n", + "print('=' * 70)\n", + "\n", + "# let's print the mean of each column\n", + "print(versicolor_data.mean())\n", + "print('=' * 70)\n", + "\n", + "# and let's grab the features means only (don't need the label) for versicolor\n", + "versicolor_features_means = np.asarray(versicolor_data.mean()[:-1])\n", + "print(versicolor_features_means)\n", + "\n", + "# now run the predictive model (see Block 34 above) and print a corresponding\n", + "# message\n", + "\n", + "# >>> YOU ADD CODE HERE" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "twR2L9IRRQ58" + }, + "outputs": [], + "source": [ + "################################################################\n", + "# BLOCK 35c: HOW DOES THE MODEL PERFORM ON MEAN OF EACH FLOWER?\n", + "################################################################\n", + "\n", + "# Automate the process used in Block 35b, across all species:\n", + "#\n", + "# Loop across species names, and for each species,\n", + "# (a) pull that corresponding data from df_final\n", + "# (b) compute the means of the features, storing as a numpy array\n", + "# (c) call the predictive model using those features\n", + "# (d) print a corresponding message\n", + "\n", + "# >> YOU ADD CODE HERE -- YOU SHOULD NEED NO MORE THAN 5 LINES OF CODE" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "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.12.2" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/HW 5/W2025 DCS 211_ In-class work – ML Workflow (Iris Dataset).pdf b/HW 5/W2025 DCS 211_ In-class work – ML Workflow (Iris Dataset).pdf new file mode 100644 index 0000000..b910bca Binary files /dev/null and b/HW 5/W2025 DCS 211_ In-class work – ML Workflow (Iris Dataset).pdf differ diff --git a/HW 5/iris.csv b/HW 5/iris.csv new file mode 100644 index 0000000..baa180f --- /dev/null +++ b/HW 5/iris.csv @@ -0,0 +1,151 @@ +sepallen,sepalwid,petallen,petalwid,irisname,junk +,3.5,1.4,0.2,setosa,remove_me +4.9,3.0,1.4,0.2,setosa,remove_me +4.7,3.2,1.3,0.2,setosa,remove_me +4.6,3.1,1.5,0.2,setosa,remove_me +5.0,3.6,1.4,0.2,setosa,remove_me +5.4,3.9,1.7,0.4,setosa,remove_me +4.6,3.4,1.4,0.3,setosa,remove_me +5.0,3.4,1.5,,setosa,remove_me +4.4,2.9,1.4,0.2,setosa,remove_me +4.9,3.1,1.5,0.1,setosa,remove_me +5.4,3.7,1.5,0.2,setosa,remove_me +4.8,3.4,1.6,0.2,setosa,remove_me +4.8,3.0,1.4,0.1,setosa,remove_me +4.3,3.0,1.1,0.1,setosa,remove_me +5.8,4.0,1.2,0.2,setosa,remove_me +5.7,4.4,1.5,0.4,setosa,remove_me +5.4,3.9,1.3,0.4,setosa,remove_me +5.1,3.5,1.4,0.3,setosa,remove_me +5.7,3.8,1.7,0.3,setosa,remove_me +5.1,3.8,1.5,0.3,setosa,remove_me +5.4,3.4,1.7,0.2,setosa,remove_me +5.1,3.7,1.5,0.4,setosa,remove_me +4.6,3.6,1.0,0.2,setosa,remove_me +5.1,3.3,1.7,0.5,setosa,remove_me +4.8,3.4,1.9,0.2,setosa,remove_me +5.0,3.0,1.6,0.2,,remove_me +5.0,3.4,1.6,0.4,setosa,remove_me +5.2,3.5,1.5,0.2,setosa,remove_me +5.2,3.4,1.4,0.2,setosa,remove_me +4.7,3.2,1.6,0.2,setosa,remove_me +4.8,3.1,1.6,0.2,setosa,remove_me +5.4,3.4,1.5,0.4,setosa,remove_me +5.2,4.1,1.5,0.1,setosa,remove_me +5.5,4.2,1.4,0.2,setosa,remove_me +4.9,3.1,1.5,0.2,setosa,remove_me +5.0,3.2,1.2,0.2,setosa,remove_me +5.5,3.5,1.3,0.2,setosa,remove_me +4.9,3.6,1.4,0.1,setosa,remove_me +4.4,3.0,1.3,0.2,setosa,remove_me +5.1,3.4,1.5,0.2,setosa,remove_me +5.0,3.5,1.3,0.3,setosa,remove_me +4.5,2.3,1.3,0.3,setosa,remove_me +4.4,3.2,1.3,0.2,setosa,remove_me +5.0,3.5,1.6,0.6,setosa,remove_me +5.1,3.8,1.9,0.4,setosa,remove_me +4.8,3.0,1.4,0.3,setosa,remove_me +5.1,3.8,1.6,0.2,setosa,remove_me +4.6,3.2,1.4,0.2,setosa,remove_me +5.3,3.7,1.5,0.2,setosa,remove_me +5.0,3.3,1.4,0.2,setosa,remove_me +7.0,3.2,4.7,1.4,versicolor,remove_me +6.4,3.2,4.5,1.5,versicolor,remove_me +6.9,3.1,4.9,1.5,versicolor,remove_me +5.5,2.3,4.0,1.3,versicolor,remove_me +6.5,2.8,4.6,1.5,versicolor,remove_me +5.7,2.8,4.5,1.3,versicolor,remove_me +6.3,3.3,4.7,1.6,versicolor,remove_me +4.9,2.4,3.3,1.0,versicolor,remove_me +6.6,2.9,4.6,1.3,versicolor,remove_me +5.2,2.7,3.9,1.4,versicolor,remove_me +5.0,2.0,3.5,1.0,versicolor,remove_me +5.9,3.0,4.2,1.5,versicolor,remove_me +6.0,2.2,4.0,1.0,versicolor,remove_me +6.1,2.9,4.7,1.4,versicolor,remove_me +5.6,2.9,3.6,1.3,versicolor,remove_me +6.7,3.1,4.4,1.4,versicolor,remove_me +5.6,3.0,4.5,1.5,versicolor,remove_me +5.8,2.7,4.1,1.0,versicolor,remove_me +6.2,2.2,4.5,1.5,versicolor,remove_me +5.6,2.5,3.9,1.1,versicolor,remove_me +5.9,3.2,4.8,1.8,versicolor,remove_me +6.1,2.8,4.0,1.3,versicolor,remove_me +6.3,2.5,4.9,1.5,versicolor,remove_me +6.1,2.8,4.7,1.2,versicolor,remove_me +6.4,2.9,4.3,1.3,versicolor,remove_me +6.6,3.0,4.4,1.4,versicolor,remove_me +6.8,2.8,4.8,1.4,versicolor,remove_me +6.7,3.0,5.0,1.7,versicolor,remove_me +6.0,2.9,4.5,1.5,versicolor,remove_me +5.7,2.6,3.5,1.0,versicolor,remove_me +5.5,2.4,3.8,1.1,versicolor,remove_me +5.5,2.4,3.7,1.0,versicolor,remove_me +5.8,2.7,3.9,1.2,versicolor,remove_me +6.0,2.7,5.1,1.6,versicolor,remove_me +5.4,3.0,4.5,1.5,versicolor,remove_me +6.0,3.4,4.5,1.6,versicolor,remove_me +6.7,3.1,4.7,1.5,versicolor,remove_me +6.3,2.3,4.4,1.3,versicolor,remove_me +5.6,3.0,4.1,1.3,versicolor,remove_me +5.5,2.5,4.0,1.3,versicolor,remove_me +5.5,2.6,4.4,1.2,versicolor,remove_me +6.1,3.0,4.6,1.4,versicolor,remove_me +5.8,2.6,4.0,1.2,versicolor,remove_me +5.0,2.3,3.3,1.0,versicolor,remove_me +5.6,2.7,4.2,1.3,versicolor,remove_me +5.7,3.0,4.2,1.2,versicolor,remove_me +5.7,2.9,4.2,1.3,versicolor,remove_me +6.2,2.9,4.3,1.3,versicolor,remove_me +5.1,2.5,3.0,1.1,versicolor,remove_me +5.7,2.8,4.1,1.3,versicolor,remove_me +6.3,3.3,6.0,2.5,virginica,remove_me +5.8,2.7,5.1,1.9,virginica,remove_me +7.1,3.0,5.9,2.1,virginica,remove_me +6.3,2.9,5.6,1.8,virginica,remove_me +6.5,3.0,5.8,2.2,virginica,remove_me +7.6,3.0,6.6,2.1,virginica,remove_me +4.9,2.5,4.5,1.7,virginica,remove_me +7.3,2.9,6.3,1.8,virginica,remove_me +6.7,2.5,5.8,1.8,virginica,remove_me +7.2,3.6,6.1,2.5,virginica,remove_me +6.5,3.2,5.1,2.0,virginica,remove_me +6.4,2.7,5.3,1.9,virginica,remove_me +6.8,3.0,5.5,2.1,virginica,remove_me +5.7,2.5,5.0,2.0,virginica,remove_me +5.8,2.8,5.1,2.4,virginica,remove_me +6.4,3.2,5.3,2.3,virginica,remove_me +6.5,3.0,5.5,1.8,virginica,remove_me +7.7,3.8,6.7,2.2,virginica,remove_me +7.7,2.6,6.9,2.3,virginica,remove_me +6.0,2.2,5.0,1.5,virginica,remove_me +6.9,3.2,5.7,2.3,virginica,remove_me +5.6,2.8,4.9,2.0,virginica,remove_me +7.7,2.8,6.7,2.0,virginica,remove_me +6.3,2.7,4.9,1.8,virginica,remove_me +6.7,3.3,5.7,2.1,virginica,remove_me +7.2,3.2,6.0,1.8,virginica,remove_me +6.2,2.8,4.8,1.8,virginica,remove_me +6.1,3.0,4.9,1.8,virginica,remove_me +6.4,2.8,5.6,2.1,virginica,remove_me +7.2,3.0,5.8,1.6,virginica,remove_me +7.4,2.8,6.1,1.9,virginica,remove_me +7.9,3.8,6.4,2.0,virginica,remove_me +6.4,2.8,5.6,2.2,virginica,remove_me +6.3,2.8,5.1,1.5,virginica,remove_me +6.1,2.6,5.6,1.4,virginica,remove_me +7.7,3.0,6.1,2.3,virginica,remove_me +6.3,3.4,5.6,2.4,virginica,remove_me +6.4,3.1,5.5,1.8,virginica,remove_me +6.0,3.0,4.8,1.8,virginica,remove_me +6.9,3.1,5.4,2.1,virginica,remove_me +6.7,3.1,5.6,2.4,virginica,remove_me +6.9,3.1,5.1,2.3,virginica,remove_me +5.8,2.7,5.1,1.9,virginica,remove_me +6.8,3.2,5.9,2.3,virginica,remove_me +6.7,3.3,5.7,2.5,virginica,remove_me +6.7,3.0,5.2,2.3,virginica,remove_me +6.3,2.5,5.0,1.9,virginica,remove_me +6.5,3.0,5.2,2.0,virginica,remove_me +6.2,3.4,5.4,2.3,alieniris,remove_me +5.9,3.0,5.1,1.8,alieniris,remove_me