diff --git a/section-3-structured-data-projects/end-to-end-bluebook-bulldozer-price-regression-tmp-v2.ipynb b/section-3-structured-data-projects/end-to-end-bluebook-bulldozer-price-regression-tmp-v2.ipynb deleted file mode 100644 index d7cd941d8..000000000 --- a/section-3-structured-data-projects/end-to-end-bluebook-bulldozer-price-regression-tmp-v2.ipynb +++ /dev/null @@ -1,12801 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "TK - add Google Colab link as well as reference notebook etc" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 🚜 Predicting the Sale Price of Bulldozers using Machine Learning \n", - "\n", - "In this notebook, we're going to go through an example machine learning project to use the characteristics of bulldozers and their past sales prices to predict the sale price of future bulldozers based on their characteristics.\n", - "\n", - "* **Inputs:** Bulldozer characteristics such as make year, base model, model series, state of sale (e.g. which US state was it sold in), drive system and more.\n", - "* **Outputs:** Bulldozer sale price (in USD).\n", - "\n", - "Since we're trying to predict a number, this kind of problem is known as a **regression problem**.\n", - "\n", - "And since we're going to predicting results with a time component (predicting future sales based on past sales), this is also known as a **time series** or **forecasting** problem.\n", - "\n", - "The data and evaluation metric we'll be using (root mean square log error or RMSLE) is from the [Kaggle Bluebook for Bulldozers competition](https://www.kaggle.com/c/bluebook-for-bulldozers/overview).\n", - "\n", - "The techniques used in here have been inspired and adapted from [the fast.ai machine learning course](https://course18.fast.ai/ml)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Overview\n", - "\n", - "Since we already have a dataset, we'll approach the problem with the following machine learning modelling framework.\n", - "\n", - "| | \n", - "|:--:| \n", - "| 6 Step Machine Learning Modelling Framework ([read more](https://whimsical.com/9g65jgoRYTxMXxDosndYTB)) |\n", - "\n", - "To work through these topics, we'll use pandas, Matplotlib and NumPy for data analysis, as well as, Scikit-Learn for machine learning and modelling tasks.\n", - "\n", - "| | \n", - "|:--:| \n", - "| Tools that can be used for each step of the machine learning modelling process. |\n", - "\n", - "We'll work through each step and by the end of the notebook, we'll have a trained machine learning model which predicts the sale price of a bulldozer given different characteristics about it." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 6 Step Machine Learning Framework\n", - "\n", - "#### 1. Problem Definition\n", - "\n", - "For this dataset, the problem we're trying to solve, or better, the question we're trying to answer is,\n", - "\n", - "> How well can we predict the future sale price of a bulldozer, given its characteristics previous examples of how much similar bulldozers have been sold for?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 2. Data\n", - "\n", - "Looking at the [dataset from Kaggle](https://www.kaggle.com/c/bluebook-for-bulldozers/data) we see that it contains historical sales data of bulldozers. Including things like, model type, size, sale date and more.\n", - "\n", - "There are 3 datasets:\n", - "\n", - "1. **Train.csv** - Historical bulldozer sales examples up to 2011 (close to 400,000 examples with 50+ different attributes, including `SalePrice` which is the **target variable**).\n", - "2. **Valid.csv** - Historical bulldozer sales examples from January 1 2012 to April 30 2012 (close to 12,000 examples with the same attributes as **Train.csv**).\n", - "3. **Test.csv** - Historical bulldozer sales examples from May 1 2012 to November 2012 (close to 12,000 examples but missing the `SalePrice` attribute, as this is what we'll be trying to predict).\n", - "\n", - "> **Note:** You can download the dataset `bluebook-for-bulldozers` dataset directly from Kaggle. Alternatively, you can also [download it directly from the course GitHub](https://github.com/mrdbourke/zero-to-mastery-ml/raw/refs/heads/master/data/bluebook-for-bulldozers.zip)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 3. Evaluation\n", - "\n", - "For this problem, [Kaggle has set the evaluation metric to being root mean squared log error (RMSLE)](https://www.kaggle.com/c/bluebook-for-bulldozers/overview/evaluation). As with many regression evaluations, the goal will be to get this value as low as possible (a low error value means our model's predictions are close to what the real values are).\n", - "\n", - "To see how well our model is doing, we'll calculate the RMSLE and then compare our results to others on the [Kaggle leaderboard](https://www.kaggle.com/c/bluebook-for-bulldozers/leaderboard)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 4. Features\n", - "\n", - "Features are different parts and attributes of the data. \n", - "\n", - "During this step, you'll want to start finding out what you can about the data.\n", - "\n", - "One of the most common ways to do this is to create a **data dictionary**.\n", - "\n", - "For this dataset, Kaggle provides a data dictionary which contains information about what each attribute of the dataset means. \n", - "\n", - "For example: \n", - "\n", - "| Variable Name | Description | Variable Type |\n", - "|------|-----|-----|\n", - "| SalesID | unique identifier of a particular sale of a machine at auction | Independent variable |\n", - "| MachineID | identifier for a particular machine; machines may have multiple sales | Independent variable |\n", - "| ModelID | identifier for a unique machine model (i.e. fiModelDesc) | Independent variable |\n", - "| datasource | source of the sale record; some sources are more diligent about reporting attributes of the machine than others. Note that a particular datasource may report on multiple auctioneerIDs. | Independent variable |\n", - "| auctioneerID | identifier of a particular auctioneer, i.e. company that sold the machine at auction. Not the same as datasource. | Independent variable |\n", - "| YearMade | year of manufacturer of the Machine | Independent variable |\n", - "| MachineHoursCurrentMeter | current usage of the machine in hours at time of sale (saledate); null or 0 means no hours have been reported for that sale | Independent variable |\n", - "| UsageBand | value (low, medium, high) calculated comparing this particular Machine-Sale hours to average usage for the fiBaseModel; e.g. 'Low' means this machine has fewer hours given its lifespan relative to the average of fiBaseModel. | Independent variable |\n", - "| Saledate | time of sale | Independent variable |\n", - "| fiModelDesc | Description of a unique machine model (see ModelID); concatenation of fiBaseModel & fiSecondaryDesc & fiModelSeries & fiModelDescriptor | Independent variable |\n", - "| State | US State in which sale occurred | Independent variable |\n", - "| Drive_System | machine configuration; typically describes whether 2 or 4 wheel drive | Independent variable |\n", - "| Enclosure | machine configuration - does the machine have an enclosed cab or not | Independent variable |\n", - "| Forks | machine configuration - attachment used for lifting | Independent variable |\n", - "| Pad_Type | machine configuration - type of treads a crawler machine uses | Independent variable |\n", - "| Ride_Control | machine configuration - optional feature on loaders to make the ride smoother | Independent variable |\n", - "| Transmission | machine configuration - describes type of transmission; typically automatic or manual | Independent variable |\n", - "| ... | ... | ... |\n", - "| SalePrice | cost of sale in USD | Target/dependent variable | \n", - "\n", - "You can download the full version of this file directly from the [Kaggle competition page](https://www.kaggle.com/c/bluebook-for-bulldozers/download/Bnl6RAHA0enbg0UfAvGA%2Fversions%2FwBG4f35Q8mAbfkzwCeZn%2Ffiles%2FData%20Dictionary.xlsx) (Kaggle account required) or view it [on Google Sheets](https://docs.google.com/spreadsheets/d/18ly-bLR8sbDJLITkWG7ozKm8l3RyieQ2Fpgix-beSYI/edit?usp=sharing).\n", - "\n", - "With all of this being known, let's get started! \n", - "\n", - "First, we'll import the dataset and start exploring. " - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Notebook last run (end-to-end): 2024-10-30 11:54:38.504966\n" - ] - } - ], - "source": [ - "# Timestamp\n", - "import datetime\n", - "\n", - "import datetime\n", - "print(f\"Notebook last run (end-to-end): {datetime.datetime.now()}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 1. Importing the data and preparing it for modelling\n", - "\n", - "First thing is first, let's get the libraries we need imported and the data we'll need for the project.\n", - "\n", - "We'll start by importing pandas, NumPy and matplotlib." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pandas version: 2.2.2\n", - "NumPy version: 2.1.1\n", - "matplotlib version: 3.9.2\n" - ] - } - ], - "source": [ - "# Import data analysis tools \n", - "import pandas as pd\n", - "import numpy as np\n", - "import matplotlib\n", - "import matplotlib.pyplot as plt\n", - "\n", - "# Print the versions we're using (as long as your versions are equal or higher than these, the code should work)\n", - "print(f\"pandas version: {pd.__version__}\")\n", - "print(f\"NumPy version: {np.__version__}\")\n", - "print(f\"matplotlib version: {matplotlib.__version__}\") " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we've got our tools for data analysis ready, we can import the data and start to explore it.\n", - "\n", - "For this project, I've [downloaded the data from Kaggle](https://www.kaggle.com/c/bluebook-for-bulldozers/data) and stored it on the [course GitHub](https://github.com/mrdbourke/zero-to-mastery-ml/) under the file path [`../data/bluebook-for-bulldozers`](https://github.com/mrdbourke/zero-to-mastery-ml/blob/master/data/bluebook-for-bulldozers.zip).\n", - "\n", - "We can write some code to check if the files are available locally (on our computer) and if not, we can download them.\n", - "\n", - "> **Note:** If you're running this notebook on Google Colab, the code below will enable you to download the dataset programmatically. Just beware that each time Google Colab shuts down, the data will have to be redownloaded. There's also an [example Google Colab notebook](https://colab.research.google.com/drive/1hf1rTcCAQP1EN8pZ0ZIqjjEy47dwzbiv?usp=sharing) showing how to download the data programmatically." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] 'bluebook-for-bulldozers' dataset exists, feel free to proceed!\n", - "[INFO] Current dataset dir: ../data/bluebook-for-bulldozers\n" - ] - } - ], - "source": [ - "from pathlib import Path\n", - "\n", - "# Check if 'bluebook-for-bulldozers' exists in the current or parent directory\n", - "# Link to data (see the file \"bluebook-for-bulldozers\"): https://github.com/mrdbourke/zero-to-mastery-ml/tree/master/data\n", - "dataset_dir = Path(\"../data/bluebook-for-bulldozers\")\n", - "if not (dataset_dir.is_dir()):\n", - " print(f\"[INFO] Can't find existing 'bluebook-for-bulldozers' dataset in current directory or parent directory, downloading...\")\n", - "\n", - " # Download and unzip the bluebook for bulldozers dataset\n", - " !wget https://github.com/mrdbourke/zero-to-mastery-ml/raw/refs/heads/master/data/bluebook-for-bulldozers.zip\n", - " !unzip bluebook-for-bulldozers.zip\n", - "\n", - " # Ensure a data directory exists and move the downloaded dataset there\n", - " !mkdir ../data/\n", - " !mv bluebook-for-bulldozers ../data/\n", - " print(f\"[INFO] Current dataset dir: {dataset_dir}\")\n", - "\n", - " # Remove .zip file from notebook directory\n", - " !rm -rf bluebook-for-bulldozers.zip\n", - "else:\n", - " # If the target dataset directory exists, we don't need to download it\n", - " print(f\"[INFO] 'bluebook-for-bulldozers' dataset exists, feel free to proceed!\")\n", - " print(f\"[INFO] Current dataset dir: {dataset_dir}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Dataset downloaded!\n", - "\n", - "Let's check what files are available." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Files/folders available in ../data/bluebook-for-bulldozers:\n" - ] - }, - { - "data": { - "text/plain": [ - "['random_forest_benchmark_test.csv',\n", - " 'Valid.csv',\n", - " 'median_benchmark.csv',\n", - " 'Valid.zip',\n", - " 'TrainAndValid.7z',\n", - " 'Test.csv',\n", - " 'predictions.csv',\n", - " 'Train.7z',\n", - " 'TrainAndValid_object_values_as_categories.parquet',\n", - " 'test_predictions.csv',\n", - " 'ValidSolution.csv',\n", - " 'train_tmp.csv',\n", - " 'Machine_Appendix.csv',\n", - " 'Train.csv',\n", - " 'Valid.7z',\n", - " 'TrainAndValid_object_values_as_categories.csv',\n", - " 'TrainAndValid_object_values_as_categories_and_missing_values_filled.parquet',\n", - " 'Data Dictionary.xlsx',\n", - " 'TrainAndValid.csv',\n", - " 'Train.zip',\n", - " 'TrainAndValid.zip']" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import os\n", - "\n", - "print(f\"[INFO] Files/folders available in {dataset_dir}:\")\n", - "os.listdir(dataset_dir)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can explore each of these files individually or read about them on the [Kaggle Competition page](https://www.kaggle.com/c/bluebook-for-bulldozers/data).\n", - "\n", - "For now, the main file we're interested in is `TrainAndValid.csv` (this is also a combination of `Train.csv` and `Valid.csv`), this is a combination of the training and validation datasets.\n", - "\n", - "* The training data (`Train.csv`) contains sale data from 1989 up to the end of 2011.\n", - "* The validation data (`Valid.csv`) contains sale data from January 1, 2012 - April 30, 2012.\n", - "* The test data (`Test.csv`) contains sale data from May 1, 2012 - November 2012.\n", - "\n", - "We'll use the training data to train our model to predict the sale price of bulldozers, we'll then validate its performance on the validation data to see if our model can be improved in any way. Finally, we'll evaluate our best model on the test dataset.\n", - "\n", - "But more on this later on.\n", - "\n", - "Let's import the `TrainAndValid.csv` file and turn it into a pandas DataFrame." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/var/folders/c4/qj4gdk190td18bqvjjh0p3p00000gn/T/ipykernel_20423/1127193594.py:2: DtypeWarning: Columns (13,39,40,41) have mixed types. Specify dtype option on import or set low_memory=False.\n", - " df = pd.read_csv(filepath_or_buffer=\"../data/bluebook-for-bulldozers/TrainAndValid.csv\")\n" - ] - } - ], - "source": [ - "# Import the training and validation set\n", - "df = pd.read_csv(filepath_or_buffer=\"../data/bluebook-for-bulldozers/TrainAndValid.csv\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Wonderful! We've got our DataFrame ready to explore.\n", - "\n", - "You might see a warning appear in the form:\n", - "\n", - "`DtypeWarning: Columns (13,39,40,41) have mixed types. Specify dtype option on import or set low_memory=False. df = pd.read_csv(\"../data/bluebook-for-bulldozers/TrainAndValid.csv\")`\n", - "\n", - "This is just saying that some of our columns have multiple/mixed data types. For example, a column may contain strings but also contain integers. This is okay for now and can be addressed later on if necessary.\n", - "\n", - "How about we get some information about our DataFrame?\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "RangeIndex: 412698 entries, 0 to 412697\n", - "Data columns (total 53 columns):\n", - " # Column Non-Null Count Dtype \n", - "--- ------ -------------- ----- \n", - " 0 SalesID 412698 non-null int64 \n", - " 1 SalePrice 412698 non-null float64\n", - " 2 MachineID 412698 non-null int64 \n", - " 3 ModelID 412698 non-null int64 \n", - " 4 datasource 412698 non-null int64 \n", - " 5 auctioneerID 392562 non-null float64\n", - " 6 YearMade 412698 non-null int64 \n", - " 7 MachineHoursCurrentMeter 147504 non-null float64\n", - " 8 UsageBand 73670 non-null object \n", - " 9 saledate 412698 non-null object \n", - " 10 fiModelDesc 412698 non-null object \n", - " 11 fiBaseModel 412698 non-null object \n", - " 12 fiSecondaryDesc 271971 non-null object \n", - " 13 fiModelSeries 58667 non-null object \n", - " 14 fiModelDescriptor 74816 non-null object \n", - " 15 ProductSize 196093 non-null object \n", - " 16 fiProductClassDesc 412698 non-null object \n", - " 17 state 412698 non-null object \n", - " 18 ProductGroup 412698 non-null object \n", - " 19 ProductGroupDesc 412698 non-null object \n", - " 20 Drive_System 107087 non-null object \n", - " 21 Enclosure 412364 non-null object \n", - " 22 Forks 197715 non-null object \n", - " 23 Pad_Type 81096 non-null object \n", - " 24 Ride_Control 152728 non-null object \n", - " 25 Stick 81096 non-null object \n", - " 26 Transmission 188007 non-null object \n", - " 27 Turbocharged 81096 non-null object \n", - " 28 Blade_Extension 25983 non-null object \n", - " 29 Blade_Width 25983 non-null object \n", - " 30 Enclosure_Type 25983 non-null object \n", - " 31 Engine_Horsepower 25983 non-null object \n", - " 32 Hydraulics 330133 non-null object \n", - " 33 Pushblock 25983 non-null object \n", - " 34 Ripper 106945 non-null object \n", - " 35 Scarifier 25994 non-null object \n", - " 36 Tip_Control 25983 non-null object \n", - " 37 Tire_Size 97638 non-null object \n", - " 38 Coupler 220679 non-null object \n", - " 39 Coupler_System 44974 non-null object \n", - " 40 Grouser_Tracks 44875 non-null object \n", - " 41 Hydraulics_Flow 44875 non-null object \n", - " 42 Track_Type 102193 non-null object \n", - " 43 Undercarriage_Pad_Width 102916 non-null object \n", - " 44 Stick_Length 102261 non-null object \n", - " 45 Thumb 102332 non-null object \n", - " 46 Pattern_Changer 102261 non-null object \n", - " 47 Grouser_Type 102193 non-null object \n", - " 48 Backhoe_Mounting 80712 non-null object \n", - " 49 Blade_Type 81875 non-null object \n", - " 50 Travel_Controls 81877 non-null object \n", - " 51 Differential_Type 71564 non-null object \n", - " 52 Steering_Controls 71522 non-null object \n", - "dtypes: float64(3), int64(5), object(45)\n", - "memory usage: 166.9+ MB\n" - ] - } - ], - "source": [ - "# Get info about DataFrame\n", - "df.info()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Woah! Over 400,000 entries!\n", - "\n", - "That's a much larger dataset than what we've worked with before.\n", - "\n", - "One thing you might have noticed is that the `saledate` column value is being treated as a Python object (it's okay if you didn't notice, these things take practice).\n", - "\n", - "When the `Dtype` is `object`, it's saying that it's a string.\n", - "\n", - "However, when we look at it...\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0 11/16/2006 0:00\n", - "1 3/26/2004 0:00\n", - "2 2/26/2004 0:00\n", - "3 5/19/2011 0:00\n", - "4 7/23/2009 0:00\n", - "5 12/18/2008 0:00\n", - "6 8/26/2004 0:00\n", - "7 11/17/2005 0:00\n", - "8 8/27/2009 0:00\n", - "9 8/9/2007 0:00\n", - "Name: saledate, dtype: object" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df[\"saledate\"][:10]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can see that these `object`'s are in the form of dates.\n", - "\n", - "Since we're working on a **time series** problem (a machine learning problem with a time component), it's probably worth it to turn these strings into Python `datetime` objects.\n", - "\n", - "Before we do, let's try visualize our `saledate` column against our `SalePrice` column.\n", - "\n", - "To do so, we can create a scatter plot.\n", - "\n", - "And to prevent our plot from being too big, how about we visualize the first 1000 values?" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fig, ax = plt.subplots()\n", - "ax.scatter(x=df[\"saledate\"][:1000], # visualize the first 1000 values\n", - " y=df[\"SalePrice\"][:1000])\n", - "ax.set_xlabel(\"Sale Date\")\n", - "ax.set_ylabel(\"Sale Price ($)\");" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Hmm... looks like the x-axis is quite crowded.\n", - "\n", - "Maybe we can fix this by turning the `saledate` column into `datetime` format.\n", - "\n", - "Good news is that is looks like our `SalePrice` column is already in `float64` format so we can view its distribution directly from the DataFrame using a histogram plot." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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HntMJSUll3fk7q7Y2FjNnTvX0gYBAABqgyqFqgYNGuiNN97Q3Llz9Z///EeS9NOf/lQNGza0tDkAAIDa4kct/nn69GmdPn1abdu2VcOGDWUYhlV9AQAA1CpVClXffPON+vTpo7vuukv9+/fX6dOnJUmxsbEspwAAAOqkKoWqMWPGqH79+jpx4oQaNGhgbh84cKBSUlIsaw4AAKC2qNI9VR9++KE2btyoli1bumxv27atjh8/bkljAAAAtUmVrlQVFha6XKEqk5eXJ09Pzx/dFAAAQG1TpVB1//3365133jGf22w2lZaWKjExUQ899JBlzQEAANQWVfr4LzExUX369FFmZqaKi4s1YcIE7d+/X3l5edq+fbvVPQIAANR4VbpS1alTJx0+fFi9e/fWb3/7WxUWFuqRRx7R7t279dOf/tTqHgEAAGq8G75SVVJSon79+ikpKUlTpky5GT0BAADUOjd8pap+/frau3fvzegFAACg1qrSx3+PP/64/va3v1ndCwAAQK1VpRvVL168qL///e/66KOP1L1793K/+Td//nxLmgMAAKgtbihUffnllwoODlZOTo66desmSTp8+LBLjc1ms647AACAWuKGQlXbtm11+vRpbd68WdLln6VZtGiRAgICbkpzAAAAtcUN3VNlGIbL8w8++ECFhYWWNgQAAFAbVelG9TI/DFkAAAB11Q2FKpvNVu6eKe6hAgAAuMF7qgzD0BNPPGH+aPKFCxf09NNPl/v23+rVq63rEAAAoBa4oVA1bNgwl+ePP/64pc0AAADUVjcUqt56662b1QcAAECt9qNuVAcAAMBlhCoAAAAL1PhQ9fXXX+vxxx9Xs2bN5O3trdDQUGVmZprjhmFo+vTpatGihby9vRUREaEjR4647CMvL08xMTHy8fGRn5+fYmNjdf78eZeavXv36v7775eXl5eCgoKUmJhYrpdVq1apffv28vLyUmhoqDZs2HBzThoAANQ6NTpUnTt3Tvfdd5/q16+vDz74QJ9//rnmzZunJk2amDWJiYlatGiRkpKSlJGRoYYNGyoyMlIXLlwwa2JiYrR//36lpqZq3bp12rJli0aMGGGOO51O9e3bV61bt1ZWVpbmzp2rmTNnaunSpWbNp59+qsGDBys2Nla7d+9WdHS0oqOjlZOTc2smAwAA1Gg2owav4Dlp0iRt375dW7durXDc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8ZOf/MSYPXt2uV7effdd46677jI8PDyMjh07GuvXr7f+hCvgdDqN0aNHG61atTK8vLyMO++805gyZYrLG+ftOA+bN2+u8G/BsGHDatw5V6YXq+fg6NGjV/17uXnz5ttmDq43DxWpKFTV1nmwGcYVy/wCAACgSrinCgAAwAKEKgAAAAsQqgAAACxAqAIAALAAoQoAAMAChCoAAAALEKoAAAAsQKgCAACwAKEKwG0rOTlZfn5+1XLsn//854qPj7/pxxkyZIheeeWVctuPHTummTNnltteXFys4OBgZWZm3vTegLqGUAWgRjp79qxGjhypVq1aydPTU4GBgYqMjNT27dtvaR8zZ86UzWaTzWaTu7u7goODNWbMGJ0/f/6ar1u9erVefPHFm9rbnj17tGHDBj333HOVfo2Hh4fGjRuniRMn3sTOgLrJvbobAICKDBgwQMXFxXr77bd15513Kjc3V2lpafrmm29ueS8dO3bURx99pIsXL2r79u166qmn9N133+nNN98sV1tcXCwPDw81bdr0pvf12muv6fe//70aNWpkbjt69KgSEhKUnp4up9OpFStW6Oc//7mSkpLMmpiYGI0dO1b79+9Xx44db3qfQF3BlSoANU5+fr62bt2qOXPm6KGHHlLr1q3Vs2dPTZ48Wb/5zW/Muvnz5ys0NFQNGzZUUFCQnnnmmeteQfr3v/+tbt26ycvLS3feeadeeOEFXbx48ZqvcXd3V2BgoFq2bKmBAwcqJiZGa9eulXT5SlaXLl3017/+VSEhIfLy8pJU/uO/oqIiTZw4UUFBQfL09FSbNm30t7/9zRzPycnRr371KzVq1EgBAQEaMmSI/vvf/161p0uXLul///d/9fDDD7tsHzp0qHJzc7VkyRI98cQTWrhwoZo1a+ZS06RJE913331asWLFNc8bwI0hVAGocRo1aqRGjRppzZo1Kioqumqdm5ubFi1apP379+vtt9/Wpk2bNGHChKvWb926VUOHDtXo0aP1+eef680331RycrJefvnlG+rP29tbxcXF5vMvvvhC//rXv7R69WplZ2dX+JqhQ4fqn//8pxYtWqQDBw7ozTffNK8w5efn6xe/+IW6du2qzMxMpaSkKDc3V3/4wx+u2sPevXtVUFCgHj16uGzfvXu34uLi1LVrV/n7+ysyMrLC8+vZs6e2bt16Q+cN4Nr4+A9AjePu7q7k5GQNHz5cSUlJ6tatmx588EENGjRIP/vZz8y6K68EBQcH66WXXtLTTz+tN954o8L9vvDCC5o0aZKGDRsmSbrzzjv14osvasKECZoxY0alesvKytLy5cv1i1/8wtxWXFysd955R3fccUeFrzl8+LDeffddpaamKiIiwjx2mcWLF6tr164uN5z//e9/V1BQkA4fPqy77rqr3D6PHz+uevXqyd/f32X7fffdpwULFqi0tPSa52G323X8+PHrnzCASuNKFYAaacCAATp16pTWrl2rfv366eOPP1a3bt2UnJxs1nz00Ufq06ePfvKTn6hx48YaMmSIvvnmG3333XcV7nPPnj3685//bF4Ja9SokYYPH67Tp09f9TWStG/fPjVq1Eje3t7q2bOnwsPDtXjxYnO8devWVw1UkpSdna169erpwQcfvGpfmzdvdumrffv2kqT//Oc/Fb7m+++/l6enp2w2m8v2ZcuWqVevXnr++ef18ssvKzw8XP/7v/9b7vXe3t7XPGcAN44rVQBqLC8vL/3yl7/UL3/5S02bNk1//OMfNWPGDD3xxBM6duyYfv3rX2vkyJF6+eWX1bRpU23btk2xsbEqLi5WgwYNyu3v/PnzeuGFF/TII49UeKyradeundauXSt3d3fZ7XZ5eHi4jDds2PCa5+Ht7X3N8fPnz+vhhx/WnDlzyo21aNGiwtc0b95c3333nXlj/JXbX3vtNY0dO1azZ89WcHCwBg4cqA8++EB9+/Y16/Ly8q4ZBAHcOEIVgFqjQ4cOWrNmjaTLH8OVlpZq3rx5cnO7fNH93Xffvebru3XrpkOHDqlNmzY3dFwPD48bfs2VQkNDVVpaqk8++cT8+O+Hff3rX/9ScHCw3N0r92e5S5cukqTPP//c/O8fCgwM1KRJk7Rq1Spt3brVJVTl5OSoa9euN3wuAK6Oj/8A1DjffPONfvGLX+gf//iH9u7dq6NHj2rVqlVKTEzUb3/7W0lSmzZtVFJSotdee01ffvml/t//+38uywZUZPr06XrnnXf0wgsvaP/+/Tpw4IBWrFihqVOn3tTzCQ4O1rBhw/TUU09pzZo1Onr0qD7++GMzBMbFxSkvL0+DBw/Wzp079Z///EcbN27Uk08+qUuXLlW4zzvuuEPdunXTtm3bXLbHxsZqx44dKiwsVFFRkVavXq39+/ere/fuLnU/DFkAfjxCFYAap1GjRgoLC9Orr76qBx54QJ06ddK0adM0fPhw816mzp07a/78+ZozZ446deqkZcuWadasWdfcb2RkpNatW6cPP/xQ99xzj3r16qVXX31VrVu3vunntGTJEj366KN65pln1L59ew0fPlyFhYWSLt80vn37dl26dEl9+/ZVaGio4uPj5efnZ16Fq8gf//hHLVu2zGWbv7+/nnrqKfXs2VNz587VuHHj9OKLLyo6OtqsSU9PV0FBgR599NGbcq5AXWUzDMOo7iYAADfu+++/V7t27bRy5UqFh4e7jB07dkzJyckV/lTNwIED1blzZz3//PO3qFOgbuBKFQDUUt7e3nrnnXeuuUjoDxUXFys0NFRjxoy5iZ0BdRNXqgAAACzAlSoAAAALEKoAAAAsQKgCAACwAKEKAADAAoQqAAAACxCqAAAALECoAgAAsAChCgAAwAKEKgAAAAv8f4g4XKxyi22QAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# View SalePrice distribution \n", - "df.SalePrice.plot.hist(xlabel=\"Sale Price ($)\");" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 1.1 Parsing dates\n", - "\n", - "When working with time series data, it's a good idea to make sure any date data is the format of a [datetime object](https://docs.python.org/3/library/datetime.html) (a Python data type which encodes specific information about dates).\n", - "\n", - "We can tell pandas which columns to read in as dates by setting the `parse_dates` parameter in [`pd.read_csv`](https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html).\n", - "\n", - "Once we've imported our CSV with the `saledate` column parsed, we can view information about our DataFrame again with `df.info()`. " - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "RangeIndex: 412698 entries, 0 to 412697\n", - "Data columns (total 53 columns):\n", - " # Column Non-Null Count Dtype \n", - "--- ------ -------------- ----- \n", - " 0 SalesID 412698 non-null int64 \n", - " 1 SalePrice 412698 non-null float64 \n", - " 2 MachineID 412698 non-null int64 \n", - " 3 ModelID 412698 non-null int64 \n", - " 4 datasource 412698 non-null int64 \n", - " 5 auctioneerID 392562 non-null float64 \n", - " 6 YearMade 412698 non-null int64 \n", - " 7 MachineHoursCurrentMeter 147504 non-null float64 \n", - " 8 UsageBand 73670 non-null object \n", - " 9 saledate 412698 non-null datetime64[ns]\n", - " 10 fiModelDesc 412698 non-null object \n", - " 11 fiBaseModel 412698 non-null object \n", - " 12 fiSecondaryDesc 271971 non-null object \n", - " 13 fiModelSeries 58667 non-null object \n", - " 14 fiModelDescriptor 74816 non-null object \n", - " 15 ProductSize 196093 non-null object \n", - " 16 fiProductClassDesc 412698 non-null object \n", - " 17 state 412698 non-null object \n", - " 18 ProductGroup 412698 non-null object \n", - " 19 ProductGroupDesc 412698 non-null object \n", - " 20 Drive_System 107087 non-null object \n", - " 21 Enclosure 412364 non-null object \n", - " 22 Forks 197715 non-null object \n", - " 23 Pad_Type 81096 non-null object \n", - " 24 Ride_Control 152728 non-null object \n", - " 25 Stick 81096 non-null object \n", - " 26 Transmission 188007 non-null object \n", - " 27 Turbocharged 81096 non-null object \n", - " 28 Blade_Extension 25983 non-null object \n", - " 29 Blade_Width 25983 non-null object \n", - " 30 Enclosure_Type 25983 non-null object \n", - " 31 Engine_Horsepower 25983 non-null object \n", - " 32 Hydraulics 330133 non-null object \n", - " 33 Pushblock 25983 non-null object \n", - " 34 Ripper 106945 non-null object \n", - " 35 Scarifier 25994 non-null object \n", - " 36 Tip_Control 25983 non-null object \n", - " 37 Tire_Size 97638 non-null object \n", - " 38 Coupler 220679 non-null object \n", - " 39 Coupler_System 44974 non-null object \n", - " 40 Grouser_Tracks 44875 non-null object \n", - " 41 Hydraulics_Flow 44875 non-null object \n", - " 42 Track_Type 102193 non-null object \n", - " 43 Undercarriage_Pad_Width 102916 non-null object \n", - " 44 Stick_Length 102261 non-null object \n", - " 45 Thumb 102332 non-null object \n", - " 46 Pattern_Changer 102261 non-null object \n", - " 47 Grouser_Type 102193 non-null object \n", - " 48 Backhoe_Mounting 80712 non-null object \n", - " 49 Blade_Type 81875 non-null object \n", - " 50 Travel_Controls 81877 non-null object \n", - " 51 Differential_Type 71564 non-null object \n", - " 52 Steering_Controls 71522 non-null object \n", - "dtypes: datetime64[ns](1), float64(3), int64(5), object(44)\n", - "memory usage: 166.9+ MB\n" - ] - } - ], - "source": [ - "df = pd.read_csv(filepath_or_buffer=\"../data/bluebook-for-bulldozers/TrainAndValid.csv\",\n", - " low_memory=False, # set low_memory=False to prevent mixed data types warning \n", - " parse_dates=[\"saledate\"]) # can use the parse_dates parameter and specify which column to treat as a date column\n", - "\n", - "# With parse_dates... check dtype of \"saledate\"\n", - "df.info()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Nice!\n", - "\n", - "Looks like our `saledate` column is now of type [`datetime64[ns]`](https://numpy.org/doc/stable/reference/arrays.scalars.html#numpy.datetime64), a NumPy-specific datetime format with high precision.\n", - "\n", - "Since pandas works well with NumPy, we can keep it in this format.\n", - "\n", - "How about we view a few samples from our `SaleDate` column again?" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0 2006-11-16\n", - "1 2004-03-26\n", - "2 2004-02-26\n", - "3 2011-05-19\n", - "4 2009-07-23\n", - "5 2008-12-18\n", - "6 2004-08-26\n", - "7 2005-11-17\n", - "8 2009-08-27\n", - "9 2007-08-09\n", - "Name: saledate, dtype: datetime64[ns]" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df[\"saledate\"][:10]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Beautiful! That's looking much better already. \n", - "\n", - "We'll see how having our dates in this format is really helpful later on.\n", - "\n", - "For now, how about we visualize our `saledate` column against our `SalePrice` column again?" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fig, ax = plt.subplots()\n", - "ax.scatter(x=df[\"saledate\"][:1000], # visualize the first 1000 values\n", - " y=df[\"SalePrice\"][:1000])\n", - "ax.set_xlabel(\"Sale Date\")\n", - "ax.set_ylabel(\"Sale Price ($)\");" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 1.2 Sorting our DataFrame by saledate\n", - "\n", - "Now we've formatted our `saledate` column to be NumPy `datetime64[ns]` objects, we can use built-in pandas methods such as `sort_values` to sort our DataFrame by date.\n", - "\n", - "And considering this is a time series problem, sorting our DataFrame by date has the added benefit of making sure our data is sequential.\n", - "\n", - "In other words, we want to use examples from the past (example sale prices from previous dates) to try and predict future bulldozer sale prices. \n", - "\n", - "Let's use the [`pandas.DataFrame.sort_values`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.sort_values.html) method to sort our DataFrame by `saledate` in ascending order." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(205615 1989-01-17\n", - " 274835 1989-01-31\n", - " 141296 1989-01-31\n", - " 212552 1989-01-31\n", - " 62755 1989-01-31\n", - " 54653 1989-01-31\n", - " 81383 1989-01-31\n", - " 204924 1989-01-31\n", - " 135376 1989-01-31\n", - " 113390 1989-01-31\n", - " Name: saledate, dtype: datetime64[ns],\n", - " 409202 2012-04-28\n", - " 408976 2012-04-28\n", - " 411695 2012-04-28\n", - " 411319 2012-04-28\n", - " 408889 2012-04-28\n", - " 410879 2012-04-28\n", - " 412476 2012-04-28\n", - " 411927 2012-04-28\n", - " 407124 2012-04-28\n", - " 409203 2012-04-28\n", - " Name: saledate, dtype: datetime64[ns])" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Sort DataFrame in date order\n", - "df.sort_values(by=[\"saledate\"], inplace=True, ascending=True)\n", - "df.saledate.head(10), df.saledate.tail(10)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Nice!\n", - "\n", - "Looks like our older samples are now coming first and the newer samples are towards the end of the DataFrame." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 1.3 Adding extra features to our DataFrame\n", - "\n", - "One way to potentially increase the predictive power of our data is to enhance it with more features.\n", - "\n", - "This practice is known as [**feature engineering**](https://en.wikipedia.org/wiki/Feature_engineering), taking existing features and using them to create more/different features. \n", - "\n", - "There is no set in stone way to do feature engineering and often it takes quite a bit of practice/exploration/experimentation to figure out what might work and what won't.\n", - "\n", - "For now, we'll use our `saledate` column to add extra features such as:\n", - "\n", - "* Year of sale\n", - "* Month of sale\n", - "* Day of sale\n", - "* Day of week sale (e.g. Monday = 1, Tuesday = 2)\n", - "* Day of year sale (e.g. January 1st = 1, January 2nd = 2)\n", - "\n", - "Since we're going to be manipulating the data, we'll make a copy of the original DataFrame and perform our changes there.\n", - "\n", - "This will keep the original DataFrame in tact if we need it again." - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [], - "source": [ - "# Make a copy of the original DataFrame to perform edits on\n", - "df_tmp = df.copy()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Because we imported the data using `read_csv()` and we asked pandas to parse the dates using `parase_dates=[\"saledate\"]`, we can now access the [different datetime attributes](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DatetimeIndex.html) of the `saledate` column.\n", - "\n", - "Let's use these attributes to add a series of different feature columns to our dataset. \n", - "\n", - "After we've added these extra columns, we can remove the original `saledate` column as its information will be dispersed across these new columns." - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [], - "source": [ - "# Add datetime parameters for saledate\n", - "df_tmp[\"saleYear\"] = df_tmp.saledate.dt.year\n", - "df_tmp[\"saleMonth\"] = df_tmp.saledate.dt.month\n", - "df_tmp[\"saleDay\"] = df_tmp.saledate.dt.day\n", - "df_tmp[\"saleDayofweek\"] = df_tmp.saledate.dt.dayofweek\n", - "df_tmp[\"saleDayofyear\"] = df_tmp.saledate.dt.dayofyear\n", - "\n", - "# Drop original saledate column\n", - "df_tmp.drop(\"saledate\", axis=1, inplace=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We could add more of these style of columns, such as, whether it was the start or end of a quarter (the sale being at the end of a quarter may bye influenced by things such as quarterly budgets) but these will do for now.\n", - "\n", - "> **Challenge:** See what other [datetime attributes](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DatetimeIndex.html) you can add to `df_tmp` using a similar technique to what we've used above. Hint: check the bottom of the [`pandas.DatetimeIndex` docs](https://pandas.pydata.org/docs/reference/api/pandas.DatetimeIndex.html).\n", - "\n", - "How about we view some of our newly created columns?" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - "
SalePricesaleYearsaleMonthsaleDaysaleDayofweeksaleDayofyear
2056159500.01989117117
27483514000.01989131131
14129650000.01989131131
21255216000.01989131131
6275522000.01989131131
\n", - "
" - ], - "text/plain": [ - " SalePrice saleYear saleMonth saleDay saleDayofweek saleDayofyear\n", - "205615 9500.0 1989 1 17 1 17\n", - "274835 14000.0 1989 1 31 1 31\n", - "141296 50000.0 1989 1 31 1 31\n", - "212552 16000.0 1989 1 31 1 31\n", - "62755 22000.0 1989 1 31 1 31" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# View newly created columns\n", - "df_tmp[[\"SalePrice\", \"saleYear\", \"saleMonth\", \"saleDay\", \"saleDayofweek\", \"saleDayofyear\"]].head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Cool!\n", - "\n", - "Now we've broken our `saledate` column into columns/features, we can perform further exploratory analysis such as visualizing the `SalePrice` against the `saleMonth`.\n", - "\n", - "How about we view the first 10,000 samples (we could also randomly select 10,000 samples too) to see if reveals anything about which month has the highest sales?" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# View 10,000 samples SalePrice against saleMonth\n", - "fig, ax = plt.subplots()\n", - "ax.scatter(x=df_tmp[\"saleMonth\"][:10000], # visualize the first 10000 values\n", - " y=df_tmp[\"SalePrice\"][:10000])\n", - "ax.set_xlabel(\"Sale Month\")\n", - "ax.set_ylabel(\"Sale Price ($)\");" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Hmm... doesn't look like there's too much conclusive evidence here about which month has the highest sales value.\n", - "\n", - "How about we plot the median sale price of each month?\n", - "\n", - "We can do so by grouping on the `saleMonth` column with [`pandas.DataFrame.groupby`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.groupby.html) and then getting the median of the `SalePrice` column." - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAk0AAAGwCAYAAAC0HlECAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAABuT0lEQVR4nO3dd3hTZfsH8G9Gk66kpZQ2LW2hUEZLSykbQRRBKktQXwcOFNertirUl/WqOFDqeB0/FcXFcKCgUmQIWMuWIggUKLRlU6ATCkmb7uT8/igJRFbSJj1J+v1cVy6b5MnJnRND7pznOfctEQRBABERERFdk1TsAIiIiIhcAZMmIiIiIiswaSIiIiKyApMmIiIiIiswaSIiIiKyApMmIiIiIiswaSIiIiKyglzsANyF0WhEQUEBVCoVJBKJ2OEQERGRFQRBQHl5OUJDQyGVXvtYEpMmOykoKEB4eLjYYRAREVEjnDx5EmFhYdccw6TJTlQqFYCGna5Wq0WOhoiIiKyh0+kQHh5u/h6/FiZNdmKaklOr1UyaiIiIXIw1S2u4EJyIiIjICkyaiIiIiKzApImIiIjICkyaiIiIiKzApImIiIjICkyaiIiIiKzApImIiIjICkyaiIiIiKzApImIiIjICkyaiIiIiKwgatKUmpqKPn36QKVSISgoCOPGjUNeXt5l4zIzM3HLLbfAx8cHarUagwcPRlVVlfn+srIyPPDAA1Cr1fD398djjz2GiooKi23s3bsXN954Izw9PREeHo533nnnsuf56aef0LVrV3h6eiIuLg6//fab/V80ERERuSRRk6aNGzciKSkJ27ZtQ3p6Ourq6jB8+HDo9XrzmMzMTNx2220YPnw4tm/fjh07diA5ORlS6cXQH3jgAezfvx/p6elYuXIlNm3ahCeffNJ8v06nw/Dhw9GuXTvs3LkT7777Ll599VV88cUX5jFbt27F+PHj8dhjj2H37t0YN24cxo0bh+zs7ObZGUREROTUJIIgCGIHYVJaWoqgoCBs3LgRgwcPBgD0798ft956K2bNmnXFx+Tk5CAmJgY7duxA7969AQBr1qzByJEjcerUKYSGhuKzzz7Diy++iKKiIigUCgDA9OnTsWzZMuTm5gIA7r33Xuj1eqxcudK87f79+6NHjx6YO3fudWPX6XTw8/ODVqu1a8Peytp6lOlr7bY9R5FLpQhWK61qeEhEROQsbPn+ljdTTFbRarUAgICAAABASUkJ/vrrLzzwwAO44YYbcOTIEXTt2hVvvvkmBg0aBKDhSJS/v785YQKAYcOGQSqV4q+//sIdd9yBzMxMDB482JwwAUBiYiLefvttnDt3Dq1atUJmZiZSUlIs4klMTMSyZcuuGGtNTQ1qamrM13U6nV32wT/9kVOC537Y7ZBt29vjgyLx0ugYscMgIiJyCKdZCG40GjFp0iQMHDgQsbGxAICjR48CAF599VU88cQTWLNmDXr27ImhQ4fi0KFDAICioiIEBQVZbEsulyMgIABFRUXmMcHBwRZjTNevN8Z0/z+lpqbCz8/PfAkPD2/Ky78qmUQCpVzq1BeFrOF/oz9yih2yD4iIiJyB0xxpSkpKQnZ2NrZs2WK+zWg0AgD+/e9/Y+LEiQCAhIQEZGRkYN68eUhNTRUlVgCYMWOGxZEpnU7nkMRpVPcQjOoeYvft2tOZihr0fuMPnCirhL6mHj5Kp/nfioiIyG6c4tstOTnZvIA7LCzMfHtISEOyEBNjOeUTHR2N/Px8AIBGo0FJSYnF/fX19SgrK4NGozGPKS62PApiun69Mab7/0mpVEKpVNr0Ot1VoK8SbVRKlJbXIK+4HD0jWokdEhERkd2JOj0nCAKSk5ORlpaGdevWITIy0uL+9u3bIzQ09LIyBAcPHkS7du0AAAMGDMD58+exc+dO8/3r1q2D0WhEv379zGM2bdqEuro685j09HR06dIFrVq1Mo/JyMiweJ709HQMGDDAfi/YjUWHNCyeyyl0zNouIiIisYmaNCUlJeG7777DokWLoFKpUFRUhKKiInMNJolEgilTpuCjjz7Czz//jMOHD+Pll19Gbm4uHnvsMQANR51uu+02PPHEE9i+fTv+/PNPJCcn47777kNoaCgA4P7774dCocBjjz2G/fv3Y/Hixfi///s/i+m1559/HmvWrMF7772H3NxcvPrqq/j777+RnJzc/DvGBUWHqAAwaSIiIjcmiAjAFS/z58+3GJeamiqEhYUJ3t7ewoABA4TNmzdb3H/27Flh/Pjxgq+vr6BWq4WJEycK5eXlFmP27NkjDBo0SFAqlULbtm2Ft95667J4lixZInTu3FlQKBRCt27dhFWrVln9WrRarQBA0Gq11u8AN7Js9ymh3bSVwp2f/il2KERERFaz5fvbqeo0uTJH1WlyFXlF5Uj8cBN8FDLsezURUinrNRERkfOz5fvbaUoOkGvr0MYHCpkU+loDTp6rFDscIiIiu2PSRHbhIZOiU7AvAK5rIiIi98Skiezm4hl05SJHQkREZH9MmshuWHaAiIjcGZMmshtz2YEiJk1EROR+mDSR3URrGo40nSyrQnl13XVGExERuRYmTWQ3rXwU0Kg9AQC5RVzXRERE7oVJE9kVK4MTEZG7YtJEdsXF4ERE5K6YNJFdsewAERG5KyZNZFempCmvqBwGIzv0EBGR+2DSRHYVGegDpVyKqjoDTpzVix0OERGR3TBpIruSSSXoojEtBucUHRERuQ8mTWR3pnpNXAxORETuhEkT2R3LDhARkTti0kR2Z1oMzgKXRETkTpg0kd11vZA0nT5fBW0l26kQEZF7YNJEdufn5YG2/l4A2LyXiIjcB5MmcghWBiciInfDpIkcgovBiYjI3TBpIodgOxUiInI3TJrIIcztVIrLUW8wihwNERFR0zFpIodoF+ANb4UMtfVGHGc7FSIicgNMmsghpJe0UznAKToiInIDTJrIYXgGHRERuRMmTeQw0RqeQUdERO6DSRM5DI80ERGRO2HSRA5jaqdSrKtBmb5W5GiIiIiahkkTOYyvUo6IAG8AQC6PNhERkYtj0kQOZaoMfoBJExERuTgmTeRQrAxORETugkkTORQXgxMRkbtg0kQOFa1pSJoOl1Sgju1UiIjIhTFpIocKa+UFX6UctQYjjpRWiB0OERFRozFpIoeSSiXoyiKXRETkBpg0kcOZ1jXlcjE4ERG5MCZN5HCmpIllB4iIyJUxaSKHM9VqYtkBIiJyZUyayOG6aFSQSIAzFTUoLa8ROxwiIqJGYdJEDuetkKN9ax8AXAxORESui0kTNYuLU3RMmoiIyDUxaaJmYSpyyaSJiIhcFZMmahbmsgNFXAxORESuiUkTNYvo0IvtVGrqDSJHQ0REZDsmTdQsQv08ofaUo94o4HAJ26kQEZHrETVpSk1NRZ8+faBSqRAUFIRx48YhLy/PYszNN98MiURicXnqqacsxvzzfolEgh9//NFizIYNG9CzZ08olUpERUVhwYIFl8UzZ84ctG/fHp6enujXrx+2b99u99fcUkkkEnQNMa1r4hQdERG5HlGTpo0bNyIpKQnbtm1Deno66urqMHz4cOj1eotxTzzxBAoLC82Xd95557JtzZ8/32LMuHHjzPcdO3YMo0aNwpAhQ5CVlYVJkybh8ccfx9q1a81jFi9ejJSUFLzyyivYtWsX4uPjkZiYiJKSEoe9/pYmJoSLwYmIyHXJxXzyNWvWWFxfsGABgoKCsHPnTgwePNh8u7e3NzQazTW35e/vf9Uxc+fORWRkJN577z0AQHR0NLZs2YIPPvgAiYmJAID3338fTzzxBCZOnGh+zKpVqzBv3jxMnz690a+RLmLZASIicmVOtaZJq9UCAAICAixu//777xEYGIjY2FjMmDEDlZWVlz02KSkJgYGB6Nu3L+bNmwdBEMz3ZWZmYtiwYRbjExMTkZmZCQCora3Fzp07LcZIpVIMGzbMPOafampqoNPpLC50bdGXHGm69P0hIiJyBaIeabqU0WjEpEmTMHDgQMTGxppvv//++9GuXTuEhoZi7969mDZtGvLy8rB06VLzmNdffx233HILvL298fvvv+OZZ55BRUUFnnvuOQBAUVERgoODLZ4vODgYOp0OVVVVOHfuHAwGwxXH5ObmXjHe1NRUvPbaa/Z6+S1C52AVpBLgXGUdSsprEKz2FDskIiIiqzlN0pSUlITs7Gxs2bLF4vYnn3zS/HdcXBxCQkIwdOhQHDlyBB07dgQAvPzyy+YxCQkJ0Ov1ePfdd81JkyPMmDEDKSkp5us6nQ7h4eEOez534OkhQ4c2vjhcUoEDhTomTURE5FKcYnouOTkZK1euxPr16xEWFnbNsf369QMAHD58+JpjTp06hZqahuawGo0GxcXFFmOKi4uhVqvh5eWFwMBAyGSyK4652joppVIJtVptcaHri+ZicCIiclGiJk2CICA5ORlpaWlYt24dIiMjr/uYrKwsAEBISMg1x7Rq1QpKpRIAMGDAAGRkZFiMSU9Px4ABAwAACoUCvXr1shhjNBqRkZFhHkP20VVjWgzOsgNERORaRJ2eS0pKwqJFi/Drr79CpVKhqKgIAODn5wcvLy8cOXIEixYtwsiRI9G6dWvs3bsXkydPxuDBg9G9e3cAwIoVK1BcXIz+/fvD09MT6enpmD17Nv7zn/+Yn+epp57CJ598gqlTp+LRRx/FunXrsGTJEqxatco8JiUlBQ8//DB69+6Nvn374sMPP4RerzefTUf2wbIDRETksgQRAbjiZf78+YIgCEJ+fr4wePBgISAgQFAqlUJUVJQwZcoUQavVmrexevVqoUePHoKvr6/g4+MjxMfHC3PnzhUMBoPFc61fv17o0aOHoFAohA4dOpif41Iff/yxEBERISgUCqFv377Ctm3brH4tWq1WAGARG12u8HyV0G7aSiFy+kqhqrZe7HCIiKiFs+X7WyIIPPfbHnQ6Hfz8/KDVarm+6RoEQUDPWek4V1mHFcmDEBfmJ3ZIRETUgtny/e0UC8Gp5ZBIJFwMTkRELolJEzU7U9J0gEkTERG5ECZN1OwunkHHpImIiFwHkyZqdmynQkRErohJEzW7TsG+kEsl0FXXo0BbLXY4REREVmHSRM1OKZehYxtfAEAup+iIiMhFMGkiUUSHcF0TERG5FiZNJIqL65rYToWIiFwDkyYSBWs1ERGRq2HSRKLoemF67thZPSpr60WOhoiI6PqYNJEoglSeCPRVQBCAvCJO0RERkfNj0kSi4bomIiJyJUyaSDSmpCm3iOuaiIjI+TFpItGw7AAREbkSJk0kGvORpsJytlMhIiKnx6SJRNMh0BceMgnKa+px6lyV2OEQERFdE5MmEo1CLkVUUMMU3QFO0RERkZNj0kSi4romIiJyFUyaSFQxrAxOREQugkkTiepi2QHWaiIiIufGpIlEZUqaTpytREUN26kQEZHzYtJEogrwUSBYrQQA5LHIJREROTEmTSS6rpqGo00H2E6FiIicGJMmEl00F4MTEZELYNJEomPZASIicgVMmkh0prIDeUXlMBrZToWIiJwTkyYSXWSgDxRyKSprDcgvqxQ7HCIioiti0kSik8uk6BLMKToiInJuTJrIKXBdExEROTsmTeQUWHaAiIicHZMmcgosO0BERM6OSRM5BdMZdKfPV0FbVSdyNERERJdj0kROwc/bA6F+ngAaSg8QERE5GyZN5DQ4RUdERM5MbsvgnJwc/Pjjj9i8eTNOnDiByspKtGnTBgkJCUhMTMRdd90FpVLpqFjJzUWHqJGRW8KkiYiInJJVR5p27dqFYcOGISEhAVu2bEG/fv0wadIkzJo1Cw8++CAEQcCLL76I0NBQvP3226ipqXF03OSGurLsABEROTGrjjTdddddmDJlCn7++Wf4+/tfdVxmZib+7//+D++99x7++9//2itGaiFM03N5xeUwGAXIpBKRIyIiIrrIqqTp4MGD8PDwuO64AQMGYMCAAair49lPZLv2rX3g6SFFdZ0Rx87oERXkK3ZIREREZlZNz1mTMDVlPBEAyKQSdLlQ5DK3iFN0RETkXJp89twff/yBV155BStWrLBHPNTCxXBdExEROSmbkqZnnnkGL7/8svn6L7/8gttuuw2rVq3Cvffei/fff9/uAVLLcrHsAGs1ERGRc7EpaVq/fj0GDx5svv7+++9j9uzZ+Pvvv/Hdd9/h008/tXuA1LKwVhMRETkrqxaCv/baawCA/Px8/Prrr8jMzIQgCNixYwfi4+Px+uuvo7q6Gvn5+Xj99dcBADNnznRc1OS2umgapucKtdU4X1kLf2+FyBERERE1sCppeuSRRwAAc+fOxa233ooePXpg8+bN0Gg0mD59OgRBgF6vx0cffYRHHnkEgiA4MmZyY2pPD4S18sKpc1U4UKjDDR0DxQ6JiIgIgJXTc+3atUO7du3Qv39/vPvuu9i6dSs+/vhj3HHHHYiIiEC7du2g1+sRGRlpvk7UWFzXREREzsimNU0ffPABJBIJnnzySQQEBOCVV14x3/f5559jzJgxNj15amoq+vTpA5VKhaCgIIwbNw55eXkWY26++WZIJBKLy1NPPWUxJj8/H6NGjYK3tzeCgoIwZcoU1NfXW4zZsGEDevbsCaVSiaioKCxYsOCyeObMmYP27dvD09MT/fr1w/bt2216PWQfpqQpl+uaiIjIidjUe659+/bYvHnzFe/76quvbH7yjRs3IikpCX369EF9fT3++9//Yvjw4Thw4AB8fHzM45544gnzWikA8Pb2Nv9tMBgwatQoaDQabN26FYWFhZgwYQI8PDwwe/ZsAMCxY8cwatQoPPXUU/j++++RkZGBxx9/HCEhIUhMTAQALF68GCkpKZg7dy769euHDz/8EImJicjLy0NQUJDNr40az1x2gLWaiIjIiUgEJ1qAVFpaiqCgIGzcuNF8lt7NN9+MHj164MMPP7ziY1avXo3Ro0ejoKAAwcHBABrWXk2bNg2lpaVQKBSYNm0aVq1ahezsbPPj7rvvPpw/fx5r1qwBAPTr1w99+vTBJ598AgAwGo0IDw/Hs88+i+nTp183dp1OBz8/P2i1WqjV6qbshhbvxFk9bnp3AxRyKQ68lgi5rMnlxIiIiK7Ilu9vq76N3nrrLVRVVVn15H/99RdWrVpl1dh/0mq1AICAgACL27///nsEBgYiNjYWM2bMQGVlpfm+zMxMxMXFmRMmAEhMTIROp8P+/fvNY4YNG2axzcTERGRmZgIAamtrsXPnTosxUqkUw4YNM4/5p5qaGuh0OosL2Ud4K2/4KGSorTfi6Bm92OEQEREBsDJpOnDgACIiIvDMM89g9erVKC0tNd9XX1+PvXv34tNPP8UNN9yAe++9FyqVyuZAjEYjJk2ahIEDByI2NtZ8+/3334/vvvsO69evx4wZM/Dtt9/iwQcfNN9fVFRkkTABMF8vKiq65hidToeqqiqcOXMGBoPhimNM2/in1NRU+Pn5mS/h4eE2v2a6MqlUYi49wHpNRETkLKxa0/TNN99gz549+OSTT3D//fdDp9NBJpNBqVSaj/okJCTg8ccfxyOPPAJPT0+bA0lKSkJ2dja2bNlicfuTTz5p/jsuLg4hISEYOnQojhw5go4dO9r8PPYyY8YMpKSkmK/rdDomTnYUHaLGrvzzOFCow9gebcUOh4iIyPqF4PHx8fjyyy/x+eefY+/evThx4gSqqqoQGBiIHj16IDCw8fV0kpOTsXLlSmzatAlhYWHXHNuvXz8AwOHDh9GxY0doNJrLznIrLi4GAGg0GvN/TbddOkatVsPLywsymQwymeyKY0zb+CelUgmlUmn9iySbsOwAERE5G5tX2EqlUvTo0QNjx47Ffffdh2HDhjU6YRIEAcnJyUhLS8O6desQGRl53cdkZWUBAEJCQgAAAwYMwL59+1BSUmIek56eDrVajZiYGPOYjIwMi+2kp6djwIABAACFQoFevXpZjDEajcjIyDCPoebFsgNERORsRD0tKSkpCd999x0WLVoElUqFoqIiFBUVmRedHzlyBLNmzcLOnTtx/PhxLF++HBMmTMDgwYPRvXt3AMDw4cMRExODhx56CHv27MHatWvx0ksvISkpyXwk6KmnnsLRo0cxdepU5Obm4tNPP8WSJUswefJkcywpKSn48ssvsXDhQuTk5ODpp5+GXq/HxIkTm3/HELpqVJBIgJLyGpytqBE7HCIiIkAQEYArXubPny8IgiDk5+cLgwcPFgICAgSlUilERUUJU6ZMEbRarcV2jh8/LowYMULw8vISAgMDhRdeeEGoq6uzGLN+/XqhR48egkKhEDp06GB+jkt9/PHHQkREhKBQKIS+ffsK27Zts/q1aLVaAcBlsVHj3fTOOqHdtJXC5oOlYodCRERuypbvb6eq0+TKWKfJ/p76difW7C/CiyOj8cTgDmKHQ0REbsjudZqIxHBxMTjXNRERkfganTQdPnwYa9euNa8/4gErsrfoC+1UDjBpIiIiJ2Bz0nT27FkMGzYMnTt3xsiRI1FYWAgAeOyxx/DCCy/YPUBquUxHmo6UVqC23ihyNERE1NLZnDRNnjwZcrkc+fn5Fo1z7733XnMfNyJ7CGvlBZWnHHUGAUdKK8QOh4iIWjibk6bff/8db7/99mVFKDt16oQTJ07YLTAiiUSCaA3XNRERkXOwOWnS6/UWR5hMysrKWCGb7M60rolJExERic3mpOnGG2/EN998Y74ukUhgNBrxzjvvYMiQIXYNjqgr26kQEZGTsLr3nMk777yDoUOH4u+//0ZtbS2mTp2K/fv3o6ysDH/++acjYqQW7NKyA4IgQCKRiBwRERG1VDYfaYqNjcXBgwcxaNAgjB07Fnq9HnfeeSd2796Njh07OiJGasG6BKsglQBn9bUoLWc7FSIiEo/NR5oAwM/PDy+++KK9YyG6jJdChvaBPjhaqkdOUTmC1J5ih0RERC2UzUea5s+fj59++umy23/66ScsXLjQLkERXYqVwYmIyBnYnDSlpqYiMDDwstuDgoIwe/ZsuwRFdKkYJk1EROQEbE6a8vPzERkZednt7dq1Q35+vl2CIrpUVw3LDhARkfhsTpqCgoKwd+/ey27fs2cPWrdubZegiC51sZ2KHtV1BpGjISKilsrmpGn8+PF47rnnsH79ehgMBhgMBqxbtw7PP/887rvvPkfESC1ciJ8n/Lw8YDAKOFzCdipERCQOm8+emzVrFo4fP46hQ4dCLm94uNFoxIQJE7imiRxCIpEgOkSFbUfLkFOoQ2xbP7FDIiKiFsjmpEmhUGDx4sWYNWsW9uzZAy8vL8TFxaFdu3aOiI8IQMMUXUPSxMrgREQkjkbVaQKAzp07o3PnzvaMheiqWHaAiIjEZlXSlJKSglmzZsHHxwcpKSnXHPv+++/bJTCiS5nLDhSxnQoREYnDqqRp9+7dqKurAwDs2rXrql9Y/CIjR4kK8oVMKsH5yjoU6aoR4ucldkhERNTCWJU0rV+/3vz3hg0bHBUL0VV5esjQIdAHh0oqkFOoY9JERETNzqaSA3V1dZDL5cjOznZUPERXdXFdExeDExFR87MpafLw8EBERAQMBhYYpObHxeBERCQmm4tbvvjii/jvf/+LsrIyR8RDdFXRIWynQkRE4rG55MAnn3yCw4cPIzQ0FO3atYOPj4/F/bt27bJbcESXMp1Bd+xMQzsVTw+ZyBEREVFLYnPSNHbsWJ4lR6Joo1IiwEeBMn0t8orKER/uL3ZIRETUgticNL366qsOCIPo+kztVP48fBY5hTomTURE1KysXtOk1+vx9NNPo23btmjTpg3uu+8+lJaWOjI2ostEa7gYnIiIxGF10vTyyy/j22+/xejRo3H//fdj3bp1ePLJJx0ZG9FlzGfQFbHsABERNS+rp+fS0tIwf/583H333QCACRMmoH///qivr4dc3ugWdkQ2ubTsANupEBFRc7L6SNOpU6cwcOBA8/VevXrBw8MDBQUFDgmM6EqignzhIZOgvLoep89XiR0OERG1IFYnTUajER4eHha3yeVyFrqkZqWQS9GxjS8AVgYnIqLmZfW8miAIGDp0qMVUXGVlJcaMGQOFQmG+jXWayNGiQ9TILSpHTqEOt8YEix0OERG1EFYnTa+88splt40dO9auwRBZIzpEhbTdPIOOiIiaV5OSJiIxsAcdERGJwebec0RiMyVNJ8oqoa+pFzkaIiJqKZg0kcsJ9FWijUoJQQDyirkYnIiImgeTJnJJnKIjIqLmxqSJXFJ0iAoAkyYiImo+TUqaqqur7RUHkU0u9qDj9BwRETUPm5Mmo9GIWbNmoW3btvD19cXRo0cBNPSm+/rrr+0eINGVmKbncgt1MBoFkaMhIqKWwOak6Y033sCCBQvwzjvvWBS1jI2NxVdffWXX4IiupkMbHyhkUuhrDTh5rlLscIiIqAWwOWn65ptv8MUXX+CBBx6ATCYz3x4fH4/c3Fy7Bkd0NR4yKToFs50KERE1H5uTptOnTyMqKuqy241GI+rq6uwSFJE1eAYdERE1J5uTppiYGGzevPmy23/++WckJCTYJSgiazBpIiKi5mRz0jRz5kwkJyfj7bffhtFoxNKlS/HEE0/gzTffxMyZM23aVmpqKvr06QOVSoWgoCCMGzcOeXl5VxwrCAJGjBgBiUSCZcuWWdwnkUguu/z4448WYzZs2ICePXtCqVQiKioKCxYsuOw55syZg/bt28PT0xP9+vXD9u3bbXo91LyiNRfKDhQxaSIiIsezOWkaO3YsVqxYgT/++AM+Pj6YOXMmcnJysGLFCtx66602bWvjxo1ISkrCtm3bkJ6ejrq6OgwfPhx6vf6ysR9++CEkEslVtzV//nwUFhaaL+PGjTPfd+zYMYwaNQpDhgxBVlYWJk2ahMcffxxr1641j1m8eDFSUlLwyiuvYNeuXYiPj0diYiJKSkpsek3UfExHmk6WVaG8mlPDRETkWBJBEJzmfO3S0lIEBQVh48aNGDx4sPn2rKwsjB49Gn///TdCQkKQlpZmkRRJJJLLbrvUtGnTsGrVKmRnZ5tvu++++3D+/HmsWbMGANCvXz/06dMHn3zyCYCGNVrh4eF49tlnMX369OvGrtPp4OfnB61WC7Va3YhXT43Rf3YGinTV+OmpAejTPkDscIiIyMXY8v3tVBXBtVotACAg4OKXX2VlJe6//37MmTMHGo3mqo9NSkpCYGAg+vbti3nz5uHSXDAzMxPDhg2zGJ+YmIjMzEwAQG1tLXbu3GkxRiqVYtiwYeYx/1RTUwOdTmdxoeZnqgyey3VNRETkYHJrBrVq1eqaU2OXKisra1QgRqMRkyZNwsCBAxEbG2u+ffLkybjhhhswduzYqz729ddfxy233AJvb2/8/vvveOaZZ1BRUYHnnnsOAFBUVITg4GCLxwQHB0On06Gqqgrnzp2DwWC44pirlVFITU3Fa6+91qjXSvYTHaLG+rxSHGDZASIicjCrkqYPP/zQwWE0HCnKzs7Gli1bzLctX74c69atw+7du6/52Jdfftn8d0JCAvR6Pd59911z0uQIM2bMQEpKivm6TqdDeHi4w56Proxn0BERUXOxKml6+OGHHRpEcnIyVq5ciU2bNiEsLMx8+7p163DkyBH4+/tbjL/rrrtw4403YsOGDVfcXr9+/TBr1izU1NRAqVRCo9GguLjYYkxxcTHUajW8vLwgk8kgk8muOOZqU4JKpRJKpdL2F0t2ZUqa8orKYTAKkEmtOyJKRERkqyY37G3Kuh5BEJCcnIy0tDSsW7cOkZGRFvdPnz4de/fuRVZWlvkCAB988AHmz59/1e1mZWWhVatW5qRmwIAByMjIsBiTnp6OAQMGAAAUCgV69eplMcZoNCIjI8M8hpxT+9beUMqlqKoz4MTZy8+6JCIisherjjRdSq/XY9q0aViyZAnOnj172f0Gg8HqbSUlJWHRokX49ddfoVKpUFRUBADw8/ODl5cXNBrNFY/0REREmBOsFStWoLi4GP3794enpyfS09Mxe/Zs/Oc//zGPf+qpp/DJJ59g6tSpePTRR7Fu3TosWbIEq1atMo9JSUnBww8/jN69e6Nv37748MMPodfrMXHiRKtfDzU/uUyKLhoV9p7SIqewHB3a+IodEhERuSvBRs8884wQHR0t/Pzzz4KXl5cwb948YdasWUJYWJjw3Xff2bQtAFe8zJ8//5qPSUtLM19fvXq10KNHD8HX11fw8fER4uPjhblz5woGg8HicevXrxd69OghKBQKoUOHDld8jo8//liIiIgQFAqF0LdvX2Hbtm1WvxatVisAELRardWPIfuY+tMeod20lcK7a3LFDoWIiFyMLd/fNtdpioiIwDfffIObb74ZarUau3btQlRUFL799lv88MMP+O233+yc1rkG1mkSz4I/j+HVFQcwLDoIXz3cR+xwiIjIhTi0TlNZWRk6dOgAAFCr1eYSA4MGDcKmTZsaES5R01w8g45lB4iIyHFsTpo6dOiAY8eOAQC6du2KJUuWAGhYW/TPs9yImkPXC0nT6fNV0FaynQoRETmGzUnTxIkTsWfPHgANZ7fNmTMHnp6emDx5MqZMmWL3AImux8/LA239vQCweS8RETmOzWfPTZ482fz3sGHDkJOTY17X1L17d7sGR2St6BAVTp+vQk6hDv07tBY7HCIickM2J03/1L59e7Rv394OoRA1XnSIGn/klLAyOBEROYzV03OZmZlYuXKlxW3ffPMNIiMjERQUhCeffBI1NTV2D5DIGqbF4LlFXAxORESOYXXS9Prrr2P//v3m6/v27cNjjz2GYcOGYfr06VixYgVSU1MdEiTR9VzaTqXeYBQ5GiIickdWJ01ZWVkYOnSo+fqPP/6Ifv364csvv0RKSgo++ugj85l0RM2tXYA3vBUy1NQbcZztVIiIyAGsTprOnTuH4OBg8/WNGzdixIgR5ut9+vTByZMn7RsdkZWkUgm6aFQAgAOs10RERA5gddIUHBxsrs9UW1uLXbt2oX///ub7y8vL4eHhYf8IiazUVWMqcsnF4EREZH9WJ00jR47E9OnTsXnzZsyYMQPe3t648cYbzffv3bsXHTt2dEiQRNaICWk40sSkiYiIHMHqkgOzZs3CnXfeiZtuugm+vr5YuHAhFAqF+f558+Zh+PDhDgmSyBoX26kwaSIiIvuzOmkKDAzEpk2boNVq4evrC5lMZnH/Tz/9BF9fX7sHSGQtUzuVYl0NyvS1CPBRXOcRRERE1rO5jYqfn99lCRMABAQEWBx5Impuvko5IgK8AQC5PNpERER2ZnPSROTMokNMZ9AxaSIiIvti0kRu5eK6JpYdICIi+2LSRG6FZQeIiMhRmDSRW4m5cKTpcEkF6thOhYiI7Mjqs+cudejQIaxfvx4lJSUwGi2/mGbOnGmXwIgaI6yVF3yVclTU1ONIaYX5yBMREVFT2Zw0ffnll3j66acRGBgIjUYDiURivk8ikTBpIlFJpRJ01ajw94lzyC0sZ9JERER2Y3PS9MYbb+DNN9/EtGnTHBEPUZNFh6jx94lzyCnUYVxCW7HDISIiN2HzmqZz587h7rvvdkQsRHZhOoOOZQeIiMiebE6a7r77bvz++++OiIXILrqae9Cx7AAREdmPzdNzUVFRePnll7Ft2zbExcXBw8PD4v7nnnvObsERNUZXjQoSCXCmogal5TVoo1KKHRIREbkBiSAIgi0PiIyMvPrGJBIcPXq0yUG5Ip1OBz8/P2i1WqjVXHwstiH/24BjZ/T45tG+GNy5jdjhEBGRk7Ll+9vmI03Hjh1rdGBEzSU6RIVjZ/TILdIxaSIiIrtgcUtyS9EatlMhIiL7alRxy1OnTmH58uXIz89HbW2txX3vv/++XQIjaoqLPeh4Bh0REdmHzUlTRkYGbr/9dnTo0AG5ubmIjY3F8ePHIQgCevbs6YgYiWwWHXqxnUpNvQFKuUzkiIiIyNXZPD03Y8YM/Oc//8G+ffvg6emJX375BSdPnsRNN93E+k3kNEL9PKH2lKPeKOBwSYXY4RARkRuwOWnKycnBhAkTAAByuRxVVVXw9fXF66+/jrffftvuARI1hkQiQdcQrmsiIiL7sTlp8vHxMa9jCgkJwZEjR8z3nTlzxn6RETVRDNc1ERGRHdm8pql///7YsmULoqOjMXLkSLzwwgvYt28fli5div79+zsiRqJGib5QGTy3iEkTERE1nc1J0/vvv4+KioY1Iq+99hoqKiqwePFidOrUiWfOkVOJvmR6ThAESCQSkSMiIiJXZnPS1KFDB/PfPj4+mDt3rl0DIrKXzsEqSCVAmb4WJeU1CFZ7ih0SERG5MBa3JLfl6SFDZKAPAOAA1zUREVETWXWkKSAgAAcPHkRgYCBatWp1zWmOsrIyuwVH1FTRIWocKdUjp1CHIV2CxA6HiIhcmFVJ0wcffACVqmFR7YcffujIeIjsKjpEjZV7C1l2gIiImsyqpOnhhx++4t9Ezs5UdiCX03NERNREViVNOp31XzhqtbrRwRDZm+kMuqNn9KiuM8DTg+1UiIiocaxKmvz9/a0+XdtgMDQpICJ7ClYr0crbA+cq63CouAJxYX5ih0RERC7KqqRp/fr15r+PHz+O6dOn45FHHsGAAQMAAJmZmVi4cCFSU1MdEyVRI0kkEkSHqLH1yFnkFOqYNBERUaNZlTTddNNN5r9ff/11vP/++xg/frz5tttvvx1xcXH44osvuOaJnE5XTUPSxLIDRETUFDbXacrMzETv3r0vu713797Yvn27XYIisidTOxX2oCMioqawOWkKDw/Hl19+edntX331FcLDw+0SFJE9RV/SuFcQBJGjISIiV2Vz0vTBBx/g448/RlxcHB5//HE8/vjj6N69Oz7++GN88MEHNm0rNTUVffr0gUqlQlBQEMaNG4e8vLwrjhUEASNGjIBEIsGyZcss7svPz8eoUaPg7e2NoKAgTJkyBfX19RZjNmzYgJ49e0KpVCIqKgoLFiy47DnmzJmD9u3bw9PTE/369eORMzfRKdgXcqkEuup6FGqrxQ6HiIhclM1J08iRI3Hw4EGMGTMGZWVlKCsrw5gxY3Dw4EGMHDnSpm1t3LgRSUlJ2LZtG9LT01FXV4fhw4dDr9dfNvbDDz+84hl8BoMBo0aNQm1tLbZu3YqFCxdiwYIFmDlzpnnMsWPHMGrUKAwZMgRZWVmYNGkSHn/8caxdu9Y8ZvHixUhJScErr7yCXbt2IT4+HomJiSgpKbHpNZHzUcpl6NjGFwCn6IiIqPEkghPNV5SWliIoKAgbN27E4MGDzbdnZWVh9OjR+PvvvxESEoK0tDSMGzcOALB69WqMHj0aBQUFCA4OBgDMnTsX06ZNQ2lpKRQKBaZNm4ZVq1YhOzvbvM377rsP58+fx5o1awAA/fr1Q58+ffDJJ58AAIxGI8LDw/Hss89i+vTp141dp9PBz88PWq2Wtaqc0KQfd2NZVgH+M7wzkm/pJHY4Lq2q1gBPD6nVZUjIdVXXGaCU871uqvOVtaioqb/+QBHJpVIEq5Ut8r225fvbqrPn/mnz5s34/PPPcfToUfz0009o27Ytvv32W0RGRmLQoEGNChoAtFotgIZedyaVlZW4//77MWfOHGg0mssek5mZibi4OHPCBACJiYl4+umnsX//fiQkJCAzMxPDhg2zeFxiYiImTZoEAKitrcXOnTsxY8YM8/1SqRTDhg1DZmbmFWOtqalBTU2N+botBUCp+UWHqLEsqwDZp/k+NcXfx8tw3xfbcH+/CLw+NlbscMiBth09iwe++gtJQ6KQcmtnscNxWZsOluLh+dvhPIcnrm7CgHb8XF+HzdNzv/zyCxITE+Hl5YVdu3aZEwetVovZs2c3OhCj0YhJkyZh4MCBiI29+KZNnjwZN9xwA8aOHXvFxxUVFVkkTADM14uKiq45RqfToaqqCmfOnIHBYLjiGNM2/ik1NRV+fn7mCxfBO7e+kQ2J+MaDpdA7+S8+Z7Zg63HUGwV8k3kCfx09K3Y45EDz/zwGg1HAgj+PoaaeRYsba+HW4xAEQC6VQCmXOu0FAL7JPIFVewtF3mPOzeYjTW+88Qbmzp2LCRMm4McffzTfPnDgQLzxxhuNDiQpKQnZ2dnYsmWL+bbly5dj3bp12L17d6O36ygzZsxASkqK+bpOp2Pi5MR6hPsjMtAHx87osSa7CHf1ChM7JJejrarD7weKzddfWpaN356/ER4ym397kZM7p6/FutyG9Zy66nqsyynBiLgQkaNyPWcqarDhYCkAYM2kwYgK8hU5oqt7e00uPttwBNOX7kX3MD+EB3iLHZJTsvlfu7y8PIv1RiZ+fn44f/58o4JITk7GypUrsX79eoSFXfwyW7duHY4cOQJ/f3/I5XLI5Q053l133YWbb74ZAKDRaFBcXGyxPdN103Te1cao1Wp4eXkhMDAQMpnsimOuNCUIAEqlEmq12uJCzksikeCOhLYAgKW7T4kcjWtava8QtfVGtG/tjQAfBQ6VVGDelmNih0UOsHJvAeoMF+eTftl1WsRoXNfyrAIYjALiw/ycOmECgJRbOyMhwh/l1fV47sfdqDMYxQ7JKdmcNGk0Ghw+fPiy27ds2YIOHTrYtC1BEJCcnIy0tDSsW7cOkZGRFvdPnz4de/fuRVZWlvkCNJQ9mD9/PgBgwIAB2Ldvn8VZbunp6VCr1YiJiTGPycjIsNh2enq6uQ2MQqFAr169LMYYjUZkZGSYx5DrMyVNW4+cRaG2SuRoXM/SC1+c9/aJwIwRXQEAH/5xCAXnuS/djSlJGt+34ej5hrwSnK2oudZD6ApMP9Du7On8R7Y9ZFJ8dF8CVJ5y7M4/jw/SD4odklOyOWl64okn8Pzzz+Ovv/6CRCJBQUEBvv/+e/znP//B008/bdO2kpKS8N1332HRokVQqVQoKipCUVERqqoa/hHWaDSIjY21uABARESEOcEaPnw4YmJi8NBDD2HPnj1Yu3YtXnrpJSQlJUGpVAIAnnrqKRw9ehRTp05Fbm4uPv30UyxZsgSTJ082x5KSkoIvv/wSCxcuRE5ODp5++mno9XpMnDjR1l1ETio8wBt9IwMgCMCy3QVih+NSTpZVYvvxMkgkwLiEUPyrVxj6tg9AVZ0Br684IHZ4ZEdHSyuQdfI8ZFIJUm7tgri2fqg3CljJtS42OVhcjuzTOsilEoyJDxU7HKuEB3jjrTu7AwA+23gEWw6dETki52Nz0jR9+nTcf//9GDp0KCoqKjB48GA8/vjj+Pe//41nn33Wpm199tln0Gq1uPnmmxESEmK+LF682OptyGQyrFy5EjKZDAMGDMCDDz6ICRMm4PXXXzePiYyMxKpVq5Ceno74+Hi89957+Oqrr5CYmGgec++99+J///sfZs6ciR49eiArKwtr1qy5bHE4ubY7TVN0u06xOrgN0nY3HHm4oWNrhPh5QSKRYNa4WMikEqzZX4T1uaxn5i5M7/XgToFoo1Lizp4XPzNkPdOR2Zu7BCHARyFyNNYb1T0E4/tGQBCAyUuycIZHGC00uk5TbW0tDh8+jIqKCsTExMDX17nnax2NdZpcg666Dr3f+AO19UasSB6EuDA/sUNyeoIgYMj/NuD42Uq8d3e8xSL62b/l4ItNRxER4I3fJw+Gp4dMxEipqYxGATe+sx6nz1fh4/EJGBMfijMVNeg/OwP1RgF/pNzk9GtznIHBKGDgW+tQpKvGZw/0dLlF9FW1BoydswUHiytwU+c2mP9IH0il7lu/yZbv70af9qJQKBATE4O+ffu2+ISJXIfa0wPDYxqOHnJBuHV2nzyP42cr4eUhw22xlidGPD+0EzRqT+SXVeLT9ZevdSTXsuN4GU6fr4JKKcetFz4ngb5K3NS5DQAgjZ8Zq2w7ehZFumqoPeW4JTpI7HBs5qWQ4ePxPaGUS7HxYCm+2nJU7JCchtUlBx599FGrxs2bN6/RwRA1hzt7tsXKvYVYnlWA/46M5inz12GalrktVgMfpeU/GT5KOV4ZE4Onv9+FuRuPYlxCW3Rowx9Rrso0pTQyLsTiqOGdPcOQkVuCtF2n8cKtXdz6qIM9/HLhMzM6PhRKuWsefe2iUWHmmBi8mJaNd9bkoV9ka8SH+4sdluis/rZYsGAB1q9fj/Pnz+PcuXNXvRA5uxs7tUGgrwJn9bXYdKGGCl1ZTb0BK/Y0LAA2rW35p9tiNbipcxvUGoyY+et+rhVzUdV1Bqzad+X3emh0EFSechRoq7HtGIuaXktlbT3WZDcURb7rKp8ZV3F/3wiMjNOg3ijg2R92o7y6TuyQRGd10vT0009Dq9Xi2LFjGDJkCL7++mukpaVddiFydh4yKW6PN9VsYv2Za1mfWwptVR2C1Urc0DHwimMkEgleH9sNCrkUWw6fMX/xkmv5/UAxKmrq0dbfC33aB1jc5+khw+juDety0liz6ZrW7i9CZa0B7Vp7o2dEK7HDaRKJRILUO7ujrb8X8ssq8WJadov/UWR10jRnzhwUFhZi6tSpWLFiBcLDw3HPPfdg7dq1LX4nkusx/ZJOP1AMbRV/PV2NaWpuXEJbyK4xJdOutQ+Sbo4CALy+4gB/kbqgtF2mmkJtrzj9Zqo19Nu+QlTVsq3K1ZimOO9IaOsWzW/9vDzw0fgEyKQSLN9TgJ92tux1bTYt5lAqlRg/fjzS09Nx4MABdOvWDc888wzat2+PiooKR8VIZHfdQtXoHOyL2nojfuORkSsq09difV5DKYE7E65fnO/fN3VA+9beKCmvwYd/HHJ0eGRHJeXV2HShJo+pCOw/9W7XCuEBXtDXGvD7gSv35GzpirTV2HK4YT9a85lxFb3atTI3bX7l1/04XFIuckTiafQKWKlUColEAkEQYDDwVwe5FolEYv7lzOmGKzO10ugWqkYXjeq64z09ZOYO6Qu2HseBAp2jQyQ7MbX7SIjwv+pC/oZWRA2fGbZVubJfs05DEIA+7VshorV79W57+qaOGBjVGlV1BiQv2o3qupb5vW9T0lRTU4MffvgBt956Kzp37ox9+/bhk08+QX5+PssOkMsZ16MtJBJg+/Ey5J+tFDscp2OaZrClBcTgzm0wKi4EBqOAl5btg9HIqXtXYCpoeedVjjKZmO7fcqgUJbpqh8flSgRBMJ815wptU2wllUrwwT090NpHgdyicqT+liN2SKKwOml65plnEBISgrfeegujR4/GyZMn8dNPP2HkyJGQSnnKNrkejZ8nBl5Y3JzGBeEWjlzSSuN2G1tAvDw6Bj4KGXbln8dPO086KEKyl9wiHfYX6OAhk2B092u/1+0DfdCrXSsYBeDXLLYiutT+Ah0OFldAIZdipIsVs7RWkNoT790TDwBYmHkCa/e3vGlaq7OduXPnQq1Wo0OHDti4cSOefPJJ3HnnnZddiFyJaUF42m62VbmUacrS1ErDFho/T0y+sP4hdXUuyvS1do+P7Mf0Xt/SNQitrGj3YfrM/MK2KhZMR2ZvjQ6Gn5eHyNE4zs1dgvDEjQ29X6f+vLfFNey2OmmaMGEChgwZAn9/f/j5+V31QuRKErtp4K2Q4fjZSuzKPy92OE7BaBQuTtc0cprhkRvao6tGhfOVdXhnTa49wyM7MhgFLMsyne1l3Xs9Oi4UCpkUuUXlXLd2Qb3BiOV7TJ8Z167NZI0piV3RPcwP2qo6PP/jbtQbjGKH1Gysrgi+YMECB4ZBJA4fpRy3ddNg6e7TWLrrFHq1c+26Kvaw/QqtNGwll0nxxrhY/GtuJn7ccRJ39w7nvnVCW4+cQbGuBv7eHhjStY1Vj/Hz9sDQ6CCszi5C2u5TiAmNcXCUzm/zoTM4U1GL1j4KDO5s3X50ZQq5FB+PT8Coj7Zgx/Fz+GjdYfPZde6Oi5GoxTMdTVm5txA19S3zjJBLmWoz/bOVhq16tw/APb0b9u1Ly7Jb1K9RV2GaUhrT3bZ2H6bPzLKsAr6vuDhVOSY+tMW0ZWrX2gdv3tFwtuwn6w4h80jLqBTfMt5domsY0LE1NGpPaKvqsD63ROxwRFVdZ8Bv+xoWd9pjmmH6iGj4e3sgp1CHhZknmrw9sh99zcV2H3fY+F7f1LkNWnl7oLS8Bn+2kC/Lq9FV1yH9QDEA4C43PGvuWsb2aIu7e4XBKACTFu9uEesXmTRRiyeTSjA2oeGsoZZef8bUSiOs1eWtNBojwEeBabd1BQC8/3seirQ8Td1ZrMkuQlWdAZGBPkiwsRGrQi41n1W5tIUvCF+9rxA19UZEBfkitq1a7HCa3Wtju6FDGx8U62ow5ac9bn9CDZMmIlys3rs+t6RF/Fq6GtMX4B0JV26l0Rj39g5HQoQ/9LUGvLHqgF22SU23dPeFmkKNbPdhmqJbu7+oRbfN+WXXxQXg7tA2xVbeCjk+Hp8AhVyKjNwSzP/zuNghORSTJiIAXTQqxLZVo94oYOXelll/pqS8GpsOlgK4eiuNxpBKJXhjXCykkoZ1Y5sPldpt29Q4hdoqbL0wrTauke919zA/dGjjg+o6I1Znt7x6PQBwsqwS24+VQSJpKJbbUnUL9cOLI6MBAG+tzkX2aa3IETkOkyaiC+5s4S0ilmcVwCjgmq00GqtbqB8evqE9AGDmr/u54F5ky3YXQBCAvpEBCA9oXLsPiURiXsPTUlsRLbtQmuOGjq0R6u8lcjTimjCgHW6NCUatwYhnf9iNipp6sUNyCCZNRBfc3iMUMqkEe06ex5HSlteA2tw2xY5HmS6VcmtnBKmUOHZGjy82HnXIc9D1CYJgnoa9q4mL/U1HqTKPnsWpcy2rFZEgCFi627YaV+5MIpHg3X91R4ifJ46d0WPmr9lih+QQTJqILgj0VeKmCzVWWtov59wiHQ4UWtdKo7FUnh54aXRDTZ9P1h9mvz+RZJ/W4VBJBZRyKUY0sd1HW38v9O/QcMJAS2urknXyPI6d0cPLQ4bbYjVih+MU/L0V+L/7EiCVNPwIS9vtficJMGkiusTFtiqnW1SzWVtbaTTWmO4hGBjVGjX1RryyPNvtz7RxRqYF4LfGBEPt2fR2H6YF4Ut3taxWRKYjs7fFauCrtLpOtNvrGxmA54c2FLp8KS0bx87oRY7Ivpg0EV1iWHQwVEo5Tp+vwl/HysQOp1kYLmmb4uhpBolEglljY6GQSbE+rxRr9xc79PnIUp3BiOUXjgjZq6bQiFgNPD2kOFKqx95T7rsA+FI19QasuHDCiD1PmnAXybdEoV9kAPS1Bjz7wy63WsPIpInoEp4eMozq3jBl4Y6Hlq/kz8NnUFJuWyuNpujQxhf/vqkDAOD1Ffuhd9MFo85o08FSnNXXItBXgRs7BdplmypPDyR2a5ieaik1m9bnluJ8ZR2CVEoMjLLPfnQnMqkEH97XA628PZB9Wod31uSJHZLdMGki+gfTdMNv+4pQVes+v5CuxnSUydZWGk2RNCQK4QFeKNBW46N1h5rlOenilNLt8W0ht2O7D9PRlhV7C1Fb7/5tVUw/qO5IaAuZneqZuZsQPy+8+694AMDXW45hXa57HFVm0kT0D73btUJYKy9U1NTj9wPuXX+mogmtNJrC00OGV8d0AwB8vfkYDhaXN9tzt1Taqjqk5zR8cdmjRc6lBkUFoo1KiTJ9LTYedO86XOf0tVh3od1Sc35mXNGwmGA8cqHUyH9+2otinet3BGDSRPQPUqnEfNr9Ujc/i64prTSaamh0MIbHBKPeKOClZVwU7mi/7Ws4CtQlWIVuofZt9yGXSTGuR8toq7JybwHqDAJiQtToqml5bVNsNWNkV3QLVaNMX4tJP2bB4OIn2DBpIrqCOy5M0W0+VIqSctf/dXQ1pi+4xrbSaKqZY2Lg5SHD9mNlbp+gis38Xjuo3YfpJIKMnBJoK923rYqpNpO9j9a5K6Vcho/HJ8BbIUPm0bP4dP1hsUNqEiZNRFcQGeiDnhH+MAown23kbgrOVyHzaNNaaTRVWCtvPDe0EwBg9m85bv1lK6b8s5XYcfwcJJKGzvSOEBOqRleNCrUGI1buc8/PzNHSCuzOPw+ppKEYLlmnQxtfzBobCwD4MOMQdhx33TOTmTQRXYXpaJO7tlVZlnW6ya007OGxQZHoFOSLs/pavPt7rmhxuDPTYv9BUYHQ+Hk67HnuMtdscs/PjGk/Du7cBkEqx+1Hd3RXrzDckdAWBqOA53/YjfOVrtkYnUkT0VWM6R4CD5kEOYU65BTqxA7HrhpaaTR8ATS1lUZTKeRSzBrX8Cv0+7/ysefkeVHjcTcN7T4uTs050tgeoZBKgJ0nzuG4mxU1NF5Sz+xOO9W4amlmjYtF+9beKNBWY9ove11yHSOTJqKr8PdWYGjXYAAXf2G6i+zTOhy2UysNe+jfoTXuTGgLQQBeWpbt8otFncmu/HM4cbYS3gqZuZ6SowSpPTGo04VWRG72mdlxvAynzlVBpZRjeEyw2OG4JF+lHB+P7wkPmQRr9xfju7/yxQ7JZkyaiK7BdErxst2n3eqL/Jdd9m2lYQ8zRkZD5SnHvtNaLPrrhNjhuI1L2314Kxzf7sN05HLpbvdqq2LajyPiNPD0aJ56Zu4oLswP027rCgCYtfKAyx3FZ9JEdA1DugTB39sDJeU1+PPwGbHDsYs6gxEr9ti3lYY9tFEpMTWxCwDgnbV5bn3WYnOpqTc0+3s9PEYDH4UMJ8uq8PeJc83ynI5WXWfAb/sKAXBqzh4eGxSJW7oGobbeiGd/2I3KWtfpCsCkiegaFHIpbo93r/ozjmilYS/392uH7mF+KK+uR+pvXBTeVOtySqCrrodG7Yn+HVo3y3N6KWTmKV93WRCefqAY5TX1aOvvhb7tA8QOx+VJJBK8+6/uCFIpcbikAq8tPyB2SFZj0kR0HaYWEWv2F6HCDfqkOaqVhj3IpBK8MS4WEknDmpjMI2fFDsmlmWoKjWvmdh+mBecr9xagus71WxGZfjDdkdAWUrZNsYvWvkp8eF8PSCTA4r9Pmo+IOjvn+heTyAn1CPdHh0AfVNcZzS1HXJW20nGtNOyle5g/HuzXDgDw8q/ZLaKXmSOU6Wux/kK7j+Z+r/tHtkaonyfKq+uRkVPSrM9tb6XlNdh0qGFqnm1T7OuGjoFIHhIFAPjv0n3IP1spckTXx6SJ6DokEon5S8fVp+hWObCVhj39Z3gXBPoqcLikAl9vOSZ2OC5pxZ4C1BsFxLX1Q+dgVbM+t1QqMRdMdfXPzPI9BTAYBfQI90fHNr5ih+N2nh/aCb3btUJ5TT2e/XE36gzO/SOJSRORFUxVlDOPnsXp81UiR9N4absd20rDXvy8PfDfkdEAgI8yDuHUOef/BepsTFNzd4hU7d30Q2PjwVKcqagRJQZ7uLT9DNmfXCbF/41PgNpTjj0nz+N/v+eJHdI1MWkiskJ4gDf6RQZAEBrKD7iiE2f1Dm+lYU93JLRF38gAVNUZ8NoK11ko6gwOl1Rgz8nzkEklorX7iApSIT7MD/VGwWXWq/xTXlE59hfo4CGTYHR3tk1xlLb+XnjnX/EAgM83HsWmg6UiR3R1TJqIrGQ6ZTtt92mXrD/TXK007EUiaVgULpdKkH6gGH8cKBY7JJdhOqJ4c+c2CPRVihbHHeYpOtf8oWGqpD6kSxACfBQiR+PebovV4MH+EQCAlCVZTltyhEkTkZVGxGmglEtxuKQC+05rxQ7HJoJwaQsI5z/KZNI5WIXHb+wAAHh1xX5U1br+mViOZjQKWLa74ciO2AuXx8SHQi6VYN9pLQ4Vl4sai60MRsF8VJm1mZrHS6Ni0FWjwpmKWrywZA+MTlhQmEkTkZVUnh4YfqENhav9cm7OVhr29tzQKIT6eeLUuSrMWX9Y7HCc3l/HynD6fBVUnnIMixa33UdrXyVu7hIE4OIaK1ex9cgZFOtq4OflgSFd24gdTovg6SHDJ/cnwNNDis2HzuDzTUfFDukyTJqIbGA6SrN8T4HTn+VxqV+auZWGPXkr5Hjl9m4AgM83HcGR0gqRI3JupoXLo7uHOEW7jzsvaUXkjEcOribtwmdmTHwIlHLx92NLERWkwmsXPu/v/Z6H3fnOVVWeSRORDW6MCkSgrxJl+lpszHPexYqXqqk3YKUTtk2xxfCYYNzSNQh1BgEzf812yTVlzaGq9mK7jzsSnOO9vqVrENSechRqq7HtqGsUK9XX1GP1hZpsnJprfvf0Dsfo7iGoNwp49ofd0FbViR2SGZMmIhvIZVKMvXA2kmmRqLMTo5WGvUkkErw6phuUcin+PHwWK/YWih2SU/r9QBH0tQaEB3ihd7tWYocDoGHKZfSFVkS/uMi09prsIlTVGRAZ6IOEcH+xw2lxJBIJZt8Zh/AAL5w6V4X/pu1zmh9KoiZNqamp6NOnD1QqFYKCgjBu3Djk5VnWaPj3v/+Njh07wsvLC23atMHYsWORm2vZk0oikVx2+fHHHy3GbNiwAT179oRSqURUVBQWLFhwWTxz5sxB+/bt4enpiX79+mH79u12f83k+kzTDX/klEBb6Ty/gK7G9EXV3K007C2itbe5evCslQegq3b+fd/cTGvt7kgIc6p2H3deOItudXahSzRnTbukxpUz1zNzZ2pPD3x0XwLkUglW7S3E4h0nxQ4JgMhJ08aNG5GUlIRt27YhPT0ddXV1GD58OPR6vXlMr169MH/+fOTk5GDt2rUQBAHDhw+HwWB5Fs38+fNRWFhovowbN85837FjxzBq1CgMGTIEWVlZmDRpEh5//HGsXbvWPGbx4sVISUnBK6+8gl27diE+Ph6JiYkoKXHtFgBkfzEhanTVqFBbb8Sqfc59xONsRQ025InTSsMRnrypAzoE+qC0vAbv/35Q7HCcSomuGpsPNUwZ3ylSQcur6dWuFSICvFFZa8Da/c7diqhQW4U/j1xom+Jk+7GlSYhohf8kdgHQcPasM5yBKWrStGbNGjzyyCPo1q0b4uPjsWDBAuTn52Pnzp3mMU8++SQGDx6M9u3bo2fPnnjjjTdw8uRJHD9+3GJb/v7+0Gg05oun58U6NHPnzkVkZCTee+89REdHIzk5Gf/617/wwQcfmMe8//77eOKJJzBx4kTExMRg7ty58Pb2xrx58xy+H8i1SCSSS+rPOPcU3cq9hag3Cohtq272VhqOoJTL8PrYWADAN5nHke1ipR8cafmeAhgFoGeEP9oH+ogdjgXLVkTOPUW3bHcBBAHo2z4A4QHeYofT4j15Ywfc2CkQ1XVGJC/aLXoDaKda06TVNvwDGBAQcMX79Xo95s+fj8jISISHh1vcl5SUhMDAQPTt2xfz5s2zmP/MzMzEsGHDLMYnJiYiMzMTAFBbW4udO3dajJFKpRg2bJh5zD/V1NRAp9NZXKjlGJfQFlIJ8PeJczhxVn/9B4jE3ALCSRYF28OgToEYEx8KowC8tCzbpc7IciTTNKyzLlw2/dD48/AZFGmds3ChIAhsm+JkpFIJ3r+nBwJ9lcgrLscbq8TtDuA0SZPRaMSkSZMwcOBAxMbGWtz36aefwtfXF76+vli9ejXS09OhUFyszvr6669jyZIlSE9Px1133YVnnnkGH3/8sfn+oqIiBAdb1isJDg6GTqdDVVUVzpw5A4PBcMUxRUVXPpScmpoKPz8/8+WfSRy5t2C1JwZGBQK4uP7B2RwuqcCeU1pRW2k4ykujouGrlCPr5Hks/ts51jqI6UCBDjmFOihkUozuHiJ2OFfUrrUPerdrBaMA/JrlnJ+Z/QU6HCqpgEIuxUgn3Y8tURuVEu/fEw+JBFDIZKL+UHKapCkpKQnZ2dmXLeAGgAceeAC7d+/Gxo0b0blzZ9xzzz2orr74S+Xll1/GwIEDkZCQgGnTpmHq1Kl49913HRrvjBkzoNVqzZeTJ/kPd0tjOn1/6S7nbKviLK00HCFY7YmUWzsDAN5anYuzLtwQ1h5M7/UtXYPg7+287T7udPLPzC8XjjINjwmG2tND5GjoUoM7t8EfKTdh5pgYUU9ycIqkKTk5GStXrsT69esRFnb5oWU/Pz906tQJgwcPxs8//4zc3FykpaVddXv9+vXDqVOnUFPT8A+pRqNBcbFl36ri4mKo1Wp4eXkhMDAQMpnsimM0mitXT1YqlVCr1RYXalmGdwuGt0KG/LJK7DzhXAXYjEbBXJxP7FYajjJhQDvEhKihrarDW6tzr/8AN1VvMGJZVkMdLmefUhoVFwKFXIq84nIcKHSuJQ11BiOWu8h+bKk6tvEVOwRxkyZBEJCcnIy0tDSsW7cOkZGRVj1GEARzQnQlWVlZaNWqFZTKhl/XAwYMQEZGhsWY9PR0DBgwAACgUCjQq1cvizFGoxEZGRnmMUT/5K2QY0RswyF8Z2sRse3YWRRoq52ilYajyGVSvHFHw1T+TztPYcfxMpEjEsefR86itLwGrbw9zC1LnJWftweGRV9oq+JkC8I3HyrFWX0tAn0VuLET26bQlYmaNCUlJeG7777DokWLoFKpUFRUhKKiIlRVVQEAjh49itTUVOzcuRP5+fnYunUr7r77bnh5eWHkyJEAgBUrVuCrr75CdnY2Dh8+jM8++wyzZ8/Gs88+a36ep556CkePHsXUqVORm5uLTz/9FEuWLMHkyZPNY1JSUvDll19i4cKFyMnJwdNPPw29Xo+JEyc2704hl3LXhV+kK/cUiH5Wx6VMR5mcpZWGo/SMaIXxfRvWE76Ulu1SrW3sxbRweUx8KBRyp5g8uCbTSQm/ZhWg3oneL9NC+tvj28JD5vz7kcQh6v8Zn332GbRaLW6++WaEhISYL4sXLwYAeHp6YvPmzRg5ciSioqJw7733QqVSYevWrQgKavi14uHhgTlz5mDAgAHo0aMHPv/8c7z//vt45ZVXzM8TGRmJVatWIT09HfHx8Xjvvffw1VdfITEx0Tzm3nvvxf/+9z/MnDkTPXr0QFZWFtasWXPZ4nCiS/Xv0Bohfp7QVddjXa5z1PRyxlYajjQ1sStaeXsgr7gcC7ceFzucZlVRU2+ue+SsZ839001d2iDAR4EzFTXYfPiM2OEAALRVdUg/0LA8g1NzdC2idu683kLA0NBQ/Pbbb9ccc9ttt+G222677nPdfPPN2L179zXHJCcnIzk5+brbIjKRSiUYl9AWn204gqW7TmNknPhn3DhjKw1HauWjwIwR0Zj6y158kH4Qo7qHIMTPS+ywmsXqfYWorjOiQxsfxIf5iR2OVTxkUtweH4oFW49j6a7TGOIEU4qr9xWitt6IzsG+6BbK9al0dTwGSdREpurLG/JKnOIsrl+ctJWGI/2rVxh6tWsFfa0Bb6zMETucZmNaF3RXzzCXavdhOprz+/4ip2iHs/SSGleutB+p+TFpImqiTsEqxLX1Q71RwIo9BaLGUqKrxpYLrTRaUgsIqVSCN8bFQiaVYNW+Qmw8WCp2SA53+nwVMo+eBQBzE2lXEdfWD1FBvqipN2LNPnHbqpwsq8T242WQSFxvP1LzY9JEZAemX85iF7r8NetiK41IJ2ul4WjRIWo8ckN7AMArv2Y71cJ8R1h24f+1/h0CENbKtdp9XNqK6BeRWxGZPrMDOwa2mGldajwmTUR2MCY+FHKpBHtOaXG4RLymkr+YW0C4xqJge5t8a2cEq5U4frYSH6S7b0Nfy3Yfrvlej0toC4kE+OtYGU6WVYoSA9umkK2YNBHZQaCvEjd3aajtIlb9mQMFOuQWlTt1Kw1H81XK8eqYbgCAzzcdxbeZx8UNyEH2ntLiSKkeSrkUI2KvXIDX2bX198KADq0BiNdWZVf+eRw/WwkvDxkSu7nmfqTmxaSJyE5Mp/cv231alN5IrtJKw9FGxIVg0rBOAICZy/eLvs7MEUxTSondNFC5cLsP0xSdWG1VTJ+ZEbEa+ChFPZmcXASTJiI7GRodBJWnHAXaamw7drZZn9uVWmk0h+eHdsJD/dtBEICUJVnYfMh9FobX1huxfI97vNcj4kLg6SHF0TN6ZJ0836zPXVNvwIo9DfXMXHWKk5ofkyYiO/H0kGF094azb5p7is6VWmk0B4lEgldv74ZR3UNQZxDw7293Yk8zfyk7ysaDpSjT1yLQV4lBUYFih9Mkvko5brswLdbcJ1Gszy2BtqoOGrUnBnRs3azPTa6LSRORHZl++a/eV4iq2uY7e8vVWmk0B5lUgvfvicegqEBU1hrwyPztOFxSIXZYTWaaUhrXIxRyN2j3YTrKs3xPAWrrm6+tiqme2diEUMhaSD0zajrX/8QROZHe7VohPMAL+loDfj/QPPVnyqvrXK6VRnNRymWY+1AvxIf54VxlHSZ8/RcKtVVih9Vo2so6/HGgoV2Pu7zXA6MCEaRS4nxlHdbnNU8rojJ9LTZceK47W0CrIbIfJk1EdiSRSMz/CP/STFN0q7OLXK6VRnPyVcox75E+6NDGBwXaajz09Xac09eKHVajrNxXgFqDEV01KsS4SbsP2YVWRMDFI6aOtnJvAeoMAmLbqtFFo2qW5yT3wKSJyM5MZwRtOVSKEl21w58vzdQCIqEtW0BcRWtfJb55tC80ak8cLqnAowt3oLK2XuywbHax3YdrLwD/J9PrWZdbgvOVjk9oL201RGQLJk1EdtY+0Ae92rWCUWio0O1Ip85VmltpjGtBbVMaI6yVN755rC/8vDywO/88nv5uV7OuoWmqE2f12HniHKQSYGwP93qvu2rUiA5Ro84gYMXeQoc+15HSCuw5eR4yqQS3x7NtCtmGSRORA5h+OTu6RYQpKXPFVhpi6ByswrxH+sDLQ4aNB0sx5ec9otTUagzTUaZBndogWO0pcjT2d1fP5pmiMx2ZvalzG7RRKR36XOR+mDQROcDouFAoZFLkFpXjQIHOIc9h0QKC0wxW69WuFT59sCfkUgl+zSrA6ysPiFJY0RaCIJhPyb/TTY8o3t4jFFIJsDv/PI6d0TvkOYzGi/uxJTW0Jvth0kTkAH7eHhga3VAvyXSKuL1ZtNKIYwsIWwzpEoT/3R0PAFiw9Tg+3XBE5IiubeeJc8gvq4SPQobh3YLFDschglSeuLFTQyuiNAcdbdp+vAynz1dBpZTj1hj33I/kWEyaiBzEdEr4sqwC1Bvsv3bGdJTJ1VtpiGVcQlvMHB0DAHh3bR5+2J4vckRXZ1q4PCIuBN4K9233YZrWXuqgVkSmz8yo7iHw9JDZffvk/pg0ETnITZ3bIMBHgdLyGmw5fMau266tN5oXzLrbmVTN6dFBkUgeEgUAeDFtH9ZkO3YRcmNU1xmwcu+FtiluPqU0PEYDX6Ucp85V4e8T5+y67apaA37bx3pm1DRMmogcRCGXYkz3EAD2bxHhTq00xPbC8M4Y3zccRgF47ocsbD1i3wS3qdbllqC8uh6hfp7o38G92314KWQYEdsw1WzvBeHpOcWoqKlHWCsv9G7Xyq7bppaDSRORA5l+0a7dX4Ty6jq7bdf0heIurTTEJJFI8Ma4ONzWTYNagxFPfrMT2ae1YodlZn6vE9pC2gLafZg+M6v2FqK6zn6tiC6eNNEy9iM5Bv+1JXKg7mF+6NjGB9V1RqzOtk9bFW1lHTJy3KuVhthkUgk+vK8H+ncIQEVNPR6et91hZ3DZ4kxFDTbklQJoOdOw/SID0NbfC+U19Ug/UGyXbZaUV2PTwYb9eAc/M9QETJqIHEgikZgTmzQ7tVVxx1YazsDTQ4YvJ/RGt1A1zupr8dDXf6G4GSq6X8uKPQWoNwroHuaHqKCW0e5DKpWYywHYa1p7eVYBjAKQEOGPyEAfu2yTWiYmTUQOZqrUnXn0LE6dq2zy9ty1lYYzUHl6YMHEvmjf2hunzlVhwtfboa2037Sqrdy9NtPV3HHh/+2NB0tRWl7T5O1d/MzwKBM1DZMmIgdr6++FARcW8Da1rcrxM+7bSsNZtFEp8e1j/dBGpURecTkeW7gDVbX2W1tjrUPF5dh7Sgu5VIIxLazdR8c2vogP94fBKGD5nqZ9ZnIKdThQqIOHTGI+MYOosZg0ETWDOy5pq9KU6tOmIw8DowLdspWGswgP8MY3j/aFylOOv0+cQ/KiXahzQK2ta1l64b2+uUsbtPZtee0+TG1Vmloc1vSZuaVrEPy9FU2Oi1o2Jk1EzWBErAaeHlIcLdVj76nGnZklCAKWXvgCuYvTDA4XHaLG1w/3gVIuRUZuCab/sq/Z+tQZjQKW7W7ZU0qju4dCLpUg+7QOeUXljdqGgfuR7IxJE1EzUHl6ILFb0+rP/H3iHE6WVbl1Kw1n0zcyAHPu7wmZVIJfdp3CW2tym+V5tx09i0JtNdSectzSNahZntPZBPgoMOTCa1/ayKNNfx4+g5LyGvh7e2BIl5a5H8m+mDQRNRPTL93lewpQW2/7VM/SFtJKw9kMiwnG23d1BwB8sekoPt/o+D51prYpo7qHtuh2H6Ypul93F8DQiKN8ph8ot8eHQiHn1x01Hf8vImomAzu2RhuVEucq67DxQs0Ya7WkVhrO6F+9wvDfkV0BAKmrc7Hk75MOe67K2nqsvtDO5a4WfobkkK5B8PPyQJGuGplHztr02Iqaeqzd31Dn6Q5+ZshOmDQRNRO5TIpxPRrOgrJ1ii4jp+W00nBWTw7uiH8P7gAAmLF0n90KL/7T7/uLUVlrQESAN3q18HYfSrkMoy+c8WbrZ2ZNdhGq6gzoEOiDHuH+DoiOWiImTUTNyDRFl5FTYlP9n5bWSsNZTR/RFXf3CoPBKCB50S78ddS2ox/W+MXU7qNnW0gkfK9Nn5nV2UXQ19Rb/bil3I/kAEyaiJpRdIgaXTUq1BqMWLnPuvozZypqzNN5LGgpLolEgtQ74zAsOhg19UY8/s3fOFCgs9v2i3XV+PNwQ8NgTik16Bnhj/atvVFVZ8Da/da1Iio4X4XMCwkt65mRPTFpImpmpnIBS61sq9ISW2k4M7lMik/uT0Cf9q1QXl2Ph+dvR/7Zpld6B4Bfs07DKAC927VCu9Zs9wE0JKp3JNj2mVmWdRqC0NDHLjzA25HhUQvDpImomY3tEQqpBNh54hyOW9EU1twCgkcenIanhwxfPdwHXTUqlJbX4KF5fzW53YcgCPhlJ2sKXYnpqNufR86gUFt1zbGCIJg/M6xnRvbGpImomQWpPTGoUxsA129Ieqi4HPtOt8xWGs7Oz8sD3zzaF+EBXjhxthIPz9sOXXXj+9QdKNQhr7gcCpkUo+LY7uNSEa290ad9KwjC9VsRZZ/W4XBJBZRyKUbEaZopQmopmDQRicB0KvnS3dduq9LSW2k4uyC1J759tB8CfRU4UKjDEwv/RnVd4/rUpV04OjIsJgh+3h72DNMtmI6+/bLz2p8Z00L64d00UHlyP5J9MWkiEsHwGA18FDKcLKvC3yfOXXEMW2m4hvaBPlgwsS98lXL8dawMz/2wG/U29qmrNxixLMtUh4vv9ZWMjAuBQi7FoZIK7L/K4vs6g9Hc4JcnTZAjMGkiEoGXQoYRcdeuP2NqpaFqwa00XEVsWz98OaE3FDIpfj9QjJeWZdvUmHnz4TM4U1GDAB8FburSxoGRui4/Lw/cGtPQPuhqC8I35pWiTF+LQF8lbowKbM7wqIVg0kQkEtMv4ZV7C684pWNqpTG6hbfScBUDOrbGR+MTIJUAP+44iXfX5ln9WFMScHt8KDxk/Gf5akwnQyzfcxp1VziaZ1ojOLZHKOTcj+QA/L+KSCT9I1sj1M8T5dX1yMgpsbiPrTRc022xGsy+Iw4A8OmGI/hq89HrPqa8ug6/X6g/xCmlaxvcuQ1a+yhwpqIWmw9ZtiLSVtYhPaehSjv3IzkKkyYikUilEtxhWhD+jym6tfuL2ErDRd3XNwJTErsAAN5YlYO03ddu/7F6XxFq6o2ICvJFXFu/5gjRZXnIpLj9QiuiX/4xRbdqXyFq643oqlEhJkQtRnjUAjBpIhKRqWjfxoOlOFNxsc6PabrmjgS2gHBFz9zcEY8OjAQATPlpL9bnllx1rOlsL77X1jEtlE8/UAxt1cUSD6bklPuRHIlJE5GIooJ8ER/mh3qjgBUXzvop0l5spcFpBtckkUjw0qho3JHQFvVGAU9/vxM7T5RdNu7UuUr8dawMEklDX0G6vti2anQK8kVtvRGr9zVMYZ84q8eO4+cg5X4kB2PSRCSyO//RVoWtNNyDVCrBO//qjpu7tEF1nRET5+9AXlG5xRhTSYkBHVqjrb+XGGG6HIlEctlnxrQAfGBUIILVnqLFRu6PSRORyMbEh0IulWDfaS0OFZdfnJrjUSaX5yGT4tMHeqJnhD901fWYMO8vnDrX0Kfu0nYfbM5rm3EJoZBIgO3Hy5B/ttKcNPHILDmaqElTamoq+vTpA5VKhaCgIIwbNw55eZan6f773/9Gx44d4eXlhTZt2mDs2LHIzc21GJOfn49Ro0bB29sbQUFBmDJlCurr6y3GbNiwAT179oRSqURUVBQWLFhwWTxz5sxB+/bt4enpiX79+mH79u12f81E/xTgo8DNXRrqML35W465lcboOLZNcQfeCjnmPdIHnYJ8UayrwYSvt+NsRQ32nNLi6Bk9PD2k5ppdZJ0QPy/c0LE1AGDm8mycOFsJb4UMid3YNoUcS9SkaePGjUhKSsK2bduQnp6Ouro6DB8+HHr9xSamvXr1wvz585GTk4O1a9dCEAQMHz4cBkNDXRuDwYBRo0ahtrYWW7duxcKFC7FgwQLMnDnTvI1jx45h1KhRGDJkCLKysjBp0iQ8/vjjWLt2rXnM4sWLkZKSgldeeQW7du1CfHw8EhMTUVJy9QWcRPZiKiuwIa/hNGq20nAv/t4KfPNYX7T198LRM3pMXLAD32aeAADc1k0DX6Vc5Ahdj2lBuOkzMyI2BN4K7kdyLIlgS9laBystLUVQUBA2btyIwYMHX3HM3r17ER8fj8OHD6Njx45YvXo1Ro8ejYKCAgQHN1SLnTt3LqZNm4bS0lIoFApMmzYNq1atQnZ2tnk79913H86fP481a9YAAPr164c+ffrgk08+AQAYjUaEh4fj2WefxfTp068bu06ng5+fH7RaLdRqnu5KtqmpN6DPG39AV91whPTLCb3N1Y/JfRwprcDdczNRpq8137bw0b64qTOrgNtKX1OP3m/8gaoLhWG/f7wfBrIKODWCLd/fTrWmSavVAgACAgKueL9er8f8+fMRGRmJ8PBwAEBmZibi4uLMCRMAJCYmQqfTYf/+/eYxw4YNs9hWYmIiMjMzAQC1tbXYuXOnxRipVIphw4aZx/xTTU0NdDqdxYWosZRyGUbHN0zHBfgo+CXqpjq28cWCiX3go2io8B6kUmLghWkmso2PUo7bYhum40L8PNG/A/cjOZ7TJE1GoxGTJk3CwIEDERsba3Hfp59+Cl9fX/j6+mL16tVIT0+HQqEAABQVFVkkTADM14uKiq45RqfToaqqCmfOnIHBYLjiGNM2/ik1NRV+fn7miymJI2qsxwZFokMbHzw/tBMUcqf5aJKddQ/zxxcTeiMiwBvPDu3Edh9N8O+bOqB9a29MHtYZMilrM5HjOc0EcFJSErKzs7Fly5bL7nvggQdw6623orCwEP/73/9wzz334M8//4Snp3inls6YMQMpKSnm6zqdjokTNUnHNr5Y98LNYodBzWBgVCA2TR0idhgur6tGjQ1TuB+p+ThF0pScnIyVK1di06ZNCAsLu+x+09GcTp06oX///mjVqhXS0tIwfvx4aDSay85yKy5u6D+k0WjM/zXddukYtVoNLy8vyGQyyGSyK44xbeOflEollEplo18zERERuRZRjwsLgoDk5GSkpaVh3bp1iIyMtOoxgiCgpqah5cSAAQOwb98+i7Pc0tPToVarERMTYx6TkZFhsZ309HQMGDAAAKBQKNCrVy+LMUajERkZGeYxRERE1LKJmjQlJSXhu+++w6JFi6BSqVBUVISioiJUVVUBAI4ePYrU1FTs3LkT+fn52Lp1K+6++254eXlh5MiRAIDhw4cjJiYGDz30EPbs2YO1a9fipZdeQlJSkvlI0FNPPYWjR49i6tSpyM3NxaeffoolS5Zg8uTJ5lhSUlLw5ZdfYuHChcjJycHTTz8NvV6PiRMnNv+OISIiIucjiAjAFS/z588XBEEQTp8+LYwYMUIICgoSPDw8hLCwMOH+++8XcnNzLbZz/PhxYcSIEYKXl5cQGBgovPDCC0JdXZ3FmPXr1ws9evQQFAqF0KFDB/NzXOrjjz8WIiIiBIVCIfTt21fYtm2b1a9Fq9UKAAStVmvzfiAiIiJx2PL97VR1mlwZ6zQRERG5Hpet00RERETkrJg0EREREVmBSRMRERGRFZg0EREREVmBSRMRERGRFZg0EREREVmBSRMRERGRFZg0EREREVmBSRMRERGRFeRiB+AuTIXVdTqdyJEQERGRtUzf29Y0SGHSZCfl5eUAgPDwcJEjISIiIluVl5fDz8/vmmPYe85OjEYjCgoKoFKpIJFIxA6n2el0OoSHh+PkyZPsvdcE3I/2wf1oH9yP9sH9aB+O2o+CIKC8vByhoaGQSq+9aolHmuxEKpUiLCxM7DBEp1ar+Y+CHXA/2gf3o31wP9oH96N9OGI/Xu8IkwkXghMRERFZgUkTERERkRWYNJFdKJVKvPLKK1AqlWKH4tK4H+2D+9E+uB/tg/vRPpxhP3IhOBEREZEVeKSJiIiIyApMmoiIiIiswKSJiIiIyApMmoiIiIiswKSJGi01NRV9+vSBSqVCUFAQxo0bh7y8PLHDcnlvvfUWJBIJJk2aJHYoLuf06dN48MEH0bp1a3h5eSEuLg5///232GG5FIPBgJdffhmRkZHw8vJCx44dMWvWLKv6crVkmzZtwpgxYxAaGgqJRIJly5ZZ3C8IAmbOnImQkBB4eXlh2LBhOHTokDjBOrFr7ce6ujpMmzYNcXFx8PHxQWhoKCZMmICCgoJmi49JEzXaxo0bkZSUhG3btiE9PR11dXUYPnw49Hq92KG5rB07duDzzz9H9+7dxQ7F5Zw7dw4DBw6Eh4cHVq9ejQMHDuC9995Dq1atxA7Npbz99tv47LPP8MknnyAnJwdvv/023nnnHXz88cdih+bU9Ho94uPjMWfOnCve/8477+Cjjz7C3Llz8ddff8HHxweJiYmorq5u5kid27X2Y2VlJXbt2oWXX34Zu3btwtKlS5GXl4fbb7+9+QIUiOykpKREACBs3LhR7FBcUnl5udCpUychPT1duOmmm4Tnn39e7JBcyrRp04RBgwaJHYbLGzVqlPDoo49a3HbnnXcKDzzwgEgRuR4AQlpamvm60WgUNBqN8O6775pvO3/+vKBUKoUffvhBhAhdwz/345Vs375dACCcOHGiWWLikSayG61WCwAICAgQORLXlJSUhFGjRmHYsGFih+KSli9fjt69e+Puu+9GUFAQEhIS8OWXX4odlsu54YYbkJGRgYMHDwIA9uzZgy1btmDEiBEiR+a6jh07hqKiIovPtp+fH/r164fMzEwRI3N9Wq0WEokE/v7+zfJ8bNhLdmE0GjFp0iQMHDgQsbGxYofjcn788Ufs2rULO3bsEDsUl3X06FF89tlnSElJwX//+1/s2LEDzz33HBQKBR5++GGxw3MZ06dPh06nQ9euXSGTyWAwGPDmm2/igQceEDs0l1VUVAQACA4Otrg9ODjYfB/Zrrq6GtOmTcP48eObrREykyayi6SkJGRnZ2PLli1ih+JyTp48ieeffx7p6enw9PQUOxyXZTQa0bt3b8yePRsAkJCQgOzsbMydO5dJkw2WLFmC77//HosWLUK3bt2QlZWFSZMmITQ0lPuRnEZdXR3uueceCIKAzz77rNmel9Nz1GTJyclYuXIl1q9fj7CwMLHDcTk7d+5ESUkJevbsCblcDrlcjo0bN+Kjjz6CXC6HwWAQO0SXEBISgpiYGIvboqOjkZ+fL1JErmnKlCmYPn067rvvPsTFxeGhhx7C5MmTkZqaKnZoLkuj0QAAiouLLW4vLi4230fWMyVMJ06cQHp6erMdZQKYNFETCIKA5ORkpKWlYd26dYiMjBQ7JJc0dOhQ7Nu3D1lZWeZL79698cADDyArKwsymUzsEF3CwIEDLyt5cfDgQbRr106kiFxTZWUlpFLLrwaZTAaj0ShSRK4vMjISGo0GGRkZ5tt0Oh3++usvDBgwQMTIXI8pYTp06BD++OMPtG7dulmfn9Nz1GhJSUlYtGgRfv31V6hUKvPcvJ+fH7y8vESOznWoVKrL1oH5+PigdevWXB9mg8mTJ+OGG27A7Nmzcc8992D79u344osv8MUXX4gdmksZM2YM3nzzTURERKBbt27YvXs33n//fTz66KNih+bUKioqcPjwYfP1Y8eOISsrCwEBAYiIiMCkSZPwxhtvoFOnToiMjMTLL7+M0NBQjBs3TrygndC19mNISAj+9a9/YdeuXVi5ciUMBoP5eycgIAAKhcLxATbLOXrklgBc8TJ//nyxQ3N5LDnQOCtWrBBiY2MFpVIpdO3aVfjiiy/EDsnl6HQ64fnnnxciIiIET09PoUOHDsKLL74o1NTUiB2aU1u/fv0V/z18+OGHBUFoKDvw8ssvC8HBwYJSqRSGDh0q5OXliRu0E7rWfjx27NhVv3fWr1/fLPFJBIFlXomIiIiuh2uaiIiIiKzApImIiIjICkyaiIiIiKzApImIiIjICkyaiIiIiKzApImIiIjICkyaiIiIiKzApImIiIjICkyaiIgcSCKRYNmyZWKHQUR2wKSJiNzSI488AolEgqeeeuqy+5KSkiCRSPDII4/Y7fleffVV9OjRw27bIyLnw6SJiNxWeHg4fvzxR1RVVZlvq66uxqJFixARESFiZETkipg0EZHb6tmzJ8LDw7F06VLzbUuXLkVERAQSEhLMt9XU1OC5555DUFAQPD09MWjQIOzYscN8/4YNGyCRSJCRkYHevXvD29sbN9xwA/Ly8gAACxYswGuvvYY9e/ZAIpFAIpFgwYIF5sefOXMGd9xxB7y9vdGpUycsX77c8S+eiOyOSRMRubVHH30U8+fPN1+fN28eJk6caDFm6tSp+OWXX7Bw4ULs2rULUVFRSExMRFlZmcW4F198Ee+99x7+/vtvyOVyPProowCAe++9Fy+88AK6deuGwsJCFBYW4t577zU/7rXXXsM999yDvXv3YuTIkXjggQcu2zYROT8mTUTk1h588EFs2bIFJ06cwIkTJ/Dnn3/iwQcfNN+v1+vx2Wef4d1338WIESMQExODL7/8El5eXvj6668ttvXmm2/ipptuQkxMDKZPn46tW7eiuroaXl5e8PX1hVwuh0ajgUajgZeXl/lxjzzyCMaPH4+oqCjMnj0bFRUV2L59e7PtAyKyD7nYARAROVKbNm0watQoLFiwAIIgYNSoUQgMDDTff+TIEdTV1WHgwIHm2zw8PNC3b1/k5ORYbKt79+7mv0NCQgAAJSUl110fdenjfHx8oFarUVJS0qTXRUTNj0kTEbm9Rx99FMnJyQCAOXPmNHo7Hh4e5r8lEgkAwGg02vQ402OteRwRORdOzxGR27vttttQW1uLuro6JCYmWtzXsWNHKBQK/Pnnn+bb6urqsGPHDsTExFj9HAqFAgaDwW4xE5Hz4ZEmInJ7MpnMPNUmk8ks7vPx8cHTTz+NKVOmICAgABEREXjnnXdQWVmJxx57zOrnaN++PY4dO4asrCyEhYVBpVJBqVTa9XUQkbiYNBFRi6BWq69631tvvQWj0YiHHnoI5eXl6N27N9auXYtWrVpZvf277roLS5cuxZAhQ3D+/HnMnz/frsUziUh8EkEQBLGDICIiInJ2XNNEREREZAUmTURERERWYNJEREREZAUmTURERERWYNJEREREZAUmTURERERWYNJEREREZAUmTURERERWYNJEREREZAUmTURERERWYNJEREREZIX/B6H/lxw8qGnwAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Group DataFrame by saleMonth and then find the median SalePrice\n", - "df_tmp.groupby([\"saleMonth\"])[\"SalePrice\"].median().plot()\n", - "plt.xlabel(\"Month\")\n", - "plt.ylabel(\"Median Sale Price ($)\");" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Ohhh it looks like the median sale prices of January and February (months 1 and 2) are quite a bit higher than the other months of the year.\n", - "\n", - "Could this be because of New Year budget spending?\n", - "\n", - "Perhaps... but this would take a bit more investigation.\n", - "\n", - "In the meantime, there are many other values we could look further into." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 1.4 Inspect values of other columns\n", - "\n", - "When first exploring a new problem, it's often a good idea to become as familiar with the data as you can.\n", - "\n", - "Of course, with a dataset that has over 400,000 samples, it's unlikely you'll ever get through every sample.\n", - "\n", - "But that's where the power of data analysis and machine learning can help.\n", - "\n", - "We can use pandas to aggregate thousands of samples into smaller more managable pieces.\n", - "\n", - "And as we'll see later on, we can use machine learning models to model the data and then later inspect which features the model thought were most important.\n", - "\n", - "How about we see which states sell the most bulldozers?" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "state\n", - "Florida 67320\n", - "Texas 53110\n", - "California 29761\n", - "Washington 16222\n", - "Georgia 14633\n", - "Maryland 13322\n", - "Mississippi 13240\n", - "Ohio 12369\n", - "Illinois 11540\n", - "Colorado 11529\n", - "Name: count, dtype: int64" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Check the different values of different columns\n", - "df_tmp.state.value_counts()[:10]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Woah! Looks like Flordia sells a fair few bulldozers.\n", - "\n", - "How about we go even further and group our samples by `state` and then find the median `SalePrice` per state?\n", - "\n", - "We also compare this to the median `SalePrice` for all samples." - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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p08f9e7dWwcPHkx3mjly5FCOHDm0ZMkSJSQkOJ23v7+/pkyZor1792rOnDlau3atBg8e7DR+48aN6tKli1544QXt27dP77//vmbPnq3XX3/d5TJeL2vWrPa7TpL066+/6vPPP9cXX3zhtGlfly5dtGDBAk2ZMkX79+/X+++/rxz/2+7nz5/XI488ourVq+vnn3/WihUrdOrUKT355JP28rNnz3bbzfuOHTvUpUsX1a9fX7ly5VLDhg311ltvKUuWLE7LxMbGys/Pz+FZu1OnTqlnz576+OOPPXo/37Zt25SUlKTGjRvbh5UrV07FixdXVFSUJCkqKkqVK1dWoUKF7DHh4eGKi4vT3r177TGpp2GLsU0DAADgVstkdQXw7/DMM89o6NCh+v333yVJP/74oz799FOtX7/eHpOQkKA33nhDq1evVlhYmCSpVKlS+uGHH/T++++rfv36eu+993Tvvfdq/PjxkqSyZctq9+7deuutt5zOu2rVqqpatar97zFjxujLL7/U119/rX79+tmHN2/eXH369JEkDRkyRBMnTtS6detUtmzZNNPMlCmTZs+erZ49e2r69OmqUaOG6tevr6eeekpVqlSxx6XuNKNkyZJ67bXX1KtXL7377rvp1nXUqFF66aWXFBERYV/+MWPGaPDgwRoxYoTTZUxt27Ztmj9/vh555BH7sMTERM2dO1cFChRIt8yhQ4e0aNEirVq1yp5wlCpVyj5+6tSpql69ut544w37sI8++kjFihXToUOHVKZMGeXKlSvddZVavXr1NGvWLIft4cqVK1c0ZMgQdezYUcHBwZIkY4y6du2qXr16qVatWjp69Kjb6cTExCgwMDBNByqFChVSTEyMPSZ1MmYbbxvnKiYuLk6XL19W1qxZPVouAACAjEJCZjVXHTcEBDj+ffq081j/6252enCR640CBQqoRYsWmj17towxatGihfLnz+8Q8+uvv+rSpUt69NFHHYYnJiaqevXqkqT9+/erTp06DuNtyZszFy9e1MiRI7V8+XKdPHlSV69e1eXLl9PcIUudSPn5+SkkJESnXayzdu3aqUWLFtq4caM2b96sb7/9VuPGjdPMmTPtHZWsXr1aY8eO1YEDBxQXF6erV6/qypUrunTpUrp3dnbu3Kkff/zR4Y5YcnKyyzKStHv3buXIkUPJyclKTExUixYtNHXqVPv4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ySM/Pz+nsWfPns2wygEAAADAncyjhGzixInKmTOnJGnSpEk3sz4AAAAAcNfwqMliRESEgoKC7P939fHG999/r5YtW6pIkSLy8/PTkiVLHMZ37dpVfn5+Dp+mTZs6xJw9e1adOnVScHCwcufOre7du9s7HbHZtWuXHnroIWXJkkXFihXTuHHj0tRl8eLFKleunLJkyaLKlSvrm2++8WpZAAAAAMBbHiVkcXFxHn+8ER8fr6pVq2ratGlOY5o2baqTJ0/aPwsWLHAY36lTJ+3du1erVq3SsmXL9P333+u5555zqHuTJk1UokQJbdu2TW+//bZGjhypGTNm2GM2bdqkjh07qnv37tqxY4dat26t1q1ba8+ePV4tDwAAAAB4w6Mmi7lz53b53FhqycnJHs+8WbNmatasmcuYoKAghYSEpDtu//79WrFihbZu3apatWpJkt555x01b95c//3vf1WkSBHNmzdPiYmJ+uijjxQYGKiKFSsqOjpaEyZMsCdukydPVtOmTTVo0CBJ0pgxY7Rq1SpNnTqVXiQBAAAA3DQe3SFbt26d1q5dq7Vr1+qjjz5SwYIFNXjwYH355Zf68ssvNXjwYBUqVEgfffRRhldw/fr1KliwoMqWLavevXvr77//to+LiopS7ty57cmYJDVu3Fj+/v7asmWLPebhhx9WYGCgPSY8PFwHDx7UuXPn7DGNGzd2mG94eLiioqKc1ishIeGG7g4CAAAAgEd3yOrXr2///+jRozVhwgR17NjRPuzxxx9X5cqVNWPGDK+fI3OladOmatu2rUJDQ3X48GG9/PLLatasmaKiohQQEKCYmBgVLFjQoUymTJmUN29excTESJJiYmIUGhrqEFOoUCH7uDx58igmJsY+LHWMbRrpGTt2rEaNGpURiwkAAADgLuX1e8iioqIc7kjZ1KpVSz/99FOGVMrmqaeesid7rVu31rJly7R161atX78+Q+fji6FDhyo2Ntb+OX78uNVVAgAAAPAv43VCVqxYMX3wwQdphs+cOVPFihXLkEo5U6pUKeXPn1+//vqrJCkkJESnT592iLl69arOnj1rf+4sJCREp06dcoix/e0uxtmza9K1Z9uCg4MdPgAAAADgDY+aLKY2ceJEtWvXTt9++63q1KkjSfrpp5/0yy+/6PPPP8/wCqb2xx9/6O+//1bhwoUlSWFhYTp//ry2bdummjVrSpLWrl2rlJQUe93CwsL0yiuvKCkpSZkzZ5YkrVq1SmXLllWePHnsMWvWrFH//v3t81q1apXCwsJu6vIAAAAAuLt5fYesefPmOnTokFq2bKmzZ8/q7NmzatmypQ4dOqTmzZt7Na2LFy8qOjpa0dHRkqQjR44oOjpax44d08WLFzVo0CBt3rxZR48e1Zo1a9SqVSuVLl1a4eHhkqTy5curadOm6tmzp3766Sf9+OOP6tevn5566ikVKVJEkvT0008rMDBQ3bt31969e7Vw4UJNnjxZkZGR9nq88MILWrFihcaPH68DBw5o5MiR+vnnn9WvXz9vVw8AAAAAeMzrO2TStWaLb7zxxg3P/Oeff1bDhg3tf9uSpIiICL333nvatWuX5syZo/Pnz6tIkSJq0qSJxowZY39JtSTNmzdP/fr1U6NGjeTv76927dppypQp9vG5cuXSd999p759+6pmzZrKnz+/hg8f7vCusgceeEDz58/XsGHD9PLLL+u+++7TkiVLVKlSpRteRgAAAABwxqeEbOPGjXr//ff122+/afHixbrnnnv08ccfKzQ0VA8++KDH02nQoIGMMU7Hr1y50u008ubNq/nz57uMqVKlijZu3Ogypn379mrfvr3b+QEAAABARvG6yeLnn3+u8PBwZc2aVdu3b1dCQoIkKTY2NkPumgEAAADA3cLrhOy1117T9OnT9cEHH9g7yZCkevXqafv27RlaOQAAAAC4k3mdkB08eFAPP/xwmuG5cuXS+fPnM6JOAAAAAHBX8DohCwkJsb8HLLUffvhBpUqVypBKAQAAAMDdwOuErGfPnnrhhRe0ZcsW+fn56cSJE5o3b54GDhyo3r1734w6AgAAAMAdyeteFl966SWlpKSoUaNGunTpkh5++GEFBQVp4MCBev75529GHQEAAADgjuR1Qubn56dXXnlFgwYN0q+//qqLFy+qQoUKypEjx82oHwAAAADcsXx6D5kkBQYGqkKFChlZFwAAAAC4q3ickD377LMexX300Uc+VwYAAAAA7iYeJ2SzZ89WiRIlVL16dRljbmadAAAAAOCu4HFC1rt3by1YsEBHjhxRt27d9Mwzzyhv3rw3s24AAAAAcEfzuNv7adOm6eTJkxo8eLCWLl2qYsWK6cknn9TKlSu5YwYAAAAAPvDqPWRBQUHq2LGjVq1apX379qli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MTExOnfunMqXL+80fs+ePSpdurSyZMmiZcuWadeuXerRo4cKFizotn53u61bt+rvv/9Oc33z7bffqkCBAqpVq5bL8klJSTp27JjD9r3TvyczEgnZXcCXk6C3B1ZcXJymTp2a5iS9aNEil/Np06aN5s6dq5SUFNWqVUtBQUFq27atRo8e7bJccnKyFi1apH379jnMz9UXSWJiot59911t3LhRkvTwww+rd+/eCgwMdFqmRo0a2r59u8OwmjVratu2bS7rd/XqVc2YMUNHjx7VuHHjdPToUR07dkwPP/ywy3K+bKtbeUGyZMkSh/XXqlUrt2VWrVqlsLAw5ciRQ++++66io6MVGRmpcuXKuSwXFRWVZvv26dPHZZldu3Zp4MCBafbD06dPOy1Tu3ZtrVmzRvHx8apbt64qVKige+65Rx988IHTMvXr19fly5fVpUsXPf300x5f4Pqy33pzAX4jF1qS78fj1atXderUKSUnJ9uHFS9e3Gm8txd1kydP1gsvvOB0+dJbrsWLF6t9+/Z69913052mq33Jl/3Ixpf91psy9erV05w5c9S+fXt7klOxYkXt3bvX5Tx+++03zZ07VwsXLlSFChUUERGhFi1aKCAgwGmZunXravLkyapTp46ka9vnP//5jzZv3uy0zJ49e9StWzctXrxYW7Zs0YQJE7R06VK3F8QNGzZUZGSkhg4dqoULF2rWrFnKkiWLXnvtNadlJkyYoM8++0yHDh1Sw4YNtXr1aj300EP6+uuvXc7r2LFjev755/XTTz/J399ftWvX1uTJkzN0n7XZv3+/xo8fr99//93h+Fi7dq3TMr58n86fP1/Dhw9X48aNZYzRunXrNHr0aD311FNpYufMmSNJ2rhxow4ePKgnn3xS0rVjpmzZsi7Pfb5sJ8m3bTVw4ECdOXNGW7Zs0YEDB3TmzBk99thj2rJli9My1apV0/bt27Vv3z517NhRnTt31sqVK7VmzRqnZb755huXdXf3ffrjjz/q6NGjDtu3S5cuTuNr166dZr9Jb1h6rl69qsTERPvf2bJlcxl/6tQpzZw5M039PvroozSxjzzyiObMmaNixYo5DD9+/Li6dOmidevWOZ3PggUL9Nprr+n48eMqW7asdu7cqVq1amnTpk1ul8lbBQoUSPM9EBwcrBo1aujNN99UqVKlMnyet4TBHW38+PEmLCzM5MuXzzzxxBMmd+7cpmXLli7LzJ8/31SoUMHkzJnT1KpVy2TOnNmEhYW5LPPYY4+ZKVOmmPvuu88sW7bMPPnkk2bgwIFu61etWjVjjDEzZ840L7/8sklJSTGVK1d2W65Tp04mMjLSlChRwkydOtXUq1fP9OnTx2WZiIgI07t3b7Np0yazadMm07dvXxMREZFu7HfffWcGDhxoChUqZAYNGmT//N///Z+5//773davc+fOZvjw4aZChQrGGGPi4uJM9erVXZbxZVt5W+aRRx4xxhiTP39+U6BAAfvH9rcrL774omnRooWZP3++mT9/vmnZsqVH27hKlSrGGGOioqLMAw88YBYuXGgeeOABl2UiIyNNu3btTOHChc3AgQNN6dKlTefOnd3Oq06dOmbXrl2mWrVq5uLFi+add94xo0ePdlnGtg9OmTLFvP7668YYY6pWrep2XkeOHDGjRo0yFStWNG3atDFffvmlSUpKclnGl/32gQceML/88ou9nsYY+351vdmzZ5vZs2eb7t27mwcffNBMmTLFTJkyxTz00EOmR48ebpfJl+Nx/PjxplChQqZGjRqmVq1aplatWm6PkQYNGpivv/7aVKxY0ezZs8e8+OKL5pVXXnEa//XXXzss3/Wf9EyfPt0YY8zIkSPT/bjiy35kjG/7rbdlbOs29f7gyf6a2jfffGOKFCliChQoYCIjI82JEyfSjbMdu+6GXW/Xrl2mYsWKpkGDBiYuLs6jOtWsWdMYY0ylSpXSDHOmUqVK5urVq/Y6HT9+3DRt2tTtvBo2bGgWLlxo/3vRokWmYcOGLst4u8/aVK5c2Xz00Udm586dZs+ePfaPK758n1apUsWcPXvW/vfZs2fdbqv777/fXL161f53UlKSqV27tssyvmwnW7y328q2j6fe190tky125MiRZsaMGcYY4/a7t2vXrqZr166mWbNmJnfu3KZdu3ambdu2Jk+ePKZ58+Yuyz711FOmQYMGZsCAAWbgwIFm4MCBZtCgQenGnjlzxuzZs8eUL1/e7Nu3z+zdu9fs3bvXREVFmbJly7qcz5o1a0zVqlVN1qxZTf78+Y2/v78pWbKkyzLGGFO7dm0zfPhw89VXX5lly5bZP+mpVauW0+m4W++VK1c28fHx9nPRjh07zJNPPum2fgsXLjSlS5f26lpk6NChZubMmebChQvmwoUL5sMPPzQDBw40ixcvNg8//LDbed6uSMjucL6cBH05sGrUqGEva4wxKSkpHiUu5cuXN7/++qtp2LCh2bx5s8M0XLGddG2xCQkJbpPG9E4ozi5koqOjzezZs03x4sUdLvw+//xzhy89Z2zrw5svEl+2la8XJL64frskJyd7tK1sdRsyZIiZO3euMcZxvbial63s+fPnTf369d3Oy3ZhkLpe7r6MK1eubFavXm1q1qxpdu3aZYwxpmLFim7nZYwxFy5cMDNnzjT33HOPCQsLM2XLljVz5sxxGu/LfuvLBbgvF1rG+HY83nfffeb8+fNup52arxd1Nn/++afTJCK15ORk069fP6/qlrou3uxHqeO92W+9LdO2bVvz888/m+rVq5uUlBTzzjvvmHbt2rmtmzHGrF692nTu3NlUrlzZjBo1yhw8eNDMmjXLlC9fPt34zp07m759+5qoqCgTFRVlnn/+efPMM8+kG2tLxG2fIkWKmIoVK9r/dicsLMykpKSYVq1amQ8++MB88803pkyZMi7L2C4gq1evbi5cuGCMMaZcuXJu5+VLounrPuvqItcZX75PK1WqZBITE+1/JyYmOtQ1PWXKlDF//vmn/e8///zTbWLgy3Yyxrdtdf/995vk5GT7sff333+7/e6oV6+eGTZsmAkNDTUnTpwwycnJbteDTaNGjczJkyftf588edI0atTIZRlnx056Zs+ebRo0aGBy5MhhGjRoYP+0bNnSfP755y7LVq9e3cTExNiXf+nSpW5/zDPG/Xdtavfee69JTk5OM/zq1avm3nvvdVnWtn2rVq1q3w89+R699957zeHDhz2uozHpfyfZjl9PfjC6XWWy+g4dbq4sWbIoICBAAQEBunjxoooWLaqjR4+6LBMUFGS/DZ6UlKRq1aq5bQ6TKdO1XalQoUJas2aNihQpor///ttt/YYPH642bdqoXr16qlOnjn777TeVLl3abbnMmTNLknLlyqVDhw6pYMGCOnXqlMsyWbJk0c8//2xvB71t2zYFBQWlG1u1alVVrVpVXbp0cdkEzJmgoCAlJCTYyx47dsxl00hb/bzdVt6WOXLkiEJDQ7Vv3750x7tqlhoQEKDjx4/bmzP8+eefLps72RQpUkSdO3fW999/r+joaCUkJDg0nUhP1qxZJV1bvtOnTytv3rz6888/3c4rW7ZsSkpKUpUqVfTqq6+qSJEibuc1efJkTZw4Ue3bt1flypX122+/qWHDhi7LrFq1SnPmzFF0dLSefPJJ/fDDDypZsqRiY2Pt+016fNlvixUrpm3btsnPz0/GGE2bNs3tMRIbG6tTp07Zn/86ffq0YmNjXZaR/jkeH3zwQY+Px5IlS7rdt68XGBgoY4zuvfdezZw5U/fcc49HnUZs3LhRPXr0UM6cOSVJFy9e1MyZM/Xggw+mG+/v768dO3YoOTnZo33Vxpf9SPJtv/W2zPvvv6/+/fvrxIkTKlKkiBo2bKjp06e7rVu5cuVUt25dPfvss2rQoIF9eJkyZZx2ujFjxgxNmzZNb731liTpwQcfdNrs9bPPPpMkXb582b5M3pg4caLi4+M1ZcoUDR8+XHFxcfamdc7UqFFD58+fV/fu3VWnTh3lzJnT3rzSlRIlSui///2vnnnmGUnSvHnzXDZXlHzfZxs1amQ/rlJ/37g61/ryffrMM8/ogQceULt27SRJX3zxhctmc5I0fvx41atXT2XLlpUk/fLLL5o8ebLLMr5sJ8m3bfWf//xHHTp00JkzZzRmzBgtXLhQr7zyissyixcv1oIFCzRnzhwVLlxYx44d06BBg9zWT5L++OMP5c+f3/53vnz59Mcff7gsU7t2bR08eNC+Dl2JiIhQRESElixZotatW3tUJxt/f38VKlRIycnJMsbosccec7suJKl169aaNWuWWrdu7bD/pdfUsVWrVnruuec0ZcoU+/hLly5pwIABatmypcv5hISE6Pz582rZsqWaNWumfPnypWn6mJ577rnH/rypp/Lnz68pU6aoQ4cOkq415c2TJ49SUlK8Os/fdqzNB3GzPffcc+bcuXNm6tSppkKFCqZOnTpOm+nZPPbYY+bcuXNm2LBhplGjRubJJ590e9dlyZIl5vz582bnzp2mfv36pkaNGmbJkiUZuCSOpk+fbs6dO2fWrl1rSpUqZUJCQsx7773nssy2bdtM5cqVTdmyZU2ZMmVMlSpVzLZt21yWKVmypAkNDU3zcWflypWmcePGpmDBgubZZ581oaGhZvXq1S7L+LKtvC3Ts2dPY4xx+HXO9nHXZGflypWmRIkSJjw83DRp0sSEhoaaVatWuSxjjDEXL140n3/+uTl06JAxxpgTJ06YlStXuiwzYsQIc+7cObNo0SJzzz33mGLFinnUPOjw4cPm8uXL5ty5c2bEiBFmwIAB5pdffnFbzltdunQxa9eudRh2+fJlY8y15mDO+LLfnjlzxnTq1MkUKlTIhISEmI4dO5ozZ864LLN06VJTsmRJEx4ebsLDw02pUqXM0qVL3S7Xzp07PRqW2pNPPmnKly9v/vOf/zg073Vl8+bN5sKFC+b33383ERERpm3btvY7cq5UqFDB7Nu3z/73vn37nDbftImIiDAPPvigefvtt820adPsH1d83Y982W+9KZOcnOzx3bDredp08PoyqZvhJiUluZxOSkqKV3cMMtJvv/3mdl+1+euvv0y/fv1MtWrVTLVq1czzzz9v/vrrL5dlrt9n27RpY6KiotzOy5dzra/fp1u3bjWTJk0ykyZNMj///LPbeGOMuXLliomOjjbR0dHmypUrHpW5Ud5sq/3795upU6eaKVOmmL1793o8j6SkJBMfH2//eGLEiBGmdu3aZuzYsebNN980devWddq82XZHuGrVqiYwMNBUqVLF3H///R412b506ZL55JNPzGuvvWZGjRpl/7jyyCOPmIsXL5revXubiIgIM3jwYFO3bl23y1SyZMk0H2fXMAkJCaZ///4mX758pkaNGqZ69eomf/78ZsCAASYhIcHtvGzWrVtnvvrqK4/K9OjRwzzyyCNmwoQJHp+fT506Zfr06WOqVatmqlatavr06WNiYmLMlStXzIEDBzyu5+2GTj3uIkeOHNGFCxdUpUoVj8usX79ecXFxatasmf3X/YwUFxenadOmpXmg3V1nIDfCdqcgV65cbmPj4+Pt/09ISNDnn3+uP/74Q6NGjXJaJiUlRZ988olatGihzZs3KyUlRWFhYQ6/vLnjy7bypYy3rly5ooMHD0qSypYtqyxZsjiNTUhIUFBQkC5dupTueHcPI6eezpUrVzzaXtHR0apatapXdzV9eVi/S5cumjt3rv3v8+fPq1WrVtqwYYPH873ZEhISdODAAUnX7o44uxucWnqd2KQ3LDVnv45HREQ4LeNr76XpdahTq1Yt/fzzz07LODtWR4wY4XJevrhy5Yr9mLDtt0lJSR4f+57s6w0bNtSyZcuUPXt2r+rmS++MderU0bp16+zHanx8vBo3buyyG/uOHTtq2LBhqlixolf186Xzi9atW2vJkiVuh90NfvzxR1WpUsV+9zguLk579uzRAw884LacNx1S+LKdJN+3lbe9LK5d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Ek67MH7//ffVoUMH7dixQz169NClS5c0cuRI/d///V+aWNsFYGJiovbv32/vIMKTL28p/WdO0ns25frxBw4c8OpCwebIkSP68ccf9eOPP2rTpk0qXry4x82oEhIS9Pfff9uT9oxWoEAB/f3338qZM6fDcrm6EPTl2PJ2/dmaEn788ccOF5hxcXHavn27y/X+8MMPa82aNerWrZtCQ0NVpEgRTZ8+3eVzRmvXrlX37t1VtmxZGWP066+/aubMmW4T1YcffljPPPOMOnbsKD8/P3366aeaO3euvv/+e6dlUjfJsjU7HjdunHbv3u20THrnQlfnQHfdfrvq4GTGjBl6++237c0C161bp4EDB6pnz54OcSdPnlThwoWddibgqhOB9Lg61/ryrK5NlSpVtHXrVvuFUkJCgu6///6b8sxM165dlS1bNnXu3FnStR97Ll686PLHHkkqXbq0vvvuO3sTQU+0adNG8fHxDk0W3T1vJV07H/3nP//R1q1b5e/vr1q1amny5MnpHtc2ZcuWTbfJrLcdubiTUfuSJ3zdVgcOHNCaNWuUkpKiRo0aub3o3rt3b5rrgO+//95t4iJda0761VdfacuWLerZs6c9AezYsaPTMi1bttTHH3+s8ePHKyoqSvny5VNcXJy+/fZbl/NasmSJQ3Lqrhnyiy++qKVLl6pSpUoOCY+7DtC2b9+url27KjExUcYYZcmSRbNmzVKNGjXSxLp6Pt7ds/MVKlTwuvmrbbpRUVE6ceKEHn30UTVp0kQnT57Ul19+6bRMet8TnvwocLsjIbvD3Xvvvfr444/TtHv35sTuaZLki759++rNN99UpkyZVL9+fR0/flwjRoxQr169XJa7//77tXXrVq/n523Pc9c/KO1s2PWeeeaZdJ/Rcvdgsac9PNnUqVNHUVFR9m2bnJxsf3i6cuXKbn+p88SN9CZlq+O0adMcfqHr06ePy3b5vl4oHD58WD/88IM2btyon376SdmyZVO9evU0fvx4p2XatGmjuXPnKiUlRbVq1VJQUJDatm2r0aNHOy3zyCOPOPzSfe7cObVv316rV692Wb9bxdv1t3PnTkVHR2v48OEOy50zZ041bNjQ5XNDv/32mwoXLqyEhARNmjRJcXFx6tOnj8v3l9WoUUNffvmlvT6///672rRp47aznPQehnf3gHzqL+9MmTKpRIkSioyM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9u3bzbx581wmGT/88IMxxpjly5en+3HFl27HfX0dx9q1a03Lli3Nm2++aYy5ltz369fPZRlP94mBAweaQYMGmSeffNKUL1/e/Oc//zGDBg2yf1yx/XiTWkpKikfn2rlz55oCBQqYe+65x+zcudNt/O7du01wcLDJly+fKVCggNsuvZ1daHrS/XXt2rXNtm3b7H9/+OGH5qGHHnIaP3LkSPP444+bI0eO2If99ttvplWrVmb48OFul+3LL780kZGRJjIy0nz11Vdu4425dtylvtDfuXOn/Vh01oW7N8f8448/bjp37mymT59u2rVrZx544AFTr149e7firjz22GPm3LlzZtiwYaZRo0bmySefdPpjwI1sJ2O831bGGHPixAkzfvx48/333xtjjPn999/dvobH9t2d2urVq12WsZ0PvPmuWL58uVm2bJmpWbOm/Ty0ZcsWj5MQ2w+p0dHRHv+Q6gtPfii8ES1atDDGGFOyZEkTGhpqSpYsaf+Ehoa6Lf/999+bRo0amdKlS9vLuyu3efNm06pVK1OtWjVTuXJl++ffjiaLd7jjx49rzJgxaV7a6qpdb//+/dW/f3/73yVKlND69etdzseX54Ska81ovvjiizTd1w8fPtxluRo1auipp57SE0884dC+21UzrubNm+v8+fMaOHCgatSoIX9/f6e36G/0xcvePKNl06RJE7333ntpXibtqv26Ny+gTm3JkiX68ccfNXv2bM2YMUPVqlXTgw8+6PKF4SEhITp//rxatmypZs2aKV++fPYmF66cOnVKq1atchuXEfPy5dmkU6dOaebMmWn2QVe9il7fy6btAWR3XWDXqFFD58+fV/fu3VWnTh3lzJnT5YvQJd+az/m6/h566CFNmDBBCQkJ2rhxo6ZNm+b2pfD58+fXlClT7E2yFi1apDx58iglJcVpM5wmTZooKipKR44c0ZNPPqlHH31Uixcvdtqz1o003/Sl23FfX8fRsGFDh05ESpUqpXfeecdlGU/3CdvLgitWrOhyedPj7++vqVOnOuyffn5+ypTJ9SVAmzZtlDlzZu3du1e///67unXrpscee8xpZx8zZszQ+PHj9eabb6pXr14eNf9N3dQuJibG3tSxdu3aKlSokMuyX3zxhVq3bq3p06dr7dq1Wrt2rVasWOE0ft68edqzZ49DM+bQ0FAtXLhQlSpVcrpc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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Group DataFrame by saleMonth and then find the median SalePrice per state as well as across the whole dataset\n", - "median_prices_by_state = df_tmp.groupby([\"state\"])[\"SalePrice\"].median() # this will return a pandas Series rather than a DataFrame\n", - "median_sale_price = df_tmp[\"SalePrice\"].median()\n", - "\n", - "# Create a plot comparing median sale price per state to median sale price overall\n", - "plt.figure(figsize=(10, 7))\n", - "plt.bar(x=median_prices_by_state.index, # Because we're working with a Series, we can use the index (state names) as the x values\n", - " height=median_prices_by_state.values)\n", - "plt.xlabel(\"State\")\n", - "plt.ylabel(\"Median Sale Price ($)\")\n", - "plt.xticks(rotation=90, fontsize=7);\n", - "plt.axhline(y=median_sale_price, \n", - " color=\"red\", \n", - " linestyle=\"--\", \n", - " label=f\"Median Sale Price: ${median_sale_price:,.0f}\")\n", - "plt.legend();" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that's a nice looking figure!\n", - "\n", - "Interestingly Florida has the most sales and the median sale price is above the overall median of all other states.\n", - "\n", - "And if you had a bulldozer and were chasing the highest sale price, the data would reveal that perhaps selling in South Dakota would be your best bet.\n", - "\n", - "Perhaps bulldozers are in higher demand in South Dakota because of a building or mining boom?\n", - "\n", - "Answering this would require a bit more research.\n", - "\n", - "But what we're doing here is slowly building up a mental model of our data. \n", - "\n", - "So that if we saw an example in the future, we could compare its values to the ones we've already seen." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 2. Model driven data exploration\n", - "\n", - "We've performed a small Exploratory Data Analysis (EDA) as well as enriched it with some `datetime` attributes, now let's try to model it.\n", - "\n", - "Why model so early?\n", - "\n", - "Well, we know the evaluation metric (root mean squared log error or RMSLE) we're heading towards. \n", - "\n", - "We could spend more time doing EDA, finding more out about the data ourselves but what we'll do instead is use a machine learning model to help us do EDA whilst simultaneously working towards the best evaluation metric we can get. \n", - "\n", - "Remember, one of the biggest goals of starting any new machine learning project is reducing the time between experiments.\n", - "\n", - "Following the [Scikit-Learn machine learning map](https://scikit-learn.org/stable/machine_learning_map.html) and taking into account the fact we've got over 100,000 examples, we find a [`sklearn.linear_model.SGDRegressor`](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.SGDRegressor.html) or a [`sklearn.ensemble.RandomForestRegressor`](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html#sklearn-ensemble-randomforestregressor) model might be a good candidate.\n", - "\n", - "Since we're worked with the Random Forest algorithm before (on the [heart disease classification problem](https://dev.mrdbourke.com/zero-to-mastery-ml/end-to-end-heart-disease-classification/)), let's try it out on our regression problem.\n", - "\n", - "> **Note:** We're trying just one model here for now. But you can try many other kinds of models from the Scikit-Learn library, they mostly work with a similar API. There are even libraries such as [`LazyPredict`](https://github.com/shankarpandala/lazypredict) which will try many models simultaneously and return a table with the results." - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ - { - "ename": "ValueError", - "evalue": "could not convert string to float: 'Low'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m/var/folders/c4/qj4gdk190td18bqvjjh0p3p00000gn/T/ipykernel_20423/2824176890.py\u001b[0m in \u001b[0;36m?\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# This won't work since we've got missing numbers and categories\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0msklearn\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mensemble\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mRandomForestRegressor\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mmodel\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mRandomForestRegressor\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn_jobs\u001b[0m\u001b[0;34m=\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[0;32m----> 5\u001b[0;31m model.fit(X=df_tmp.drop(\"SalePrice\", axis=1), # use all columns except SalePrice as X input\n\u001b[0m\u001b[1;32m 6\u001b[0m y=df_tmp.SalePrice) # use SalePrice column as y input\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/base.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(estimator, *args, **kwargs)\u001b[0m\n\u001b[1;32m 1469\u001b[0m skip_parameter_validation=(\n\u001b[1;32m 1470\u001b[0m \u001b[0mprefer_skip_nested_validation\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mglobal_skip_validation\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1471\u001b[0m )\n\u001b[1;32m 1472\u001b[0m ):\n\u001b[0;32m-> 1473\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mfit_method\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mestimator\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/ensemble/_forest.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, X, y, sample_weight)\u001b[0m\n\u001b[1;32m 359\u001b[0m \u001b[0;31m# Validate or convert input data\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 360\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0missparse\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my\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 361\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"sparse multilabel-indicator for y is not supported.\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 362\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 363\u001b[0;31m X, y = self._validate_data(\n\u001b[0m\u001b[1;32m 364\u001b[0m \u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 365\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 366\u001b[0m \u001b[0mmulti_output\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/base.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, X, y, reset, validate_separately, cast_to_ndarray, **check_params)\u001b[0m\n\u001b[1;32m 646\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;34m\"estimator\"\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mcheck_y_params\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 647\u001b[0m \u001b[0mcheck_y_params\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m**\u001b[0m\u001b[0mdefault_check_params\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mcheck_y_params\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 648\u001b[0m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcheck_array\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minput_name\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"y\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mcheck_y_params\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 649\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 650\u001b[0;31m \u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcheck_X_y\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mcheck_params\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 651\u001b[0m \u001b[0mout\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 652\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 653\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mno_val_X\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mcheck_params\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"ensure_2d\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mTrue\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[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/utils/validation.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(X, y, accept_sparse, accept_large_sparse, dtype, order, copy, force_writeable, force_all_finite, ensure_2d, allow_nd, multi_output, ensure_min_samples, ensure_min_features, y_numeric, estimator)\u001b[0m\n\u001b[1;32m 1297\u001b[0m raise ValueError(\n\u001b[1;32m 1298\u001b[0m \u001b[0;34mf\"{estimator_name} requires y to be passed, but the target y is None\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1299\u001b[0m )\n\u001b[1;32m 1300\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1301\u001b[0;31m X = check_array(\n\u001b[0m\u001b[1;32m 1302\u001b[0m \u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1303\u001b[0m \u001b[0maccept_sparse\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0maccept_sparse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1304\u001b[0m \u001b[0maccept_large_sparse\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0maccept_large_sparse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/utils/validation.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(array, accept_sparse, accept_large_sparse, dtype, order, copy, force_writeable, force_all_finite, ensure_2d, allow_nd, ensure_min_samples, ensure_min_features, estimator, input_name)\u001b[0m\n\u001b[1;32m 1009\u001b[0m )\n\u001b[1;32m 1010\u001b[0m \u001b[0marray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mxp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mastype\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1011\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1012\u001b[0m \u001b[0marray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_asarray_with_order\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0morder\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0morder\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mxp\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mxp\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1013\u001b[0;31m \u001b[0;32mexcept\u001b[0m \u001b[0mComplexWarning\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mcomplex_warning\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 1014\u001b[0m raise ValueError(\n\u001b[1;32m 1015\u001b[0m \u001b[0;34m\"Complex data not supported\\n{}\\n\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1016\u001b[0m ) from complex_warning\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/utils/_array_api.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(array, dtype, order, copy, xp, device)\u001b[0m\n\u001b[1;32m 747\u001b[0m \u001b[0;31m# Use NumPy API to support order\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 748\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mcopy\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 749\u001b[0m \u001b[0marray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnumpy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0morder\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0morder\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 750\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 751\u001b[0;31m \u001b[0marray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnumpy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0morder\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0morder\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\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 752\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 753\u001b[0m \u001b[0;31m# At this point array is a NumPy ndarray. We convert it to an array\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 754\u001b[0m \u001b[0;31m# container that is consistent with the input's namespace.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/pandas/core/generic.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, dtype, copy)\u001b[0m\n\u001b[1;32m 2149\u001b[0m def __array__(\n\u001b[1;32m 2150\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mnpt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mDTypeLike\u001b[0m \u001b[0;34m|\u001b[0m \u001b[0;32mNone\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mbool_t\u001b[0m \u001b[0;34m|\u001b[0m \u001b[0;32mNone\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2151\u001b[0m ) -> np.ndarray:\n\u001b[1;32m 2152\u001b[0m \u001b[0mvalues\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_values\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2153\u001b[0;31m \u001b[0marr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\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 2154\u001b[0m if (\n\u001b[1;32m 2155\u001b[0m \u001b[0mastype_is_view\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0marr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2156\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0musing_copy_on_write\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[0;31mValueError\u001b[0m: could not convert string to float: 'Low'" - ] - } - ], - "source": [ - "# This won't work since we've got missing numbers and categories\n", - "from sklearn.ensemble import RandomForestRegressor\n", - "\n", - "model = RandomForestRegressor(n_jobs=-1)\n", - "model.fit(X=df_tmp.drop(\"SalePrice\", axis=1), # use all columns except SalePrice as X input\n", - " y=df_tmp.SalePrice) # use SalePrice column as y input" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Oh no!\n", - "\n", - "When we try to fit our model to the data, we get a value error similar to:\n", - "\n", - "> `ValueError: could not convert string to float: 'Low'`\n", - "\n", - "The problem here is that some of the features of our data are in string format and machine learning models love numbers.\n", - "\n", - "Not to mention some of our samples have missing values.\n", - "\n", - "And typically, machine learning models require all data to be in numerical format as well as all missing values to be filled.\n", - "\n", - "Let's start to fix this by inspecting the different datatypes in our DataFrame.\n", - "\n", - "We can do so using the [`pandas.DataFrame.info()`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.info.html) method, this will give us the different datatypes as well as how many non-null (a null value is generally a missing value) in our `df_tmp` DataFrame.\n", - "\n", - "> **Note:** There are some ML models such as [`sklearn.ensemble.HistGradientBoostingRegressor`](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.HistGradientBoostingRegressor.html), [CatBoost](https://catboost.ai/) and [XGBoost](https://xgboost.ai/) which can handle missing values, however, I'll leave exploring each of these as extra-curriculum/extensions." - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Index: 412698 entries, 205615 to 409203\n", - "Data columns (total 57 columns):\n", - " # Column Non-Null Count Dtype \n", - "--- ------ -------------- ----- \n", - " 0 SalesID 412698 non-null int64 \n", - " 1 SalePrice 412698 non-null float64\n", - " 2 MachineID 412698 non-null int64 \n", - " 3 ModelID 412698 non-null int64 \n", - " 4 datasource 412698 non-null int64 \n", - " 5 auctioneerID 392562 non-null float64\n", - " 6 YearMade 412698 non-null int64 \n", - " 7 MachineHoursCurrentMeter 147504 non-null float64\n", - " 8 UsageBand 73670 non-null object \n", - " 9 fiModelDesc 412698 non-null object \n", - " 10 fiBaseModel 412698 non-null object \n", - " 11 fiSecondaryDesc 271971 non-null object \n", - " 12 fiModelSeries 58667 non-null object \n", - " 13 fiModelDescriptor 74816 non-null object \n", - " 14 ProductSize 196093 non-null object \n", - " 15 fiProductClassDesc 412698 non-null object \n", - " 16 state 412698 non-null object \n", - " 17 ProductGroup 412698 non-null object \n", - " 18 ProductGroupDesc 412698 non-null object \n", - " 19 Drive_System 107087 non-null object \n", - " 20 Enclosure 412364 non-null object \n", - " 21 Forks 197715 non-null object \n", - " 22 Pad_Type 81096 non-null object \n", - " 23 Ride_Control 152728 non-null object \n", - " 24 Stick 81096 non-null object \n", - " 25 Transmission 188007 non-null object \n", - " 26 Turbocharged 81096 non-null object \n", - " 27 Blade_Extension 25983 non-null object \n", - " 28 Blade_Width 25983 non-null object \n", - " 29 Enclosure_Type 25983 non-null object \n", - " 30 Engine_Horsepower 25983 non-null object \n", - " 31 Hydraulics 330133 non-null object \n", - " 32 Pushblock 25983 non-null object \n", - " 33 Ripper 106945 non-null object \n", - " 34 Scarifier 25994 non-null object \n", - " 35 Tip_Control 25983 non-null object \n", - " 36 Tire_Size 97638 non-null object \n", - " 37 Coupler 220679 non-null object \n", - " 38 Coupler_System 44974 non-null object \n", - " 39 Grouser_Tracks 44875 non-null object \n", - " 40 Hydraulics_Flow 44875 non-null object \n", - " 41 Track_Type 102193 non-null object \n", - " 42 Undercarriage_Pad_Width 102916 non-null object \n", - " 43 Stick_Length 102261 non-null object \n", - " 44 Thumb 102332 non-null object \n", - " 45 Pattern_Changer 102261 non-null object \n", - " 46 Grouser_Type 102193 non-null object \n", - " 47 Backhoe_Mounting 80712 non-null object \n", - " 48 Blade_Type 81875 non-null object \n", - " 49 Travel_Controls 81877 non-null object \n", - " 50 Differential_Type 71564 non-null object \n", - " 51 Steering_Controls 71522 non-null object \n", - " 52 saleYear 412698 non-null int32 \n", - " 53 saleMonth 412698 non-null int32 \n", - " 54 saleDay 412698 non-null int32 \n", - " 55 saleDayofweek 412698 non-null int32 \n", - " 56 saleDayofyear 412698 non-null int32 \n", - "dtypes: float64(3), int32(5), int64(5), object(44)\n", - "memory usage: 174.7+ MB\n" - ] - } - ], - "source": [ - "# Check for missing values and different datatypes \n", - "df_tmp.info();" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Ok, it seems as though we've got a fair few different datatypes. \n", - "\n", - "There are `int64` types such as `MachineID`.\n", - "\n", - "There are `float64` types such as `SalePrice`.\n", - "\n", - "And there are `object` (the `object` dtype can hold any Python object, including strings) types such as `UseageBand`.\n", - "\n", - "> **Resource:** You can see a list of all the [pandas dtypes in the pandas user guide](https://pandas.pydata.org/docs/user_guide/basics.html#dtypes).\n", - "\n", - "How about we find out how many missing values are in each column?\n", - "\n", - "We can do so using [`pandas.DataFrame.isna()`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.isna.html) (`isna` stands for 'is null or NaN') which will return a boolean `True`/`False` if a value is missing (`True` if missing, `False` if not). \n", - "\n", - "Let's start by checking the missing values in the head of our DataFrame." - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - " \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", - "
SalesIDSalePriceMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandfiModelDesc...Backhoe_MountingBlade_TypeTravel_ControlsDifferential_TypeSteering_ControlssaleYearsaleMonthsaleDaysaleDayofweeksaleDayofyear
205615FalseFalseFalseFalseFalseFalseFalseTrueTrueFalse...FalseFalseFalseTrueTrueFalseFalseFalseFalseFalse
274835FalseFalseFalseFalseFalseFalseFalseTrueTrueFalse...TrueTrueTrueFalseFalseFalseFalseFalseFalseFalse
141296FalseFalseFalseFalseFalseFalseFalseTrueTrueFalse...FalseFalseFalseTrueTrueFalseFalseFalseFalseFalse
212552FalseFalseFalseFalseFalseFalseFalseTrueTrueFalse...TrueTrueTrueFalseFalseFalseFalseFalseFalseFalse
62755FalseFalseFalseFalseFalseFalseFalseTrueTrueFalse...FalseFalseFalseTrueTrueFalseFalseFalseFalseFalse
\n", - "

5 rows × 57 columns

\n", - "
" - ], - "text/plain": [ - " SalesID SalePrice MachineID ModelID datasource auctioneerID \\\n", - "205615 False False False False False False \n", - "274835 False False False False False False \n", - "141296 False False False False False False \n", - "212552 False False False False False False \n", - "62755 False False False False False False \n", - "\n", - " YearMade MachineHoursCurrentMeter UsageBand fiModelDesc ... \\\n", - "205615 False True True False ... \n", - "274835 False True True False ... \n", - "141296 False True True False ... \n", - "212552 False True True False ... \n", - "62755 False True True False ... \n", - "\n", - " Backhoe_Mounting Blade_Type Travel_Controls Differential_Type \\\n", - "205615 False False False True \n", - "274835 True True True False \n", - "141296 False False False True \n", - "212552 True True True False \n", - "62755 False False False True \n", - "\n", - " Steering_Controls saleYear saleMonth saleDay saleDayofweek \\\n", - "205615 True False False False False \n", - "274835 False False False False False \n", - "141296 True False False False False \n", - "212552 False False False False False \n", - "62755 True False False False False \n", - "\n", - " saleDayofyear \n", - "205615 False \n", - "274835 False \n", - "141296 False \n", - "212552 False \n", - "62755 False \n", - "\n", - "[5 rows x 57 columns]" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Find missing values in the head of our DataFrame \n", - "df_tmp.head().isna()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Alright it seems as though we've got some missing values in the `MachineHoursCurrentMeter` as well as the `UsageBand` and a few other columns.\n", - "\n", - "But so far we've only viewed the first few rows.\n", - "\n", - "It'll be very time consuming to go through each row one by one so how about we get the total missing values per column?\n", - "\n", - "We can do so by calling `.isna()` on the whole DataFrame and then chaining it together with `.sum()`.\n", - "\n", - "Doing so will give us the total `True`/`False` values in a given column (when summing, `True` = 1, `False` = 0)." - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "SalesID 0\n", - "SalePrice 0\n", - "MachineID 0\n", - "ModelID 0\n", - "datasource 0\n", - "auctioneerID 20136\n", - "YearMade 0\n", - "MachineHoursCurrentMeter 265194\n", - "UsageBand 339028\n", - "fiModelDesc 0\n", - "fiBaseModel 0\n", - "fiSecondaryDesc 140727\n", - "fiModelSeries 354031\n", - "fiModelDescriptor 337882\n", - "ProductSize 216605\n", - "fiProductClassDesc 0\n", - "state 0\n", - "ProductGroup 0\n", - "ProductGroupDesc 0\n", - "Drive_System 305611\n", - "Enclosure 334\n", - "Forks 214983\n", - "Pad_Type 331602\n", - "Ride_Control 259970\n", - "Stick 331602\n", - "Transmission 224691\n", - "Turbocharged 331602\n", - "Blade_Extension 386715\n", - "Blade_Width 386715\n", - "Enclosure_Type 386715\n", - "Engine_Horsepower 386715\n", - "Hydraulics 82565\n", - "Pushblock 386715\n", - "Ripper 305753\n", - "Scarifier 386704\n", - "Tip_Control 386715\n", - "Tire_Size 315060\n", - "Coupler 192019\n", - "Coupler_System 367724\n", - "Grouser_Tracks 367823\n", - "Hydraulics_Flow 367823\n", - "Track_Type 310505\n", - "Undercarriage_Pad_Width 309782\n", - "Stick_Length 310437\n", - "Thumb 310366\n", - "Pattern_Changer 310437\n", - "Grouser_Type 310505\n", - "Backhoe_Mounting 331986\n", - "Blade_Type 330823\n", - "Travel_Controls 330821\n", - "Differential_Type 341134\n", - "Steering_Controls 341176\n", - "saleYear 0\n", - "saleMonth 0\n", - "saleDay 0\n", - "saleDayofweek 0\n", - "saleDayofyear 0\n", - "dtype: int64" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Check for total missing values per column\n", - "df_tmp.isna().sum()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Woah! It looks like our DataFrame has quite a few missing values.\n", - "\n", - "Not to worry, we can work on fixing this later on.\n", - "\n", - "How about we start by tring to turn all of our data in numbers? " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2.1 Inspecting the datatypes in our DataFrame \n", - "\n", - "One way to help turn all of our data into numbers is to convert the columns with the `object` datatype into a `category` datatype using [`pandas.CategoricalDtype`](https://pandas.pydata.org/docs/reference/api/pandas.CategoricalDtype.html).\n", - "\n", - "> **Note:** There are many different ways to convert values into numbers. And often the best way will be specific to the value you're trying to convert. The method we're going to use, converting all objects (that are mostly strings) to categories is one of the faster methods as it makes a quick assumption that each unique value is its own number. \n", - "\n", - "We can check the datatype of an individual column using the `.dtype` attribute and we can get its full name using `.dtype.name`." - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(dtype('O'), 'object')" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Get the dtype of a given column\n", - "df_tmp[\"UsageBand\"].dtype, df_tmp[\"UsageBand\"].dtype.name" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Beautiful!\n", - "\n", - "Now we've got a way to check a column's datatype individually.\n", - "\n", - "There's also another group of methods to check a column's datatype directly.\n", - "\n", - "For example, using [`pd.api.types.is_object_dtype(arr_or_dtype)`](https://pandas.pydata.org/docs/reference/api/pandas.api.types.is_object_dtype.html) we can get a boolean response as to whether the input is an object or not.\n", - "\n", - "> **Note:** There are many more of these checks you can perform for other datatypes such as strings under a similar name space `pd.api.types.is_XYZ_dtype`. See the [pandas documentation](https://pandas.pydata.org/docs/reference/arrays.html) for more.\n", - "\n", - "Let's see how it works on our `df_tmp[\"UsageBand\"]` column." - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Check whether a column is an object\n", - "pd.api.types.is_object_dtype(df_tmp[\"UsageBand\"])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can also check whether a column is a string with [`pd.api.types.is_string_dtype(arr_or_dtype)`](https://pandas.pydata.org/docs/reference/api/pandas.api.types.is_string_dtype.html). " - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 35, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Check whether a column is a string\n", - "pd.api.types.is_string_dtype(df_tmp[\"state\"])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Nice!\n", - "\n", - "We can even loop through the items (columns and their labels) in our DataFrame using [`pandas.DataFrame.items()`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.items.html) (in Python dictionary terms, calling `.items()` on a DataFrame will treat the column names as the keys and the column values as the values) and print out samples of columns which have the `string` datatype.\n", - "\n", - "As an extra check, passing the sample to [`pd.api.types.infer_dtype()`](https://pandas.pydata.org/docs/reference/api/pandas.api.types.infer_dtype.html) will return the datatype of the sample.\n", - "\n", - "This will be a good way to keep exploring our data." - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "This is a key: key1\n", - "This is a value: hello\n", - "This is a key: key2\n", - "This is a value: world!\n" - ] - } - ], - "source": [ - "# Quick exampke of calling .items() on a dictionary\n", - "random_dict = {\"key1\": \"hello\",\n", - " \"key2\": \"world!\"}\n", - "\n", - "for key, value in random_dict.items():\n", - " print(f\"This is a key: {key}\")\n", - " print(f\"This is a value: {value}\")" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Column name: fiModelDesc | Column dtype: object | Example value: ['35ZTS'] | Example value dtype: string\n", - "Column name: fiBaseModel | Column dtype: object | Example value: ['PC75'] | Example value dtype: string\n", - "Column name: fiProductClassDesc | Column dtype: object | Example value: ['Backhoe Loader - 14.0 to 15.0 Ft Standard Digging Depth'] | Example value dtype: string\n", - "Column name: state | Column dtype: object | Example value: ['Florida'] | Example value dtype: string\n", - "Column name: ProductGroup | Column dtype: object | Example value: ['TTT'] | Example value dtype: string\n", - "Column name: ProductGroupDesc | Column dtype: object | Example value: ['Track Excavators'] | Example value dtype: string\n" - ] - } - ], - "source": [ - "# Print column names and example content of columns which contain strings\n", - "for label, content in df_tmp.items():\n", - " if pd.api.types.is_string_dtype(content):\n", - " # Check datatype of target column\n", - " column_datatype = df_tmp[label].dtype.name\n", - "\n", - " # Get random sample from column values\n", - " example_value = content.sample(1).values\n", - "\n", - " # Infer random sample datatype\n", - " example_value_dtype = pd.api.types.infer_dtype(example_value)\n", - " print(f\"Column name: {label} | Column dtype: {column_datatype} | Example value: {example_value} | Example value dtype: {example_value_dtype}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Hmm... it seems that there are many more columns in the `df_tmp` with the `object` type that didn't display when checking for the string datatype (we know there are many `object` datatype columns in our DataFrame from using `df_tmp.info()`).\n", - "\n", - "How about we try the same as above, except this time instead of `pd.api.types.is_string_dtype`, we use `pd.api.types.is_object_dtype`?\n", - "\n", - "Let's try it." - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Column name: UsageBand | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: fiModelDesc | Column dtype: object | Example value: ['590SUPER MII'] | Example value dtype: string\n", - "Column name: fiBaseModel | Column dtype: object | Example value: ['580'] | Example value dtype: string\n", - "Column name: fiSecondaryDesc | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: fiModelSeries | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: fiModelDescriptor | Column dtype: object | Example value: ['H'] | Example value dtype: string\n", - "Column name: ProductSize | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: fiProductClassDesc | Column dtype: object | Example value: ['Track Type Tractor, Dozer - 75.0 to 85.0 Horsepower'] | Example value dtype: string\n", - "Column name: state | Column dtype: object | Example value: ['Florida'] | Example value dtype: string\n", - "Column name: ProductGroup | Column dtype: object | Example value: ['TEX'] | Example value dtype: string\n", - "Column name: ProductGroupDesc | Column dtype: object | Example value: ['Skid Steer Loaders'] | Example value dtype: string\n", - "Column name: Drive_System | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Enclosure | Column dtype: object | Example value: ['EROPS'] | Example value dtype: string\n", - "Column name: Forks | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Pad_Type | Column dtype: object | Example value: ['None or Unspecified'] | Example value dtype: string\n", - "Column name: Ride_Control | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Stick | Column dtype: object | Example value: ['Extended'] | Example value dtype: string\n", - "Column name: Transmission | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Turbocharged | Column dtype: object | Example value: ['None or Unspecified'] | Example value dtype: string\n", - "Column name: Blade_Extension | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Blade_Width | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Enclosure_Type | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Engine_Horsepower | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Hydraulics | Column dtype: object | Example value: ['Standard'] | Example value dtype: string\n", - "Column name: Pushblock | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Ripper | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Scarifier | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Tip_Control | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Tire_Size | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Coupler | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Coupler_System | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Grouser_Tracks | Column dtype: object | Example value: ['None or Unspecified'] | Example value dtype: string\n", - "Column name: Hydraulics_Flow | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Track_Type | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Undercarriage_Pad_Width | Column dtype: object | Example value: ['20 inch'] | Example value dtype: string\n", - "Column name: Stick_Length | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Thumb | Column dtype: object | Example value: ['None or Unspecified'] | Example value dtype: string\n", - "Column name: Pattern_Changer | Column dtype: object | Example value: ['None or Unspecified'] | Example value dtype: string\n", - "Column name: Grouser_Type | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Backhoe_Mounting | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Blade_Type | Column dtype: object | Example value: ['Straight'] | Example value dtype: string\n", - "Column name: Travel_Controls | Column dtype: object | Example value: ['None or Unspecified'] | Example value dtype: string\n", - "Column name: Differential_Type | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Steering_Controls | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "\n", - "[INFO] Total number of object type columns: 44\n" - ] - } - ], - "source": [ - "# Start a count of how many object type columns there are\n", - "number_of_object_type_columns = 0\n", - "\n", - "for label, content in df_tmp.items():\n", - " # Check to see if column is of object type (this will include the string columns)\n", - " if pd.api.types.is_object_dtype(content): \n", - " # Check datatype of target column\n", - " column_datatype = df_tmp[label].dtype.name\n", - "\n", - " # Get random sample from column values\n", - " example_value = content.sample(1).values\n", - "\n", - " # Infer random sample datatype\n", - " example_value_dtype = pd.api.types.infer_dtype(example_value)\n", - " print(f\"Column name: {label} | Column dtype: {column_datatype} | Example value: {example_value} | Example value dtype: {example_value_dtype}\")\n", - "\n", - " number_of_object_type_columns += 1\n", - "\n", - "print(f\"\\n[INFO] Total number of object type columns: {number_of_object_type_columns}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Wonderful, looks like we've got sample outputs from all of the columns with the `object` datatype.\n", - "\n", - "It also looks like that many of random samples are missing values." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2.2 Converting strings to categories with pandas \n", - "\n", - "In pandas, one way to convert object/string values to numerical values is to convert them to categories or more specifically, the `pd.CategoricalDtype` datatype.\n", - "\n", - "This datatype keeps the underlying data the same (e.g. doesn't change the string) but enables easy conversion to a numeric code using [`.cat.codes`](https://pandas.pydata.org/docs/reference/api/pandas.Series.cat.codes.html).\n", - "\n", - "For example, the column `state` might have the values `'Alabama', 'Alaska', 'Arizona'...` and these could be mapped to numeric values `1, 2, 3...` respectively.\n", - "\n", - "To see this in action, let's first convert the object datatype columns to `\"category\"` datatype.\n", - "\n", - "We can do so by looping through the `.items()` of our DataFrame and reassigning each object datatype column using [`pandas.Series.astype(dtype=\"category\")`](https://pandas.pydata.org/docs/reference/api/pandas.Series.astype.html)." - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [], - "source": [ - "# This will turn all of the object columns into category values\n", - "for label, content in df_tmp.items(): \n", - " if pd.api.types.is_object_dtype(content):\n", - " df_tmp[label] = df_tmp[label].astype(\"category\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Wonderful!\n", - "\n", - "Now let's check if it worked by calling `.info()` on our DataFrame." - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Index: 412698 entries, 205615 to 409203\n", - "Data columns (total 57 columns):\n", - " # Column Non-Null Count Dtype \n", - "--- ------ -------------- ----- \n", - " 0 SalesID 412698 non-null int64 \n", - " 1 SalePrice 412698 non-null float64 \n", - " 2 MachineID 412698 non-null int64 \n", - " 3 ModelID 412698 non-null int64 \n", - " 4 datasource 412698 non-null int64 \n", - " 5 auctioneerID 392562 non-null float64 \n", - " 6 YearMade 412698 non-null int64 \n", - " 7 MachineHoursCurrentMeter 147504 non-null float64 \n", - " 8 UsageBand 73670 non-null category\n", - " 9 fiModelDesc 412698 non-null category\n", - " 10 fiBaseModel 412698 non-null category\n", - " 11 fiSecondaryDesc 271971 non-null category\n", - " 12 fiModelSeries 58667 non-null category\n", - " 13 fiModelDescriptor 74816 non-null category\n", - " 14 ProductSize 196093 non-null category\n", - " 15 fiProductClassDesc 412698 non-null category\n", - " 16 state 412698 non-null category\n", - " 17 ProductGroup 412698 non-null category\n", - " 18 ProductGroupDesc 412698 non-null category\n", - " 19 Drive_System 107087 non-null category\n", - " 20 Enclosure 412364 non-null category\n", - " 21 Forks 197715 non-null category\n", - " 22 Pad_Type 81096 non-null category\n", - " 23 Ride_Control 152728 non-null category\n", - " 24 Stick 81096 non-null category\n", - " 25 Transmission 188007 non-null category\n", - " 26 Turbocharged 81096 non-null category\n", - " 27 Blade_Extension 25983 non-null category\n", - " 28 Blade_Width 25983 non-null category\n", - " 29 Enclosure_Type 25983 non-null category\n", - " 30 Engine_Horsepower 25983 non-null category\n", - " 31 Hydraulics 330133 non-null category\n", - " 32 Pushblock 25983 non-null category\n", - " 33 Ripper 106945 non-null category\n", - " 34 Scarifier 25994 non-null category\n", - " 35 Tip_Control 25983 non-null category\n", - " 36 Tire_Size 97638 non-null category\n", - " 37 Coupler 220679 non-null category\n", - " 38 Coupler_System 44974 non-null category\n", - " 39 Grouser_Tracks 44875 non-null category\n", - " 40 Hydraulics_Flow 44875 non-null category\n", - " 41 Track_Type 102193 non-null category\n", - " 42 Undercarriage_Pad_Width 102916 non-null category\n", - " 43 Stick_Length 102261 non-null category\n", - " 44 Thumb 102332 non-null category\n", - " 45 Pattern_Changer 102261 non-null category\n", - " 46 Grouser_Type 102193 non-null category\n", - " 47 Backhoe_Mounting 80712 non-null category\n", - " 48 Blade_Type 81875 non-null category\n", - " 49 Travel_Controls 81877 non-null category\n", - " 50 Differential_Type 71564 non-null category\n", - " 51 Steering_Controls 71522 non-null category\n", - " 52 saleYear 412698 non-null int32 \n", - " 53 saleMonth 412698 non-null int32 \n", - " 54 saleDay 412698 non-null int32 \n", - " 55 saleDayofweek 412698 non-null int32 \n", - " 56 saleDayofyear 412698 non-null int32 \n", - "dtypes: category(44), float64(3), int32(5), int64(5)\n", - "memory usage: 55.4 MB\n" - ] - } - ], - "source": [ - "df_tmp.info()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "It looks like it worked!\n", - "\n", - "All of the object datatype columns now have the category datatype.\n", - "\n", - "We can inspect this on a single column using `pandas.Series.dtype`." - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "CategoricalDtype(categories=['Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California',\n", - " 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia',\n", - " 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas',\n", - " 'Kentucky', 'Louisiana', 'Maine', 'Maryland',\n", - " 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi',\n", - " 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire',\n", - " 'New Jersey', 'New Mexico', 'New York', 'North Carolina',\n", - " 'North Dakota', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania',\n", - " 'Puerto Rico', 'Rhode Island', 'South Carolina',\n", - " 'South Dakota', 'Tennessee', 'Texas', 'Unspecified', 'Utah',\n", - " 'Vermont', 'Virginia', 'Washington', 'Washington DC',\n", - " 'West Virginia', 'Wisconsin', 'Wyoming'],\n", - ", ordered=False, categories_dtype=object)" - ] - }, - "execution_count": 41, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Check the datatype of a single column\n", - "df_tmp.state.dtype" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Excellent, notice how the column is now of type `pd.CategoricalDtype`.\n", - "\n", - "We can also access these categories using [`pandas.Series.cat.categories`](https://pandas.pydata.org/docs/reference/api/pandas.Series.cat.categories.html)." - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Index(['Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado',\n", - " 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho',\n", - " 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana',\n", - " 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota',\n", - " 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada',\n", - " 'New Hampshire', 'New Jersey', 'New Mexico', 'New York',\n", - " 'North Carolina', 'North Dakota', 'Ohio', 'Oklahoma', 'Oregon',\n", - " 'Pennsylvania', 'Puerto Rico', 'Rhode Island', 'South Carolina',\n", - " 'South Dakota', 'Tennessee', 'Texas', 'Unspecified', 'Utah', 'Vermont',\n", - " 'Virginia', 'Washington', 'Washington DC', 'West Virginia', 'Wisconsin',\n", - " 'Wyoming'],\n", - " dtype='object')" - ] - }, - "execution_count": 42, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Get the category names of a given column\n", - "df_tmp.state.cat.categories" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, we can get the category codes (the numeric values representing the category) using [`pandas.Series.cat.codes`](https://pandas.pydata.org/docs/reference/api/pandas.Series.cat.codes.html)." - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "205615 43\n", - "274835 8\n", - "141296 8\n", - "212552 8\n", - "62755 8\n", - " ..\n", - "410879 4\n", - "412476 4\n", - "411927 4\n", - "407124 4\n", - "409203 4\n", - "Length: 412698, dtype: int8" - ] - }, - "execution_count": 43, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Inspect the category codes\n", - "df_tmp.state.cat.codes" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This gives us a numeric representation of our object/string datatype columns." - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Target state category number 43 maps to: Texas\n" - ] - } - ], - "source": [ - "# Get example string using category number\n", - "target_state_cat_number = 43\n", - "target_state_cat_value = df_tmp.state.cat.categories[target_state_cat_number] \n", - "print(f\"[INFO] Target state category number {target_state_cat_number} maps to: {target_state_cat_value}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Epic! \n", - "\n", - "All of our data is categorical and thus we can now turn the categories into numbers, however it's still missing values, not to worry though, we'll get to these shortly." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2.3 Saving our preprocessed data (part 1)\n", - "\n", - "Before we start doing any further preprocessing steps on our DataFrame, how about we save our current DataFrame to file so we could import it again later if necessary.\n", - "\n", - "Saving and updating your dataset as you go is common practice in machine learning problems. As your problem changes and evolves, the dataset you're working with will likely change too.\n", - "\n", - "Making checkpoints of your dataset is similar to making checkpoints of your code." - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": {}, - "outputs": [], - "source": [ - "# Save preprocessed data to file\n", - "df_tmp.to_csv(\"../data/bluebook-for-bulldozers/TrainAndValid_object_values_as_categories.csv\",\n", - " index=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we've saved our preprocessed data to file, we can re-import it and make sure it's in the same format." - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - " \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", - "
SalesIDSalePriceMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandfiModelDesc...Backhoe_MountingBlade_TypeTravel_ControlsDifferential_TypeSteering_ControlssaleYearsaleMonthsaleDaysaleDayofweeksaleDayofyear
016467709500.01126363843413218.01974NaNNaNTD20...None or UnspecifiedStraightNone or UnspecifiedNaNNaN1989117117
1182151414000.011940891015013299.01980NaNNaNA66...NaNNaNNaNStandardConventional1989131131
2150513850000.01473654413913299.01978NaNNaND7G...None or UnspecifiedStraightNone or UnspecifiedNaNNaN1989131131
3167117416000.01327630859113299.01980NaNNaNA62...NaNNaNNaNStandardConventional1989131131
4132905622000.01336053408913299.01984NaNNaND3B...None or UnspecifiedPATLeverNaNNaN1989131131
\n", - "

5 rows × 57 columns

\n", - "
" - ], - "text/plain": [ - " SalesID SalePrice MachineID ModelID datasource auctioneerID YearMade \\\n", - "0 1646770 9500.0 1126363 8434 132 18.0 1974 \n", - "1 1821514 14000.0 1194089 10150 132 99.0 1980 \n", - "2 1505138 50000.0 1473654 4139 132 99.0 1978 \n", - "3 1671174 16000.0 1327630 8591 132 99.0 1980 \n", - "4 1329056 22000.0 1336053 4089 132 99.0 1984 \n", - "\n", - " MachineHoursCurrentMeter UsageBand fiModelDesc ... Backhoe_Mounting \\\n", - "0 NaN NaN TD20 ... None or Unspecified \n", - "1 NaN NaN A66 ... NaN \n", - "2 NaN NaN D7G ... None or Unspecified \n", - "3 NaN NaN A62 ... NaN \n", - "4 NaN NaN D3B ... None or Unspecified \n", - "\n", - " Blade_Type Travel_Controls Differential_Type Steering_Controls \\\n", - "0 Straight None or Unspecified NaN NaN \n", - "1 NaN NaN Standard Conventional \n", - "2 Straight None or Unspecified NaN NaN \n", - "3 NaN NaN Standard Conventional \n", - "4 PAT Lever NaN NaN \n", - "\n", - " saleYear saleMonth saleDay saleDayofweek saleDayofyear \n", - "0 1989 1 17 1 17 \n", - "1 1989 1 31 1 31 \n", - "2 1989 1 31 1 31 \n", - "3 1989 1 31 1 31 \n", - "4 1989 1 31 1 31 \n", - "\n", - "[5 rows x 57 columns]" - ] - }, - "execution_count": 46, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Import preprocessed data to file\n", - "df_tmp = pd.read_csv(\"../data/bluebook-for-bulldozers/TrainAndValid_object_values_as_categories.csv\",\n", - " low_memory=False)\n", - "\n", - "df_tmp.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Excellent, looking at the tale end (the far right side) our processed DataFrame has the columns we added to it (the extra data features) but it's still missing values.\n", - "\n", - "But if we check `df_tmp.info()`..." - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "RangeIndex: 412698 entries, 0 to 412697\n", - "Data columns (total 57 columns):\n", - " # Column Non-Null Count Dtype \n", - "--- ------ -------------- ----- \n", - " 0 SalesID 412698 non-null int64 \n", - " 1 SalePrice 412698 non-null float64\n", - " 2 MachineID 412698 non-null int64 \n", - " 3 ModelID 412698 non-null int64 \n", - " 4 datasource 412698 non-null int64 \n", - " 5 auctioneerID 392562 non-null float64\n", - " 6 YearMade 412698 non-null int64 \n", - " 7 MachineHoursCurrentMeter 147504 non-null float64\n", - " 8 UsageBand 73670 non-null object \n", - " 9 fiModelDesc 412698 non-null object \n", - " 10 fiBaseModel 412698 non-null object \n", - " 11 fiSecondaryDesc 271971 non-null object \n", - " 12 fiModelSeries 58667 non-null object \n", - " 13 fiModelDescriptor 74816 non-null object \n", - " 14 ProductSize 196093 non-null object \n", - " 15 fiProductClassDesc 412698 non-null object \n", - " 16 state 412698 non-null object \n", - " 17 ProductGroup 412698 non-null object \n", - " 18 ProductGroupDesc 412698 non-null object \n", - " 19 Drive_System 107087 non-null object \n", - " 20 Enclosure 412364 non-null object \n", - " 21 Forks 197715 non-null object \n", - " 22 Pad_Type 81096 non-null object \n", - " 23 Ride_Control 152728 non-null object \n", - " 24 Stick 81096 non-null object \n", - " 25 Transmission 188007 non-null object \n", - " 26 Turbocharged 81096 non-null object \n", - " 27 Blade_Extension 25983 non-null object \n", - " 28 Blade_Width 25983 non-null object \n", - " 29 Enclosure_Type 25983 non-null object \n", - " 30 Engine_Horsepower 25983 non-null object \n", - " 31 Hydraulics 330133 non-null object \n", - " 32 Pushblock 25983 non-null object \n", - " 33 Ripper 106945 non-null object \n", - " 34 Scarifier 25994 non-null object \n", - " 35 Tip_Control 25983 non-null object \n", - " 36 Tire_Size 97638 non-null object \n", - " 37 Coupler 220679 non-null object \n", - " 38 Coupler_System 44974 non-null object \n", - " 39 Grouser_Tracks 44875 non-null object \n", - " 40 Hydraulics_Flow 44875 non-null object \n", - " 41 Track_Type 102193 non-null object \n", - " 42 Undercarriage_Pad_Width 102916 non-null object \n", - " 43 Stick_Length 102261 non-null object \n", - " 44 Thumb 102332 non-null object \n", - " 45 Pattern_Changer 102261 non-null object \n", - " 46 Grouser_Type 102193 non-null object \n", - " 47 Backhoe_Mounting 80712 non-null object \n", - " 48 Blade_Type 81875 non-null object \n", - " 49 Travel_Controls 81877 non-null object \n", - " 50 Differential_Type 71564 non-null object \n", - " 51 Steering_Controls 71522 non-null object \n", - " 52 saleYear 412698 non-null int64 \n", - " 53 saleMonth 412698 non-null int64 \n", - " 54 saleDay 412698 non-null int64 \n", - " 55 saleDayofweek 412698 non-null int64 \n", - " 56 saleDayofyear 412698 non-null int64 \n", - "dtypes: float64(3), int64(10), object(44)\n", - "memory usage: 179.5+ MB\n" - ] - } - ], - "source": [ - "df_tmp.info()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Hmm... what happened here? \n", - "\n", - "Notice that all of the `category` datatype columns are back to the `object` datatype.\n", - "\n", - "This is strange since we already converted the `object` datatype columns to `category`.\n", - "\n", - "Well then why did they change back?\n", - "\n", - "This happens because of the limitations of the CSV (`.csv`) file format, it doesn't preserve data types, rather it stores all the values as strings.\n", - "\n", - "So when we read in a CSV, pandas defaults to interpreting strings as `object` datatypes.\n", - "\n", - "Not to worry though, we can easily convert them to the `category` datatype as we did before.\n", - "\n", - "> **Note:** If you'd like to retain the datatypes when saving your data, you can use file formats such as [`parquet`](https://pandas.pydata.org/docs/user_guide/io.html#parquet) (Apache Parquet) and [`feather`](https://pandas.pydata.org/docs/user_guide/io.html#feather). These filetypes have several advantages over CSV in terms of processing speeds and storage size. However, data stored in these formats is not human-readable so you won't be able to open the files and inspect them without specific tools. For more on different file formats in pandas, see the [IO tools documentation page](https://pandas.pydata.org/docs/user_guide/io.html#)." - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": {}, - "outputs": [], - "source": [ - "for label, content in df_tmp.items():\n", - " if pd.api.types.is_object_dtype(content):\n", - " # Turn object columns into category datatype\n", - " df_tmp[label] = df_tmp[label].astype(\"category\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now if we wanted to preserve the datatypes of our data, we can save to `parquet` or `feather` format.\n", - "\n", - "Let's try using `parquet` format.\n", - "\n", - "To do so, we can use the [`pandas.DataFrame.to_parquet()`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_parquet.html) method.\n", - "\n", - "Files in the `parquet` format typically have the file extension of `.parquet`." - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "metadata": {}, - "outputs": [], - "source": [ - "# To save to parquet format requires pyarrow or fastparquet (or both)\n", - "# Can install via `pip install pyarrow fastparquet`\n", - "df_tmp.to_parquet(path=\"../data/bluebook-for-bulldozers/TrainAndValid_object_values_as_categories.parquet\", \n", - " engine=\"auto\") # \"auto\" will automatically use pyarrow or fastparquet, defaulting to pyarrow first" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Wonderful! Now let's try importing our DataFrame from the `parquet` format and check it using `df_tmp.info()`." - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "RangeIndex: 412698 entries, 0 to 412697\n", - "Data columns (total 57 columns):\n", - " # Column Non-Null Count Dtype \n", - "--- ------ -------------- ----- \n", - " 0 SalesID 412698 non-null int64 \n", - " 1 SalePrice 412698 non-null float64 \n", - " 2 MachineID 412698 non-null int64 \n", - " 3 ModelID 412698 non-null int64 \n", - " 4 datasource 412698 non-null int64 \n", - " 5 auctioneerID 392562 non-null float64 \n", - " 6 YearMade 412698 non-null int64 \n", - " 7 MachineHoursCurrentMeter 147504 non-null float64 \n", - " 8 UsageBand 73670 non-null category\n", - " 9 fiModelDesc 412698 non-null category\n", - " 10 fiBaseModel 412698 non-null category\n", - " 11 fiSecondaryDesc 271971 non-null category\n", - " 12 fiModelSeries 58667 non-null category\n", - " 13 fiModelDescriptor 74816 non-null category\n", - " 14 ProductSize 196093 non-null category\n", - " 15 fiProductClassDesc 412698 non-null category\n", - " 16 state 412698 non-null category\n", - " 17 ProductGroup 412698 non-null category\n", - " 18 ProductGroupDesc 412698 non-null category\n", - " 19 Drive_System 107087 non-null category\n", - " 20 Enclosure 412364 non-null category\n", - " 21 Forks 197715 non-null category\n", - " 22 Pad_Type 81096 non-null category\n", - " 23 Ride_Control 152728 non-null category\n", - " 24 Stick 81096 non-null category\n", - " 25 Transmission 188007 non-null category\n", - " 26 Turbocharged 81096 non-null category\n", - " 27 Blade_Extension 25983 non-null category\n", - " 28 Blade_Width 25983 non-null category\n", - " 29 Enclosure_Type 25983 non-null category\n", - " 30 Engine_Horsepower 25983 non-null category\n", - " 31 Hydraulics 330133 non-null category\n", - " 32 Pushblock 25983 non-null category\n", - " 33 Ripper 106945 non-null category\n", - " 34 Scarifier 25994 non-null category\n", - " 35 Tip_Control 25983 non-null category\n", - " 36 Tire_Size 97638 non-null category\n", - " 37 Coupler 220679 non-null category\n", - " 38 Coupler_System 44974 non-null category\n", - " 39 Grouser_Tracks 44875 non-null category\n", - " 40 Hydraulics_Flow 44875 non-null category\n", - " 41 Track_Type 102193 non-null category\n", - " 42 Undercarriage_Pad_Width 102916 non-null category\n", - " 43 Stick_Length 102261 non-null category\n", - " 44 Thumb 102332 non-null category\n", - " 45 Pattern_Changer 102261 non-null category\n", - " 46 Grouser_Type 102193 non-null category\n", - " 47 Backhoe_Mounting 80712 non-null category\n", - " 48 Blade_Type 81875 non-null category\n", - " 49 Travel_Controls 81877 non-null category\n", - " 50 Differential_Type 71564 non-null category\n", - " 51 Steering_Controls 71522 non-null category\n", - " 52 saleYear 412698 non-null int64 \n", - " 53 saleMonth 412698 non-null int64 \n", - " 54 saleDay 412698 non-null int64 \n", - " 55 saleDayofweek 412698 non-null int64 \n", - " 56 saleDayofyear 412698 non-null int64 \n", - "dtypes: category(44), float64(3), int64(10)\n", - "memory usage: 60.1 MB\n" - ] - } - ], - "source": [ - "# Read in df_tmp from parquet format\n", - "df_tmp = pd.read_parquet(path=\"../data/bluebook-for-bulldozers/TrainAndValid_object_values_as_categories.parquet\",\n", - " engine=\"auto\")\n", - "\n", - "# Using parquet format, datatypes are preserved\n", - "df_tmp.info()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Nice! Looks like using the `parquet` format preserved all of our datatypes.\n", - "\n", - "For more on the `parquet` and `feather` formats, be sure to check out the [pandas IO (input/output) documentation](https://pandas.pydata.org/docs/user_guide/io.html#parquet)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2.4 Finding and filling missing values\n", - "\n", - "Let's remind ourselves of the missing values by getting the top 20 columns with the most missing values.\n", - "\n", - "We do so by summing the results of [`pandas.DataFrame.isna()`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.isna.html) and then using [`sort_values(ascending=False)`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.sort_values.html) to showcase the rows with the most missing." - ] - }, - { - "cell_type": "code", - "execution_count": 51, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Blade_Width 386715\n", - "Engine_Horsepower 386715\n", - "Tip_Control 386715\n", - "Pushblock 386715\n", - "Blade_Extension 386715\n", - "Enclosure_Type 386715\n", - "Scarifier 386704\n", - "Hydraulics_Flow 367823\n", - "Grouser_Tracks 367823\n", - "Coupler_System 367724\n", - "fiModelSeries 354031\n", - "Steering_Controls 341176\n", - "Differential_Type 341134\n", - "UsageBand 339028\n", - "fiModelDescriptor 337882\n", - "Backhoe_Mounting 331986\n", - "Stick 331602\n", - "Turbocharged 331602\n", - "Pad_Type 331602\n", - "Blade_Type 330823\n", - "dtype: int64" - ] - }, - "execution_count": 51, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Check missing values\n", - "df_tmp.isna().sum().sort_values(ascending=False)[:20]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Ok, it seems like there are a fair few columns with missing values and there are several datatypes across these columns (numerical, categorical).\n", - "\n", - "How about we break the problem down and work on filling each datatype separately?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2.5 Filling missing numerical values\n", - "\n", - "There's no set way to fill missing values in your dataset.\n", - "\n", - "And unless you're filling the missing samples with newly discovered actual data, every way you fill your dataset's missing values will introduce some sort of noise or bias. \n", - "\n", - "We'll start by filling the missing numerical values in ourdataet.\n", - "\n", - "To do this, we'll first find the numeric datatype columns.\n", - "\n", - "We can do by looping through the columns in our DataFrame and calling [`pd.api.types.is_numeric_dtype(arr_or_dtype)`](https://pandas.pydata.org/docs/reference/api/pandas.api.types.is_numeric_dtype.html) on them." - ] - }, - { - "cell_type": "code", - "execution_count": 52, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Column name: SalesID | Column dtype: int64 | Example value: [1748586] | Example value dtype: integer\n", - "Column name: SalePrice | Column dtype: float64 | Example value: [13000.] | Example value dtype: floating\n", - "Column name: MachineID | Column dtype: int64 | Example value: [1441940] | Example value dtype: integer\n", - "Column name: ModelID | Column dtype: int64 | Example value: [1333] | Example value dtype: integer\n", - "Column name: datasource | Column dtype: int64 | Example value: [132] | Example value dtype: integer\n", - "Column name: auctioneerID | Column dtype: float64 | Example value: [2.] | Example value dtype: floating\n", - "Column name: YearMade | Column dtype: int64 | Example value: [1000] | Example value dtype: integer\n", - "Column name: MachineHoursCurrentMeter | Column dtype: float64 | Example value: [nan] | Example value dtype: floating\n", - "Column name: saleYear | Column dtype: int64 | Example value: [2010] | Example value dtype: integer\n", - "Column name: saleMonth | Column dtype: int64 | Example value: [6] | Example value dtype: integer\n", - "Column name: saleDay | Column dtype: int64 | Example value: [16] | Example value dtype: integer\n", - "Column name: saleDayofweek | Column dtype: int64 | Example value: [3] | Example value dtype: integer\n", - "Column name: saleDayofyear | Column dtype: int64 | Example value: [285] | Example value dtype: integer\n" - ] - } - ], - "source": [ - "# Find numeric columns \n", - "for label, content in df_tmp.items():\n", - " if pd.api.types.is_numeric_dtype(content):\n", - " # Check datatype of target column\n", - " column_datatype = df_tmp[label].dtype.name\n", - "\n", - " # Get random sample from column values\n", - " example_value = content.sample(1).values\n", - "\n", - " # Infer random sample datatype\n", - " example_value_dtype = pd.api.types.infer_dtype(example_value)\n", - " print(f\"Column name: {label} | Column dtype: {column_datatype} | Example value: {example_value} | Example value dtype: {example_value_dtype}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Beautiful! Looks like we've got a mixture of `int64` and `float64` numerical datatypes.\n", - "\n", - "Now how about we find out which numeric columns are missing values?\n", - "\n", - "We can do so by using `pandas.isnull(obj).sum()` to detect and sum the missing values in a given array-like object (in our case, the data in a target column).\n", - "\n", - "Let's loop through our DataFrame columns, find the numeric datatypes and check if they have any missing values." - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Column name: SalesID | Has missing values: False\n", - "Column name: SalePrice | Has missing values: False\n", - "Column name: MachineID | Has missing values: False\n", - "Column name: ModelID | Has missing values: False\n", - "Column name: datasource | Has missing values: False\n", - "Column name: auctioneerID | Has missing values: True\n", - "Column name: YearMade | Has missing values: False\n", - "Column name: MachineHoursCurrentMeter | Has missing values: True\n", - "Column name: saleYear | Has missing values: False\n", - "Column name: saleMonth | Has missing values: False\n", - "Column name: saleDay | Has missing values: False\n", - "Column name: saleDayofweek | Has missing values: False\n", - "Column name: saleDayofyear | Has missing values: False\n" - ] - } - ], - "source": [ - "# Check for which numeric columns have null values\n", - "for label, content in df_tmp.items():\n", - " if pd.api.types.is_numeric_dtype(content):\n", - " if pd.isnull(content).sum():\n", - " print(f\"Column name: {label} | Has missing values: {True}\")\n", - " else:\n", - " print(f\"Column name: {label} | Has missing values: {False}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Okay, it looks like our `auctioneerID` and `MachineHoursCurrentMeter` columns have missing numeric values.\n", - "\n", - "Let's have a look at how we might handle these." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2.6 Discussing possible ways to handle missing values\n", - "\n", - "As previously discussed, there are many ways to fill missing values.\n", - "\n", - "For missing numeric values, some potential options are:\n", - "\n", - "| **Method** | **Pros** | **Cons** |\n", - "|-----|-----|-----|\n", - "| **Fill with mean of column** | - Easy to calculate/implement
- Retains overall data distribution | - Averages out variation
- Affected by outliers (e.g. if one value is much higher/lower than others) |\n", - "| **Fill with median of column** | - Easy to calculate/implement
- Robust to outliers
- Preserves center of data | - Ignores data distribution shape |\n", - "| **Fill with mode of column** | - Easy to calculate/implement
- More useful for categorical-like data | - May not make sense for continuous/numerical data |\n", - "| **Fill with 0 (or another constant)** | - Simple to implement
- Useful in certain contexts like counts | - Introduces bias (e.g. if 0 was a value that meant something)
- Skews data (e.g. if many missing values, replacing all with 0 makes it look like that's the most common value) |\n", - "| **Forward/Backward fill (use previous/future values to fill future/previous values)** | - Maintains temporal continuity (for time series) | - Assumes data is continuous, which may not be valid |\n", - "| **Use a calculation from other columns** | - Takes existing information and reinterprets it | - Can result in unlikely outputs if calculations are not continuous | \n", - "| **Interpolate (e.g. like dragging a cell in Excel/Google Sheets)** | - Captures trends
- Suitable for ordered data | - Can introduce errors
- May assume linearity (data continues in a straight line) |\n", - "| **Drop missing values** | - Ensures complete data (only use samples with all information)
- Useful for small datasets | - Can result in data loss (e.g. if many missing values are scattered across columns, data size can be dramatically reduced)
- Reduces dataset size |\n", - "\n", - "Which method you choose will be dataset and problem dependant and will likely require several phases of experimentation to see what works and what doesn't.\n", - "\n", - "For now, we'll fill our missing numeric values with the median value of the target column.\n", - "\n", - "We'll also add a binary column (0 or 1) with rows reflecting whether or not a value was missing.\n", - "\n", - "For example, `MachineHoursCurrentMeter_is_missing` will be a column with rows which have a value of `0` if that row's `MachineHoursCurrentMeter` column was *not* missing and `1` if it was.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 54, - "metadata": {}, - "outputs": [], - "source": [ - "# Fill missing numeric values with the median of the target column\n", - "for label, content in df_tmp.items():\n", - " if pd.api.types.is_numeric_dtype(content):\n", - " if pd.isnull(content).sum():\n", - " \n", - " # Add a binary column which tells if the data was missing our not\n", - " df_tmp[label+\"_is_missing\"] = pd.isnull(content).astype(int) # this will add a 0 or 1 value to rows with missing values (e.g. 0 = not missing, 1 = missing)\n", - "\n", - " # Fill missing numeric values with median since it's more robust than the mean\n", - " df_tmp[label] = content.fillna(content.median())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Why add a binary column indicating whether the data was missing or not?\n", - "\n", - "We can easily fill all of the missing numeric values in our dataset with the median. \n", - "\n", - "However, a numeric value may be missing for a reason. \n", - "\n", - "Adding a binary column which indicates whether the value was missing or not helps to retain this information. It also means we can inspect these rows later on." - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - " \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", - "
SalesIDSalePriceMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandfiModelDesc...Travel_ControlsDifferential_TypeSteering_ControlssaleYearsaleMonthsaleDaysaleDayofweeksaleDayofyearauctioneerID_is_missingMachineHoursCurrentMeter_is_missing
150110163153135000.0126745647941322.019980.0NaN710D...NaNNaNNaN2003911325401
111297132765815000.01185021411213299.019800.0NaND5B...None or UnspecifiedNaNNaN200158112801
177121143217952000.078865412631321.019970.0NaN330BL...NaNNaNNaN200521514601
138512144017927000.079057735471327.019990.0NaN426C...NaNNaNNaN2002126434001
69375147390167500.019653038231326.019910.0NaN950F...NaNStandardConventional1998827323901
\n", - "

5 rows × 59 columns

\n", - "
" - ], - "text/plain": [ - " SalesID SalePrice MachineID ModelID datasource auctioneerID \\\n", - "150110 1631531 35000.0 1267456 4794 132 2.0 \n", - "111297 1327658 15000.0 1185021 4112 132 99.0 \n", - "177121 1432179 52000.0 788654 1263 132 1.0 \n", - "138512 1440179 27000.0 790577 3547 132 7.0 \n", - "69375 1473901 67500.0 196530 3823 132 6.0 \n", - "\n", - " YearMade MachineHoursCurrentMeter UsageBand fiModelDesc ... \\\n", - "150110 1998 0.0 NaN 710D ... \n", - "111297 1980 0.0 NaN D5B ... \n", - "177121 1997 0.0 NaN 330BL ... \n", - "138512 1999 0.0 NaN 426C ... \n", - "69375 1991 0.0 NaN 950F ... \n", - "\n", - " Travel_Controls Differential_Type Steering_Controls saleYear \\\n", - "150110 NaN NaN NaN 2003 \n", - "111297 None or Unspecified NaN NaN 2001 \n", - "177121 NaN NaN NaN 2005 \n", - "138512 NaN NaN NaN 2002 \n", - "69375 NaN Standard Conventional 1998 \n", - "\n", - " saleMonth saleDay saleDayofweek saleDayofyear auctioneerID_is_missing \\\n", - "150110 9 11 3 254 0 \n", - "111297 5 8 1 128 0 \n", - "177121 2 15 1 46 0 \n", - "138512 12 6 4 340 0 \n", - "69375 8 27 3 239 0 \n", - "\n", - " MachineHoursCurrentMeter_is_missing \n", - "150110 1 \n", - "111297 1 \n", - "177121 1 \n", - "138512 1 \n", - "69375 1 \n", - "\n", - "[5 rows x 59 columns]" - ] - }, - "execution_count": 55, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Show rows where MachineHoursCurrentMeter_is_missing == 1\n", - "df_tmp[df_tmp[\"MachineHoursCurrentMeter_is_missing\"] == 1].sample(5)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Missing numeric values filled!\n", - "\n", - "How about we check again whether or not the numeric columns have missing values?" - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Column name: SalesID | Has missing values: False\n", - "Column name: SalePrice | Has missing values: False\n", - "Column name: MachineID | Has missing values: False\n", - "Column name: ModelID | Has missing values: False\n", - "Column name: datasource | Has missing values: False\n", - "Column name: auctioneerID | Has missing values: False\n", - "Column name: YearMade | Has missing values: False\n", - "Column name: MachineHoursCurrentMeter | Has missing values: False\n", - "Column name: saleYear | Has missing values: False\n", - "Column name: saleMonth | Has missing values: False\n", - "Column name: saleDay | Has missing values: False\n", - "Column name: saleDayofweek | Has missing values: False\n", - "Column name: saleDayofyear | Has missing values: False\n", - "Column name: auctioneerID_is_missing | Has missing values: False\n", - "Column name: MachineHoursCurrentMeter_is_missing | Has missing values: False\n" - ] - } - ], - "source": [ - "# Check for which numeric columns have null values\n", - "for label, content in df_tmp.items():\n", - " if pd.api.types.is_numeric_dtype(content):\n", - " if pd.isnull(content).sum():\n", - " print(f\"Column name: {label} | Has missing values: {True}\")\n", - " else:\n", - " print(f\"Column name: {label} | Has missing values: {False}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Woohoo! Numeric missing values filled!\n", - "\n", - "And thanks to our binary `_is_missing` columns, we can even check how many were missing." - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "auctioneerID_is_missing\n", - "0 392562\n", - "1 20136\n", - "Name: count, dtype: int64" - ] - }, - "execution_count": 57, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Check to see how many examples in the auctioneerID were missing\n", - "df_tmp.auctioneerID_is_missing.value_counts()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2.7 Filling missing categorical values with pandas\n", - "\n", - "Now we've filled the numeric values, we'll do the same with the categorical values whilst ensuring that they are all numerical too.\n", - "\n", - "Let's first investigate the columns which *aren't* numeric (we've already worked with these). " - ] - }, - { - "cell_type": "code", - "execution_count": 58, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Columns which are not numeric:\n", - "Column name: UsageBand | Column dtype: category\n", - "Column name: fiModelDesc | Column dtype: category\n", - "Column name: fiBaseModel | Column dtype: category\n", - "Column name: fiSecondaryDesc | Column dtype: category\n", - "Column name: fiModelSeries | Column dtype: category\n", - "Column name: fiModelDescriptor | Column dtype: category\n", - "Column name: ProductSize | Column dtype: category\n", - "Column name: fiProductClassDesc | Column dtype: category\n", - "Column name: state | Column dtype: category\n", - "Column name: ProductGroup | Column dtype: category\n", - "Column name: ProductGroupDesc | Column dtype: category\n", - "Column name: Drive_System | Column dtype: category\n", - "Column name: Enclosure | Column dtype: category\n", - "Column name: Forks | Column dtype: category\n", - "Column name: Pad_Type | Column dtype: category\n", - "Column name: Ride_Control | Column dtype: category\n", - "Column name: Stick | Column dtype: category\n", - "Column name: Transmission | Column dtype: category\n", - "Column name: Turbocharged | Column dtype: category\n", - "Column name: Blade_Extension | Column dtype: category\n", - "Column name: Blade_Width | Column dtype: category\n", - "Column name: Enclosure_Type | Column dtype: category\n", - "Column name: Engine_Horsepower | Column dtype: category\n", - "Column name: Hydraulics | Column dtype: category\n", - "Column name: Pushblock | Column dtype: category\n", - "Column name: Ripper | Column dtype: category\n", - "Column name: Scarifier | Column dtype: category\n", - "Column name: Tip_Control | Column dtype: category\n", - "Column name: Tire_Size | Column dtype: category\n", - "Column name: Coupler | Column dtype: category\n", - "Column name: Coupler_System | Column dtype: category\n", - "Column name: Grouser_Tracks | Column dtype: category\n", - "Column name: Hydraulics_Flow | Column dtype: category\n", - "Column name: Track_Type | Column dtype: category\n", - "Column name: Undercarriage_Pad_Width | Column dtype: category\n", - "Column name: Stick_Length | Column dtype: category\n", - "Column name: Thumb | Column dtype: category\n", - "Column name: Pattern_Changer | Column dtype: category\n", - "Column name: Grouser_Type | Column dtype: category\n", - "Column name: Backhoe_Mounting | Column dtype: category\n", - "Column name: Blade_Type | Column dtype: category\n", - "Column name: Travel_Controls | Column dtype: category\n", - "Column name: Differential_Type | Column dtype: category\n", - "Column name: Steering_Controls | Column dtype: category\n" - ] - } - ], - "source": [ - "# Check columns which aren't numeric\n", - "print(f\"[INFO] Columns which are not numeric:\")\n", - "for label, content in df_tmp.items():\n", - " if not pd.api.types.is_numeric_dtype(content):\n", - " print(f\"Column name: {label} | Column dtype: {df_tmp[label].dtype.name}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Okay, we've got plenty of category type columns.\n", - "\n", - "Let's now write some code to fill the missing categorical values as well as ensure they are numerical (non-string). \n", - "\n", - "To do so, we'll:\n", - "\n", - "1. Create a blank column to category dictionary, we'll use this to store categorical value names (e.g. their string name) as well as their categorical code. We'll end with a dictionary of dictionaries in the form `{\"column_name\": {category_code: \"category_value\"...}...}`.\n", - "2. Loop through the items in the DataFrame.\n", - "3. Check if the column is numeric or not.\n", - "4. Add a binary column in the form `ORIGINAL_COLUMN_NAME_is_missing` with a `0` or `1` value for if the row had a missing value.\n", - "5. Ensure the column values are in the `pd.Categorical` datatype and get their category codes with `pd.Series.cat.codes` (we'll add `1` to these values since pandas defaults to assigning `-1` to `NaN` values, we'll use `0` instead).\n", - "6. Turn the column categories and column category codes from 5 into a dictionary with Python's [`dict(zip(category_names, category_codes))`](https://docs.python.org/3.3/library/functions.html#zip) and save this to the blank dictionary from 1 with the target column name as key.\n", - "7. Set the target column value to the numerical category values from 5.\n", - "\n", - "Phew!\n", - "\n", - "That's a fair few steps but nothing we can't handle.\n", - "\n", - "Let's do it!" - ] - }, - { - "cell_type": "code", - "execution_count": 59, - "metadata": {}, - "outputs": [], - "source": [ - "# 1. Create a dictionary to store column to category values (e.g. we turn our category types into numbers but we keep a record so we can go back)\n", - "column_to_category_dict = {} \n", - "\n", - "# 2. Turn categorical variables into numbers\n", - "for label, content in df_tmp.items():\n", - "\n", - " # 3. Check columns which *aren't* numeric\n", - " if not pd.api.types.is_numeric_dtype(content):\n", - "\n", - " # 4. Add binary column to inidicate whether sample had missing value\n", - " df_tmp[label+\"_is_missing\"] = pd.isnull(content).astype(int)\n", - "\n", - " # 5. Ensure content is categorical and get its category codes\n", - " content_categories = pd.Categorical(content)\n", - " content_category_codes = content_categories.codes + 1 # prevents -1 (the default for NaN values) from being used for missing values (we'll treat missing values as 0)\n", - "\n", - " # 6. Add column key to dictionary with code: category mapping per column\n", - " column_to_category_dict[label] = dict(zip(content_category_codes, content_categories))\n", - " \n", - " # 7. Set the column to the numerical values (the category code value) \n", - " df_tmp[label] = content_category_codes " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Ho ho! No errors!\n", - "\n", - "Let's check out a few random samples of our DataFrame." - ] - }, - { - "cell_type": "code", - "execution_count": 60, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - " \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", - "
SalesIDSalePriceMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandfiModelDesc...Undercarriage_Pad_Width_is_missingStick_Length_is_missingThumb_is_missingPattern_Changer_is_missingGrouser_Type_is_missingBackhoe_Mounting_is_missingBlade_Type_is_missingTravel_Controls_is_missingDifferential_Type_is_missingSteering_Controls_is_missing
232167241266053000.011447296071361.020000.004823...1111111100
398100122174618500.0104724527591213.01000319.022224...1111100011
363820250255931000.0133354231721491.020071149.031081...1111111111
32223024327527500.01537457360331361.020030.004259...1111111111
10401135658126000.0139493340901321.019880.002121...1111100011
\n", - "

5 rows × 103 columns

\n", - "
" - ], - "text/plain": [ - " SalesID SalePrice MachineID ModelID datasource auctioneerID \\\n", - "232167 2412660 53000.0 1144729 607 136 1.0 \n", - "398100 1221746 18500.0 1047245 2759 121 3.0 \n", - "363820 2502559 31000.0 1333542 3172 149 1.0 \n", - "322230 2432752 7500.0 1537457 36033 136 1.0 \n", - "10401 1356581 26000.0 1394933 4090 132 1.0 \n", - "\n", - " YearMade MachineHoursCurrentMeter UsageBand fiModelDesc ... \\\n", - "232167 2000 0.0 0 4823 ... \n", - "398100 1000 319.0 2 2224 ... \n", - "363820 2007 1149.0 3 1081 ... \n", - "322230 2003 0.0 0 4259 ... \n", - "10401 1988 0.0 0 2121 ... \n", - "\n", - " Undercarriage_Pad_Width_is_missing Stick_Length_is_missing \\\n", - "232167 1 1 \n", - "398100 1 1 \n", - "363820 1 1 \n", - "322230 1 1 \n", - "10401 1 1 \n", - "\n", - " Thumb_is_missing Pattern_Changer_is_missing Grouser_Type_is_missing \\\n", - "232167 1 1 1 \n", - "398100 1 1 1 \n", - "363820 1 1 1 \n", - "322230 1 1 1 \n", - "10401 1 1 1 \n", - "\n", - " Backhoe_Mounting_is_missing Blade_Type_is_missing \\\n", - "232167 1 1 \n", - "398100 0 0 \n", - "363820 1 1 \n", - "322230 1 1 \n", - "10401 0 0 \n", - "\n", - " Travel_Controls_is_missing Differential_Type_is_missing \\\n", - "232167 1 0 \n", - "398100 0 1 \n", - "363820 1 1 \n", - "322230 1 1 \n", - "10401 0 1 \n", - "\n", - " Steering_Controls_is_missing \n", - "232167 0 \n", - "398100 1 \n", - "363820 1 \n", - "322230 1 \n", - "10401 1 \n", - "\n", - "[5 rows x 103 columns]" - ] - }, - "execution_count": 60, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df_tmp.sample(5)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Beautiful! Looks like our data is all in numerical form.\n", - "\n", - "How about we investigate an item from our `column_to_category_dict`?\n", - "\n", - "This will show the mapping from numerical value to category (most likely a string) value." - ] - }, - { - "cell_type": "code", - "execution_count": 61, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0 -> nan\n", - "1 -> High\n", - "2 -> Low\n", - "3 -> Medium\n" - ] - } - ], - "source": [ - "# Check the UsageBand (measure of bulldozer usage)\n", - "for key, value in sorted(column_to_category_dict[\"UsageBand\"].items()): # note: calling sorted() on dictionary.items() sorts the dictionary by keys \n", - " print(f\"{key} -> {value}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "> **Note:** Categorical values do not necessarily have order. They are strictly a mapping from number to value. In this case, our categorical values are mapped in numerical order. If you feel that the order of a value may influence a model in a negative way (e.g. `1 -> High` is *lower* than `3 -> Medium` but should be *higher*), you may want to look into ordering the values in a particular way or using a different numerical encoding technique such as [one-hot encoding](https://en.wikipedia.org/wiki/One-hot).\n", - "\n", - "And we can do the same for the `state` column values." - ] - }, - { - "cell_type": "code", - "execution_count": 62, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1 -> Alabama\n", - "2 -> Alaska\n", - "3 -> Arizona\n", - "4 -> Arkansas\n", - "5 -> California\n", - "6 -> Colorado\n", - "7 -> Connecticut\n", - "8 -> Delaware\n", - "9 -> Florida\n", - "10 -> Georgia\n" - ] - } - ], - "source": [ - "# Check the first 10 state column values\n", - "for key, value in sorted(column_to_category_dict[\"state\"].items())[:10]:\n", - " print(f\"{key} -> {value}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Beautiful!\n", - "\n", - "How about we check to see all of the missing values have been filled?" - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Total missing values: 0 - Woohoo! Let's build a model!\n" - ] - } - ], - "source": [ - "# Check total number of missing values\n", - "total_missing_values = df_tmp.isna().sum().sum()\n", - "\n", - "if total_missing_values == 0:\n", - " print(f\"[INFO] Total missing values: {total_missing_values} - Woohoo! Let's build a model!\")\n", - "else:\n", - " print(f\"[INFO] Uh ohh... total missing values: {total_missing_values} - Perhaps we might have to retrace our steps to fill the values?\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2.8 Saving our preprocessed data (part 2)\n", - "\n", - "One more step before we train new model!\n", - "\n", - "Let's save our work so far so we could re-import our preprocessed dataset if we wanted to.\n", - "\n", - "We'll save it to the `parquet` format again, this time with a suffix to show we've filled the missing values." - ] - }, - { - "cell_type": "code", - "execution_count": 64, - "metadata": {}, - "outputs": [], - "source": [ - "# Save preprocessed data with object values as categories as well as missing values filled\n", - "df_tmp.to_parquet(path=\"../data/bluebook-for-bulldozers/TrainAndValid_object_values_as_categories_and_missing_values_filled.parquet\",\n", - " engine=\"auto\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And to make sure it worked, we can re-import it." - ] - }, - { - "cell_type": "code", - "execution_count": 65, - "metadata": {}, - "outputs": [], - "source": [ - "# Read in preprocessed dataset\n", - "df_tmp = pd.read_parquet(path=\"../data/bluebook-for-bulldozers/TrainAndValid_object_values_as_categories_and_missing_values_filled.parquet\",\n", - " engine=\"auto\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Does it have any missing values?" - ] - }, - { - "cell_type": "code", - "execution_count": 66, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Total missing values: 0 - Woohoo! Let's build a model!\n" - ] - } - ], - "source": [ - "# Check total number of missing values\n", - "total_missing_values = df_tmp.isna().sum().sum()\n", - "\n", - "if total_missing_values == 0:\n", - " print(f\"[INFO] Total missing values: {total_missing_values} - Woohoo! Let's build a model!\")\n", - "else:\n", - " print(f\"[INFO] Uh ohh... total missing values: {total_missing_values} - Perhaps we might have to retrace our steps to fill the values?\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Checkpoint reached!\n", - "\n", - "We've turned all of our data into numbers as well as filled the missing values, time to try fitting a model to it again." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2.9 Fitting a machine learning model to our preprocessed data\n", - "\n", - "Now all of our data is numeric and there are no missing values, we should be able to fit a machine learning model to it!\n", - "\n", - "Let's reinstantiate our trusty [`sklearn.ensemble.RandomForestRegressor`](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html) model.\n", - "\n", - "Since our dataset has a substantial amount of rows (~400k+), let's first make sure the model will work on a smaller sample of 1000 or so.\n", - "\n", - "> **Note:** It's common practice on machine learning problems to see if your experiments will work on smaller scale problems (e.g. smaller amounts of data) before scaling them up to the full dataset. This practice enables you to try many different kinds of experiments with faster runtimes. The benefit of this is that you can figure out what doesn't work before spending more time on what does.\n", - "\n", - "Our `X` values (features) will be every column except the `SalePrice` column.\n", - "\n", - "And our `y` values (labels) will be the entirety of the `SalePrice` column.\n", - "\n", - "\n", - "We'll time how long our smaller experiment takes using the [magic function `%%time`](https://jakevdp.github.io/PythonDataScienceHandbook/01.07-timing-and-profiling.html) and placing it at the top of the notebook cell.\n", - "\n", - "> **Note:** You can find out more about the `%%time` magic command by typing `%%time?` (note the question mark on the end) in a notebook cell.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 67, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 1.06 s, sys: 2.37 s, total: 3.43 s\n", - "Wall time: 976 ms\n" - ] - }, - { - "data": { - "text/html": [ - "
RandomForestRegressor(n_jobs=-1)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" - ], - "text/plain": [ - "RandomForestRegressor(n_jobs=-1)" - ] - }, - "execution_count": 67, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "\n", - "# Sample 1000 samples with random state 42 for reproducibility\n", - "df_tmp_sample_1k = df_tmp.sample(n=1000, random_state=42)\n", - "\n", - "# Instantiate a model\n", - "model = RandomForestRegressor(n_jobs=-1) # use -1 to utilise all available processors\n", - "\n", - "# Create features and labels\n", - "X_sample_1k = df_tmp_sample_1k.drop(\"SalePrice\", axis=1) # use all columns except SalePrice as X values\n", - "y_sample_1k = df_tmp_sample_1k[\"SalePrice\"] # use SalePrice as y values (target variable)\n", - "\n", - "# Fit the model to the sample data\n", - "model.fit(X=X_sample_1k, \n", - " y=y_sample_1k) " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Woah! It looks like things worked!\n", - "\n", - "And quite quick too (since we're only using a relatively small number of rows).\n", - "\n", - "How about we score our model?\n", - "\n", - "We can do so using the built-in method `score()`. \n", - "\n", - "By default, `sklearn.ensemble.RandomForestRegressor` uses [coefficient of determination](https://en.wikipedia.org/wiki/Coefficient_of_determination) ($R^2$ or R-squared) as the evaluation metric (higher is better, with a score of 1.0 being perfect)." - ] - }, - { - "cell_type": "code", - "execution_count": 68, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Model score on 1000 samples: 0.9563062437082765\n" - ] - } - ], - "source": [ - "# Evaluate the model\n", - "model_sample_1k_score = model.score(X=X_sample_1k,\n", - " y=y_sample_1k)\n", - "\n", - "print(f\"[INFO] Model score on {len(df_tmp_sample_1k)} samples: {model_sample_1k_score}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Wow, it looks like our model got a pretty good score on only 1000 samples (the best possible score it could achieve would've been 1.0). \n", - "\n", - "How about we try our model on the whole dataset?" - ] - }, - { - "cell_type": "code", - "execution_count": 69, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 10min 21s, sys: 8min 31s, total: 18min 53s\n", - "Wall time: 3min 24s\n" - ] - }, - { - "data": { - "text/html": [ - "
RandomForestRegressor(n_jobs=-1)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" - ], - "text/plain": [ - "RandomForestRegressor(n_jobs=-1)" - ] - }, - "execution_count": 69, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "\n", - "# Instantiate model\n", - "model = RandomForestRegressor(n_jobs=-1) # note: this could take quite a while depending on your machine (it took ~1.5 minutes on my MacBook Pro M1 Pro with 10 cores)\n", - "\n", - "# Create features and labels with entire dataset\n", - "X_all = df_tmp.drop(\"SalePrice\", axis=1)\n", - "y_all = df_tmp[\"SalePrice\"]\n", - "\n", - "# Fit the model\n", - "model.fit(X=X_all, \n", - " y=y_all)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Ok, that took a little bit longer than fitting on 1000 samples (but that's too be expected, as many more calculations had to be made).\n", - "\n", - "There's a reason we used `n_jobs=-1` too.\n", - "\n", - "If we stuck with the default of `n_jobs=None` (the same as `n_jobs=1`), it would've taken much longer.\n", - "\n", - "| Configuration (MacBook Pro M1 Pro, 10 Cores) | CPU Times (User) | CPU Times (Sys) | CPU Times (Total) | Wall Time |\n", - "|-----|-----|-----|-----|-----|\n", - "| `n_jobs=-1` (all cores) | 9min 14s | 3.85s | 9min 18s | 1min 15s |\n", - "| `n_jobs=None` (default) | 7min 14s | 1.75s | 7min 16s | 7min 25s |\n", - "\n", - "And as we've discussed many times, one of the main goals when starting a machine learning project is to reduce your time between experiments.\n", - "\n", - "How about we score the model trained on all of the data?" - ] - }, - { - "cell_type": "code", - "execution_count": 70, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Model score on 412698 samples: 0.9875710658782831\n" - ] - } - ], - "source": [ - "# Evaluate the model\n", - "model_sample_all_score = model.score(X=X_all,\n", - " y=y_all)\n", - "\n", - "print(f\"[INFO] Model score on {len(df_tmp)} samples: {model_sample_all_score}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "An even better score!\n", - "\n", - "Oh wait...\n", - "\n", - "Oh no...\n", - "\n", - "I think we've got an error... (you might've noticed it already)\n", - "\n", - "Why might this metric be unreliable?\n", - "\n", - "Hint: Compare the data we trained on versus the data we evaluated on." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2.10 A big (but fixable) mistake \n", - "\n", - "One of the hard things about bugs in machine learning projects is that they are often silent.\n", - "\n", - "For example, our model seems to have fit the data with no issues and then evaluated with a good score.\n", - "\n", - "So what's wrong?\n", - "\n", - "It seems we've stumbled across one of the most common bugs in machine learning and that's **data leakage** (data from the training set leaking into the validation/testing sets).\n", - "\n", - "We've evaluated our model on the same data it was trained on.\n", - "\n", - "This isn't the model's fault either.\n", - "\n", - "It's our fault.\n", - "\n", - "Right back at the start we imported a file called `TrainAndValid.csv`, this file contains both the training and validation data.\n", - "\n", - "And while we preprocessed it to make sure there were no missing values and the samples were all numeric, we never split the data into separate training and validation splits.\n", - "\n", - "The right workflow would've been to train the model on the training split and then evaluate it on the *unseen* and *separate* validation split.\n", - "\n", - "Our evaluation scores above are quite good but they can't necessarily be trusted to be replicated on unseen data (data in the real world) because they've been obtained by evaluating the model on data its already seen during training. \n", - "\n", - "This would be the equivalent of a final exam at university containing all of the same questions as the practice exam without any changes, you may get a good grade, but does that good grade translate to the real world?\n", - "\n", - "Not to worry, we can fix this!\n", - "\n", - "How?\n", - "\n", - "We can import the training and validation datasets separately via `Train.csv` and `Valid.csv` respectively.\n", - "\n", - "Or we could import `TrainAndValid.csv` and perform the appropriate splits according the original [Kaggle competition page](https://www.kaggle.com/c/bluebook-for-bulldozers/data) (training data includes all samples prior to 2012 and validation data includes samples from January 1 2012 to April 30 2012).\n", - "\n", - "In both methods, we'll have to perform similar preprocessing steps we've done so far.\n", - "\n", - "Except because the validation data is supposed to remain as *unseen* data, we'll only use information from the training set to preprocess the validation set (and not mix the two). \n", - "\n", - "We'll work on this in the subsequent sections.\n", - "\n", - "The takeaway?\n", - "\n", - "Always (if possible) **create appropriate data splits at the start of a project**.\n", - "\n", - "Because it's one thing to train a machine learning model but if you can't evaluate it properly (on unseen data), how can you know how it'll perform (or may perform) in the real world on new and unseen data?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3. Splitting data into the right train/validation sets\n", - "\n", - "The bad news is, we evaluated our model on the same data we trained it on.\n", - "\n", - "The good news is, we get to practice importing and preprocessing our data again. \n", - "\n", - "This time we'll make sure we've got separate training and validation splits. \n", - "\n", - "Previously, we used pandas to ensure our data was all numeric and had no missing values. \n", - "\n", - "And we can still use pandas for things such as creating/altering date-related columns.\n", - "\n", - "But using pandas for all of our data preprocessing can be an issue with larger scale datasets or when new data is introduced. \n", - "\n", - "How about this time we add Scikit-Learn to the mix and make a reproducible pipeline for our data preprocessing needs?\n", - "\n", - "> **Note:** Scikit-Learn has a fantastic guide on [data transformations](https://scikit-learn.org/1.5/data_transforms.html) and in particular [data preprocessing](https://scikit-learn.org/1.5/modules/preprocessing.html). I'd highly recommend spending an hour or so reading through this documentation, even if it doesn't make a lot of sense to begin with. Rest assured, with practice and experimentation you'll start to get the hang of it.\n", - "\n", - "According to the [Kaggle data page](https://www.kaggle.com/c/bluebook-for-bulldozers/data), the train, validation and test sets are split according to dates.\n", - "\n", - "This makes sense since we're working on a time series problem (using past sale prices to try and predict future sale prices).\n", - "\n", - "Knowing this, randomly splitting our data into train, validation and test sets using something like [`sklearn.model_selection.train_test_split()`](https://scikit-learn.org/1.5/modules/generated/sklearn.model_selection.train_test_split.html) wouldn't work as this would mix samples from different dates in an unintended way.\n", - "\n", - "Instead, we split our data into training, validation and test sets using the date each sample occured.\n", - "\n", - "In our case:\n", - "\n", - "* Training data (`Train.csv`) = all samples up until 2011.\n", - "* Validation data (`Valid.csv`) = all samples form January 1, 2012 - April 30, 2012.\n", - "* Testing data (`Test.csv`) = all samples from May 1, 2012 - November 2012.\n", - "\n", - "Previously we imported `TrainAndValid.csv` which is a combination of `Train.csv` and `Valid.csv` in one file.\n", - "\n", - "We could split this based on the `saledate` column.\n", - "\n", - "However, we could also import the `Train.csv` and `Valid.csv` files separately (we'll import `Test.csv` later on when we've trained a model).\n", - "\n", - "We'll also import `ValidSolution.csv` which contains the `SalePrice` of `Valid.csv` and make sure we match the columns based on the `SalesID` key.\n", - "\n", - "> **Note:** For more on making good training, validation and test sets, check out the post [How (and why) to create a good validation set](https://www.fast.ai/2017/11/13/validation-sets/) by Rachel Thomas as well as [The importance of a test set](https://www.learnml.io/posts/the-importance-of-a-test-set/) by Daniel Bourke." - ] - }, - { - "cell_type": "code", - "execution_count": 71, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Number of samples in training DataFrame: 401125\n", - "[INFO] Number of samples in validation DataFrame: 11573\n" - ] - } - ], - "source": [ - "# Import train samples (making sure to parse dates and then sort by them)\n", - "train_df = pd.read_csv(filepath_or_buffer=\"../data/bluebook-for-bulldozers/Train.csv\",\n", - " parse_dates=[\"saledate\"],\n", - " low_memory=False).sort_values(by=\"saledate\", ascending=True)\n", - "\n", - "# Import validation samples (making sure to parse dates and then sort by them)\n", - "valid_df = pd.read_csv(filepath_or_buffer=\"../data/bluebook-for-bulldozers/Valid.csv\",\n", - " parse_dates=[\"saledate\"])\n", - "\n", - "# The ValidSolution.csv contains the SalePrice values for the samples in Valid.csv\n", - "valid_solution = pd.read_csv(filepath_or_buffer=\"../data/bluebook-for-bulldozers/ValidSolution.csv\")\n", - "\n", - "# Map valid_solution to valid_df\n", - "valid_df[\"SalePrice\"] = valid_df[\"SalesID\"].map(valid_solution.set_index(\"SalesID\")[\"SalePrice\"])\n", - "\n", - "# Make sure valid_df is sorted by saledate still\n", - "valid_df = valid_df.sort_values(\"saledate\", ascending=True).reset_index(drop=True)\n", - "\n", - "# How many samples are in each DataFrame?\n", - "print(f\"[INFO] Number of samples in training DataFrame: {len(train_df)}\")\n", - "print(f\"[INFO] Number of samples in validation DataFrame: {len(valid_df)}\")" - ] - }, - { - "cell_type": "code", - "execution_count": 72, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - " \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", - "
SalesIDSalePriceMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandsaledate...Undercarriage_Pad_WidthStick_LengthThumbPattern_ChangerGrouser_TypeBackhoe_MountingBlade_TypeTravel_ControlsDifferential_TypeSteering_Controls
118276145733358000143414641471321.01980NaNNaN1990-05-03...NaNNaNNaNNaNNaNNone or UnspecifiedStraightNone or UnspecifiedNaNNaN
149220152245737000147361641991322.01992NaNNaN1996-11-16...None or UnspecifiedNone or UnspecifiedNone or UnspecifiedNone or UnspecifiedDoubleNaNNaNNaNNaNNaN
1181591457054192501503681414713299.01979NaNNaN2009-10-01...NaNNaNNaNNaNNaNNone or UnspecifiedSemi UNone or UnspecifiedNaNNaN
2824012585918250145993467881326.01971NaNNaN1990-04-18...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
39634862827804160019161981427214999.02003NaNNaN2011-11-09...None or UnspecifiedNone or UnspecifiedNone or UnspecifiedNone or UnspecifiedDoubleNaNNaNNaNNaNNaN
\n", - "

5 rows × 53 columns

\n", - "
" - ], - "text/plain": [ - " SalesID SalePrice MachineID ModelID datasource auctioneerID \\\n", - "118276 1457333 58000 1434146 4147 132 1.0 \n", - "149220 1522457 37000 1473616 4199 132 2.0 \n", - "118159 1457054 19250 1503681 4147 132 99.0 \n", - "28240 1258591 8250 1459934 6788 132 6.0 \n", - "396348 6282780 41600 1916198 14272 149 99.0 \n", - "\n", - " YearMade MachineHoursCurrentMeter UsageBand saledate ... \\\n", - "118276 1980 NaN NaN 1990-05-03 ... \n", - "149220 1992 NaN NaN 1996-11-16 ... \n", - "118159 1979 NaN NaN 2009-10-01 ... \n", - "28240 1971 NaN NaN 1990-04-18 ... \n", - "396348 2003 NaN NaN 2011-11-09 ... \n", - "\n", - " Undercarriage_Pad_Width Stick_Length Thumb \\\n", - "118276 NaN NaN NaN \n", - "149220 None or Unspecified None or Unspecified None or Unspecified \n", - "118159 NaN NaN NaN \n", - "28240 NaN NaN NaN \n", - "396348 None or Unspecified None or Unspecified None or Unspecified \n", - "\n", - " Pattern_Changer Grouser_Type Backhoe_Mounting Blade_Type \\\n", - "118276 NaN NaN None or Unspecified Straight \n", - "149220 None or Unspecified Double NaN NaN \n", - "118159 NaN NaN None or Unspecified Semi U \n", - "28240 NaN NaN NaN NaN \n", - "396348 None or Unspecified Double NaN NaN \n", - "\n", - " Travel_Controls Differential_Type Steering_Controls \n", - "118276 None or Unspecified NaN NaN \n", - "149220 NaN NaN NaN \n", - "118159 None or Unspecified NaN NaN \n", - "28240 NaN NaN NaN \n", - "396348 NaN NaN NaN \n", - "\n", - "[5 rows x 53 columns]" - ] - }, - "execution_count": 72, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Let's check out the training DataFrame\n", - "train_df.sample(5)" - ] - }, - { - "cell_type": "code", - "execution_count": 73, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - " \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", - "
SalesIDMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandsaledatefiModelDesc...Stick_LengthThumbPattern_ChangerGrouser_TypeBackhoe_MountingBlade_TypeTravel_ControlsDifferential_TypeSteering_ControlsSalePrice
7504432520823068264840172119879540.0Low2012-03-22850B...NaNNaNNaNNaNNone or UnspecifiedStraightNone or UnspecifiedNaNNaN10000.0
4853628222314823072884214902004NaNNaN2012-02-2380C...None or UnspecifiedNone or UnspecifiedNone or UnspecifiedDoubleNaNNaNNaNNaNNaN27000.0
2862698181791122725714999197848.0Low2012-01-11910...NaNNaNNaNNaNNaNNaNNaNStandardConventional10600.0
745112264782058981269121320049333.0Medium2012-03-22330CL...None or UnspecifiedHydraulicYesDoubleNaNNaNNaNNaNNaN90000.0
69312234791438073538121319972154.0Low2012-01-27416C...NaNNaNNaNNaNNaNNaNNaNNaNNaN19500.0
\n", - "

5 rows × 53 columns

\n", - "
" - ], - "text/plain": [ - " SalesID MachineID ModelID datasource auctioneerID YearMade \\\n", - "7504 4325208 2306826 4840 172 1 1987 \n", - "4853 6282223 1482307 28842 149 0 2004 \n", - "28 6269818 1791122 7257 149 99 1978 \n", - "7451 1226478 205898 1269 121 3 2004 \n", - "693 1223479 143807 3538 121 3 1997 \n", - "\n", - " MachineHoursCurrentMeter UsageBand saledate fiModelDesc ... \\\n", - "7504 9540.0 Low 2012-03-22 850B ... \n", - "4853 NaN NaN 2012-02-23 80C ... \n", - "28 48.0 Low 2012-01-11 910 ... \n", - "7451 9333.0 Medium 2012-03-22 330CL ... \n", - "693 2154.0 Low 2012-01-27 416C ... \n", - "\n", - " Stick_Length Thumb Pattern_Changer \\\n", - "7504 NaN NaN NaN \n", - "4853 None or Unspecified None or Unspecified None or Unspecified \n", - "28 NaN NaN NaN \n", - "7451 None or Unspecified Hydraulic Yes \n", - "693 NaN NaN NaN \n", - "\n", - " Grouser_Type Backhoe_Mounting Blade_Type Travel_Controls \\\n", - "7504 NaN None or Unspecified Straight None or Unspecified \n", - "4853 Double NaN NaN NaN \n", - "28 NaN NaN NaN NaN \n", - "7451 Double NaN NaN NaN \n", - "693 NaN NaN NaN NaN \n", - "\n", - " Differential_Type Steering_Controls SalePrice \n", - "7504 NaN NaN 10000.0 \n", - "4853 NaN NaN 27000.0 \n", - "28 Standard Conventional 10600.0 \n", - "7451 NaN NaN 90000.0 \n", - "693 NaN NaN 19500.0 \n", - "\n", - "[5 rows x 53 columns]" - ] - }, - "execution_count": 73, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# And how about the validation DataFrame?\n", - "valid_df.sample(5)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Nice! \n", - "\n", - "We've now got separate training and validation datasets imported.\n", - "\n", - "In a previous section, we created a function to decompose the `saledate` column into multiple features such as `saleYear`, `saleMonth`, `saleDay` and more.\n", - "\n", - "Let's now replicate that function here and apply it to our `train_df` and `valid_df`." - ] - }, - { - "cell_type": "code", - "execution_count": 74, - "metadata": {}, - "outputs": [], - "source": [ - "# Make a function to add date columns\n", - "def add_datetime_features_to_df(df, date_column=\"saledate\"):\n", - " # Add datetime parameters for saledate\n", - " df[\"saleYear\"] = df[date_column].dt.year\n", - " df[\"saleMonth\"] = df[date_column].dt.month\n", - " df[\"saleDay\"] = df[date_column].dt.day\n", - " df[\"saleDayofweek\"] = df[date_column].dt.dayofweek\n", - " df[\"saleDayofyear\"] = df[date_column].dt.dayofyear\n", - "\n", - " # Drop original saledate column\n", - " df.drop(\"saledate\", axis=1, inplace=True)\n", - "\n", - " return df\n", - "\n", - "train_df = add_datetime_features_to_df(df=train_df)\n", - "valid_df = add_datetime_features_to_df(df=valid_df)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Wonderful, now let's make sure it worked by inspecting the last 5 columns of `train_df`." - ] - }, - { - "cell_type": "code", - "execution_count": 75, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - "
saleYearsaleMonthsaleDaysaleDayofweeksaleDayofyear
31999820104223112
1335092003220351
29120020085234144
2801462006318577
33550920084291120
\n", - "
" - ], - "text/plain": [ - " saleYear saleMonth saleDay saleDayofweek saleDayofyear\n", - "319998 2010 4 22 3 112\n", - "133509 2003 2 20 3 51\n", - "291200 2008 5 23 4 144\n", - "280146 2006 3 18 5 77\n", - "335509 2008 4 29 1 120" - ] - }, - "execution_count": 75, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Display the last 5 columns (the recently added datetime breakdowns)\n", - "train_df.iloc[:, -5:].sample(5)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Perfect! How about we try and fit a model?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 3.1 Trying to fit a model on our training data\n", - "\n", - "I'm a big fan of trying to fit a model on your dataset as early as possible.\n", - "\n", - "If it works, you'll have to inspect and check its results.\n", - "\n", - "And if it doesn't work, you'll get some insights into what you may have to do to your dataset to prepare it.\n", - "\n", - "Let's turn our DataFrames into features (`X`) by dropping the `SalePrice` column (this is the value we're trying to predict) and labels (`y`) by extracting the `SalePrice` column.\n", - "\n", - "Then we'll create a model using `sklearn.ensemble.RandomForestRegressor` and finally we'll try to fit it to only the training data." - ] - }, - { - "cell_type": "code", - "execution_count": 76, - "metadata": {}, - "outputs": [ - { - "ename": "ValueError", - "evalue": "could not convert string to float: 'Medium'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m/var/folders/c4/qj4gdk190td18bqvjjh0p3p00000gn/T/ipykernel_20423/150598518.py\u001b[0m in \u001b[0;36m?\u001b[0;34m()\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;31m# Create a model\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0mmodel\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mRandomForestRegressor\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn_jobs\u001b[0m\u001b[0;34m=\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 11\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0;31m# Fit a model to the training data only\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 13\u001b[0;31m model.fit(X=X_train,\n\u001b[0m\u001b[1;32m 14\u001b[0m y=y_train)\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/base.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(estimator, *args, **kwargs)\u001b[0m\n\u001b[1;32m 1469\u001b[0m skip_parameter_validation=(\n\u001b[1;32m 1470\u001b[0m \u001b[0mprefer_skip_nested_validation\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mglobal_skip_validation\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1471\u001b[0m )\n\u001b[1;32m 1472\u001b[0m ):\n\u001b[0;32m-> 1473\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mfit_method\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mestimator\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/ensemble/_forest.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, X, y, sample_weight)\u001b[0m\n\u001b[1;32m 359\u001b[0m \u001b[0;31m# Validate or convert input data\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 360\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0missparse\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my\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 361\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"sparse multilabel-indicator for y is not supported.\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 362\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 363\u001b[0;31m X, y = self._validate_data(\n\u001b[0m\u001b[1;32m 364\u001b[0m \u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 365\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 366\u001b[0m \u001b[0mmulti_output\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/base.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, X, y, reset, validate_separately, cast_to_ndarray, **check_params)\u001b[0m\n\u001b[1;32m 646\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;34m\"estimator\"\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mcheck_y_params\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 647\u001b[0m \u001b[0mcheck_y_params\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m**\u001b[0m\u001b[0mdefault_check_params\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mcheck_y_params\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 648\u001b[0m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcheck_array\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minput_name\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"y\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mcheck_y_params\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 649\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 650\u001b[0;31m \u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcheck_X_y\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mcheck_params\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 651\u001b[0m \u001b[0mout\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 652\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 653\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mno_val_X\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mcheck_params\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"ensure_2d\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mTrue\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[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/utils/validation.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(X, y, accept_sparse, accept_large_sparse, dtype, order, copy, force_writeable, force_all_finite, ensure_2d, allow_nd, multi_output, ensure_min_samples, ensure_min_features, y_numeric, estimator)\u001b[0m\n\u001b[1;32m 1297\u001b[0m raise ValueError(\n\u001b[1;32m 1298\u001b[0m \u001b[0;34mf\"{estimator_name} requires y to be passed, but the target y is None\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1299\u001b[0m )\n\u001b[1;32m 1300\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1301\u001b[0;31m X = check_array(\n\u001b[0m\u001b[1;32m 1302\u001b[0m \u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1303\u001b[0m \u001b[0maccept_sparse\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0maccept_sparse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1304\u001b[0m \u001b[0maccept_large_sparse\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0maccept_large_sparse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/utils/validation.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(array, accept_sparse, accept_large_sparse, dtype, order, copy, force_writeable, force_all_finite, ensure_2d, allow_nd, ensure_min_samples, ensure_min_features, estimator, input_name)\u001b[0m\n\u001b[1;32m 1009\u001b[0m )\n\u001b[1;32m 1010\u001b[0m \u001b[0marray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mxp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mastype\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1011\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1012\u001b[0m \u001b[0marray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_asarray_with_order\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0morder\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0morder\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mxp\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mxp\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1013\u001b[0;31m \u001b[0;32mexcept\u001b[0m \u001b[0mComplexWarning\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mcomplex_warning\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 1014\u001b[0m raise ValueError(\n\u001b[1;32m 1015\u001b[0m \u001b[0;34m\"Complex data not supported\\n{}\\n\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1016\u001b[0m ) from complex_warning\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/utils/_array_api.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(array, dtype, order, copy, xp, device)\u001b[0m\n\u001b[1;32m 747\u001b[0m \u001b[0;31m# Use NumPy API to support order\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 748\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mcopy\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 749\u001b[0m \u001b[0marray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnumpy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0morder\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0morder\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 750\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 751\u001b[0;31m \u001b[0marray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnumpy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0morder\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0morder\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\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 752\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 753\u001b[0m \u001b[0;31m# At this point array is a NumPy ndarray. We convert it to an array\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 754\u001b[0m \u001b[0;31m# container that is consistent with the input's namespace.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/pandas/core/generic.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, dtype, copy)\u001b[0m\n\u001b[1;32m 2149\u001b[0m def __array__(\n\u001b[1;32m 2150\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mnpt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mDTypeLike\u001b[0m \u001b[0;34m|\u001b[0m \u001b[0;32mNone\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mbool_t\u001b[0m \u001b[0;34m|\u001b[0m \u001b[0;32mNone\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2151\u001b[0m ) -> np.ndarray:\n\u001b[1;32m 2152\u001b[0m \u001b[0mvalues\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_values\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2153\u001b[0;31m \u001b[0marr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\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 2154\u001b[0m if (\n\u001b[1;32m 2155\u001b[0m \u001b[0mastype_is_view\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0marr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2156\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0musing_copy_on_write\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[0;31mValueError\u001b[0m: could not convert string to float: 'Medium'" - ] - } - ], - "source": [ - "# Split training data into features and labels\n", - "X_train = train_df.drop(\"SalePrice\", axis=1)\n", - "y_train = train_df[\"SalePrice\"]\n", - "\n", - "# Split validation data into features and labels\n", - "X_valid = valid_df.drop(\"SalePrice\", axis=1)\n", - "y_valid = valid_df[\"SalePrice\"]\n", - "\n", - "# Create a model\n", - "model = RandomForestRegressor(n_jobs=-1)\n", - "\n", - "# Fit a model to the training data only\n", - "model.fit(X=X_train,\n", - " y=y_train)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Oh no!\n", - "\n", - "We run into the error:\n", - "\n", - "> ValueError: could not convert string to float: 'Medium'\n", - "\n", - "Hmm... \n", - "\n", - "Where have we seen this error before?\n", - "\n", - "It looks like since we re-imported our training dataset (from `Train.csv`) its no longer all numerical (hence the `ValueError` above).\n", - "\n", - "Not to worry, we can fix this!" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 3.2 Encoding categorical features as numbers using Scikit-Learn\n", - "\n", - "We've preprocessed our data previously with pandas.\n", - "\n", - "And while this is a viable approach, how about we practice using another method?\n", - "\n", - "This time we'll use Scikit-Learn's built-in preprocessing methods. \n", - "\n", - "Why?\n", - "\n", - "Because it's good exposure to different techniques.\n", - "\n", - "And Scikit-Learn has many built-in helpful and well tested methods for preparing data. \n", - "\n", - "You can also string together many of these methods and create a [reusable pipeline](https://scikit-learn.org/1.5/modules/generated/sklearn.pipeline.Pipeline.html) (you can think of this pipeline as plumbing for data).\n", - "\n", - "To preprocess our data with Scikit-Learn, we'll first define the numerical and categorical features of our dataset." - ] - }, - { - "cell_type": "code", - "execution_count": 77, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Numeric features: ['SalesID', 'MachineID', 'ModelID', 'datasource', 'auctioneerID', 'YearMade', 'MachineHoursCurrentMeter', 'saleYear', 'saleMonth', 'saleDay', 'saleDayofweek', 'saleDayofyear']\n", - "[INFO] Categorical features: ['UsageBand', 'fiModelDesc', 'fiBaseModel', 'fiSecondaryDesc', 'fiModelSeries', 'fiModelDescriptor', 'ProductSize', 'fiProductClassDesc', 'state', 'ProductGroup']...\n" - ] - } - ], - "source": [ - "# Define numerical and categorical features\n", - "numerical_features = [label for label, content in X_train.items() if pd.api.types.is_numeric_dtype(content)]\n", - "categorical_features = [label for label, content in X_train.items() if not pd.api.types.is_numeric_dtype(content)]\n", - "\n", - "print(f\"[INFO] Numeric features: {numerical_features}\")\n", - "print(f\"[INFO] Categorical features: {categorical_features[:10]}...\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Nice!\n", - "\n", - "We define our different feature types so we can use different preprocessing methods on each type.\n", - "\n", - "Scikit-Learn has many built-in methods for preprocessing data under the [`sklearn.preprocessing` module](https://scikit-learn.org/stable/api/sklearn.preprocessing.html#).\n", - "\n", - "And I'd encourage you to spend some time reading the [preprocessing data section of the Scikit-Learn user guide](https://scikit-learn.org/stable/modules/preprocessing.html#preprocessing) for more details.\n", - "\n", - "For now, let's focus on turning our categorical features into numbers (from object/string datatype to numeric datatype).\n", - "\n", - "The practice of turning non-numerical features into numerical features is often referred to as [**encoding**](https://scikit-learn.org/stable/modules/preprocessing.html#encoding-categorical-features).\n", - "\n", - "There are several encoders available for different use cases.\n", - "\n", - "TK - does this table show up?\n", - "\n", - "| **Encoder** | **Description** | **Use case** | **For use on** |\n", - "|-------------|-----------------|--------------|----------------|\n", - "| [LabelEncoder](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.LabelEncoder.html#sklearn.preprocessing.LabelEncoder) | Encode target labels with value between 0 and n_classes-1. | Useful for turning classification target values into numeric representations. | Target labels. |\n", - "| [OneHotEncoder](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html#onehotencoder) | Encode categorical features as a [one-hot numeric array](https://en.wikipedia.org/wiki/One-hot). | Turns every positive class of a unique category into a 1 and every negative class into a 0. | Categorical variables/features. |\n", - "| [OrdinalEncoder](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OrdinalEncoder.html#ordinalencoder) | Encode categorical features as an integer array. | Turn unique categorical values into a range of integers, for example, 0 maps to \"cat\", 1 maps to \"dog\" and more. | Categorical variables/features. |\n", - "| [TargetEncoder](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.TargetEncoder.html#targetencoder) | Encode regression and classification targets into a shrunk estimate of the average target values for observations of the category. - Useful for converting targets into a certain range of values. | Target variables. |\n", - "\n", - "For our case, we're going to start with `OrdinalEncoder`.\n", - "\n", - "When transforming/encoding values with Scikit-Learn, the steps as follows:\n", - "\n", - "1. Instantiate an encoder, for example, `sklearn.preprocessing.OrdinalEncoder`.\n", - "2. Use the [`sklearn.preprocessing.OrdinalEncoder.fit`](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OrdinalEncoder.html#sklearn.preprocessing.OrdinalEncoder.fit) method on the **training** data (this helps the encoder learn a mapping of categorical to numeric values).\n", - "3. Use the [`sklearn.preprocessing.OrdinalEncoder.transform`](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OrdinalEncoder.html#sklearn.preprocessing.OrdinalEncoder.transform) method on the **training** data to apply the learned mapping from categorical to numeric values.\n", - " * **Note:** The [`sklearn.preprocessing.OrdinalEncoder.fit_transform`](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OrdinalEncoder.html#sklearn.preprocessing.OrdinalEncoder.fit_transform) method combines steps 1 & 2 into a single method.\n", - "4. Apply the learned mapping to subsequent datasets such as **validation** and **test** splits using `sklearn.preprocessing.OrdinalEncoder.transform` only.\n", - "\n", - "Notice how the `fit` and `fit_transform` methods were reserved for the **training dataset only**.\n", - "\n", - "This is because in practice the validation and testing datasets are meant to be unseen, meaning only information from the training dataset should be used to preprocess the validation/test datasets.\n", - "\n", - "In short:\n", - "\n", - "1. Instantiate an encoder such as `sklearn.preprocessing.OrdinalEncoder`.\n", - "2. Fit the encoder to and transform the training dataset categorical variables/features with `sklearn.preprocessing.OrdinalEncoder.fit_transform`.\n", - "3. Transform categorical variables/features from subsequent datasets such as the validation and test datasets with the learned encoding from step 2 using `sklearn.preprocessing.OridinalEncoder.transform`. \n", - " * **Note:** Notice the use of the `transform` method on validation/test datasets rather than `fit_transform`.\n", - "\n", - "Let's do it!\n", - "\n", - "We'll use the `OrdinalEncoder` class to fill any missing values with `np.nan` (`NaN`).\n", - "\n", - "We'll also make sure to only use the `OrdinalEncoder` on the categorical features of our DataFrame.\n", - "\n", - "Finally, the `OrdinalEncoder` expects all input variables to be of the same type (e.g. either numeric only or string only) so we'll make sure all the input variables are strings only using [`pandas.DataFrame.astype(str)`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.astype.html)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Nice!\n", - "\n", - "We define our different feature types so we can use different preprocessing methods on each type.\n", - "\n", - "Scikit-Learn has many built-in methods for preprocessing data under the [`sklearn.preprocessing` module](https://scikit-learn.org/stable/api/sklearn.preprocessing.html#).\n", - "\n", - "And I'd encourage you to spend some time reading the [preprocessing data section of the Scikit-Learn user guide](https://scikit-learn.org/stable/modules/preprocessing.html#preprocessing) for more details.\n", - "\n", - "For now, let's focus on turning our categorical features into numbers (from object/string datatype to numeric datatype).\n", - "\n", - "The practice of turning non-numerical features into numerical features is often referred to as [**encoding**](https://scikit-learn.org/stable/modules/preprocessing.html#encoding-categorical-features).\n", - "\n", - "There are several encoders available for different use cases.\n", - "\n", - "TK - does this table show up?\n", - "\n", - "\n", - "\n", - "For our case, we're going to start with `OrdinalEncoder`.\n", - "\n", - "When transforming/encoding values with Scikit-Learn, the steps as follows:\n", - "\n", - "1. Instantiate an encoder, for example, `sklearn.preprocessing.OrdinalEncoder`.\n", - "2. Use the [`sklearn.preprocessing.OrdinalEncoder.fit`](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OrdinalEncoder.html#sklearn.preprocessing.OrdinalEncoder.fit) method on the **training** data (this helps the encoder learn a mapping of categorical to numeric values).\n", - "3. Use the [`sklearn.preprocessing.OrdinalEncoder.transform`](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OrdinalEncoder.html#sklearn.preprocessing.OrdinalEncoder.transform) method on the **training** data to apply the learned mapping from categorical to numeric values.\n", - " * **Note:** The [`sklearn.preprocessing.OrdinalEncoder.fit_transform`](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OrdinalEncoder.html#sklearn.preprocessing.OrdinalEncoder.fit_transform) method combines steps 1 & 2 into a single method.\n", - "4. Apply the learned mapping to subsequent datasets such as **validation** and **test** splits using `sklearn.preprocessing.OrdinalEncoder.transform` only.\n", - "\n", - "Notice how the `fit` and `fit_transform` methods were reserved for the **training dataset only**.\n", - "\n", - "This is because in practice the validation and testing datasets are meant to be unseen, meaning only information from the training dataset should be used to preprocess the validation/test datasets.\n", - "\n", - "In short:\n", - "\n", - "1. Instantiate an encoder such as `sklearn.preprocessing.OrdinalEncoder`.\n", - "2. Fit the encoder to and transform the training dataset categorical variables/features with `sklearn.preprocessing.OrdinalEncoder.fit_transform`.\n", - "3. Transform categorical variables/features from subsequent datasets such as the validation and test datasets with the learned encoding from step 2 using `sklearn.preprocessing.OridinalEncoder.transform`. \n", - " * **Note:** Notice the use of the `transform` method on validation/test datasets rather than `fit_transform`.\n", - "\n", - "Let's do it!\n", - "\n", - "We'll use the `OrdinalEncoder` class to fill any missing values with `np.nan` (`NaN`).\n", - "\n", - "We'll also make sure to only use the `OrdinalEncoder` on the categorical features of our DataFrame.\n", - "\n", - "Finally, the `OrdinalEncoder` expects all input variables to be of the same type (e.g. either numeric only or string only) so we'll make sure all the input variables are strings only using [`pandas.DataFrame.astype(str)`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.astype.html)." - ] - }, - { - "cell_type": "code", - "execution_count": 78, - "metadata": {}, - "outputs": [], - "source": [ - "from sklearn.preprocessing import OrdinalEncoder\n", - "\n", - "# 1. Create an ordinal encoder (turns category items into numeric representation)\n", - "ordinal_encoder = OrdinalEncoder(categories=\"auto\",\n", - " handle_unknown=\"use_encoded_value\",\n", - " unknown_value=np.nan,\n", - " encoded_missing_value=np.nan) # treat unknown categories as np.nan (or None)\n", - "\n", - "# 2. Fit and transform the categorical columns of X_train\n", - "X_train_preprocessed = X_train.copy() # make copies of the oringal DataFrames so we can keep the original values in tact and view them later\n", - "X_train_preprocessed[categorical_features] = ordinal_encoder.fit_transform(X_train_preprocessed[categorical_features].astype(str)) # OrdinalEncoder expects all values as the same type (e.g. string or numeric only)\n", - "\n", - "# 3. Transform the categorical columns of X_valid \n", - "X_valid_preprocessed = X_valid.copy()\n", - "X_valid_preprocessed[categorical_features] = ordinal_encoder.transform(X_valid_preprocessed[categorical_features].astype(str)) # only use `transform` on the validation data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Wonderful! \n", - "\n", - "Let's see if it worked.\n", - "\n", - "First, we'll check out the original `X_train` DataFrame." - ] - }, - { - "cell_type": "code", - "execution_count": 79, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - " \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", - "
SalesIDMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandfiModelDescfiBaseModel...Backhoe_MountingBlade_TypeTravel_ControlsDifferential_TypeSteering_ControlssaleYearsaleMonthsaleDaysaleDayofweeksaleDayofyear
20561516467701126363843413218.01974NaNNaNTD20TD20...None or UnspecifiedStraightNone or UnspecifiedNaNNaN1989117117
9280314040191169900711013299.01986NaNNaN416416...NaNNaNNaNNaNNaN1989131131
9834614156461262088335713299.01975NaNNaN12G12...NaNNaNNaNNaNNaN1989131131
16929715963581433229824713299.01978NaNNaN644644...NaNNaNNaNStandardConventional1989131131
274835182151411940891015013299.01980NaNNaNA66A66...NaNNaNNaNStandardConventional1989131131
\n", - "

5 rows × 56 columns

\n", - "
" - ], - "text/plain": [ - " SalesID MachineID ModelID datasource auctioneerID YearMade \\\n", - "205615 1646770 1126363 8434 132 18.0 1974 \n", - "92803 1404019 1169900 7110 132 99.0 1986 \n", - "98346 1415646 1262088 3357 132 99.0 1975 \n", - "169297 1596358 1433229 8247 132 99.0 1978 \n", - "274835 1821514 1194089 10150 132 99.0 1980 \n", - "\n", - " MachineHoursCurrentMeter UsageBand fiModelDesc fiBaseModel ... \\\n", - "205615 NaN NaN TD20 TD20 ... \n", - "92803 NaN NaN 416 416 ... \n", - "98346 NaN NaN 12G 12 ... \n", - "169297 NaN NaN 644 644 ... \n", - "274835 NaN NaN A66 A66 ... \n", - "\n", - " Backhoe_Mounting Blade_Type Travel_Controls Differential_Type \\\n", - "205615 None or Unspecified Straight None or Unspecified NaN \n", - "92803 NaN NaN NaN NaN \n", - "98346 NaN NaN NaN NaN \n", - "169297 NaN NaN NaN Standard \n", - "274835 NaN NaN NaN Standard \n", - "\n", - " Steering_Controls saleYear saleMonth saleDay saleDayofweek \\\n", - "205615 NaN 1989 1 17 1 \n", - "92803 NaN 1989 1 31 1 \n", - "98346 NaN 1989 1 31 1 \n", - "169297 Conventional 1989 1 31 1 \n", - "274835 Conventional 1989 1 31 1 \n", - "\n", - " saleDayofyear \n", - "205615 17 \n", - "92803 31 \n", - "98346 31 \n", - "169297 31 \n", - "274835 31 \n", - "\n", - "[5 rows x 56 columns]" - ] - }, - "execution_count": 79, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "X_train.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And how about `X_train_preprocessed`?" - ] - }, - { - "cell_type": "code", - "execution_count": 80, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - " \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", - "
SalesIDMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandfiModelDescfiBaseModel...Backhoe_MountingBlade_TypeTravel_ControlsDifferential_TypeSteering_ControlssaleYearsaleMonthsaleDaysaleDayofweeksaleDayofyear
20561516467701126363843413218.01974NaN3.04536.01734.0...0.07.05.04.05.01989117117
9280314040191169900711013299.01986NaN3.0734.0242.0...2.010.07.04.05.01989131131
9834614156461262088335713299.01975NaN3.081.018.0...2.010.07.04.05.01989131131
16929715963581433229824713299.01978NaN3.01157.0348.0...2.010.07.03.01.01989131131
274835182151411940891015013299.01980NaN3.01799.0556.0...2.010.07.03.01.01989131131
\n", - "

5 rows × 56 columns

\n", - "
" - ], - "text/plain": [ - " SalesID MachineID ModelID datasource auctioneerID YearMade \\\n", - "205615 1646770 1126363 8434 132 18.0 1974 \n", - "92803 1404019 1169900 7110 132 99.0 1986 \n", - "98346 1415646 1262088 3357 132 99.0 1975 \n", - "169297 1596358 1433229 8247 132 99.0 1978 \n", - "274835 1821514 1194089 10150 132 99.0 1980 \n", - "\n", - " MachineHoursCurrentMeter UsageBand fiModelDesc fiBaseModel ... \\\n", - "205615 NaN 3.0 4536.0 1734.0 ... \n", - "92803 NaN 3.0 734.0 242.0 ... \n", - "98346 NaN 3.0 81.0 18.0 ... \n", - "169297 NaN 3.0 1157.0 348.0 ... \n", - "274835 NaN 3.0 1799.0 556.0 ... \n", - "\n", - " Backhoe_Mounting Blade_Type Travel_Controls Differential_Type \\\n", - "205615 0.0 7.0 5.0 4.0 \n", - "92803 2.0 10.0 7.0 4.0 \n", - "98346 2.0 10.0 7.0 4.0 \n", - "169297 2.0 10.0 7.0 3.0 \n", - "274835 2.0 10.0 7.0 3.0 \n", - "\n", - " Steering_Controls saleYear saleMonth saleDay saleDayofweek \\\n", - "205615 5.0 1989 1 17 1 \n", - "92803 5.0 1989 1 31 1 \n", - "98346 5.0 1989 1 31 1 \n", - "169297 1.0 1989 1 31 1 \n", - "274835 1.0 1989 1 31 1 \n", - "\n", - " saleDayofyear \n", - "205615 17 \n", - "92803 31 \n", - "98346 31 \n", - "169297 31 \n", - "274835 31 \n", - "\n", - "[5 rows x 56 columns]" - ] - }, - "execution_count": 80, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "X_train_preprocessed.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Beautiful!\n", - "\n", - "Notice all of the non-numerical values in `X_train` have been converted to numerical values in `X_train_preprocessed`.\n", - "\n", - "Now how about missing values?\n", - "\n", - "Let's see the top 10 columns with the highest number of missing values from `X_train`." - ] - }, - { - "cell_type": "code", - "execution_count": 81, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Engine_Horsepower 375906\n", - "Blade_Extension 375906\n", - "Tip_Control 375906\n", - "Pushblock 375906\n", - "Enclosure_Type 375906\n", - "Blade_Width 375906\n", - "Scarifier 375895\n", - "Hydraulics_Flow 357763\n", - "Grouser_Tracks 357763\n", - "Coupler_System 357667\n", - "dtype: int64" - ] - }, - "execution_count": 81, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "X_train[categorical_features].isna().sum().sort_values(ascending=False)[:10]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Ok, plenty of missing values.\n", - "\n", - "How about `X_train_preprocessed`?" - ] - }, - { - "cell_type": "code", - "execution_count": 82, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "UsageBand 0\n", - "fiModelDesc 0\n", - "Pushblock 0\n", - "Ripper 0\n", - "Scarifier 0\n", - "Tip_Control 0\n", - "Tire_Size 0\n", - "Coupler 0\n", - "Coupler_System 0\n", - "Grouser_Tracks 0\n", - "dtype: int64" - ] - }, - "execution_count": 82, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "X_train_preprocessed[categorical_features].isna().sum().sort_values(ascending=False)[:10]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Perfect! No missing values as well!\n", - "\n", - "Now, what if we wanted to retrieve the original categorical values?\n", - "\n", - "We can do using the [`OrdinalEncoder.categories_` attribute](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OrdinalEncoder.html#sklearn.preprocessing.OrdinalEncoder.fit_transform).\n", - "\n", - "This will return the categories of each feature found during `fit` (or during `fit_transform`), the categories will be in the order of the features seen (same order as the columns of the DataFrame)." - ] - }, - { - "cell_type": "code", - "execution_count": 83, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[array(['High', 'Low', 'Medium', 'nan'], dtype=object),\n", - " array(['100C', '104', '1066', ..., 'ZX800LC', 'ZX80LCK', 'ZX850H'],\n", - " dtype=object),\n", - " array(['10', '100', '104', ..., 'ZX80', 'ZX800', 'ZX850'], dtype=object)]" - ] - }, - "execution_count": 83, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Let's inspect the first three categories\n", - "ordinal_encoder.categories_[:3]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Since these come in the order of the features seen, we can create a mapping of these using the categorical column names of our DataFrame." - ] - }, - { - "cell_type": "code", - "execution_count": 84, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{0: 'High', 1: 'Low', 2: 'Medium', 3: 'nan'}" - ] - }, - "execution_count": 84, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Create a dictionary of dictionaries mapping column names and their variables to their numerical encoding\n", - "column_to_category_mapping = {}\n", - "\n", - "for column_name, category_values in zip(categorical_features, ordinal_encoder.categories_):\n", - " int_to_category = {i: category for i, category in enumerate(category_values)}\n", - " column_to_category_mapping[column_name] = int_to_category\n", - "\n", - "# Inspect an example column name to category mapping\n", - "column_to_category_mapping[\"UsageBand\"]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can also reverse our `OrdinalEncoder` values with the [`inverse_transform()`](https://scikit-learn.org/1.5/modules/generated/sklearn.preprocessing.OrdinalEncoder.html#sklearn.preprocessing.OrdinalEncoder.inverse_transform) method.\n", - "\n", - "This is helpful for reversing a preprocessing step or viewing the original data again if necessary." - ] - }, - { - "cell_type": "code", - "execution_count": 85, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - " \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", - "
UsageBandfiModelDescfiBaseModelfiSecondaryDescfiModelSeriesfiModelDescriptorProductSizefiProductClassDescstateProductGroup...Undercarriage_Pad_WidthStick_LengthThumbPattern_ChangerGrouser_TypeBackhoe_MountingBlade_TypeTravel_ControlsDifferential_TypeSteering_Controls
214315nan160CLC160CnanLCSmallHydraulic Excavator, Track - 14.0 to 16.0 Metr...AlabamaTEX...28 inchNone or UnspecifiedNone or UnspecifiedNone or UnspecifiedTriplenannannannannan
96782nanD4HD4HnannannanTrack Type Tractor, Dozer - 85.0 to 105.0 Hors...CaliforniaTTT...nannannannannanNone or UnspecifiedPATNone or Unspecifiednannan
224604nan140G140GnannannanMotorgrader - 145.0 to 170.0 HorsepowerMissouriMG...nannannannannannannannannannan
310524High966E966EnannanMediumWheel Loader - 200.0 to 225.0 HorsepowerMichiganWL...nannannannannannannannanStandardConventional
156716nan650H650HnannannanTrack Type Tractor, Dozer - 85.0 to 105.0 Hors...FloridaTTT...nannannannannanNone or UnspecifiedPATNone or Unspecifiednannan
\n", - "

5 rows × 44 columns

\n", - "
" - ], - "text/plain": [ - " UsageBand fiModelDesc fiBaseModel fiSecondaryDesc fiModelSeries \\\n", - "214315 nan 160CLC 160 C nan \n", - "96782 nan D4H D4 H nan \n", - "224604 nan 140G 140 G nan \n", - "310524 High 966E 966 E nan \n", - "156716 nan 650H 650 H nan \n", - "\n", - " fiModelDescriptor ProductSize \\\n", - "214315 LC Small \n", - "96782 nan nan \n", - "224604 nan nan \n", - "310524 nan Medium \n", - "156716 nan nan \n", - "\n", - " fiProductClassDesc state \\\n", - "214315 Hydraulic Excavator, Track - 14.0 to 16.0 Metr... Alabama \n", - "96782 Track Type Tractor, Dozer - 85.0 to 105.0 Hors... California \n", - "224604 Motorgrader - 145.0 to 170.0 Horsepower Missouri \n", - "310524 Wheel Loader - 200.0 to 225.0 Horsepower Michigan \n", - "156716 Track Type Tractor, Dozer - 85.0 to 105.0 Hors... Florida \n", - "\n", - " ProductGroup ... Undercarriage_Pad_Width Stick_Length \\\n", - "214315 TEX ... 28 inch None or Unspecified \n", - "96782 TTT ... nan nan \n", - "224604 MG ... nan nan \n", - "310524 WL ... nan nan \n", - "156716 TTT ... nan nan \n", - "\n", - " Thumb Pattern_Changer Grouser_Type \\\n", - "214315 None or Unspecified None or Unspecified Triple \n", - "96782 nan nan nan \n", - "224604 nan nan nan \n", - "310524 nan nan nan \n", - "156716 nan nan nan \n", - "\n", - " Backhoe_Mounting Blade_Type Travel_Controls Differential_Type \\\n", - "214315 nan nan nan nan \n", - "96782 None or Unspecified PAT None or Unspecified nan \n", - "224604 nan nan nan nan \n", - "310524 nan nan nan Standard \n", - "156716 None or Unspecified PAT None or Unspecified nan \n", - "\n", - " Steering_Controls \n", - "214315 nan \n", - "96782 nan \n", - "224604 nan \n", - "310524 Conventional \n", - "156716 nan \n", - "\n", - "[5 rows x 44 columns]" - ] - }, - "execution_count": 85, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Create a copy of the preprocessed DataFrame\n", - "X_train_unprocessed = X_train_preprocessed[categorical_features].copy()\n", - "\n", - "# This will return an array of the original untransformed data\n", - "X_train_unprocessed = ordinal_encoder.inverse_transform(X_train_unprocessed)\n", - "\n", - "# Turn back into a DataFrame for viewing pleasure\n", - "X_train_unprocessed_df = pd.DataFrame(X_train_unprocessed, columns=categorical_features)\n", - "\n", - "# Check out a sample\n", - "X_train_unprocessed_df.sample(5)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Nice!\n", - "\n", - "Now how about we try fitting a model again?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 3.3 Fitting a model to our preprocessed training data\n", - "\n", - "We've used Scikit-Learn to convert the categorical data in our training and validation sets into numbers.\n", - "\n", - "But we haven't yet done anything with missing numerical values.\n", - "\n", - "As it turns out, we can still try and fit a model.\n", - "\n", - "Why?\n", - "\n", - "Because there are several estimators/models in Scikit-Learn that can handle missing (`NaN`) values.\n", - "\n", - "And our trusty `sklearn.ensemble.RandomForestRegressor` is one of them!\n", - "\n", - "Let's try it out on our `X_train_preprocessed` DataFrame.\n", - "\n", - "> **Note:** For a list of all Scikit-Learn estimators that can handle `NaN` values, check out the [Scikit-Learn imputation of missing values user guide](https://scikit-learn.org/1.5/modules/impute.html#estimators-that-handle-nan-values). " - ] - }, - { - "cell_type": "code", - "execution_count": 86, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 8min 54s, sys: 6min 26s, total: 15min 20s\n", - "Wall time: 2min 40s\n" - ] - }, - { - "data": { - "text/html": [ - "
RandomForestRegressor(n_jobs=-1)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" - ], - "text/plain": [ - "RandomForestRegressor(n_jobs=-1)" - ] - }, - "execution_count": 86, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "\n", - "# Instantiate a Random Forest Regression model\n", - "model = RandomForestRegressor(n_jobs=-1)\n", - "\n", - "# Fit the model to the preprocessed training data\n", - "model.fit(X=X_train_preprocessed,\n", - " y=y_train)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "It worked!\n", - "\n", - "Now you might be thinking, \"well if we could fit a model on a dataset with missing values, why did we bother filling them before?\"\n", - "\n", - "And that's a great question.\n", - "\n", - "The main reason is to *practice, practice, practice*. \n", - "\n", - "While there are some models which can handle missing values, others can't.\n", - "\n", - "So it's good to have experience with both of these scenarios.\n", - "\n", - "Let's see how our model scores on the validation set, data our model has never seen." - ] - }, - { - "cell_type": "code", - "execution_count": 88, - "metadata": {}, - "outputs": [ - { - "ename": "ValueError", - "evalue": "could not convert string to float: 'Low'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m?\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;34m'Could not get source, probably due dynamically evaluated source code.'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/base.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, X, y, sample_weight)\u001b[0m\n\u001b[1;32m 844\u001b[0m \"\"\"\n\u001b[1;32m 845\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 846\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m\u001b[0mmetrics\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mr2_score\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 847\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 848\u001b[0;31m \u001b[0my_pred\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpredict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mX\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 849\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mr2_score\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my_pred\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msample_weight\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msample_weight\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/ensemble/_forest.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, X)\u001b[0m\n\u001b[1;32m 1059\u001b[0m \u001b[0mThe\u001b[0m \u001b[0mpredicted\u001b[0m \u001b[0mvalues\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1060\u001b[0m \"\"\"\n\u001b[1;32m 1061\u001b[0m \u001b[0mcheck_is_fitted\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1062\u001b[0m \u001b[0;31m# Check data\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1063\u001b[0;31m \u001b[0mX\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_validate_X_predict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mX\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 1064\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1065\u001b[0m \u001b[0;31m# Assign chunk of trees to jobs\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1066\u001b[0m \u001b[0mn_jobs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_partition_estimators\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mn_estimators\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mn_jobs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/ensemble/_forest.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, X)\u001b[0m\n\u001b[1;32m 637\u001b[0m \u001b[0mforce_all_finite\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"allow-nan\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 638\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 639\u001b[0m \u001b[0mforce_all_finite\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 640\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 641\u001b[0;31m X = self._validate_data(\n\u001b[0m\u001b[1;32m 642\u001b[0m \u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 643\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mDTYPE\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 644\u001b[0m \u001b[0maccept_sparse\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"csr\"\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/base.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, X, y, reset, validate_separately, cast_to_ndarray, **check_params)\u001b[0m\n\u001b[1;32m 629\u001b[0m \u001b[0mout\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 630\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 631\u001b[0m \u001b[0mout\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 632\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mno_val_X\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mno_val_y\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 633\u001b[0;31m \u001b[0mout\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcheck_array\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minput_name\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"X\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mcheck_params\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 634\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mno_val_X\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mno_val_y\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 635\u001b[0m \u001b[0mout\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_check_y\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mcheck_params\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 636\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/utils/validation.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(array, accept_sparse, accept_large_sparse, dtype, order, copy, force_writeable, force_all_finite, ensure_2d, allow_nd, ensure_min_samples, ensure_min_features, estimator, input_name)\u001b[0m\n\u001b[1;32m 1009\u001b[0m )\n\u001b[1;32m 1010\u001b[0m \u001b[0marray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mxp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mastype\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1011\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1012\u001b[0m \u001b[0marray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_asarray_with_order\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0morder\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0morder\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mxp\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mxp\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1013\u001b[0;31m \u001b[0;32mexcept\u001b[0m \u001b[0mComplexWarning\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mcomplex_warning\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 1014\u001b[0m raise ValueError(\n\u001b[1;32m 1015\u001b[0m \u001b[0;34m\"Complex data not supported\\n{}\\n\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1016\u001b[0m ) from complex_warning\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/utils/_array_api.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(array, dtype, order, copy, xp, device)\u001b[0m\n\u001b[1;32m 747\u001b[0m \u001b[0;31m# Use NumPy API to support order\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 748\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mcopy\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 749\u001b[0m \u001b[0marray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnumpy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0morder\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0morder\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 750\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 751\u001b[0;31m \u001b[0marray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnumpy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0morder\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0morder\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\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 752\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 753\u001b[0m \u001b[0;31m# At this point array is a NumPy ndarray. We convert it to an array\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 754\u001b[0m \u001b[0;31m# container that is consistent with the input's namespace.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/pandas/core/generic.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, dtype, copy)\u001b[0m\n\u001b[1;32m 2149\u001b[0m def __array__(\n\u001b[1;32m 2150\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mnpt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mDTypeLike\u001b[0m \u001b[0;34m|\u001b[0m \u001b[0;32mNone\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mbool_t\u001b[0m \u001b[0;34m|\u001b[0m \u001b[0;32mNone\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2151\u001b[0m ) -> np.ndarray:\n\u001b[1;32m 2152\u001b[0m \u001b[0mvalues\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_values\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2153\u001b[0;31m \u001b[0marr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\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 2154\u001b[0m if (\n\u001b[1;32m 2155\u001b[0m \u001b[0mastype_is_view\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0marr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2156\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0musing_copy_on_write\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[0;31mValueError\u001b[0m: could not convert string to float: 'Low'" - ] - } - ], - "source": [ - "%%time\n", - "\n", - "# Check model performance on the validation set\n", - "model.score(X=X_valid,\n", - " y=y_valid)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Oops!\n", - "\n", - "Looks like we get an error:\n", - "\n", - "> `ValueError: could not convert string to float: 'Low'`\n", - "\n", - "This is because we tried to evaluate our model on the original `X_valid` dataset which still contains strings rather than `X_valid_preprocessed` which contains all numerical values.\n", - "\n", - "As we've discussed before, in machine learning problems, it's important to **evaluate your models on data in the same format as they were trained on**.\n", - "\n", - "Knowing this, let's evaluate our model on our preprocessed validation dataset." - ] - }, - { - "cell_type": "code", - "execution_count": 89, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 766 ms, sys: 3.54 s, total: 4.3 s\n", - "Wall time: 1.27 s\n" - ] - }, - { - "data": { - "text/plain": [ - "0.8700295442271035" - ] - }, - "execution_count": 89, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "\n", - "# Check model performance on the validation set\n", - "model.score(X=X_valid_preprocessed,\n", - " y=y_valid)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Excellent!\n", - "\n", - "Now you might be wondering why this score ($R^2$ or R-squared by default) is lower than the previous score of ~0.9875.\n", - "\n", - "That's because this score is based on a model that has only seen the training data and is being evaluated on an unseen dataset (training on `Train.csv`, evaluating on `Valid.csv`).\n", - "\n", - "Our previous score was from a model that had all of the evaluation samples in the training data (training and evaluating on `TrainAndValid.csv`).\n", - "\n", - "So in practice, we would consider the most recent score as a much more reliable metric of how well our model might perform on future unseen data.\n", - "\n", - "Just for fun, let's see how our model scores on the training dataset." - ] - }, - { - "cell_type": "code", - "execution_count": 90, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 17.6 s, sys: 19.2 s, total: 36.8 s\n", - "Wall time: 7.42 s\n" - ] - }, - { - "data": { - "text/plain": [ - "0.9872786621410867" - ] - }, - "execution_count": 90, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "\n", - "# Check model performance on the training set\n", - "model.score(X=X_train_preprocessed,\n", - " y=y_train)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As expected our model performs better on the training set than the validation set.\n", - "\n", - "It also scores much closer to the previous score of ~0.9875 we obtained when training and scoring on `TrainAndValid.csv` combined.\n", - "\n", - "> **Note:** It is common to see a model perform slightly worse on a validation/testing dataset than on a training set. This is because the model has seen all of the examples in the training set, where as, if done correctly, the validation and test sets are keep separate during training. So you would expect a model to do better on problems that it has seen before versus problems it hasn't. If you find your model scoring much higher on unseen data versus seen data (e.g. higher scores on the test set compared to the training set), you might want to inspect your data to make sure there isn't any leakage from the validation/test set into the training set." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 4. Building an evaluation function\n", - "\n", - "Evaluating a machine learning model is just as important as training one.\n", - "\n", - "And so because of this, let's create an evaluation function to make evaluation faster and reproducible.\n", - "\n", - "According to Kaggle for the Bluebook for Bulldozers competition, [the evaluation function](https://www.kaggle.com/c/bluebook-for-bulldozers/overview/evaluation) they use is root mean squared log error (RMSLE).\n", - "\n", - "$$ \\text{RMSLE} = \\sqrt{\\frac{1}{n} \\sum_{i=1}^{n} \\left( \\log(1 + \\hat{y}_i) - \\log(1 + y_i) \\right)^2} $$\n", - "\n", - "Where:\n", - "\n", - "* $ \\hat{y}_i $ is the predicted value, \n", - "* $ y_i $ is the actual value, \n", - "* $ n $ is the number of observations.\n", - "\n", - "Contrast this with mean absolute error (MAE), another common regression metric.\n", - "\n", - "$$ \\text{MAE} = \\frac{1}{n} \\sum_{i=1}^{n} \\left| \\hat{y}_i - y_i \\right| $$\n", - "\n", - "With RMSLE, the relative error is more meaningful than the absolute error. You care more about ratios than absolute errors. For example, being off by $100 on a $1000 prediction (10% error) is more significant than being off by $100 on a $10,000 prediction (1% error). RMSLE is sensitive to large percentage errors.\n", - "\n", - "Where as with MAE, is more about exact differences, a $100 prediction error is weighted the same regardless of the actual value.\n", - "\n", - "In each of case, a lower value (closer to 0) is better.\n", - "\n", - "For any problem, it's important to define the evaluation metric you're going to try and improve on.\n", - "\n", - "In our case, let's create a function that calculates multiple evaluation metrics.\n", - "\n", - "Namely, we'll use:\n", - "\n", - "* MAE (mean absolute error) via [`sklearn.metrics.mean_absolute_error`](https://scikit-learn.org/1.5/modules/generated/sklearn.metrics.mean_absolute_error.html) - lower is better.\n", - "* RMSLE (root mean squared log error) via [`sklearn.metrics.root_mean_squared_log_error`](https://scikit-learn.org/1.5/modules/generated/sklearn.metrics.root_mean_squared_log_error.html) - lower is better.\n", - "* $R^2$ (R-squared or coefficient of determination) via the [`score` method](https://scikit-learn.org/dev/modules/generated/sklearn.ensemble.RandomForestRegressor.html#sklearn.ensemble.RandomForestRegressor.score) - higher is better.\n", - "\n", - "For MAE and RMSLE we'll be comparing the model's predictions to the truth labels.\n", - "\n", - "We can get an array of predicted values from our model using [`model.predict(X=features_to_predict_on)`](https://scikit-learn.org/dev/modules/generated/sklearn.ensemble.RandomForestRegressor.html#sklearn.ensemble.RandomForestRegressor.predict). " - ] - }, - { - "cell_type": "code", - "execution_count": 93, - "metadata": {}, - "outputs": [], - "source": [ - "# Create evaluation function (the competition uses Root Mean Square Log Error)\n", - "from sklearn.metrics import mean_absolute_error, root_mean_squared_log_error\n", - "\n", - "# Create function to evaluate our model\n", - "def show_scores(model, \n", - " train_features=X_train_preprocessed,\n", - " train_labels=y_train,\n", - " valid_features=X_valid_preprocessed,\n", - " valid_labels=y_valid):\n", - " \n", - " # Make predictions on train and validation features\n", - " train_preds = model.predict(X=train_features)\n", - " val_preds = model.predict(X=valid_features)\n", - "\n", - " # Create a scores dictionary of different evaluation metrics\n", - " scores = {\"Training MAE\": mean_absolute_error(y_true=train_labels, \n", - " y_pred=train_preds),\n", - " \"Valid MAE\": mean_absolute_error(y_true=valid_labels, \n", - " y_pred=val_preds),\n", - " \"Training RMSLE\": root_mean_squared_log_error(y_true=train_labels, \n", - " y_pred=train_preds),\n", - " \"Valid RMSLE\": root_mean_squared_log_error(y_true=valid_labels, \n", - " y_pred=val_preds),\n", - " \"Training R^2\": model.score(X=train_features, \n", - " y=train_labels),\n", - " \"Valid R^2\": model.score(X=valid_features, \n", - " y=valid_labels)}\n", - " return scores" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that's a nice looking function!\n", - "\n", - "How about we test it out?" - ] - }, - { - "cell_type": "code", - "execution_count": 94, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'Training MAE': np.float64(1596.4113176025767),\n", - " 'Valid MAE': np.float64(6172.124644142976),\n", - " 'Training RMSLE': np.float64(0.08546822305943352),\n", - " 'Valid RMSLE': np.float64(0.2576977236694938),\n", - " 'Training R^2': 0.9872786621410867,\n", - " 'Valid R^2': 0.8700295442271035}" - ] - }, - "execution_count": 94, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Try our model scoring function out\n", - "model_scores = show_scores(model=model)\n", - "model_scores" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Beautiful!\n", - "\n", - "Now we can reuse this in the future for evaluating other models." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 5. Tuning our model's hyperparameters\n", - "\n", - "Hyperparameters are the settings we can change on our model.\n", - "\n", - "And tuning hyperparameters on a given model can often alter its performance on a given dataset.\n", - "\n", - "Ideally, changing hyperparameters would lead to better results.\n", - "\n", - "However, it's often hard to know what hyperparameter changes would improve a model ahead of time.\n", - "\n", - "So what we can do is run several experiments across various different hyperparameter settings and record which lead to the best results." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 5.1 Making our modelling experiments faster (to speed up hyperparameter tuning)\n", - "\n", - "Because of the size of our dataset (~400,000 rows), retraining an entire model (about 1-1.5 minutes on my MacBook Pro M1 Pro) for each new set of hyperparameters would take far too long to continuing experimenting as fast as we want to.\n", - "\n", - "So what we'll do is take a sample of the training set and tune the hyperparameters on that before training a larger model.\n", - "\n", - "> **Note:** If you're experiments are taking longer than 10-seconds (or far longer than what you can interact with), you should be trying to speed things up. You can speed experiments up by sampling less data, using a faster computer or using a smaller model.\n", - "\n", - "We can take a artificial sample of the training set by altering the number of samples seen by each `n_estimator` (an `n_estimator` is a [decision tree](https://en.wikipedia.org/wiki/Decision_tree_learning) a random forest will create during training, more trees generally leads to better performance but sacrifices compute time) in [`sklearn.ensemble.RandomForestRegressor`](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html) using the `max_samples` parameter.\n", - "\n", - "For example, setting `max_samples` to 10,000 means every `n_estimator` (default 100) in our `RandomForestRegressor` will only see 10,000 random samples from our DataFrame instead of the entire ~400,000.\n", - "\n", - "In other words, we'll be looking at 40x less samples which means we should get faster computation speeds but we should also expect our results to worsen (because the model has less samples to learn patterns from).\n", - "\n", - "Let's see if reducing the number samples speeds up our modelling time." - ] - }, - { - "cell_type": "code", - "execution_count": 95, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 19.2 s, sys: 18.5 s, total: 37.6 s\n", - "Wall time: 7.53 s\n" - ] - }, - { - "data": { - "text/html": [ - "
RandomForestRegressor(max_samples=10000, n_jobs=-1)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" - ], - "text/plain": [ - "RandomForestRegressor(max_samples=10000, n_jobs=-1)" - ] - }, - "execution_count": 95, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "\n", - "# Change max samples in RandomForestRegressor\n", - "model = RandomForestRegressor(n_estimators=100, # this is the default\n", - " n_jobs=-1,\n", - " max_samples=10000) # each estimator sees max_samples (the default is to see all available samples)\n", - "\n", - "# Cutting down the max number of samples each tree can see improves training time\n", - "model.fit(X_train_preprocessed, \n", - " y_train)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Nice! That worked much faster than training on the whole dataset.\n", - "\n", - "Let's evaluate our model with our `show_scores` function." - ] - }, - { - "cell_type": "code", - "execution_count": 96, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'Training MAE': np.float64(5605.344206319725),\n", - " 'Valid MAE': np.float64(7176.1651147786515),\n", - " 'Training RMSLE': np.float64(0.26030112528907273),\n", - " 'Valid RMSLE': np.float64(0.2935839690284876),\n", - " 'Training R^2': 0.858111849057448,\n", - " 'Valid R^2': 0.828549722372896}" - ] - }, - "execution_count": 96, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Get evaluation metrics from reduced sample model\n", - "base_model_scores = show_scores(model=model)\n", - "base_model_scores" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Excellent! Even though our new model saw far less data than the previous model, it still looks to be performing quite well.\n", - "\n", - "With this faster model, we can start to run a series of different hyperparameter experiments." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 5.2 Hyperparameter tuning with RandomizedSearchCV\n", - "\n", - "The goal of hyperparameter tuning is to values for our model's settings which lead to better results.\n", - "\n", - "We could sit there and do this by hand, adjusting parameters on `sklearn.ensemble.RandomForestRegressor` such as `n_estimators`, `max_depth`, `min_samples_split` and more.\n", - "\n", - "However, this would quite tedious.\n", - "\n", - "Instead, we can define a dictionary of hyperparametmer settings in the form `{\"hyperparamter_name\": [values_to_test]}` and then use [`sklearn.model_selection.RandomizedSearchCV`](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.RandomizedSearchCV.html#randomizedsearchcv) (randomly search for best combination of hyperparameters) or [`sklearn.model_selection.GridSearchCV`](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html#gridsearchcv) (exhaustively search for best combination of hyperparameters) to go through all of these settings for us on a given model and dataset and then record which perform best.\n", - "\n", - "A general workflow is to start with a large number and wide range of potential settings and use `RandomizedSearchCV` to search across these randomly for a limited number of iterations (e.g. `n_iter=10`).\n", - "\n", - "And then take the best results and narrow the search space down before exhaustively search for the best hyperparameters with `GridSearchCV`.\n", - "\n", - "Let's start trying to find better hyperparameters by:\n", - "\n", - "1. Define a dictionary of hyperparameter values for our `RandomForestRegressor` model. We'll keep `max_samples=10000` so our experiments run faster.\n", - "2. Setup an instance of `RandomizedSearchCV` to explore the parameter values defined in step 1. We can adjust how many sets of hyperparameters our model tries using the `n_iter` parameter as well as how many times our model performs cross-validation using the `cv` parameter. For example, setting `n_iter=20` and `cv=3` means there will be 3 cross-validation folds for each of the 20 different combinations of hyperparameters, a total of 60 (3*20) experiments.\n", - "3. Fit the instance of `RandomizedSearchCV` to the data. This will automatically go through the defined number of iterations and record the results for each. The best model gets loaded at the end.\n", - "\n", - "> **Note:** You can read more about the [tuning of hyperparameters of an esimator/model in the Scikit-Learn user guide](https://scikit-learn.org/stable/modules/grid_search.html#tuning-the-hyper-parameters-of-an-estimator). " - ] - }, - { - "cell_type": "code", - "execution_count": 97, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Fitting 3 folds for each of 20 candidates, totalling 60 fits\n", - "[CV 1/3] END max_depth=10, max_features=1.0, max_samples=10000, min_samples_leaf=1, min_samples_split=3, n_estimators=160;, score=0.539 total time= 21.6s\n", - "[CV 2/3] END max_depth=10, max_features=1.0, max_samples=10000, min_samples_leaf=1, min_samples_split=3, n_estimators=160;, score=0.720 total time= 23.0s\n", - "[CV 3/3] END max_depth=10, max_features=1.0, max_samples=10000, min_samples_leaf=1, min_samples_split=3, n_estimators=160;, score=0.596 total time= 22.2s\n", - "[CV 1/3] END max_depth=10, max_features=sqrt, max_samples=10000, min_samples_leaf=9, min_samples_split=5, n_estimators=60;, score=0.491 total time= 3.3s\n", - "[CV 2/3] END max_depth=10, max_features=sqrt, max_samples=10000, min_samples_leaf=9, min_samples_split=5, n_estimators=60;, score=0.655 total time= 3.4s\n", - "[CV 3/3] END max_depth=10, max_features=sqrt, max_samples=10000, min_samples_leaf=9, min_samples_split=5, n_estimators=60;, score=0.614 total time= 3.3s\n", - "[CV 1/3] END max_depth=None, max_features=sqrt, max_samples=10000, min_samples_leaf=9, min_samples_split=8, n_estimators=130;, score=0.520 total time= 6.7s\n", - "[CV 2/3] END max_depth=None, max_features=sqrt, max_samples=10000, min_samples_leaf=9, min_samples_split=8, n_estimators=130;, score=0.702 total time= 6.6s\n", - "[CV 3/3] END max_depth=None, max_features=sqrt, max_samples=10000, min_samples_leaf=9, min_samples_split=8, n_estimators=130;, score=0.636 total time= 6.6s\n", - "[CV 1/3] END max_depth=20, max_features=sqrt, max_samples=10000, min_samples_leaf=8, min_samples_split=9, n_estimators=30;, score=0.512 total time= 3.0s\n", - "[CV 2/3] END max_depth=20, max_features=sqrt, max_samples=10000, min_samples_leaf=8, min_samples_split=9, n_estimators=30;, score=0.703 total time= 2.7s\n", - "[CV 3/3] END max_depth=20, max_features=sqrt, max_samples=10000, min_samples_leaf=8, min_samples_split=9, n_estimators=30;, score=0.636 total time= 2.7s\n", - "[CV 1/3] END max_depth=None, max_features=0.5, max_samples=10000, min_samples_leaf=9, min_samples_split=3, n_estimators=100;, score=0.541 total time= 9.9s\n", - "[CV 2/3] END max_depth=None, max_features=0.5, max_samples=10000, min_samples_leaf=9, min_samples_split=3, n_estimators=100;, score=0.745 total time= 11.1s\n", - "[CV 3/3] END max_depth=None, max_features=0.5, max_samples=10000, min_samples_leaf=9, min_samples_split=3, n_estimators=100;, score=0.632 total time= 10.2s\n", - "[CV 1/3] END max_depth=10, max_features=0.5, max_samples=10000, min_samples_leaf=3, min_samples_split=8, n_estimators=50;, score=0.529 total time= 6.1s\n", - "[CV 2/3] END max_depth=10, max_features=0.5, max_samples=10000, min_samples_leaf=3, min_samples_split=8, n_estimators=50;, score=0.713 total time= 5.5s\n", - "[CV 3/3] END max_depth=10, max_features=0.5, max_samples=10000, min_samples_leaf=3, min_samples_split=8, n_estimators=50;, score=0.625 total time= 5.2s\n", - "[CV 1/3] END max_depth=10, max_features=0.5, max_samples=10000, min_samples_leaf=4, min_samples_split=6, n_estimators=170;, score=0.532 total time= 13.9s\n", - "[CV 2/3] END max_depth=10, max_features=0.5, max_samples=10000, min_samples_leaf=4, min_samples_split=6, n_estimators=170;, score=0.712 total time= 14.6s\n", - "[CV 3/3] END max_depth=10, max_features=0.5, max_samples=10000, min_samples_leaf=4, min_samples_split=6, n_estimators=170;, score=0.631 total time= 14.2s\n", - "[CV 1/3] END max_depth=20, max_features=0.5, max_samples=10000, min_samples_leaf=1, min_samples_split=5, n_estimators=40;, score=0.545 total time= 6.6s\n", - "[CV 2/3] END max_depth=20, max_features=0.5, max_samples=10000, min_samples_leaf=1, min_samples_split=5, n_estimators=40;, score=0.767 total time= 6.5s\n", - "[CV 3/3] END max_depth=20, max_features=0.5, max_samples=10000, min_samples_leaf=1, min_samples_split=5, n_estimators=40;, score=0.619 total time= 6.2s\n", - "[CV 1/3] END max_depth=None, max_features=sqrt, max_samples=10000, min_samples_leaf=9, min_samples_split=5, n_estimators=120;, score=0.518 total time= 6.0s\n", - "[CV 2/3] END max_depth=None, max_features=sqrt, max_samples=10000, min_samples_leaf=9, min_samples_split=5, n_estimators=120;, score=0.703 total time= 6.4s\n", - "[CV 3/3] END max_depth=None, max_features=sqrt, max_samples=10000, min_samples_leaf=9, min_samples_split=5, n_estimators=120;, score=0.637 total time= 6.2s\n", - "[CV 1/3] END max_depth=10, max_features=0.5, max_samples=10000, min_samples_leaf=9, min_samples_split=9, n_estimators=120;, score=0.533 total time= 10.7s\n", - "[CV 2/3] END max_depth=10, max_features=0.5, max_samples=10000, min_samples_leaf=9, min_samples_split=9, n_estimators=120;, score=0.708 total time= 13.7s\n", - "[CV 3/3] END max_depth=10, max_features=0.5, max_samples=10000, min_samples_leaf=9, min_samples_split=9, n_estimators=120;, score=0.628 total time= 10.5s\n", - "[CV 1/3] END max_depth=20, max_features=1.0, max_samples=10000, min_samples_leaf=2, min_samples_split=7, n_estimators=90;, score=0.542 total time= 20.0s\n", - "[CV 2/3] END max_depth=20, max_features=1.0, max_samples=10000, min_samples_leaf=2, min_samples_split=7, n_estimators=90;, score=0.756 total time= 19.9s\n", - "[CV 3/3] END max_depth=20, max_features=1.0, max_samples=10000, min_samples_leaf=2, min_samples_split=7, n_estimators=90;, score=0.611 total time= 17.1s\n", - "[CV 1/3] END max_depth=None, max_features=sqrt, max_samples=10000, min_samples_leaf=8, min_samples_split=8, n_estimators=190;, score=0.524 total time= 9.1s\n", - "[CV 2/3] END max_depth=None, max_features=sqrt, max_samples=10000, min_samples_leaf=8, min_samples_split=8, n_estimators=190;, score=0.706 total time= 8.7s\n", - "[CV 3/3] END max_depth=None, max_features=sqrt, max_samples=10000, min_samples_leaf=8, min_samples_split=8, n_estimators=190;, score=0.637 total time= 8.6s\n", - "[CV 1/3] END max_depth=None, max_features=1.0, max_samples=10000, min_samples_leaf=5, min_samples_split=8, n_estimators=70;, score=0.539 total time= 16.0s\n", - "[CV 2/3] END max_depth=None, max_features=1.0, max_samples=10000, min_samples_leaf=5, min_samples_split=8, n_estimators=70;, score=0.754 total time= 14.8s\n", - "[CV 3/3] END max_depth=None, max_features=1.0, max_samples=10000, min_samples_leaf=5, min_samples_split=8, n_estimators=70;, score=0.615 total time= 14.2s\n", - "[CV 1/3] END max_depth=None, max_features=0.5, max_samples=10000, min_samples_leaf=1, min_samples_split=9, n_estimators=60;, score=0.548 total time= 9.3s\n", - "[CV 2/3] END max_depth=None, max_features=0.5, max_samples=10000, min_samples_leaf=1, min_samples_split=9, n_estimators=60;, score=0.766 total time= 8.6s\n", - "[CV 3/3] END max_depth=None, max_features=0.5, max_samples=10000, min_samples_leaf=1, min_samples_split=9, n_estimators=60;, score=0.623 total time= 9.0s\n", - "[CV 1/3] END max_depth=10, max_features=1.0, max_samples=10000, min_samples_leaf=9, min_samples_split=5, n_estimators=170;, score=0.535 total time= 23.8s\n", - "[CV 2/3] END max_depth=10, max_features=1.0, max_samples=10000, min_samples_leaf=9, min_samples_split=5, n_estimators=170;, score=0.715 total time= 25.5s\n", - "[CV 3/3] END max_depth=10, max_features=1.0, max_samples=10000, min_samples_leaf=9, min_samples_split=5, n_estimators=170;, score=0.595 total time= 27.2s\n", - "[CV 1/3] END max_depth=20, max_features=0.5, max_samples=10000, min_samples_leaf=2, min_samples_split=3, n_estimators=80;, score=0.544 total time= 12.0s\n", - "[CV 2/3] END max_depth=20, max_features=0.5, max_samples=10000, min_samples_leaf=2, min_samples_split=3, n_estimators=80;, score=0.764 total time= 11.5s\n", - "[CV 3/3] END max_depth=20, max_features=0.5, max_samples=10000, min_samples_leaf=2, min_samples_split=3, n_estimators=80;, score=0.642 total time= 10.4s\n", - "[CV 1/3] END max_depth=None, max_features=0.5, max_samples=10000, min_samples_leaf=6, min_samples_split=7, n_estimators=70;, score=0.538 total time= 8.2s\n", - "[CV 2/3] END max_depth=None, max_features=0.5, max_samples=10000, min_samples_leaf=6, min_samples_split=7, n_estimators=70;, score=0.752 total time= 8.4s\n", - "[CV 3/3] END max_depth=None, max_features=0.5, max_samples=10000, min_samples_leaf=6, min_samples_split=7, n_estimators=70;, score=0.640 total time= 8.5s\n", - "[CV 1/3] END max_depth=None, max_features=0.5, max_samples=10000, min_samples_leaf=9, min_samples_split=5, n_estimators=90;, score=0.537 total time= 9.8s\n", - "[CV 2/3] END max_depth=None, max_features=0.5, max_samples=10000, min_samples_leaf=9, min_samples_split=5, n_estimators=90;, score=0.747 total time= 9.5s\n", - "[CV 3/3] END max_depth=None, max_features=0.5, max_samples=10000, min_samples_leaf=9, min_samples_split=5, n_estimators=90;, score=0.630 total time= 9.7s\n", - "[CV 1/3] END max_depth=10, max_features=1.0, max_samples=10000, min_samples_leaf=2, min_samples_split=8, n_estimators=180;, score=0.536 total time= 28.3s\n", - "[CV 2/3] END max_depth=10, max_features=1.0, max_samples=10000, min_samples_leaf=2, min_samples_split=8, n_estimators=180;, score=0.721 total time= 28.6s\n", - "[CV 3/3] END max_depth=10, max_features=1.0, max_samples=10000, min_samples_leaf=2, min_samples_split=8, n_estimators=180;, score=0.597 total time= 28.1s\n", - "[CV 1/3] END max_depth=None, max_features=sqrt, max_samples=10000, min_samples_leaf=2, min_samples_split=3, n_estimators=150;, score=0.539 total time= 9.0s\n", - "[CV 2/3] END max_depth=None, max_features=sqrt, max_samples=10000, min_samples_leaf=2, min_samples_split=3, n_estimators=150;, score=0.733 total time= 10.7s\n", - "[CV 3/3] END max_depth=None, max_features=sqrt, max_samples=10000, min_samples_leaf=2, min_samples_split=3, n_estimators=150;, score=0.643 total time= 8.9s\n", - "CPU times: user 8min 6s, sys: 25min 58s, total: 34min 4s\n", - "Wall time: 11min 54s\n" - ] - }, - { - "data": { - "text/html": [ - "
RandomizedSearchCV(cv=3, estimator=RandomForestRegressor(), n_iter=20,\n",
-       "                   param_distributions={'max_depth': [None, 10, 20],\n",
-       "                                        'max_features': [0.5, 1.0, 'sqrt'],\n",
-       "                                        'max_samples': [10000],\n",
-       "                                        'min_samples_leaf': array([1, 2, 3, 4, 5, 6, 7, 8, 9]),\n",
-       "                                        'min_samples_split': array([2, 3, 4, 5, 6, 7, 8, 9]),\n",
-       "                                        'n_estimators': array([ 10,  20,  30,  40,  50,  60,  70,  80,  90, 100, 110, 120, 130,\n",
-       "       140, 150, 160, 170, 180, 190])},\n",
-       "                   verbose=3)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" - ], - "text/plain": [ - "RandomizedSearchCV(cv=3, estimator=RandomForestRegressor(), n_iter=20,\n", - " param_distributions={'max_depth': [None, 10, 20],\n", - " 'max_features': [0.5, 1.0, 'sqrt'],\n", - " 'max_samples': [10000],\n", - " 'min_samples_leaf': array([1, 2, 3, 4, 5, 6, 7, 8, 9]),\n", - " 'min_samples_split': array([2, 3, 4, 5, 6, 7, 8, 9]),\n", - " 'n_estimators': array([ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130,\n", - " 140, 150, 160, 170, 180, 190])},\n", - " verbose=3)" - ] - }, - "execution_count": 97, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "\n", - "from sklearn.model_selection import RandomizedSearchCV\n", - "\n", - "# 1. Define a dictionary with different values for RandomForestRegressor hyperparameters\n", - "# See documatation for potential different values - https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html \n", - "rf_grid = {\"n_estimators\": np.arange(10, 200, 10),\n", - " \"max_depth\": [None, 10, 20],\n", - " \"min_samples_split\": np.arange(2, 10, 1), # min_samples_split must be an int in the range [2, inf) or a float in the range (0.0, 1.0]\n", - " \"min_samples_leaf\": np.arange(1, 10, 1),\n", - " \"max_features\": [0.5, 1.0, \"sqrt\"], # Note: \"max_features='auto'\" is equivalent to \"max_features=1.0\", as of Scikit-Learn version 1.1\n", - " \"max_samples\": [10000]}\n", - "\n", - "# 2. Setup instance of RandomizedSearchCV to explore different parameters \n", - "rs_model = RandomizedSearchCV(estimator=RandomForestRegressor(), # can pass new model instance directly, all settings will be taken from the rf_grid\n", - " param_distributions=rf_grid,\n", - " n_iter=20,\n", - " # scoring=\"neg_root_mean_squared_log_error\", # want to optimize for RMSLE, though sometimes optimizing for the default metric (R^2) can lead to just as good results all round\n", - " cv=3,\n", - " verbose=3) # control how much output gets produced, higher number = more output\n", - "\n", - "# 3. Fit the model using a series of different hyperparameter values\n", - "rs_model.fit(X=X_train_preprocessed, \n", - " y=y_train)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Phew! That's quite a bit of testing!\n", - "\n", - "Good news for us is that we can check the best hyperparameters with the `best_params_` attribute." - ] - }, - { - "cell_type": "code", - "execution_count": 113, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'n_estimators': np.int64(80),\n", - " 'min_samples_split': np.int64(3),\n", - " 'min_samples_leaf': np.int64(2),\n", - " 'max_samples': 10000,\n", - " 'max_features': 0.5,\n", - " 'max_depth': 20}" - ] - }, - "execution_count": 113, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Find the best parameters from RandomizedSearchCV\n", - "rs_model.best_params_" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And we can evaluate this model with our `show_scores` function." - ] - }, - { - "cell_type": "code", - "execution_count": 114, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'Training MAE': np.float64(5804.886346446167),\n", - " 'Valid MAE': np.float64(7271.010705137403),\n", - " 'Training RMSLE': np.float64(0.2668477962708691),\n", - " 'Valid RMSLE': np.float64(0.2985683128197976),\n", - " 'Training R^2': 0.8494436266937344,\n", - " 'Valid R^2': 0.8280568050158131}" - ] - }, - "execution_count": 114, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Evaluate the RandomizedSearch model\n", - "rs_model_scores = show_scores(rs_model)\n", - "rs_model_scores" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 5.3 Training a model with the best hyperparameters\n", - "\n", - "Like all good machine learning cooking shows, I prepared a model earlier. \n", - "\n", - "I tried 100 different combinations of hyperparameters (setting `n_iter=100` in `RandomizedSearchCV`) and found the best results came from the settings below.\n", - "\n", - "* `n_estimators=90`\n", - "* `max_depth=None`\n", - "* `min_samples_leaf=1`\n", - "* `min_samples_split=5`\n", - "* `max_features=0.5`\n", - "* `n_jobs=-1`\n", - "* `max_samples=None`\n", - "\n", - "> **Note:** This search (`n_iter=100`) took ~2-hours on my MacBook Pro M1 Pro. So it's kind of a set and come back later experiment. That's one of the things you'll have to get used to as a machine learning engineer, figuring out what to do whilst your model trains. I like to go for long walks or to the gym (rule of thumb: while my model trains, I train).\n", - "\n", - "We'll instantiate a new model with these discovered hyperparameters and reset the `max_samples` back to its original value." - ] - }, - { - "cell_type": "code", - "execution_count": 115, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 4min 6s, sys: 4min 34s, total: 8min 40s\n", - "Wall time: 2min\n" - ] - }, - { - "data": { - "text/html": [ - "
RandomForestRegressor(max_features=0.5, min_samples_split=5, n_estimators=90,\n",
-       "                      n_jobs=-1)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" - ], - "text/plain": [ - "RandomForestRegressor(max_features=0.5, min_samples_split=5, n_estimators=90,\n", - " n_jobs=-1)" - ] - }, - "execution_count": 115, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "\n", - "# Create a model with best found hyperparameters \n", - "# Note: There may be better values out there with longer searches but these are \n", - "# the best I found with a ~2 hour search. A good challenge would be to see if you \n", - "# can find better values.\n", - "ideal_model = RandomForestRegressor(n_estimators=90,\n", - " max_depth=None,\n", - " min_samples_leaf=1,\n", - " min_samples_split=5,\n", - " max_features=0.5,\n", - " n_jobs=-1,\n", - " max_samples=None)\n", - "\n", - "# Fit a model to the preprocessed data\n", - "ideal_model.fit(X=X_train_preprocessed, \n", - " y=y_train)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And of course, we can evaluate our `ideal_model` with our `show_scores` function." - ] - }, - { - "cell_type": "code", - "execution_count": 116, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 28.8 s, sys: 37.4 s, total: 1min 6s\n", - "Wall time: 14.5 s\n" - ] - }, - { - "data": { - "text/plain": [ - "{'Training MAE': np.float64(1955.980118634043),\n", - " 'Valid MAE': np.float64(5979.47564414195),\n", - " 'Training RMSLE': np.float64(0.10224456852444506),\n", - " 'Valid RMSLE': np.float64(0.24733387014318542),\n", - " 'Training R^2': 0.9809704227866279,\n", - " 'Valid R^2': 0.8810497144604977}" - ] - }, - "execution_count": 116, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "\n", - "# Evaluate ideal model\n", - "ideal_model_scores = show_scores(model=ideal_model)\n", - "ideal_model_scores" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Woohoo!\n", - "\n", - "With these new hyperparameters as well as using all the samples, we can see an improvement to our models performance.\n", - "\n", - "One thing to keep in mind is that a larger model isn't always the best for a given problem even if it performs better.\n", - "\n", - "For example, you may require a model that performs inference (makes predictions) very fast with a slight tradeoff to performance.\n", - "\n", - "One way to a faster model is by altering some of the hyperparameters to create a smaller overall model. \n", - "\n", - "Particularly by lowering `n_estimators` since each increase in `n_estimators` is basically building another small model.\n", - "\n", - "Let's half our `n_estimators` value and see how it goes." - ] - }, - { - "cell_type": "code", - "execution_count": 117, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 2min, sys: 1min 58s, total: 3min 58s\n", - "Wall time: 44.9 s\n" - ] - }, - { - "data": { - "text/html": [ - "
RandomForestRegressor(max_features=0.5, min_samples_split=5, n_estimators=45,\n",
-       "                      n_jobs=-1)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" - ], - "text/plain": [ - "RandomForestRegressor(max_features=0.5, min_samples_split=5, n_estimators=45,\n", - " n_jobs=-1)" - ] - }, - "execution_count": 117, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "\n", - "# Halve the number of estimators\n", - "fast_model = RandomForestRegressor(n_estimators=45,\n", - " max_depth=None,\n", - " min_samples_leaf=1,\n", - " min_samples_split=5,\n", - " max_features=0.5,\n", - " n_jobs=-1,\n", - " max_samples=None)\n", - "\n", - "# Fit the faster model to the data\n", - "fast_model.fit(X=X_train_preprocessed, \n", - " y=y_train)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Nice! The faster model fits to the training data in about half the time of the full model.\n", - "\n", - "Now how does it go on performance?\n" - ] - }, - { - "cell_type": "code", - "execution_count": 118, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 14.6 s, sys: 23.7 s, total: 38.3 s\n", - "Wall time: 9.59 s\n" - ] - }, - { - "data": { - "text/plain": [ - "{'Training MAE': np.float64(1989.0544948757317),\n", - " 'Valid MAE': np.float64(6029.137329100962),\n", - " 'Training RMSLE': np.float64(0.10373049008046713),\n", - " 'Valid RMSLE': np.float64(0.24897544966690316),\n", - " 'Training R^2': 0.9802744452357592,\n", - " 'Valid R^2': 0.8788749110488039}" - ] - }, - "execution_count": 118, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "\n", - "# Get results from the fast model\n", - "fast_model_scores = show_scores(model=fast_model)\n", - "fast_model_scores" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Woah! Looks like our faster model evaluates (performs inference/makes predictions) in about half the time too.\n", - "\n", - "And only for a small tradeoff in validation RMSLE performance." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 5.4 Comparing our model's scores\n", - "\n", - "We've built four models so far with varying amounts of data and hyperparameters.\n", - "\n", - "Let's compile the results into a DataFrame and then make a plot to compare them." - ] - }, - { - "cell_type": "code", - "execution_count": 119, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - "
Training MAEValid MAETraining RMSLEValid RMSLETraining R^2Valid R^2model_name
15804.8863467271.0107050.2668480.2985680.8494440.828057random_search_model
05605.3442067176.1651150.2603010.2935840.8581120.828550default_model
31989.0544956029.1373290.1037300.2489750.9802740.878875fast_model
21955.9801195979.4756440.1022450.2473340.9809700.881050ideal_model
\n", - "
" - ], - "text/plain": [ - " Training MAE Valid MAE Training RMSLE Valid RMSLE Training R^2 \\\n", - "1 5804.886346 7271.010705 0.266848 0.298568 0.849444 \n", - "0 5605.344206 7176.165115 0.260301 0.293584 0.858112 \n", - "3 1989.054495 6029.137329 0.103730 0.248975 0.980274 \n", - "2 1955.980119 5979.475644 0.102245 0.247334 0.980970 \n", - "\n", - " Valid R^2 model_name \n", - "1 0.828057 random_search_model \n", - "0 0.828550 default_model \n", - "3 0.878875 fast_model \n", - "2 0.881050 ideal_model " - ] - }, - "execution_count": 119, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Add names of models to dictionaries\n", - "base_model_scores[\"model_name\"] = \"default_model\"\n", - "rs_model_scores[\"model_name\"] = \"random_search_model\"\n", - "ideal_model_scores[\"model_name\"] = \"ideal_model\" \n", - "fast_model_scores[\"model_name\"] = \"fast_model\" \n", - "\n", - "# Turn all model score dictionaries into a list\n", - "all_model_scores = [base_model_scores, \n", - " rs_model_scores, \n", - " ideal_model_scores,\n", - " fast_model_scores]\n", - "\n", - "# Create DataFrame and sort model scores by validation RMSLE\n", - "model_comparison_df = pd.DataFrame(all_model_scores).sort_values(by=\"Valid RMSLE\", ascending=False)\n", - "model_comparison_df.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we've got our model result data in a DataFrame, let's turn it into a bar plot comparing the validation RMSLE of each model." - ] - }, - { - "cell_type": "code", - "execution_count": 120, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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PfTQQyooKND06dMVFBSkmjVr6oUXXrDZLj09XX379lXlypXl5+enO++8U5mZmTYx06ZNU2BgoHx9fTVixAidOXOmyPNf7LMFzunvwwKPHj2qPn36yNvbW/Xq1dOiRYuKxGdlZem+++5TjRo15OfnpxtuuEE//fSTdX1qaqr69u2rwMBAVa5cWR06dNDq1asdzs9iseitt95S79695ePjo/DwcKWkpGjfvn3q3r27KlWqpM6dO9v87knSm2++qfr168vDw0ONGzfWBx98YLN+79696tatm7y8vNS0aVOtWrWqyHMfPHhQd955p6pUqaKqVauqb9++2r9/v8P7gmIYqJAiIyONypUrG+PGjTN2795t7N6923j11VeNb775xkhLSzOSkpKMxo0bGw8++KB1m/nz5xvu7u5GVFSUsWnTJmPz5s1GeHi4cffdd1tjXnrpJSMgIMBYunSpsXPnTmPEiBGGr6+v0bdvX2vMmDFjjJCQEOPLL780duzYYQwZMsQICAgwfv/9d8MwDGPNmjWGJOPaa681vv/+e2PLli1GgwYNjMjISKNHjx7Gli1bjO+++86oVq2aMW3atIvu6+HDhw03Nzdj5syZRlpamrF9+3Zjzpw5xsmTJw3DMIz//Oc/RnBwsLF06VLj//7v/4ylS5caVatWNRYsWGDtY+rUqca6deuMtLQ0Y/ny5UZgYKDx0ksvWdfHxcUZlSpVMmJiYowtW7YYP/30k1FQUGBce+21RrNmzYyvv/7aSE1NNf773/8aX375ZZlfz9IMGTLE8PX1NR5++GFj9+7dxnvvvWdIMqKjo40XXnjB+PXXX42pU6ca7u7uxsGDBw3DMIycnBwjODjYuO2224yff/7ZSEpKMurVq2cMGTLErv/D559/3mjSpImRmJhopKamGvPnzzc8PT2N5ORkm//DP//8s0z7ciV58MEHjTp16hirV682tm/fbvTu3dvw9fU1Hn30UcMwDOO+++4zOnfubHz33XfGvn37jJdfftnw9PQ0fv31VyMvL8/Ys2ePIclYunSpceTIESMvL8/47bffjJdfftnYunWrkZqaasyePdtwdXU1NmzYYH3eunXrGq+++qpNLq1atTLi4uKsy5KMzz77zDAMw9i4caMhyVi9erVx5MgR6+9faTjmYI+srCzjueeeM2rXrm0cOXLEOHr0qPHpp58aS5cuNfbu3Wts3brV6NOnj9GiRQujoKDAMAzDePnll43Q0FDju+++M/bv32+sXbvW+PDDDw3DMIyjR48akoz58+db+7uYuLg4o3Llysbtt99u7Nixw1i+fLnh4eFhREdHG4888oixe/duY968eYYk44cffjAMwzAKCgqM1q1bG127djV+/PFH44cffjDatWtnREZGWvtdsmSJ4enpabz77rvG7t27jYkTJxq+vr5Gq1atrDEX+2xJS0szJBlbt2415wXHvyYyMtL6nt6zZ0+jVatWRkpKivHjjz8anTt3Nry9vW3ej6Oioow+ffoYmzZtMn799Vfj8ccfN6pVq2Z93922bZsxd+5c4+effzZ+/fVXY9KkSYaXl5dx4MABax/FvceXRJJRq1YtY8mSJcaePXuMfv36GWFhYcYNN9xgJCYmGjt37jSuvfZaIyYmxrrNsmXLDHd3d2POnDnGnj17jBkzZhiurq7GN998YxjG+d+L5s2bGzfeeKOxbds249tvvzXatGlj87mSn59vhIeHG8OHDze2b99u7Ny507j77ruNxo0bG3l5eYZhnP8c+ft7O+xHcVVBRUZGGm3atCk15pNPPjGqVatmXZ4/f74hydi3b5+1bc6cOUZgYKB1OTg42Jg+fbp1+ezZs0bt2rWtv0g5OTmGu7u7sWjRImtMfn6+ERISYt3uwpek1atXW2Pi4+MNSUZqaqq17f777zeio6Mvuq+bN282JBn79+8vdn39+vWtH94XTJ061YiIiCixz5dfftlo166ddTkuLs5wd3e3+bBfuXKl4eLiYuzZs6fYPsryepZmyJAhRt26da1fSgzDMBo3bmxcd9111uVz584ZlSpVMj766CPDMAzj7bffNgICAoycnBxrzIoVKwwXFxcjIyPDMIyL/x+eOXPG8PHxMdavX2+Tz4gRI4yBAwcahnH1ftE9efKk4eHhYXz88cfWtt9//93w9vY2Hn30UePAgQOGq6urcejQIZvtbrzxRmPChAmGYRjGn3/+aUgy1qxZU+pz9erVy3j88cety/YWV458seOYg71effVVo27duiWuP3bsmCHJ+Pnnnw3DMIxHHnnEuOGGG4zCwsJi4/9+DJdFXFyc4ePjY2RnZ1vboqOjjbCwsCLHcXx8vGEYhvH1118brq6uRnp6unX9jh07DEnGxo0bDcMwjIiICOOhhx6yea5O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05AhQ/Tss8/q2LFjeuSRR3Tvvfdahw1c7P/Q19dXTzzxhB577DEVFhaqa9euOnHihNatWyc/Pz8NGTKkXPatIqhcubJGjBihcePGqVq1aqpZs6YmTpxoHX7UqFEjDRo0SIMHD9aMGTPUpk0bHTt2TElJSWrZsqV69epVbL8NGzbUp59+qvXr1ysgIEAzZ85UZmamzR8kbrjhBi1YsEB9+vRRlSpVNHny5FL/Ql6zZk15e3srMTFRtWvXlpeX12X58OOYwwUBAQGqVq2a3n77bQUHBys9PV1PPfWUTczMmTMVHBysNm3ayMXFRZ988omCgoKsf+EPCwtTUlKSunTpIk9PTwUEBJieZ1RUlFq0aKFBgwYpISFB586d00MPPaTIyEi1b99e0vljdujQoWrfvr26dOmiRYsWaceOHTZD1y/22QLnd2H46v33368333xTbm5uGjt2rM3IlaioKEVERKhfv36aPn269Y/XK1as0K233mr9o+2yZcvUp08fWSwWPfPMM6aeUSqLcePG6c4771SbNm0UFRWl//73v1q2bJl11sKoqCg1atRIQ4YM0csvv6zs7GxNnDjRpo9Bgwbp5ZdfVt++ffXcc8+pdu3aOnDggJYtW6bx48erdu3a/+o+Xak4c+UkWrVqpZkzZ+qll15S8+bNtWjRIuv0t/Z4/PHHde+992rIkCGKiIiQr6+vbr31VpuYadOmqX///rr33nvVtm1b7du3TytXrrwsH5LS+b+Cfvfdd7r55pvVqFEjTZo0STNmzFDPnj0lSffdd5/effddzZ8/Xy1atFBkZKQWLFhg/eviLbfcoscee0yjR49W69attX79ej3zzDNleu6lS5eqQ4cOGjhwoJo2barx48df9r+6lsbHx0crV67UH3/8oQ4dOuj222/XjTfeqNdff90aU5b/w6lTp+qZZ55RfHy8wsPDFRMToxUrVvAXWZ0fwnfdddepT58+ioqKUteuXW3G48+fP1+DBw/W448/rsaNG6tfv37atGmT6tSpU2KfkyZNUtu2bRUdHa3u3bsrKCioyE1UJ0yYoMjISPXu3Vu9evVSv379bK7n+yc3NzfNnj1bb731lkJCQtS3b99L3vficMzhAhcXFy1evFibN29W8+bN9dhjj+nll1+2ifH19dX06dPVvn17dejQQfv379eXX35p/QPFjBkztGrVKoWGhl626+0sFou++OILBQQEqFu3boqKitI111yjJUuWWGMGDBigZ555RuPHj1e7du104MABPfjggzb9XOyzBVeG+fPnKyQkRJGRkbrttts0atQo1axZ07reYrHoyy+/VLdu3TRs2DA1atRId911lw4cOGD9A9PMmTMVEBCgzp07q0+fPoqOjlbbtm3/1f3o16+fZs2apVdeeUXNmjXTW2+9pfnz51tv0+Hi4qLPPvtMp0+fVseOHXXfffcVuYWBj4+PvvvuO9WpU0e33XabwsPDrbcp+Od16nCcxbhcF+QAAAAAwFWEM1cAAAAAYAKKK1x26enpqly5comPS5nKtDyVtk9r164t7/RwBeKYg7Np1qxZicdscTOWAc5u0aJFJR7zzZo1K+/08C9gWCAuu3PnzpU6q05YWJjc3JxvbpV9+/aVuK5WrVplmuodsAfHHJzNgQMHSrzlQGBgYJH77QDO7uTJk8rMzCx2nbu7u+rWrfsvZ4R/G8UVAAAAAJiAYYEAAAAAYAKKKwAAAAAwAcUVAAAAAJiA4goAADskJyfLYrEoKyurzNuEhYUpISHhsuUEAKgYKK4AAFeUoUOHymKx6IEHHiiy7uGHH5bFYtHQoUP//cQAAFc8iisAwBUnNDRUixcv1unTp61tZ86c0Ycffqg6deqUY2YAgCsZxRUA4IrTtm1bhYaGatmyZda2ZcuWqU6dOmrTpo21LS8vT2PGjFHNmjXl5eWlrl27atOmTTZ9ffnll2rUqJG8vb11/fXXF3vfvu+//17XXXedvL29FRoaqjFjxujUqVOXbf8AABUTxRUA4Io0fPhwzZ8/37o8b948DRs2zCZm/PjxWrp0qd5//31t2bJFDRo0UHR0tP744w9J0sGDB3XbbbepT58+2rZtm+677z499dRTNn2kpqYqJiZG/fv31/bt27VkyRJ9//33Gj169OXfSQBAhUJxBQC4It1zzz36/vvvdeDAAR04cEDr1q3TPffcY11/6tQpvfnmm3r55ZfVs2dPNW3aVO+88468vb313nvvSZLefPNN1a9fXzNmzFDjxo01aNCgItdrxcfHa9CgQRo7dqwaNmyozp07a/bs2Vq4cKHOnDnzb+4yAKCcuZV3AgAAXA41atRQr169tGDBAhmGoV69eql69erW9ampqTp79qy6dOlibXN3d1fHjh21a9cuSdKuXbvUqVMnm34jIiJsln/66Sdt375dixYtsrYZhqHCwkKlpaUpPDz8cuweAKACorgCAFyxhg8fbh2eN2fOnMvyHDk5Obr//vs1ZsyYIuuYPAMAri4UVwCAK1ZMTIzy8/NlsVgUHR1ts65+/fry8PDQunXrVLduXUnS2bNntWnTJo0dO1aSFB4eruXLl9ts98MPP9gst23bVjt37lSDBg0u344AAJwC11wBAK5Yrq6u2rVrl3bu3ClXV1ebdZUqVdKDDz6ocePGKTExUTt37tTIkSOVm5urESNGSJIeeOAB7d27V+PGjdOePXv04YcfasGCBTb9PPnkk1q/fr1Gjx6tbdu2ae/evfriiy+Y0AIArkIUVwCAK5qfn5/8/PyKXTdt2jT1799f9957r9q2bat9+/Zp5cqVCggIkHR+WN/SpUv1+eefq1WrVpo7d65efPFFmz5atmypb7/9Vr/++quuu+46tWnTRpMnT1ZISMhl3zcAQMViMQzDKO8kAAAAAMDZceYKAAAAAExAcQUAAAAAJqC4AgAAAAATUFwBAAAAgAkorgAAAADABBRXAAAAAGACiisAAAAAMAHFFQAAAACYgOIKAAAAAExAcQUAAAAAJqC4AgAAAAATUFwBAAAAgAn+Hxl0xRuqWUBvAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Get mean RSMLE score of all models\n", - "mean_rsmle_score = model_comparison_df[\"Valid RMSLE\"].mean()\n", - "\n", - "# Plot validation RMSLE against each other \n", - "plt.figure(figsize=(10, 5))\n", - "plt.bar(x=model_comparison_df[\"model_name\"],\n", - " height=model_comparison_df[\"Valid RMSLE\"].values)\n", - "plt.xlabel(\"Model\")\n", - "plt.ylabel(\"Validation RMSLE (lower is better)\")\n", - "plt.xticks(rotation=0, fontsize=10);\n", - "plt.axhline(y=mean_rsmle_score, \n", - " color=\"red\", \n", - " linestyle=\"--\", \n", - " label=f\"Mean RMSLE: {mean_rsmle_score:.4f}\")\n", - "plt.legend();" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "By the looks of the plot, our `ideal_model` is indeed the ideal model, slightly edging out `fast_model` in terms of validation RMSLE." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 6. Saving our best model to file\n", - "\n", - "Since we've confirmed our best model as our `ideal_model` object, we can save it to file so we can load it in later and use it without having to retrain it.\n", - "\n", - "> **Note:** For more on model saving options with Scikit-Learn, see the [documentation on model persistence](https://scikit-learn.org/stable/model_persistence.html).\n", - "\n", - "To save our model we can use the [`joblib.dump`](https://joblib.readthedocs.io/en/stable/generated/joblib.dump.html) method." - ] - }, - { - "cell_type": "code", - "execution_count": 121, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['randomforest_regressor_best_RMSLE.pkl']" - ] - }, - "execution_count": 121, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import joblib\n", - "\n", - "bulldozer_price_prediction_model_name = \"randomforest_regressor_best_RMSLE.pkl\"\n", - "\n", - "# Save model to file\n", - "joblib.dump(value=ideal_model, \n", - " filename=bulldozer_price_prediction_model_name)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And to load our model we can use the [`joblib.load`](https://joblib.readthedocs.io/en/stable/generated/joblib.load.html) method." - ] - }, - { - "cell_type": "code", - "execution_count": 122, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
RandomForestRegressor(max_features=0.5, min_samples_split=5, n_estimators=90,\n",
-       "                      n_jobs=-1)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" - ], - "text/plain": [ - "RandomForestRegressor(max_features=0.5, min_samples_split=5, n_estimators=90,\n", - " n_jobs=-1)" - ] - }, - "execution_count": 122, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Load the best model\n", - "best_model = joblib.load(filename=bulldozer_price_prediction_model_name)\n", - "best_model" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can make sure our model saving and loading worked by evaluating our `best_model` with `show_scores`." - ] - }, - { - "cell_type": "code", - "execution_count": 123, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'Training MAE': np.float64(1955.9801186340424),\n", - " 'Valid MAE': np.float64(5979.47564414195),\n", - " 'Training RMSLE': np.float64(0.10224456852444506),\n", - " 'Valid RMSLE': np.float64(0.24733387014318542),\n", - " 'Training R^2': 0.9809704227866279,\n", - " 'Valid R^2': 0.8810497144604977}" - ] - }, - "execution_count": 123, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Confirm that the model works\n", - "best_model_scores = show_scores(model=best_model)\n", - "best_model_scores" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And to confirm our `ideal_model` and `best_model` results are very close (if not the exact same), we can compare them with:\n", - "* The equality operator `==`.\n", - "* [`np.iclose`](https://numpy.org/doc/stable/reference/generated/numpy.isclose.html) and setting the absolute tolerance (`atol`) to `1e-4`." - ] - }, - { - "cell_type": "code", - "execution_count": 124, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "np.True_" - ] - }, - "execution_count": 124, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# See if loaded model and pre-saved model results are the same\n", - "# Note: these values may be very slightly different depending on how precise your computer stores values.\n", - "best_model_scores[\"Valid RMSLE\"] == ideal_model_scores[\"Valid RMSLE\"]" - ] - }, - { - "cell_type": "code", - "execution_count": 125, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Model results are close!\n" - ] - } - ], - "source": [ - "# Is the loaded model as good as the non-loaded model?\n", - "if np.isclose(a=best_model_scores[\"Valid RMSLE\"], \n", - " b=ideal_model_scores[\"Valid RMSLE\"],\n", - " atol=1e-4): # Make sure values are within 0.0001 of each other\n", - " print(f\"[INFO] Model results are close!\")\n", - "else:\n", - " print(f\"[INFO] Model results aren't close, did something go wrong?\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "> **Note:** When saving and loading a model, it is often the case to have very slightly different values at the extremes. For example, the pre-saved model may have an RMSLE of `0.24654150224930685` where as the loaded model may have an RMSLE of `0.24654150224930684` where in this case the values are off by `0.00000000000000001` (a very small number). This is due to the [precision of computing](https://en.wikipedia.org/wiki/Precision_(computer_science)) and the way computers store values, where numbers are exact but can be represented up to a certain amount of precision. This is why we generally compare results with many decimals using `np.isclose` rather than the `==` operator." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 7. Making predictions on test data\n", - "\n", - "Now we've got a trained model saved and loaded, it's time to make predictions on the test data.\n", - "\n", - "Our model is trained on data prior to 2011, however, the test data is from May 1 2012 to November 2012.\n", - "\n", - "So what we're doing is trying to use the patterns our model has learned from the training data to predict the sale price of a bulldozer with characteristics it's never seen before but are assumed to be similar to that of those in the training data.\n", - "\n", - "Let's load in the test data from `Test.csv`, we'll make sure to parse the dates of the `saledate` column." - ] - }, - { - "cell_type": "code", - "execution_count": 126, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - " \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", - "
SalesIDMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandsaledatefiModelDesc...Undercarriage_Pad_WidthStick_LengthThumbPattern_ChangerGrouser_TypeBackhoe_MountingBlade_TypeTravel_ControlsDifferential_TypeSteering_Controls
0122782910063093168121319993688.0Low2012-05-03580G...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
11227844102281772711213100028555.0High2012-05-10936...NaNNaNNaNNaNNaNNaNNaNNaNStandardConventional
21227847103156022805121320046038.0Medium2012-05-10EC210BLC...None or Unspecified9' 6\"ManualNone or UnspecifiedDoubleNaNNaNNaNNaNNaN
31227848562041269121320068940.0High2012-05-10330CL...None or UnspecifiedNone or UnspecifiedManualYesTripleNaNNaNNaNNaNNaN
41227863105388722312121320052286.0Low2012-05-10650K...NaNNaNNaNNaNNaNNone or UnspecifiedPATNone or UnspecifiedNaNNaN
\n", - "

5 rows × 52 columns

\n", - "
" - ], - "text/plain": [ - " SalesID MachineID ModelID datasource auctioneerID YearMade \\\n", - "0 1227829 1006309 3168 121 3 1999 \n", - "1 1227844 1022817 7271 121 3 1000 \n", - "2 1227847 1031560 22805 121 3 2004 \n", - "3 1227848 56204 1269 121 3 2006 \n", - "4 1227863 1053887 22312 121 3 2005 \n", - "\n", - " MachineHoursCurrentMeter UsageBand saledate fiModelDesc ... \\\n", - "0 3688.0 Low 2012-05-03 580G ... \n", - "1 28555.0 High 2012-05-10 936 ... \n", - "2 6038.0 Medium 2012-05-10 EC210BLC ... \n", - "3 8940.0 High 2012-05-10 330CL ... \n", - "4 2286.0 Low 2012-05-10 650K ... \n", - "\n", - " Undercarriage_Pad_Width Stick_Length Thumb Pattern_Changer \\\n", - "0 NaN NaN NaN NaN \n", - "1 NaN NaN NaN NaN \n", - "2 None or Unspecified 9' 6\" Manual None or Unspecified \n", - "3 None or Unspecified None or Unspecified Manual Yes \n", - "4 NaN NaN NaN NaN \n", - "\n", - " Grouser_Type Backhoe_Mounting Blade_Type Travel_Controls \\\n", - "0 NaN NaN NaN NaN \n", - "1 NaN NaN NaN NaN \n", - "2 Double NaN NaN NaN \n", - "3 Triple NaN NaN NaN \n", - "4 NaN None or Unspecified PAT None or Unspecified \n", - "\n", - " Differential_Type Steering_Controls \n", - "0 NaN NaN \n", - "1 Standard Conventional \n", - "2 NaN NaN \n", - "3 NaN NaN \n", - "4 NaN NaN \n", - "\n", - "[5 rows x 52 columns]" - ] - }, - "execution_count": 126, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Load the test data\n", - "test_df = pd.read_csv(filepath_or_buffer=\"../data/bluebook-for-bulldozers/Test.csv\",\n", - " parse_dates=[\"saledate\"])\n", - "test_df.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You might notice that the `test_df` is missing the `SalePrice` column.\n", - "\n", - "That's because that's the variable we're trying to predict based on all of the other variables.\n", - "\n", - "We can make predictions with our `best_model` using the [`predict` method](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html#sklearn.ensemble.RandomForestRegressor.predict)." - ] - }, - { - "cell_type": "code", - "execution_count": 127, - "metadata": {}, - "outputs": [ - { - "ename": "ValueError", - "evalue": "The feature names should match those that were passed during fit.\nFeature names unseen at fit time:\n- saledate\nFeature names seen at fit time, yet now missing:\n- saleDay\n- saleDayofweek\n- saleDayofyear\n- saleMonth\n- saleYear\n", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[127], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Let's see how the model goes predicting on the test data\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m test_preds \u001b[38;5;241m=\u001b[39m \u001b[43mbest_model\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpredict\u001b[49m\u001b[43m(\u001b[49m\u001b[43mX\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtest_df\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/ensemble/_forest.py:1063\u001b[0m, in \u001b[0;36mForestRegressor.predict\u001b[0;34m(self, X)\u001b[0m\n\u001b[1;32m 1061\u001b[0m check_is_fitted(\u001b[38;5;28mself\u001b[39m)\n\u001b[1;32m 1062\u001b[0m \u001b[38;5;66;03m# Check data\u001b[39;00m\n\u001b[0;32m-> 1063\u001b[0m X \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_validate_X_predict\u001b[49m\u001b[43m(\u001b[49m\u001b[43mX\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1065\u001b[0m \u001b[38;5;66;03m# Assign chunk of trees to jobs\u001b[39;00m\n\u001b[1;32m 1066\u001b[0m n_jobs, _, _ \u001b[38;5;241m=\u001b[39m _partition_estimators(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mn_estimators, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mn_jobs)\n", - "File \u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/ensemble/_forest.py:641\u001b[0m, in \u001b[0;36mBaseForest._validate_X_predict\u001b[0;34m(self, X)\u001b[0m\n\u001b[1;32m 638\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 639\u001b[0m force_all_finite \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[0;32m--> 641\u001b[0m X \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_validate_data\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 642\u001b[0m \u001b[43m \u001b[49m\u001b[43mX\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 643\u001b[0m \u001b[43m \u001b[49m\u001b[43mdtype\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mDTYPE\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 644\u001b[0m \u001b[43m \u001b[49m\u001b[43maccept_sparse\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mcsr\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 645\u001b[0m \u001b[43m \u001b[49m\u001b[43mreset\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 646\u001b[0m \u001b[43m \u001b[49m\u001b[43mforce_all_finite\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mforce_all_finite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 647\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 648\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m issparse(X) \u001b[38;5;129;01mand\u001b[39;00m (X\u001b[38;5;241m.\u001b[39mindices\u001b[38;5;241m.\u001b[39mdtype \u001b[38;5;241m!=\u001b[39m np\u001b[38;5;241m.\u001b[39mintc \u001b[38;5;129;01mor\u001b[39;00m X\u001b[38;5;241m.\u001b[39mindptr\u001b[38;5;241m.\u001b[39mdtype \u001b[38;5;241m!=\u001b[39m np\u001b[38;5;241m.\u001b[39mintc):\n\u001b[1;32m 649\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNo support for np.int64 index based sparse matrices\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", - "File \u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/base.py:608\u001b[0m, in \u001b[0;36mBaseEstimator._validate_data\u001b[0;34m(self, X, y, reset, validate_separately, cast_to_ndarray, **check_params)\u001b[0m\n\u001b[1;32m 537\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_validate_data\u001b[39m(\n\u001b[1;32m 538\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 539\u001b[0m X\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mno_validation\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 544\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mcheck_params,\n\u001b[1;32m 545\u001b[0m ):\n\u001b[1;32m 546\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Validate input data and set or check the `n_features_in_` attribute.\u001b[39;00m\n\u001b[1;32m 547\u001b[0m \n\u001b[1;32m 548\u001b[0m \u001b[38;5;124;03m Parameters\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 606\u001b[0m \u001b[38;5;124;03m validated.\u001b[39;00m\n\u001b[1;32m 607\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 608\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_check_feature_names\u001b[49m\u001b[43m(\u001b[49m\u001b[43mX\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mreset\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mreset\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 610\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m y \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_get_tags()[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrequires_y\u001b[39m\u001b[38;5;124m\"\u001b[39m]:\n\u001b[1;32m 611\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 612\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThis \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__class__\u001b[39m\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m estimator \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 613\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrequires y to be passed, but the target y is None.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 614\u001b[0m )\n", - "File \u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/base.py:535\u001b[0m, in \u001b[0;36mBaseEstimator._check_feature_names\u001b[0;34m(self, X, reset)\u001b[0m\n\u001b[1;32m 530\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m missing_names \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m unexpected_names:\n\u001b[1;32m 531\u001b[0m message \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m (\n\u001b[1;32m 532\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mFeature names must be in the same order as they were in fit.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 533\u001b[0m )\n\u001b[0;32m--> 535\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(message)\n", - "\u001b[0;31mValueError\u001b[0m: The feature names should match those that were passed during fit.\nFeature names unseen at fit time:\n- saledate\nFeature names seen at fit time, yet now missing:\n- saleDay\n- saleDayofweek\n- saleDayofyear\n- saleMonth\n- saleYear\n" - ] - } - ], - "source": [ - "# Let's see how the model goes predicting on the test data\n", - "test_preds = best_model.predict(X=test_df)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Oh no!\n", - "\n", - "We get an error:\n", - "\n", - "> ValueError: The feature names should match those that were passed during fit.\n", - "> Feature names unseen at fit time:\n", - "> - saledate\n", - "> Feature names seen at fit time, yet now missing:\n", - "> - saleDay\n", - "> - saleDayofweek\n", - "> - saleDayofyear\n", - "> - saleMonth\n", - "> - saleYear\n", - "\n", - "Ahhh... the test data isn't in the same format of our other data, so we have to fix it. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 7.1 Preprocessing the test data (to be in the same format as the training data)\n", - "\n", - "Our model has been trained on data preprocessed in a certain way. \n", - "\n", - "This means in order to make predictions on the test data, we need to take the same steps we used to preprocess the training data to preprocess the test data.\n", - "\n", - "Remember, whatever you do to preprocess the training data, you have to do to the test data.\n", - "\n", - "Let's recreate the steps we used for preprocessing the training data except this time we'll do it on the test data. \n", - "\n", - "First, we'll add the extra date features to breakdown the `saledate` column." - ] - }, - { - "cell_type": "code", - "execution_count": 128, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - " \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", - "
SalesIDMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandfiModelDescfiBaseModel...Backhoe_MountingBlade_TypeTravel_ControlsDifferential_TypeSteering_ControlssaleYearsaleMonthsaleDaysaleDayofweeksaleDayofyear
0122782910063093168121319993688.0Low580G580...NaNNaNNaNNaNNaN2012533124
11227844102281772711213100028555.0High936936...NaNNaNNaNStandardConventional20125103131
21227847103156022805121320046038.0MediumEC210BLCEC210...NaNNaNNaNNaNNaN20125103131
31227848562041269121320068940.0High330CL330...NaNNaNNaNNaNNaN20125103131
41227863105388722312121320052286.0Low650K650...None or UnspecifiedPATNone or UnspecifiedNaNNaN20125103131
\n", - "

5 rows × 56 columns

\n", - "
" - ], - "text/plain": [ - " SalesID MachineID ModelID datasource auctioneerID YearMade \\\n", - "0 1227829 1006309 3168 121 3 1999 \n", - "1 1227844 1022817 7271 121 3 1000 \n", - "2 1227847 1031560 22805 121 3 2004 \n", - "3 1227848 56204 1269 121 3 2006 \n", - "4 1227863 1053887 22312 121 3 2005 \n", - "\n", - " MachineHoursCurrentMeter UsageBand fiModelDesc fiBaseModel ... \\\n", - "0 3688.0 Low 580G 580 ... \n", - "1 28555.0 High 936 936 ... \n", - "2 6038.0 Medium EC210BLC EC210 ... \n", - "3 8940.0 High 330CL 330 ... \n", - "4 2286.0 Low 650K 650 ... \n", - "\n", - " Backhoe_Mounting Blade_Type Travel_Controls Differential_Type \\\n", - "0 NaN NaN NaN NaN \n", - "1 NaN NaN NaN Standard \n", - "2 NaN NaN NaN NaN \n", - "3 NaN NaN NaN NaN \n", - "4 None or Unspecified PAT None or Unspecified NaN \n", - "\n", - " Steering_Controls saleYear saleMonth saleDay saleDayofweek saleDayofyear \n", - "0 NaN 2012 5 3 3 124 \n", - "1 Conventional 2012 5 10 3 131 \n", - "2 NaN 2012 5 10 3 131 \n", - "3 NaN 2012 5 10 3 131 \n", - "4 NaN 2012 5 10 3 131 \n", - "\n", - "[5 rows x 56 columns]" - ] - }, - "execution_count": 128, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Make a function to add date columns\n", - "def add_datetime_features_to_df(df, date_column=\"saledate\"):\n", - " # Add datetime parameters for saledate\n", - " df[\"saleYear\"] = df[date_column].dt.year\n", - " df[\"saleMonth\"] = df[date_column].dt.month\n", - " df[\"saleDay\"] = df[date_column].dt.day\n", - " df[\"saleDayofweek\"] = df[date_column].dt.dayofweek\n", - " df[\"saleDayofyear\"] = df[date_column].dt.dayofyear\n", - "\n", - " # Drop original saledate column\n", - " df.drop(\"saledate\", axis=1, inplace=True)\n", - "\n", - " return df\n", - "\n", - "# Preprocess test_df to have same columns as train_df (add the datetime features)\n", - "test_df = add_datetime_features_to_df(df=test_df)\n", - "test_df.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Date features added!\n", - "\n", - "Now can we make predictions with our model on the test data? " - ] - }, - { - "cell_type": "code", - "execution_count": 129, - "metadata": {}, - "outputs": [ - { - "ename": "ValueError", - "evalue": "could not convert string to float: 'Low'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m/var/folders/c4/qj4gdk190td18bqvjjh0p3p00000gn/T/ipykernel_20423/2042912174.py\u001b[0m in \u001b[0;36m?\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# Try to predict with model\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mtest_preds\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mbest_model\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpredict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtest_df\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/ensemble/_forest.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, X)\u001b[0m\n\u001b[1;32m 1059\u001b[0m \u001b[0mThe\u001b[0m \u001b[0mpredicted\u001b[0m \u001b[0mvalues\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1060\u001b[0m \"\"\"\n\u001b[1;32m 1061\u001b[0m \u001b[0mcheck_is_fitted\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1062\u001b[0m \u001b[0;31m# Check data\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1063\u001b[0;31m \u001b[0mX\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_validate_X_predict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mX\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 1064\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1065\u001b[0m \u001b[0;31m# Assign chunk of trees to jobs\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1066\u001b[0m \u001b[0mn_jobs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_partition_estimators\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mn_estimators\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mn_jobs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/ensemble/_forest.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, X)\u001b[0m\n\u001b[1;32m 637\u001b[0m \u001b[0mforce_all_finite\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"allow-nan\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 638\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 639\u001b[0m \u001b[0mforce_all_finite\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 640\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 641\u001b[0;31m X = self._validate_data(\n\u001b[0m\u001b[1;32m 642\u001b[0m \u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 643\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mDTYPE\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 644\u001b[0m \u001b[0maccept_sparse\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"csr\"\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/base.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, X, y, reset, validate_separately, cast_to_ndarray, **check_params)\u001b[0m\n\u001b[1;32m 629\u001b[0m \u001b[0mout\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 630\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 631\u001b[0m \u001b[0mout\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 632\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mno_val_X\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mno_val_y\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 633\u001b[0;31m \u001b[0mout\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcheck_array\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minput_name\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"X\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mcheck_params\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 634\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mno_val_X\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mno_val_y\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 635\u001b[0m \u001b[0mout\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_check_y\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mcheck_params\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 636\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/utils/validation.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(array, accept_sparse, accept_large_sparse, dtype, order, copy, force_writeable, force_all_finite, ensure_2d, allow_nd, ensure_min_samples, ensure_min_features, estimator, input_name)\u001b[0m\n\u001b[1;32m 1009\u001b[0m )\n\u001b[1;32m 1010\u001b[0m \u001b[0marray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mxp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mastype\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1011\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1012\u001b[0m \u001b[0marray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_asarray_with_order\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0morder\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0morder\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mxp\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mxp\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1013\u001b[0;31m \u001b[0;32mexcept\u001b[0m \u001b[0mComplexWarning\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mcomplex_warning\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 1014\u001b[0m raise ValueError(\n\u001b[1;32m 1015\u001b[0m \u001b[0;34m\"Complex data not supported\\n{}\\n\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1016\u001b[0m ) from complex_warning\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/utils/_array_api.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(array, dtype, order, copy, xp, device)\u001b[0m\n\u001b[1;32m 747\u001b[0m \u001b[0;31m# Use NumPy API to support order\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 748\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mcopy\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 749\u001b[0m \u001b[0marray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnumpy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0morder\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0morder\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 750\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 751\u001b[0;31m \u001b[0marray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnumpy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0morder\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0morder\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\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 752\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 753\u001b[0m \u001b[0;31m# At this point array is a NumPy ndarray. We convert it to an array\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 754\u001b[0m \u001b[0;31m# container that is consistent with the input's namespace.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/pandas/core/generic.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, dtype, copy)\u001b[0m\n\u001b[1;32m 2149\u001b[0m def __array__(\n\u001b[1;32m 2150\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mnpt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mDTypeLike\u001b[0m \u001b[0;34m|\u001b[0m \u001b[0;32mNone\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mbool_t\u001b[0m \u001b[0;34m|\u001b[0m \u001b[0;32mNone\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2151\u001b[0m ) -> np.ndarray:\n\u001b[1;32m 2152\u001b[0m \u001b[0mvalues\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_values\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2153\u001b[0;31m \u001b[0marr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\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 2154\u001b[0m if (\n\u001b[1;32m 2155\u001b[0m \u001b[0mastype_is_view\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0marr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2156\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0musing_copy_on_write\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[0;31mValueError\u001b[0m: could not convert string to float: 'Low'" - ] - } - ], - "source": [ - "# Try to predict with model\n", - "test_preds = best_model.predict(test_df)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Another error...\n", - "\n", - "> ValueError: could not convert string to float: 'Low'\n", - "\n", - "We can fix this by running our `ordinal_encoder` (that we used to preprocess the training data) on the categorical features in our test DataFrame. " - ] - }, - { - "cell_type": "code", - "execution_count": 130, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "RangeIndex: 12457 entries, 0 to 12456\n", - "Data columns (total 56 columns):\n", - " # Column Non-Null Count Dtype \n", - "--- ------ -------------- ----- \n", - " 0 SalesID 12457 non-null int64 \n", - " 1 MachineID 12457 non-null int64 \n", - " 2 ModelID 12457 non-null int64 \n", - " 3 datasource 12457 non-null int64 \n", - " 4 auctioneerID 12457 non-null int64 \n", - " 5 YearMade 12457 non-null int64 \n", - " 6 MachineHoursCurrentMeter 2129 non-null float64\n", - " 7 UsageBand 12457 non-null float64\n", - " 8 fiModelDesc 12349 non-null float64\n", - " 9 fiBaseModel 12431 non-null float64\n", - " 10 fiSecondaryDesc 12449 non-null float64\n", - " 11 fiModelSeries 12456 non-null float64\n", - " 12 fiModelDescriptor 12452 non-null float64\n", - " 13 ProductSize 12457 non-null float64\n", - " 14 fiProductClassDesc 12457 non-null float64\n", - " 15 state 12457 non-null float64\n", - " 16 ProductGroup 12457 non-null float64\n", - " 17 ProductGroupDesc 12457 non-null float64\n", - " 18 Drive_System 12457 non-null float64\n", - " 19 Enclosure 12457 non-null float64\n", - " 20 Forks 12457 non-null float64\n", - " 21 Pad_Type 12457 non-null float64\n", - " 22 Ride_Control 12457 non-null float64\n", - " 23 Stick 12457 non-null float64\n", - " 24 Transmission 12457 non-null float64\n", - " 25 Turbocharged 12457 non-null float64\n", - " 26 Blade_Extension 12457 non-null float64\n", - " 27 Blade_Width 12457 non-null float64\n", - " 28 Enclosure_Type 12457 non-null float64\n", - " 29 Engine_Horsepower 12457 non-null float64\n", - " 30 Hydraulics 12457 non-null float64\n", - " 31 Pushblock 12457 non-null float64\n", - " 32 Ripper 12457 non-null float64\n", - " 33 Scarifier 12457 non-null float64\n", - " 34 Tip_Control 12457 non-null float64\n", - " 35 Tire_Size 12457 non-null float64\n", - " 36 Coupler 12457 non-null float64\n", - " 37 Coupler_System 12457 non-null float64\n", - " 38 Grouser_Tracks 12457 non-null float64\n", - " 39 Hydraulics_Flow 12457 non-null float64\n", - " 40 Track_Type 12457 non-null float64\n", - " 41 Undercarriage_Pad_Width 12457 non-null float64\n", - " 42 Stick_Length 12457 non-null float64\n", - " 43 Thumb 12457 non-null float64\n", - " 44 Pattern_Changer 12457 non-null float64\n", - " 45 Grouser_Type 12457 non-null float64\n", - " 46 Backhoe_Mounting 12457 non-null float64\n", - " 47 Blade_Type 12457 non-null float64\n", - " 48 Travel_Controls 12457 non-null float64\n", - " 49 Differential_Type 12457 non-null float64\n", - " 50 Steering_Controls 12457 non-null float64\n", - " 51 saleYear 12457 non-null int32 \n", - " 52 saleMonth 12457 non-null int32 \n", - " 53 saleDay 12457 non-null int32 \n", - " 54 saleDayofweek 12457 non-null int32 \n", - " 55 saleDayofyear 12457 non-null int32 \n", - "dtypes: float64(45), int32(5), int64(6)\n", - "memory usage: 5.1 MB\n" - ] - } - ], - "source": [ - "# Create a copy of the test DataFrame to keep the original intact\n", - "test_df_preprocessed = test_df.copy()\n", - "\n", - "# Transform the categorical features of the test DataFrame into numbers\n", - "test_df_preprocessed[categorical_features] = ordinal_encoder.transform(test_df_preprocessed[categorical_features].astype(str))\n", - "test_df_preprocessed.info()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Ok, date features created and categorical features turned into numbers, can we make predictions on the test data now?" - ] - }, - { - "cell_type": "code", - "execution_count": 131, - "metadata": {}, - "outputs": [], - "source": [ - "# Make predictions on the preprocessed test data\n", - "test_preds = best_model.predict(test_df_preprocessed)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Holy smokes! It worked!\n", - "\n", - "Let's check out our `test_preds`." - ] - }, - { - "cell_type": "code", - "execution_count": 132, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([14384.79497354, 31377.65862841, 48589.23540965, 95857.57194966,\n", - " 26910.53992304, 29401.41534392, 27061.53819945, 20377.23364598,\n", - " 17325.67857143, 33646.67768959])" - ] - }, - "execution_count": 132, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Check the first 10 test predictions\n", - "test_preds[:10]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Wonderful, looks like we're getting the price predictions of a given bulldozer.\n", - "\n", - "How many predictions are there?" - ] - }, - { - "cell_type": "code", - "execution_count": 133, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "((12457,), (12457, 56))" - ] - }, - "execution_count": 133, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Check number of test predictions\n", - "test_preds.shape, test_df.shape" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Perfect, looks like theres one prediction per sample in the test DataFrame.\n", - "\n", - "Now how would we submit our predictions to Kaggle?\n", - "\n", - "Well, when looking at the [Kaggle submission requirements](https://www.kaggle.com/c/bluebook-for-bulldozers/overview/evaluation), we see that if we wanted to make a submission, the data is required to be in a certain format. \n", - "\n", - "Namely, a DataFrame containing the `SalesID` and the predicted `SalePrice` of the bulldozer.\n", - "\n", - "Let's make it." - ] - }, - { - "cell_type": "code", - "execution_count": 134, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - "
SalesIDSalePrice
6517630461978522.550705
922123120413500.628307
6859631105010891.180556
6634630773128503.776455
8882644729050641.411817
\n", - "
" - ], - "text/plain": [ - " SalesID SalePrice\n", - "6517 6304619 78522.550705\n", - "922 1231204 13500.628307\n", - "6859 6311050 10891.180556\n", - "6634 6307731 28503.776455\n", - "8882 6447290 50641.411817" - ] - }, - "execution_count": 134, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Create DataFrame compatible with Kaggle submission requirements\n", - "pred_df = pd.DataFrame()\n", - "pred_df[\"SalesID\"] = test_df[\"SalesID\"]\n", - "pred_df[\"SalePrice\"] = test_preds\n", - "pred_df.sample(5)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Excellent! We've got a `SalePrice` prediction for every `SalesID` in the test DataFrame.\n", - "\n", - "Let's save this to CSV so we could upload it or share it with someone else if we had to." - ] - }, - { - "cell_type": "code", - "execution_count": 135, - "metadata": {}, - "outputs": [], - "source": [ - "# Export test dataset predictions to CSV\n", - "pred_df.to_csv(\"../data/bluebook-for-bulldozers/predictions.csv\",\n", - " index=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 8. Making a prediction on a custom sample\n", - "\n", - "We've made predictions on the test dataset which contains sale data from May to November 2012.\n", - "\n", - "But how does our model go on a more recent bulldozer sale?\n", - "\n", - "If we were to find an advertisement on a bulldozer sale, could we use our model on the information in the advertisement to predict the sale price?\n", - "\n", - "In other words, how could we use our model on a single custom sample?\n", - "\n", - "It's one thing to predict on data that has already been formatted but it's another thing to be able to predict a on a completely new and unseen sample.\n", - "\n", - "> **Note:** For predicting on a custom sample, the same rules apply as making predictions on the test dataset. The data you make predictions on should be in the same format that your model was trained on. For example, it should have all the same features and the numerical encodings should be in the same ballpark (e.g. preprocessed by the `ordinal_encoder` we fit to the training set). It's likely that samples you collect from the wild may not be as well formatted as samples in a pre-existing dataset. So it's the job of the machine learning engineer to be able to format/preprocess new samples in the same way a model was trained on.\n", - "\n", - "If we're going to make a prediction on a custom sample, it'll need to be in the same format as our other datasets.\n", - "\n", - "So let's remind ourselves of the columns/features in our test dataset." - ] - }, - { - "cell_type": "code", - "execution_count": 136, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'SalesID': 1229148,\n", - " 'MachineID': 1042578,\n", - " 'ModelID': 9579,\n", - " 'datasource': 121,\n", - " 'auctioneerID': 3,\n", - " 'YearMade': 2004,\n", - " 'MachineHoursCurrentMeter': 3290.0,\n", - " 'UsageBand': 'Medium',\n", - " 'fiModelDesc': 'S250',\n", - " 'fiBaseModel': 'S250',\n", - " 'fiSecondaryDesc': 'nan',\n", - " 'fiModelSeries': 'nan',\n", - " 'fiModelDescriptor': 'nan',\n", - " 'ProductSize': 'nan',\n", - " 'fiProductClassDesc': 'Skid Steer Loader - 2201.0 to 2701.0 Lb Operating Capacity',\n", - " 'state': 'Missouri',\n", - " 'ProductGroup': 'SSL',\n", - " 'ProductGroupDesc': 'Skid Steer Loaders',\n", - " 'Drive_System': 'nan',\n", - " 'Enclosure': 'EROPS',\n", - " 'Forks': 'None or Unspecified',\n", - " 'Pad_Type': 'nan',\n", - " 'Ride_Control': 'nan',\n", - " 'Stick': 'nan',\n", - " 'Transmission': 'nan',\n", - " 'Turbocharged': 'nan',\n", - " 'Blade_Extension': 'nan',\n", - " 'Blade_Width': 'nan',\n", - " 'Enclosure_Type': 'nan',\n", - " 'Engine_Horsepower': 'nan',\n", - " 'Hydraulics': 'Auxiliary',\n", - " 'Pushblock': 'nan',\n", - " 'Ripper': 'nan',\n", - " 'Scarifier': 'nan',\n", - " 'Tip_Control': 'nan',\n", - " 'Tire_Size': 'nan',\n", - " 'Coupler': 'Hydraulic',\n", - " 'Coupler_System': 'Yes',\n", - " 'Grouser_Tracks': 'None or Unspecified',\n", - " 'Hydraulics_Flow': 'Standard',\n", - " 'Track_Type': 'nan',\n", - " 'Undercarriage_Pad_Width': 'nan',\n", - " 'Stick_Length': 'nan',\n", - " 'Thumb': 'nan',\n", - " 'Pattern_Changer': 'nan',\n", - " 'Grouser_Type': 'nan',\n", - " 'Backhoe_Mounting': 'nan',\n", - " 'Blade_Type': 'nan',\n", - " 'Travel_Controls': 'nan',\n", - " 'Differential_Type': 'nan',\n", - " 'Steering_Controls': 'nan',\n", - " 'saleYear': 2012,\n", - " 'saleMonth': 6,\n", - " 'saleDay': 15,\n", - " 'saleDayofweek': 4,\n", - " 'saleDayofyear': 167}]" - ] - }, - "execution_count": 136, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Get example from test_df\n", - "test_df_preprocessed_sample = test_df_preprocessed.sample(n=1, random_state=42)\n", - "\n", - "# Turn back into original format\n", - "test_df_unpreprocessed_sample = test_df_preprocessed_sample.copy() \n", - "test_df_unpreprocessed_sample[categorical_features] = ordinal_encoder.inverse_transform(test_df_unpreprocessed_sample[categorical_features])\n", - "test_df_unpreprocessed_sample.to_dict(orient=\"records\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Wonderful, so if we're going to make a prediction on a custom sample, we'll need to fill out these details as much as we can.\n", - "\n", - "Let's try and make a prediction on the example test sample." - ] - }, - { - "cell_type": "code", - "execution_count": 137, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([13519.31657848])" - ] - }, - "execution_count": 137, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Make a prediction on the preprocessed test sample\n", - "best_model.predict(test_df_preprocessed_sample)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Nice!\n", - "\n", - "We get an output array containing a predicted `SalePrice`.\n", - "\n", - "Let's now try it on a custom sample.\n", - "\n", - "Again, like all good machine learning cooking shows, I've searched the internet for \"bulldozer sales in America\" and [found a sale from 6th July 2024](https://www.purplewave.com/auction/240606/item/EK8504/2004-Caterpillar-D6R_XL-Crawlers-Crawler_Dozer-Missouri) (I'm writing these materials in mid 2024 so if it's many years in the future and the link doesn't work, check out the screenshot below). \n", - "\n", - "TK - image of bulldozer (add raw GitHub link from master)\n", - "\n", - "| \"Image | \n", - "|:--:| \n", - "| Screenshot of a bulldozer sale advertisement. I took information from this advertisement to create our own custom sample for testing our machine learning model on data from the wild. [Source](https://www.purplewave.com/auction/240606/item/EK8504/2004-Caterpillar-D6R_XL-Crawlers-Crawler_Dozer-Missouri). |\n", - "\n", - "I went through the advertisement online and collected as much detail as I could and formatted the dictionary below with all of the related fields.\n", - "\n", - "It may not be perfect but data in the real world is rarely perfect.\n", - "\n", - "For values I couldn't find or were inconspicuous, I filled them with `np.nan` (or `NaN`). \n", - "\n", - "Some values such as `SalesID` were unobtainable because they were part of the original collected dataset, for these I've also used `np.nan`.\n", - "\n", - "Also notice how I've already created the extra date features `saleYear`, `saleMonth`, `saleDay` and more by manually breaking down the listed sale date of 6 July 2024." - ] - }, - { - "cell_type": "code", - "execution_count": 138, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a dictionary of features and values from an internet-based bulldozer advertisement\n", - "# See link: https://www.purplewave.com/auction/240606/item/EK8504/2004-Caterpillar-D6R_XL-Crawlers-Crawler_Dozer-Missouri (note: this link is/was valid as of October 2024 but may be invalid in the future)\n", - "custom_sample = {\n", - " \"SalesID\": np.nan,\n", - " \"MachineID\": 8504,\n", - " \"ModelID\": np.nan,\n", - " \"datasource\": np.nan,\n", - " \"auctioneerID\": np.nan,\n", - " \"YearMade\": 2004,\n", - " \"MachineHoursCurrentMeter\": 11770.0,\n", - " \"UsageBand\": \"High\",\n", - " \"fiModelDesc\": \"D6RXL\",\n", - " \"fiBaseModel\": \"D6\",\n", - " \"fiSecondaryDesc\": \"XL\",\n", - " \"fiModelSeries\": np.nan,\n", - " \"fiModelDescriptor\": np.nan,\n", - " \"ProductSize\": \"Medium\",\n", - " \"fiProductClassDesc\": \"Track Type Tractor, Dozer - 130.0 to 160.0 Horsepower\",\n", - " \"state\": \"Missouri\",\n", - " \"ProductGroup\": \"TTT\",\n", - " \"ProductGroupDesc\": \"Track Type Tractors\",\n", - " \"Drive_System\": \"No\",\n", - " \"Enclosure\": \"EROPS\",\n", - " \"Forks\": \"None or Unspecified\",\n", - " \"Pad_Type\": \"Grouser\",\n", - " \"Ride_Control\": \"None or Unspecified\",\n", - " \"Stick\": \"nan\",\n", - " \"Transmission\": \"Powershift\",\n", - " \"Turbocharged\": \"None or Unspecified\",\n", - " \"Blade_Extension\": \"None or Unspecified\",\n", - " \"Blade_Width\": np.nan,\n", - " \"Enclosure_Type\": np.nan,\n", - " \"Engine_Horsepower\": np.nan,\n", - " \"Hydraulics\": np.nan,\n", - " \"Pushblock\": \"None or Unspecified\",\n", - " \"Ripper\": \"None or Unspecified\",\n", - " \"Scarifier\": \"None or Unspecified\",\n", - " \"Tip_Control\": \"Tip\",\n", - " \"Tire_Size\": np.nan,\n", - " \"Coupler\": np.nan,\n", - " \"Coupler_System\": np.nan,\n", - " \"Grouser_Tracks\": \"Yes\",\n", - " \"Hydraulics_Flow\": np.nan,\n", - " \"Track_Type\": \"Steel\",\n", - " \"Undercarriage_Pad_Width\": \"22 inch\",\n", - " \"Stick_Length\": np.nan,\n", - " \"Thumb\": np.nan,\n", - " \"Pattern_Changer\": np.nan,\n", - " \"Grouser_Type\": \"Single\",\n", - " \"Backhoe_Mounting\": \"None or Unspecified\",\n", - " \"Blade_Type\": \"Semi U\",\n", - " \"Travel_Controls\": np.nan,\n", - " \"Differential_Type\": np.nan,\n", - " \"Steering_Controls\": \"Command Control\",\n", - " \"saleYear\": 2024,\n", - " \"saleMonth\": 6,\n", - " \"saleDay\": 7,\n", - " \"saleDayofweek\": 5,\n", - " \"saleDayofyear\": 159\n", - "}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we've got a single custom sample in the form of a dictionary, we can turn it into a DataFrame." - ] - }, - { - "cell_type": "code", - "execution_count": 139, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - "
SalesIDMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandfiModelDescfiBaseModel...Backhoe_MountingBlade_TypeTravel_ControlsDifferential_TypeSteering_ControlssaleYearsaleMonthsaleDaysaleDayofweeksaleDayofyear
0NaN8504NaNNaNNaN200411770.0HighD6RXLD6...None or UnspecifiedSemi UNaNNaNCommand Control2024675159
\n", - "

1 rows × 56 columns

\n", - "
" - ], - "text/plain": [ - " SalesID MachineID ModelID datasource auctioneerID YearMade \\\n", - "0 NaN 8504 NaN NaN NaN 2004 \n", - "\n", - " MachineHoursCurrentMeter UsageBand fiModelDesc fiBaseModel ... \\\n", - "0 11770.0 High D6RXL D6 ... \n", - "\n", - " Backhoe_Mounting Blade_Type Travel_Controls Differential_Type \\\n", - "0 None or Unspecified Semi U NaN NaN \n", - "\n", - " Steering_Controls saleYear saleMonth saleDay saleDayofweek saleDayofyear \n", - "0 Command Control 2024 6 7 5 159 \n", - "\n", - "[1 rows x 56 columns]" - ] - }, - "execution_count": 139, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Turn single sample in a DataFrame\n", - "custom_sample_df = pd.DataFrame(custom_sample, index=[0])\n", - "custom_sample_df.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And of course, we can preprocess the categoricial features using our `ordinal_encoder` (we use the same instance of `OrdinalEncoder` as we trained on the training dataset)." - ] - }, - { - "cell_type": "code", - "execution_count": 140, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - "
SalesIDMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandfiModelDescfiBaseModel...Backhoe_MountingBlade_TypeTravel_ControlsDifferential_TypeSteering_ControlssaleYearsaleMonthsaleDaysaleDayofweeksaleDayofyear
0NaN8504NaNNaNNaN200411770.00.02308.0703.0...0.06.07.04.00.02024675159
\n", - "

1 rows × 56 columns

\n", - "
" - ], - "text/plain": [ - " SalesID MachineID ModelID datasource auctioneerID YearMade \\\n", - "0 NaN 8504 NaN NaN NaN 2004 \n", - "\n", - " MachineHoursCurrentMeter UsageBand fiModelDesc fiBaseModel ... \\\n", - "0 11770.0 0.0 2308.0 703.0 ... \n", - "\n", - " Backhoe_Mounting Blade_Type Travel_Controls Differential_Type \\\n", - "0 0.0 6.0 7.0 4.0 \n", - "\n", - " Steering_Controls saleYear saleMonth saleDay saleDayofweek \\\n", - "0 0.0 2024 6 7 5 \n", - "\n", - " saleDayofyear \n", - "0 159 \n", - "\n", - "[1 rows x 56 columns]" - ] - }, - "execution_count": 140, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Transform the categorical features of the custom sample\n", - "custom_sample_df[categorical_features] = ordinal_encoder.transform(custom_sample_df[categorical_features].astype(str))\n", - "custom_sample_df" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Custom sample preprocessed, let's make a prediction!" - ] - }, - { - "cell_type": "code", - "execution_count": 141, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Predicted sale price of custom sample: $51474.96\n" - ] - } - ], - "source": [ - "# Make a prediction on the preprocessed custom sample\n", - "custom_sample_pred = best_model.predict(custom_sample_df)\n", - "print(f\"[INFO] Predicted sale price of custom sample: ${round(custom_sample_pred[0], 2)}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now how close was this to the actual sale price (listed on the advertisement) of $72,600?" - ] - }, - { - "cell_type": "code", - "execution_count": 142, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Model MAE on custom sample: 21125.040564373892\n", - "[INFO] Model RMSLE on custom sample: 0.3438638042344433\n" - ] - } - ], - "source": [ - "from sklearn.metrics import mean_absolute_error, root_mean_squared_log_error\n", - "\n", - "# Evaluate our model versus the actual sale price\n", - "custom_sample_actual_sale_price = [72600] # this is the sale price listed on the advertisement\n", - "\n", - "print(f\"[INFO] Model MAE on custom sample: {mean_absolute_error(y_pred=custom_sample_pred, y_true=custom_sample_actual_sale_price)}\")\n", - "print(f\"[INFO] Model RMSLE on custom sample: {root_mean_squared_log_error(y_pred=custom_sample_pred, y_true=custom_sample_actual_sale_price)}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Woah!\n", - "\n", - "We get a quite high MAE value, however, it looks like our model's RMSLE performance on the custom sample was even better than the `best_model` on the validation dataset.\n", - "\n", - "Not too bad for a model trained on sales data over 12 years older than our custom sample's sale date.\n", - "\n", - "> **Note:** In practice, to make this process easier, rather than manually typing out all of the feature values by hand, you might want to create an application capable of ingesting these values in a nice user interface. To create such machine learning applications, I'd practice by checking out [Streamlit](https://streamlit.io/) or [Gradio](https://www.gradio.app/)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 9. Finding the most important predictive features\n", - "\n", - "Since we've built a model which is able to make predictions, the people you share these predictions with (or yourself) might be curious of what parts of the data led to these predictions.\n", - "\n", - "This is where **feature importance** comes in. \n", - "\n", - "Feature importance seeks to figure out which different attributes of the data were most important when it comes to predicting the **target variable**.\n", - "\n", - "In our case, after our model learned the patterns in the data, which bulldozer sale attributes were most important for predicting its overall sale price?\n", - "\n", - "We can do this for our `sklearn.ensemble.RandomForestRegressor` instance using the [`feature_importances_`](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html#sklearn.ensemble.RandomForestRegressor.feature_importances_) attribute.\n", - "\n", - "Let's check it out." - ] - }, - { - "cell_type": "code", - "execution_count": 143, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([3.78948522e-02, 2.70954102e-02, 5.85804002e-02, 1.79438322e-03,\n", - " 5.25621132e-03, 1.92040831e-01, 6.71461619e-03, 1.42137572e-03,\n", - " 4.79324438e-02, 4.73967258e-02, 4.12235661e-02, 4.75379381e-03,\n", - " 2.55283197e-02, 1.60578799e-01, 5.08919397e-02, 8.34245434e-03,\n", - " 3.43077232e-03, 4.16871935e-03, 1.45645185e-03, 6.32089976e-02,\n", - " 1.93106853e-03, 7.91189110e-04, 2.16468186e-03, 2.42755109e-04,\n", - " 1.44729959e-03, 1.10292279e-04, 4.69525167e-03, 4.70046399e-03,\n", - " 2.18877572e-03, 4.03668217e-03, 4.46781002e-03, 2.86947732e-03,\n", - " 5.20668987e-03, 3.50894384e-03, 1.75215277e-03, 1.16769900e-02,\n", - " 1.84682779e-03, 2.08450645e-02, 1.17370327e-02, 5.26785421e-03,\n", - " 2.07101299e-03, 1.36424627e-03, 1.60680297e-03, 9.71604299e-04,\n", - " 7.85735364e-04, 7.29302663e-04, 6.74283032e-04, 3.28828690e-03,\n", - " 2.83781098e-03, 3.92432694e-04, 4.73081800e-04, 7.26042221e-02,\n", - " 5.42512552e-03, 8.54840059e-03, 4.42773246e-03, 1.26015531e-02])" - ] - }, - "execution_count": 143, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Find feature importance of our best model\n", - "best_model_feature_importances = best_model.feature_importances_\n", - "best_model_feature_importances" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Woah, looks like we get one value per feature in our dataset." - ] - }, - { - "cell_type": "code", - "execution_count": 144, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Number of feature importance values: 56\n", - "[INFO] Number of features in training dataset: 56\n" - ] - } - ], - "source": [ - "print(f\"[INFO] Number of feature importance values: {best_model_feature_importances.shape[0]}\") \n", - "print(f\"[INFO] Number of features in training dataset: {X_train_preprocessed.shape[1]}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can inspect these further by turning them into a DataFrame.\n", - "\n", - "We'll sort it descending order so we can see which feature our model is assigning the highest value." - ] - }, - { - "cell_type": "code", - "execution_count": 145, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - "
feature_namesfeature_importance
5YearMade0.192041
13ProductSize0.160579
51saleYear0.072604
19Enclosure0.063209
2ModelID0.058580
\n", - "
" - ], - "text/plain": [ - " feature_names feature_importance\n", - "5 YearMade 0.192041\n", - "13 ProductSize 0.160579\n", - "51 saleYear 0.072604\n", - "19 Enclosure 0.063209\n", - "2 ModelID 0.058580" - ] - }, - "execution_count": 145, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Create feature importance DataFrame\n", - "column_names = test_df.columns\n", - "feature_importance_df = pd.DataFrame({\"feature_names\": column_names,\n", - " \"feature_importance\": best_model_feature_importances}).sort_values(by=\"feature_importance\",\n", - " ascending=False)\n", - "feature_importance_df.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Hmmm... looks like `YearMade` may be contributing the most value in the model's eyes.\n", - "\n", - "How about we turn our DataFrame into a plot to compare values?" - ] - }, - { - "cell_type": "code", - "execution_count": 146, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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03NFRERERET0sVghQJVKamoq+vbtC29vb8TFxSEiIgI9evSAIAh49eoVPD09cerUKZw9exY2Njbo2LEjXr16VWRZubm5cHNzg6amJiIjIxEVFQUNDQ20b99e7CbQqlUrjBgxAp6enti5cyd27NiBDRs2QBCED25b0nhmzJiB7t2749q1a/D29paLMycnB+np6TILERERERFReZMIgiBUdBBEhS5fvgwnJyckJyfDzMzsvXkLCgqgo6ODLVu2wN3dHcCbN/K///47unXrhk2bNmH27NmIi4uDRCIBALx+/Ro6OjrYu3cv2rVrBwD4999/0bBhQyQkJGDhwoXw8/Mr8bYlicfPzw+LFi0q9jhmzJiBwMBAufUmfjs47SARlSlOO0hERPRlSU9Ph7a2NtLS0qClpVXm5bOFAFUq9evXR5s2beDg4IDevXtj9erVePHiBQDgn3/+weDBg2FjYwNtbW1oaWkhIyMDKSkpRZYVExOD27dvQ1NTExoaGtDQ0ICuri6ys7ORmJgo5lNVVcWECROgpqaGMWPGlHjbksbTqFGj9x5zQEAA0tLSxOXevXsfff6IiIiIiIhKSqmiAyB6m6KiIo4cOYLTp0/j8OHDWLJkCf73v//h3LlzGD58OJ49e4aQkBCYmZlBKpWiWbNmcrMEFMrIyICTkxM2b94sl6avry/zWUlJCYqKimJrgJJs6+npWaJ41NXV33vMUqkUUqn0vXmIiIiIiIjKGisEqNKRSCRo0aIFWrRogWnTpsHMzAy///47oqKisGzZMnTs2BHAmwEDnz59Wmw5jo6O2L59OwwMDErdvKYk25Y2HiIiIiIiosqEXQaoUjl37hzmzp2LixcvIiUlBXv27MGTJ09gb28PGxsbbNy4EXFxcTh37hw8PDygqqpabFkeHh6oVq0aunbtisjISCQlJSEiIgK+vr64f//+e+MoybaljYeIiIiIiKgyYYUAVSpaWlr4+++/0bFjR9SqVQtTpkzBwoUL0aFDB6xduxYvXryAo6Mj+vfvD19fXxgYGBRblpqaGv7++2+YmpqiR48esLe3h4+PD7Kzsz/YYqAk25Y2HiIiIiIiosqEswwQVTKFI4lylgEiKmucZYCIiOjLUt6zDHAMAaJK6nqgW7nc9ERERERERAC7DBARERERERF9lVghQERERERERPQVYpcBokqq7vRwjiFA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efMm7OzssGvXLlhbWz/3MXbp0gVjxozBkCFDkJ2djdmzZ6u8epCIiIiIiKgukwiCINR2J4joP3l5eY/eNjD5B6hJtaut3YyFfautLSIiIiIiqnmPrw1yc3Of6/HpquIIAaI66my4Z438oyciIiIiIgI4hwARERERERFRvcSEABEREREREVE9xIQAERERERERUT3EhAARERERERFRPcSEABEREREREVE9xIQAERERERERUT3EhAARERERERFRPcSEABEREREREVE9xIQAERERERERUT3EhAARERERERFRPcSEABEREREREVE9xIQAERERERERUT3EhAARERERERFRPcSEABEREREREVE9xIQAERERERERUT3EhAARERERERFRPaRR2x0gIlWCIAAA8vLyarknRERERERUmx5fEzy+RqhuTAgQ1THZ2dkAAHNz81ruCRERERER1QV3796FXC6v9naZECCqY/T19QEAmZmZNfKPniqXl5cHc3NzZGVlQU9Pr7a7Uy/xd1C7GP/axfjXLsa/djH+tYvxr10VxV8QBNy9exdmZmY1sl8mBIjqGDW1R1N7yOVyfhnXIj09Pca/lvF3ULsY/9rF+Ncuxr92Mf61i/GvXeXFvyZvEnJSQSIiIiIiIqJ6iAkBIiIiIiIionqICQGiOkYqlWL27NmQSqW13ZV6ifGvffwd1C7Gv3Yx/rWL8a9djH/tYvxrV23FXyLU1PsLiIiIiIiIiKjO4ggBIiIiIiIionqICQEiIiIiIiKieogJASIiIiIiIqJ6iAkBIiIiIiIionqICQGiGvDll1/CysoKDRs2ROfOnXHixIlK6//4449o3bo1GjZsCHt7e/zyyy8q6wVBQFhYGExNTaGlpQUPDw9cuHBBpc6///6LgIAA6OnpQaFQYOTIkcjPz6/2Y3sdVGf8i4uLMX36dNjb20NHRwdmZmYYPnw4rl27ptKGlZUVJBKJyrJw4cIaOb66rrrP/6CgoDKx9fLyUqnD8/8/1R3/p2P/ePn888/FOjz//1OV+J87dw4DBw4U47d8+fIXarOgoADjx4+HgYEBZDIZBg4ciBs3blTnYb02qjv+ERER6NixI3R1dWFsbAxfX1+kpqaq1OnevXuZ83/MmDHVfWivheqO/5w5c8rEtnXr1ip1eP7/p7rjX953u0Qiwfjx48U6PP//U5X4r1u3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b98+dOzYEW+99RaWLVsGS0tLAI9eNffFF19g0aJFaNu2LTZv3oyIiAiVNrp06YIxY8ZgyJAhMDIywuLFiwEAS5cuhbm5Obp27YqhQ4ciJCSk0kcMHhs1ahQiIyMRFRUFe3t7uLm5ITo6Gs2aNav+ADxFW1sb06dPx9ChQ+Hq6gqZTIatW7eK6319fbFixQosWbIEbdq0wddff42oqCh079690nabNGmC8PBwfPLJJ2jcuDEmTJgANTU1bNmyBadOnULbtm3x0Ucf4fPPP69yn21sbLBv3z4kJyejU6dOcHFxwc6dO6Gh8eh+0rx58zBr1ixERETA1tYWXl5e2LNnzzPj+c4774hzRfj6+qqs++abb3Dnzh04OTlh2LBhmDhxosoIgqc1aNAA33//Pf7++284ODhg0aJF+Oyzz1TqODg44NChQ/jnn3/QtWtXtG/fHmFhYTAzM6tyTIiI3jQS4emH8IiIiIio2kRHR2Py5MnIycmp7a4QERGp4AgBIiIiIiIionqICQEiIiIiIiKieoiPDBARERERERHVQxwhQERERERERFQPMSFAREREREREVA8xIUBERERERERUDzEhQERERERERFQPMSFAREREREREVA8xIUBERERERERUDzEhQERERERERFQPMSFAREREREREVA/9P5hVLn9AR4jaAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Plot the top feature importance values\n", - "top_n = 20\n", - "plt.figure(figsize=(10, 5))\n", - "plt.barh(y=feature_importance_df[\"feature_names\"][:top_n], # Plot the top_n feature importance values\n", - " width=feature_importance_df[\"feature_importance\"][:top_n])\n", - "plt.title(f\"Top {top_n} Feature Importance Values for Best RandomForestRegressor Model\")\n", - "plt.xlabel(\"Feature importance value\")\n", - "plt.ylabel(\"Feature name\")\n", - "plt.gca().invert_yaxis();" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Ok, looks like the top 4 features contributing to our model's predictions are `YearMade`, `ProductSize`, `Enclosure` and `saleYear`.\n", - "\n", - "Referring to the original [data dictionary](https://docs.google.com/spreadsheets/d/18ly-bLR8sbDJLITkWG7ozKm8l3RyieQ2Fpgix-beSYI/edit?usp=sharing), do these values make sense to be contributing the most to the model?\n", - "\n", - "* `YearMade` - Year of manufacture of the machine.\n", - "* `ProductSize` - Size of the bulldozer.\n", - "* `Enclosure` - Type of bulldozer enclosure (e.g. OROPS = Open Rollover Protective Structures, EROPS = Enclosed Rollover Protective Structures).\n", - "* `saleYear` - The year the bulldozer was sold (this is one of our engineered features from `saledate`).\n", - "\n", - "Now I've never sold a bulldozer but reading about each of these values seems to make sense that they would contribute significantly to the sale price.\n", - "\n", - "I know when I've bought cars in the past, the year that is was made was an important part of my decision. \n", - "\n", - "And it also makes sense that `ProductSize` be an important feature when deciding on the price of a bulldozer.\n", - "\n", - "Let's check out the unique values for `ProductSize` and `Enclosure`.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 147, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Unique ProductSize values: ['Medium' nan 'Compact' 'Small' 'Large' 'Large / Medium' 'Mini']\n", - "[INFO] Unique Enclosure values: ['OROPS' 'EROPS' 'EROPS w AC' nan 'EROPS AC' 'NO ROPS'\n", - " 'None or Unspecified']\n" - ] - } - ], - "source": [ - "print(f\"[INFO] Unique ProductSize values: {train_df['ProductSize'].unique()}\")\n", - "print(f\"[INFO] Unique Enclosure values: {train_df['Enclosure'].unique()}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "My guess is that a bulldozer with a `ProductSize` of `'Mini'` would sell for less than a bulldozer with a size of `'Large'`.\n", - "\n", - "We could investigate this further in an extension to model driven data exploratory analysis or we could take this information to a colleague or client to discuss further.\n", - "\n", - "Either way, we've now got a machine learning model capable of predicting the sale price of bulldozers given their features/attributes!\n", - "\n", - "That's a huuuuuuge effort!\n", - "\n", - "And you should be very proud of yourself for making it this far." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Summary\n", - "\n", - "We've covered a lot of ground.\n", - "\n", - "But there are some main takeaways to go over.\n", - "\n", - "* **Every machine learning problem is different** - Since machine learning is such a widespread technology, it can be used for a multitude of different problems. In saying this, there will often be many different ways to approach a problem. In this example, we've focused on predicting a number, which is a regression problem. And since our data had a time component, it could also be considered a time series problem.\n", - "* **The machine learner's motto: Experiment, experiment, experiment!** - Since there are many different ways to approach machine learning problems, one of the best habits you can develop is an experimental mindset. That means not being afraid to try new things over and over. Because the more things you try, the quicker you can figure what doesn't work and the quicker you can start to move towards what does.\n", - "* **Always keep the test set separate** - If you can't evaluate your model on unseen data, how would you know how it will perform in the real world on future unseen data? Of course, using a test set isn't a perfect replica of the real world but if it's done right, it can give you a good idea. Because evaluating a model is just as important as training a model.\n", - "* **If you've trained a model on a data in a certain format, you'll have to make predictions in the same format** - Any preprocessing you do to the training dataset, you'll have to do to the validation, test and custom data. Any computed values should happen on the training set only and then be used to update any subsequent datasets." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Exercises\n", - "\n", - "1. Fill the missing values in the numeric columns with the median using Scikit-Learn and see if that helps our best model's performance (hint: see [`sklearn.impute.SimpleImputer`](https://scikit-learn.org/stable/modules/generated/sklearn.impute.SimpleImputer.html#sklearn.impute.SimpleImputer) for more).\n", - "2. Try putting multiple steps together (e.g. preprocessing -> modelling) with Scikit-Learn's [`sklearn.pipeline.Pipeline`](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html) features. \n", - "3. Try using another regression model/estimator on our preprocessed dataset and see how it goes. See the [Scikit-Learn machine learning map](https://scikit-learn.org/stable/machine_learning_map.html) for potential model options.\n", - "4. Try replacing the `sklearn.preprocessing.OrdinalEncoder` we used for the categorical variables with `sklearn.preprocessing.OneHotEncoder` (you may even want to do this within a pipeline) with the `sklearn.ensemble.RandomForestRegressor` model and see how it performs. Which is better for our specific dataset? " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Extra-curriculum\n", - "\n", - "The following resources are suggested extra reading and activities to add backing to the materials we've covered in this project.\n", - "\n", - "Reading documentation and knowing where to find information is one of the best skills you can develop as an engineer.\n", - "\n", - "* Read the pandas [IO tools documentation page](https://pandas.pydata.org/docs/user_guide/io.html#) for an idea of all the possible ways to get data in and out of pandas.\n", - "* See all of the [available datatypes in the pandas user guide](https://pandas.pydata.org/docs/user_guide/basics.html#dtypes) (knowing what type your data is in can help prevent a lot of future errors).\n", - "* Read the Scikit-Learn [dataset transformations](https://scikit-learn.org/stable/data_transforms.html) and [data preprocessing guide](https://scikit-learn.org/stable/modules/preprocessing.html) for an overview of all the different ways you can preprocess and transform data. \n", - "* For more on saving and loading model objects with Scikit-Learn, see the documentation on [model persistence](https://scikit-learn.org/stable/model_persistence.html).\n", - "* For more on the importance of creating good validation and test sets, I'd recommend reading [How (and why) to create a good validation set](https://www.fast.ai/2017/11/13/validation-sets/) by Rachel Thomas as well as [The importance of a test set](https://www.learnml.io/posts/the-importance-of-a-test-set/) by Daniel Bourke.\n", - "* We've covered a handful of models in the Scikit-Learn library, however, there are some other ML models which are worth exploring such as [CatBoost](https://catboost.ai/) and [XGBoost](https://xgboost.ai/). Both of these models can handle missing values and are often touted as some of the most performant ML models on the market. A good extension would be to try get one of them working on our bulldozer data.\n", - " * Bonus: You can also see a [list of models in Scikit-Learn which can handle missing/NaN values](https://scikit-learn.org/stable/modules/impute.html#estimators-that-handle-nan-values). " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Example Exercise Solutions\n", - "\n", - "The following are examples of how to solve the above exercises." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 1. Fill the missing values in the numeric columns with the median using Scikit-Learn and see if that helps our best model's performance" - ] - }, - { - "cell_type": "code", - "execution_count": 244, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Number of samples in training DataFrame: 401125\n", - "[INFO] Number of samples in validation DataFrame: 11573\n" - ] - }, - { - "data": { - "text/plain": [ - "{'Training MAE': np.float64(1951.2971558280735),\n", - " 'Valid MAE': np.float64(5964.025764507629),\n", - " 'Training RMSLE': np.float64(0.101909965049995),\n", - " 'Valid RMSLE': np.float64(0.24697812443315573),\n", - " 'Training R^2': 0.9810825663665007,\n", - " 'Valid R^2': 0.8809697755766817}" - ] - }, - "execution_count": 244, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from sklearn.impute import SimpleImputer\n", - "from sklearn.preprocessing import OrdinalEncoder\n", - "from sklearn.metrics import mean_absolute_error, root_mean_squared_log_error\n", - "from sklearn.ensemble import RandomForestRegressor\n", - "\n", - "# Import train samples (making sure to parse dates and then sort by them)\n", - "train_df = pd.read_csv(filepath_or_buffer=\"../data/bluebook-for-bulldozers/Train.csv\",\n", - " parse_dates=[\"saledate\"],\n", - " low_memory=False).sort_values(by=\"saledate\", ascending=True)\n", - "\n", - "# Import validation samples (making sure to parse dates and then sort by them)\n", - "valid_df = pd.read_csv(filepath_or_buffer=\"../data/bluebook-for-bulldozers/Valid.csv\",\n", - " parse_dates=[\"saledate\"])\n", - "\n", - "# The ValidSolution.csv contains the SalePrice values for the samples in Valid.csv\n", - "valid_solution = pd.read_csv(filepath_or_buffer=\"../data/bluebook-for-bulldozers/ValidSolution.csv\")\n", - "\n", - "# Map valid_solution to valid_df\n", - "valid_df[\"SalePrice\"] = valid_df[\"SalesID\"].map(valid_solution.set_index(\"SalesID\")[\"SalePrice\"])\n", - "\n", - "# Make sure valid_df is sorted by saledate still\n", - "valid_df = valid_df.sort_values(\"saledate\", ascending=True).reset_index(drop=True)\n", - "\n", - "# How many samples are in each DataFrame?\n", - "print(f\"[INFO] Number of samples in training DataFrame: {len(train_df)}\")\n", - "print(f\"[INFO] Number of samples in validation DataFrame: {len(valid_df)}\")\n", - "\n", - "# Make a function to add date columns\n", - "def add_datetime_features_to_df(df, date_column=\"saledate\"):\n", - " # Add datetime parameters for saledate\n", - " df[\"saleYear\"] = df[date_column].dt.year\n", - " df[\"saleMonth\"] = df[date_column].dt.month\n", - " df[\"saleDay\"] = df[date_column].dt.day\n", - " df[\"saleDayofweek\"] = df[date_column].dt.dayofweek\n", - " df[\"saleDayofyear\"] = df[date_column].dt.dayofyear\n", - "\n", - " # Drop original saledate column\n", - " df.drop(\"saledate\", axis=1, inplace=True)\n", - "\n", - " return df\n", - "\n", - "# Add datetime features to DataFrames\n", - "train_df = add_datetime_features_to_df(df=train_df)\n", - "valid_df = add_datetime_features_to_df(df=valid_df)\n", - "\n", - "# Split training data into features and labels\n", - "X_train = train_df.drop(\"SalePrice\", axis=1)\n", - "y_train = train_df[\"SalePrice\"]\n", - "\n", - "# Split validation data into features and labels\n", - "X_valid = valid_df.drop(\"SalePrice\", axis=1)\n", - "y_valid = valid_df[\"SalePrice\"]\n", - "\n", - "# Define numerical and categorical features\n", - "numeric_features = [label for label, content in X_train.items() if pd.api.types.is_numeric_dtype(content)]\n", - "categorical_features = [label for label, content in X_train.items() if not pd.api.types.is_numeric_dtype(content)]\n", - "\n", - "### Filling missing values ### \n", - "\n", - "# Create an ordinal encoder (turns category items into numeric representation)\n", - "ordinal_encoder = OrdinalEncoder(categories=\"auto\",\n", - " handle_unknown=\"use_encoded_value\",\n", - " unknown_value=np.nan,\n", - " encoded_missing_value=np.nan) # treat unknown categories as np.nan (or None)\n", - "\n", - "# Create a simple imputer to fill missing values with median\n", - "simple_imputer_median = SimpleImputer(missing_values=np.nan,\n", - " strategy=\"median\")\n", - "\n", - "# Fit and transform the categorical and numerical columns of X_train\n", - "X_train_preprocessed = X_train.copy() # make copies of the oringal DataFrames so we can keep the original values in tact and view them later\n", - "X_train_preprocessed[categorical_features] = ordinal_encoder.fit_transform(X_train_preprocessed[categorical_features].astype(str)) # OrdinalEncoder expects all values as the same type (e.g. string or numeric only)\n", - "X_train_preprocessed[numerical_features] = simple_imputer_median.fit_transform(X_train_preprocessed[numerical_features])\n", - "\n", - "# Transform the categorical and numerical columns of X_valid \n", - "X_valid_preprocessed = X_valid.copy()\n", - "X_valid_preprocessed[categorical_features] = ordinal_encoder.transform(X_valid_preprocessed[categorical_features].astype(str)) # only use `transform` on the validation data\n", - "X_valid_preprocessed[numerical_features] = simple_imputer_median.transform(X_valid_preprocessed[numerical_features])\n", - "\n", - "# Create function to evaluate our model\n", - "def show_scores(model, \n", - " train_features=X_train_preprocessed,\n", - " train_labels=y_train,\n", - " valid_features=X_valid_preprocessed,\n", - " valid_labels=y_valid):\n", - " \n", - " # Make predictions on train and validation features\n", - " train_preds = model.predict(X=train_features)\n", - " val_preds = model.predict(X=valid_features)\n", - "\n", - " # Create a scores dictionary of different evaluation metrics\n", - " scores = {\"Training MAE\": mean_absolute_error(y_true=train_labels, \n", - " y_pred=train_preds),\n", - " \"Valid MAE\": mean_absolute_error(y_true=valid_labels, \n", - " y_pred=val_preds),\n", - " \"Training RMSLE\": root_mean_squared_log_error(y_true=train_labels, \n", - " y_pred=train_preds),\n", - " \"Valid RMSLE\": root_mean_squared_log_error(y_true=valid_labels, \n", - " y_pred=val_preds),\n", - " \"Training R^2\": model.score(X=train_features, \n", - " y=train_labels),\n", - " \"Valid R^2\": model.score(X=valid_features, \n", - " y=valid_labels)}\n", - " return scores\n", - "\n", - "# Instantiate a model with best hyperparameters \n", - "ideal_model_2 = RandomForestRegressor(n_estimators=90,\n", - " max_depth=None,\n", - " min_samples_leaf=1,\n", - " min_samples_split=5,\n", - " max_features=0.5,\n", - " n_jobs=-1,\n", - " max_samples=None)\n", - "\n", - "# Fit a model to the preprocessed data\n", - "ideal_model_2.fit(X=X_train_preprocessed, \n", - " y=y_train)\n", - "\n", - "# Evalute the model\n", - "ideal_model_2_scores = show_scores(model=ideal_model_2)\n", - "ideal_model_2_scores" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Looks like filling the missing numeric values made our `ideal_model_2` perform slightly worse than our original `ideal_model`.\n", - "\n", - "`ideal_model_2` had a validation RMSLE of `0.24697812443315573` where as `ideal_model` had a validation RMSLE of `0.24654150224930685`." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2. Try putting multiple steps together (e.g. preprocessing -> modelling) with Scikit-Learn's `sklearn.pipeline.Pipeline`" - ] - }, - { - "cell_type": "code", - "execution_count": 247, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Pipeline Scores:\n" - ] - }, - { - "data": { - "text/plain": [ - "{'Training MAE': np.float64(1951.4776197781914),\n", - " 'Valid MAE': np.float64(5974.931566226864),\n", - " 'Training RMSLE': np.float64(0.10196097739473307),\n", - " 'Valid RMSLE': np.float64(0.24760612684722114),\n", - " 'Training R^2': 0.9811027965058758,\n", - " 'Valid R^2': 0.8807288353268701}" - ] - }, - "execution_count": 247, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas as pd\n", - "import numpy as np\n", - "\n", - "from sklearn.compose import ColumnTransformer\n", - "from sklearn.ensemble import RandomForestRegressor\n", - "from sklearn.impute import SimpleImputer\n", - "from sklearn.metrics import mean_absolute_error, root_mean_squared_log_error\n", - "from sklearn.preprocessing import OrdinalEncoder, FunctionTransformer\n", - "from sklearn.pipeline import Pipeline\n", - "\n", - "\n", - "# Import and prepare data\n", - "train_df = pd.read_csv(\"../data/bluebook-for-bulldozers/Train.csv\",\n", - " parse_dates=[\"saledate\"],\n", - " low_memory=False).sort_values(by=\"saledate\", ascending=True)\n", - "\n", - "valid_df = pd.read_csv(\"../data/bluebook-for-bulldozers/Valid.csv\",\n", - " parse_dates=[\"saledate\"])\n", - "\n", - "valid_solution = pd.read_csv(\"../data/bluebook-for-bulldozers/ValidSolution.csv\")\n", - "valid_df[\"SalePrice\"] = valid_df[\"SalesID\"].map(valid_solution.set_index(\"SalesID\")[\"SalePrice\"])\n", - "valid_df = valid_df.sort_values(\"saledate\", ascending=True).reset_index(drop=True)\n", - "\n", - "# Add datetime features\n", - "def add_datetime_features_to_df(df, date_column=\"saledate\"):\n", - " df = df.copy()\n", - " df[\"saleYear\"] = df[date_column].dt.year\n", - " df[\"saleMonth\"] = df[date_column].dt.month\n", - " df[\"saleDay\"] = df[date_column].dt.day\n", - " df[\"saleDayofweek\"] = df[date_column].dt.dayofweek\n", - " df[\"saleDayofyear\"] = df[date_column].dt.dayofyear\n", - " return df.drop(date_column, axis=1)\n", - "\n", - "# Apply datetime features\n", - "train_df = add_datetime_features_to_df(train_df)\n", - "valid_df = add_datetime_features_to_df(valid_df)\n", - "\n", - "# Split data into features and labels\n", - "X_train = train_df.drop(\"SalePrice\", axis=1)\n", - "y_train = train_df[\"SalePrice\"]\n", - "X_valid = valid_df.drop(\"SalePrice\", axis=1)\n", - "y_valid = valid_df[\"SalePrice\"]\n", - "\n", - "# Define feature types\n", - "numeric_features = [label for label, content in X_train.items() \n", - " if pd.api.types.is_numeric_dtype(content)]\n", - "categorical_features = [label for label, content in X_train.items() \n", - " if not pd.api.types.is_numeric_dtype(content)]\n", - "\n", - "# Create preprocessing steps\n", - "numeric_transformer = Pipeline(steps=[\n", - " ('imputer', SimpleImputer(strategy='median'))\n", - "])\n", - "\n", - "categorical_transformer = Pipeline(steps=[\n", - " ('string_converter', FunctionTransformer(lambda x: x.astype(str))), # convert values to string\n", - " ('ordinal', OrdinalEncoder(handle_unknown='use_encoded_value',\n", - " unknown_value=np.nan,\n", - " encoded_missing_value=np.nan)),\n", - "])\n", - "\n", - "# Create preprocessor using ColumnTransformer\n", - "preprocessor = ColumnTransformer(\n", - " transformers=[\n", - " ('numerical_transforms', numeric_transformer, numeric_features),\n", - " ('categorical_transforms', categorical_transformer, categorical_features)\n", - " ])\n", - "\n", - "# Create full pipeline\n", - "model_pipeline = Pipeline([\n", - " ('preprocessor', preprocessor),\n", - " ('regressor', RandomForestRegressor(\n", - " n_estimators=90,\n", - " max_depth=None,\n", - " min_samples_leaf=1,\n", - " min_samples_split=5,\n", - " max_features=0.5,\n", - " n_jobs=-1,\n", - " max_samples=None\n", - " ))\n", - "])\n", - "\n", - "# Function to evaluate the pipeline\n", - "def evaluate_pipeline(pipeline, X_train, y_train, X_valid, y_valid):\n", - " # Make predictions\n", - " train_preds = pipeline.predict(X_train)\n", - " valid_preds = pipeline.predict(X_valid)\n", - " \n", - " # Calculate scores\n", - " scores = {\n", - " \"Training MAE\": mean_absolute_error(y_train, train_preds),\n", - " \"Valid MAE\": mean_absolute_error(y_valid, valid_preds),\n", - " \"Training RMSLE\": root_mean_squared_log_error(y_train, train_preds),\n", - " \"Valid RMSLE\": root_mean_squared_log_error(y_valid, valid_preds),\n", - " \"Training R^2\": pipeline.score(X_train, y_train),\n", - " \"Valid R^2\": pipeline.score(X_valid, y_valid)\n", - " }\n", - " return scores\n", - "\n", - "# Fit and evaluate pipeline\n", - "model_pipeline.fit(X_train, y_train)\n", - "pipeline_scores = evaluate_pipeline(model_pipeline, X_train, y_train, X_valid, y_valid)\n", - "print(\"\\nPipeline Scores:\")\n", - "pipeline_scores" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 3. Try using another regression model/estimator on our preprocessed dataset and see how it goes\n", - "\n", - "Going to use [`sklearn.linear_model.HistGradientBoostingRegressor`](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.HistGradientBoostingRegressor.html#histgradientboostingregressor)." - ] - }, - { - "cell_type": "code", - "execution_count": 148, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Fitting HistGradientBoostingRegressor model with pipeline...\n", - "[INFO] Evaluating HistGradientBoostingRegressor model with pipeline...\n", - "\n", - "Pipeline HistGradientBoostingRegressor Scores:\n" - ] - }, - { - "data": { - "text/plain": [ - "{'Training MAE': np.float64(5638.6121797753785),\n", - " 'Valid MAE': np.float64(7264.258786098576),\n", - " 'Training RMSLE': np.float64(0.2691456681483351),\n", - " 'Valid RMSLE': np.float64(0.30482586120872424),\n", - " 'Training R^2': 0.8646511348082063,\n", - " 'Valid R^2': 0.8319021596407035}" - ] - }, - "execution_count": 148, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas as pd\n", - "import numpy as np\n", - "\n", - "from sklearn.compose import ColumnTransformer\n", - "from sklearn.ensemble import HistGradientBoostingRegressor\n", - "from sklearn.impute import SimpleImputer\n", - "from sklearn.metrics import mean_absolute_error, root_mean_squared_log_error\n", - "from sklearn.preprocessing import OrdinalEncoder, FunctionTransformer, StandardScaler\n", - "from sklearn.pipeline import Pipeline\n", - "\n", - "# Import and prepare data\n", - "train_df = pd.read_csv(\"../data/bluebook-for-bulldozers/Train.csv\",\n", - " parse_dates=[\"saledate\"],\n", - " low_memory=False).sort_values(by=\"saledate\", ascending=True)\n", - "\n", - "valid_df = pd.read_csv(\"../data/bluebook-for-bulldozers/Valid.csv\",\n", - " parse_dates=[\"saledate\"])\n", - "\n", - "valid_solution = pd.read_csv(\"../data/bluebook-for-bulldozers/ValidSolution.csv\")\n", - "valid_df[\"SalePrice\"] = valid_df[\"SalesID\"].map(valid_solution.set_index(\"SalesID\")[\"SalePrice\"])\n", - "valid_df = valid_df.sort_values(\"saledate\", ascending=True).reset_index(drop=True)\n", - "\n", - "# Add datetime features\n", - "def add_datetime_features_to_df(df, date_column=\"saledate\"):\n", - " df = df.copy()\n", - " df[\"saleYear\"] = df[date_column].dt.year\n", - " df[\"saleMonth\"] = df[date_column].dt.month\n", - " df[\"saleDay\"] = df[date_column].dt.day\n", - " df[\"saleDayofweek\"] = df[date_column].dt.dayofweek\n", - " df[\"saleDayofyear\"] = df[date_column].dt.dayofyear\n", - " return df.drop(date_column, axis=1)\n", - "\n", - "# Apply datetime features\n", - "train_df = add_datetime_features_to_df(train_df)\n", - "valid_df = add_datetime_features_to_df(valid_df)\n", - "\n", - "# Split data into features and labels\n", - "X_train = train_df.drop(\"SalePrice\", axis=1)\n", - "y_train = train_df[\"SalePrice\"]\n", - "X_valid = valid_df.drop(\"SalePrice\", axis=1)\n", - "y_valid = valid_df[\"SalePrice\"]\n", - "\n", - "# Define feature types\n", - "numeric_features = [label for label, content in X_train.items() \n", - " if pd.api.types.is_numeric_dtype(content)]\n", - "categorical_features = [label for label, content in X_train.items() \n", - " if not pd.api.types.is_numeric_dtype(content)]\n", - "\n", - "# Create preprocessing steps for different types of values\n", - "numeric_transformer = Pipeline(steps=[\n", - " ('imputer', SimpleImputer(strategy='median')),\n", - "])\n", - "\n", - "categorical_transformer = Pipeline(steps=[\n", - " ('string_converter', FunctionTransformer(lambda x: x.astype(str))), # convert values to string\n", - " ('ordinal', OrdinalEncoder(categories='auto',\n", - " handle_unknown='use_encoded_value',\n", - " unknown_value=np.nan,\n", - " encoded_missing_value=np.nan)), \n", - "])\n", - "\n", - "# Create preprocessor using ColumnTransformer\n", - "preprocessor = ColumnTransformer(\n", - " transformers=[\n", - " ('numerical_transforms', numeric_transformer, numeric_features),\n", - " ('categorical_transforms', categorical_transformer, categorical_features)\n", - " ])\n", - "\n", - "# Create full pipeline\n", - "model_pipeline_hist_gradient_boosting_regressor = Pipeline([\n", - " ('preprocessor', preprocessor),\n", - " ('regressor', HistGradientBoostingRegressor()) # Change model to HistGradientBoostingRegressor\n", - "])\n", - "\n", - "# Function to evaluate the pipeline\n", - "def evaluate_pipeline(pipeline, X_train, y_train, X_valid, y_valid):\n", - " # Make predictions\n", - " train_preds = pipeline.predict(X_train)\n", - " valid_preds = pipeline.predict(X_valid)\n", - " \n", - " # Calculate scores\n", - " scores = {\n", - " \"Training MAE\": mean_absolute_error(y_train, train_preds),\n", - " \"Valid MAE\": mean_absolute_error(y_valid, valid_preds),\n", - " \"Training RMSLE\": root_mean_squared_log_error(y_train, train_preds),\n", - " \"Valid RMSLE\": root_mean_squared_log_error(y_valid, valid_preds),\n", - " \"Training R^2\": pipeline.score(X_train, y_train),\n", - " \"Valid R^2\": pipeline.score(X_valid, y_valid)\n", - " }\n", - " return scores\n", - "\n", - "# Fit and evaluate pipeline\n", - "print(f\"[INFO] Fitting HistGradientBoostingRegressor model with pipeline...\")\n", - "model_pipeline_hist_gradient_boosting_regressor.fit(X_train, y_train)\n", - "print(f\"[INFO] Evaluating HistGradientBoostingRegressor model with pipeline...\")\n", - "pipeline_hist_scores = evaluate_pipeline(model_pipeline_hist_gradient_boosting_regressor, X_train, y_train, X_valid, y_valid)\n", - "print(\"\\nPipeline HistGradientBoostingRegressor Scores:\")\n", - "pipeline_hist_scores" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 4. Try replacing the `sklearn.preprocessing.OrdinalEncoder` we used for the categorical variables with `sklearn.preprocessing.OneHotEncoder`\n", - "\n", - "> **Note:** This may take quite a long time depending on your machine. For example, on my MacBook Pro M1 Pro it took ~10 minutes with `n_estimators=10` (9x lower than what we used for our `best_model`). This is because using `sklearn.preprocessing.OneHotEncoder` adds many more features to our dataset (each feature gets turned into an array of 0's and 1's for each unique value). And the more features, the longer it takes to compute and find patterns between them." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Fitting model with one hot encoded values...\n", - "[INFO] Evaluating model with one hot encoded values...\n", - "[INFO] Pipeline with one hot encoding scores:\n", - "CPU times: user 29min, sys: 23min 12s, total: 52min 13s\n", - "Wall time: 9min 14s\n" - ] - }, - { - "data": { - "text/plain": [ - "{'Training MAE': np.float64(2133.748251811842),\n", - " 'Valid MAE': np.float64(6176.810802667383),\n", - " 'Training RMSLE': np.float64(0.11021214524792695),\n", - " 'Valid RMSLE': np.float64(0.2539881442090813),\n", - " 'Training R^2': 0.9759312990258391,\n", - " 'Valid R^2': 0.870741470996933}" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "\n", - "import pandas as pd\n", - "import numpy as np\n", - "from sklearn.impute import SimpleImputer\n", - "from sklearn.preprocessing import OneHotEncoder\n", - "from sklearn.ensemble import RandomForestRegressor\n", - "from sklearn.metrics import mean_absolute_error, root_mean_squared_log_error\n", - "from sklearn.pipeline import Pipeline\n", - "from sklearn.compose import ColumnTransformer\n", - "from sklearn.preprocessing import FunctionTransformer\n", - "\n", - "# Import and prepare data\n", - "train_df = pd.read_csv(\"../data/bluebook-for-bulldozers/Train.csv\",\n", - " parse_dates=[\"saledate\"],\n", - " low_memory=False).sort_values(by=\"saledate\", ascending=True)\n", - "\n", - "valid_df = pd.read_csv(\"../data/bluebook-for-bulldozers/Valid.csv\",\n", - " parse_dates=[\"saledate\"])\n", - "\n", - "valid_solution = pd.read_csv(\"../data/bluebook-for-bulldozers/ValidSolution.csv\")\n", - "valid_df[\"SalePrice\"] = valid_df[\"SalesID\"].map(valid_solution.set_index(\"SalesID\")[\"SalePrice\"])\n", - "valid_df = valid_df.sort_values(\"saledate\", ascending=True).reset_index(drop=True)\n", - "\n", - "# Add datetime features\n", - "def add_datetime_features_to_df(df, date_column=\"saledate\"):\n", - " df = df.copy()\n", - " df[\"saleYear\"] = df[date_column].dt.year\n", - " df[\"saleMonth\"] = df[date_column].dt.month\n", - " df[\"saleDay\"] = df[date_column].dt.day\n", - " df[\"saleDayofweek\"] = df[date_column].dt.dayofweek\n", - " df[\"saleDayofyear\"] = df[date_column].dt.dayofyear\n", - " return df.drop(date_column, axis=1)\n", - "\n", - "# Apply datetime features\n", - "train_df = add_datetime_features_to_df(train_df)\n", - "valid_df = add_datetime_features_to_df(valid_df)\n", - "\n", - "# Split data\n", - "X_train = train_df.drop(\"SalePrice\", axis=1)\n", - "y_train = train_df[\"SalePrice\"]\n", - "X_valid = valid_df.drop(\"SalePrice\", axis=1)\n", - "y_valid = valid_df[\"SalePrice\"]\n", - "\n", - "# Define feature types\n", - "numeric_features = [label for label, content in X_train.items() \n", - " if pd.api.types.is_numeric_dtype(content)]\n", - "categorical_features = [label for label, content in X_train.items() \n", - " if not pd.api.types.is_numeric_dtype(content)]\n", - "\n", - "# Create preprocessing steps\n", - "numeric_transformer = Pipeline(steps=[\n", - " ('imputer', SimpleImputer(strategy='median'))\n", - "])\n", - "\n", - "categorical_transformer = Pipeline(steps=[\n", - " ('string_converter', FunctionTransformer(lambda x: x.astype(str))),\n", - " ('imputer', SimpleImputer(strategy='constant', fill_value='missing')), # fill missing values with the term \"missing\"\n", - " ('onehot', OneHotEncoder(handle_unknown='ignore', sparse_output=True)) # use OneHotEncoder instead of OrdinalEncoder\n", - "])\n", - "\n", - "# Create preprocessor using ColumnTransformer\n", - "preprocessor = ColumnTransformer(\n", - " transformers=[\n", - " ('num', numeric_transformer, numeric_features),\n", - " ('cat', categorical_transformer, categorical_features)\n", - " ],\n", - " verbose_feature_names_out=False # Simplify feature names\n", - ")\n", - "\n", - "# Create full pipeline\n", - "model_one_hot_pipeline = Pipeline([\n", - " ('preprocessor', preprocessor),\n", - " ('regressor', RandomForestRegressor(\n", - " n_estimators=10,\n", - " max_depth=None,\n", - " min_samples_leaf=1,\n", - " min_samples_split=5,\n", - " max_features=0.5,\n", - " n_jobs=-1,\n", - " max_samples=None\n", - " ))\n", - "])\n", - "\n", - "# Function to evaluate the pipeline\n", - "def evaluate_pipeline(pipeline, X_train, y_train, X_valid, y_valid):\n", - " # Make predictions\n", - " train_preds = pipeline.predict(X_train)\n", - " valid_preds = pipeline.predict(X_valid)\n", - " \n", - " # Calculate scores\n", - " scores = {\n", - " \"Training MAE\": mean_absolute_error(y_train, train_preds),\n", - " \"Valid MAE\": mean_absolute_error(y_valid, valid_preds),\n", - " \"Training RMSLE\": root_mean_squared_log_error(y_train, train_preds),\n", - " \"Valid RMSLE\": root_mean_squared_log_error(y_valid, valid_preds),\n", - " \"Training R^2\": pipeline.score(X_train, y_train),\n", - " \"Valid R^2\": pipeline.score(X_valid, y_valid)\n", - " }\n", - " return scores\n", - "\n", - "# Fit and evaluate pipeline\n", - "print(f\"[INFO] Fitting model with one hot encoded values...\")\n", - "model_one_hot_pipeline.fit(X_train, y_train)\n", - "print(f\"[INFO] Evaluating model with one hot encoded values...\")\n", - "pipeline_one_hot_scores = evaluate_pipeline(model_one_hot_pipeline, X_train, y_train, X_valid, y_valid)\n", - "print(\"[INFO] Pipeline with one hot encoding scores:\")\n", - "pipeline_one_hot_scores" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Next:\n", - "# Go through TK's" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/section-3-structured-data-projects/end-to-end-bluebook-bulldozer-price-regression.ipynb b/section-3-structured-data-projects/end-to-end-bluebook-bulldozer-price-regression.ipynb deleted file mode 100644 index 11f287777..000000000 --- a/section-3-structured-data-projects/end-to-end-bluebook-bulldozer-price-regression.ipynb +++ /dev/null @@ -1,7331 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "TK - add Google Colab link as well as reference notebook etc" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 🚜 Predicting the Sale Price of Bulldozers using Machine Learning \n", - "\n", - "In this notebook, we're going to go through an example machine learning project to use the characteristics of bulldozers and their past sales prices to predict the sale price of future bulldozers based on their characteristics.\n", - "\n", - "* **Inputs:** Bulldozer characteristics such as make year, base model, model series, state of sale (e.g. which US state was it sold in), drive system and more.\n", - "* **Outputs:** Bulldozer sale price (in USD).\n", - "\n", - "Since we're trying to predict a number, this kind of problem is known as a **regression problem**.\n", - "\n", - "And since we're going to predicting results with a time component (predicting future sales based on past sales), this is also known as a **time series** or **forecasting** problem.\n", - "\n", - "The data and evaluation metric we'll be using (root mean square log error or RMSLE) is from the [Kaggle Bluebook for Bulldozers competition](https://www.kaggle.com/c/bluebook-for-bulldozers/overview).\n", - "\n", - "The techniques used in here have been inspired and adapted from [the fast.ai machine learning course](https://course18.fast.ai/ml)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Overview\n", - "\n", - "Since we already have a dataset, we'll approach the problem with the following machine learning modelling framework.\n", - "\n", - "| | \n", - "|:--:| \n", - "| 6 Step Machine Learning Modelling Framework ([read more](https://whimsical.com/9g65jgoRYTxMXxDosndYTB)) |\n", - "\n", - "To work through these topics, we'll use pandas, Matplotlib and NumPy for data analysis, as well as, Scikit-Learn for machine learning and modelling tasks.\n", - "\n", - "| | \n", - "|:--:| \n", - "| Tools that can be used for each step of the machine learning modelling process. |\n", - "\n", - "We'll work through each step and by the end of the notebook, we'll have a trained machine learning model which predicts the sale price of a bulldozer given different characteristics about it." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 6 Step Machine Learning Framework\n", - "\n", - "#### 1. Problem Definition\n", - "\n", - "For this dataset, the problem we're trying to solve, or better, the question we're trying to answer is,\n", - "\n", - "> How well can we predict the future sale price of a bulldozer, given its characteristics previous examples of how much similar bulldozers have been sold for?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 2. Data\n", - "\n", - "Looking at the [dataset from Kaggle](https://www.kaggle.com/c/bluebook-for-bulldozers/data), you can you it's a time series problem. This means there's a time attribute to dataset.\n", - "\n", - "In this case, it's historical sales data of bulldozers. Including things like, model type, size, sale date and more.\n", - "\n", - "There are 3 datasets:\n", - "\n", - "1. **Train.csv** - Historical bulldozer sales examples up to 2011 (close to 400,000 examples with 50+ different attributes, including `SalePrice` which is the **target variable**).\n", - "2. **Valid.csv** - Historical bulldozer sales examples from January 1 2012 to April 30 2012 (close to 12,000 examples with the same attributes as **Train.csv**).\n", - "3. **Test.csv** - Historical bulldozer sales examples from May 1 2012 to November 2012 (close to 12,000 examples but missing the `SalePrice` attribute, as this is what we'll be trying to predict).\n", - "\n", - "> **Note:** You can download the dataset `bluebook-for-bulldozers` dataset directly from Kaggle. Alternatively, you can also [download it directly from the course GitHub](https://github.com/mrdbourke/zero-to-mastery-ml/raw/refs/heads/master/data/bluebook-for-bulldozers.zip)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 3. Evaluation\n", - "\n", - "For this problem, [Kaggle has set the evaluation metric to being root mean squared log error (RMSLE)](https://www.kaggle.com/c/bluebook-for-bulldozers/overview/evaluation). As with many regression evaluations, the goal will be to get this value as low as possible.\n", - "\n", - "To see how well our model is doing, we'll calculate the RMSLE and then compare our results to others on the [Kaggle leaderboard](https://www.kaggle.com/c/bluebook-for-bulldozers/leaderboard)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 4. Features\n", - "\n", - "Features are different parts of the data. During this step, you'll want to start finding out what you can about the data.\n", - "\n", - "One of the most common ways to do this is to create a **data dictionary**.\n", - "\n", - "For this dataset, Kaggle provides a data dictionary which contains information about what each attribute of the dataset means. \n", - "\n", - "For example: \n", - "\n", - "| Variable Name | Description | Variable Type |\n", - "|------|-----|-----|\n", - "| SalesID | unique identifier of a particular sale of a machine at auction | Independent variable |\n", - "| MachineID | identifier for a particular machine; machines may have multiple sales | Independent variable |\n", - "| ModelID | identifier for a unique machine model (i.e. fiModelDesc) | Independent variable |\n", - "| datasource | source of the sale record; some sources are more diligent about reporting attributes of the machine than others. Note that a particular datasource may report on multiple auctioneerIDs. | Independent variable |\n", - "| auctioneerID | identifier of a particular auctioneer, i.e. company that sold the machine at auction. Not the same as datasource. | Independent variable |\n", - "| YearMade | year of manufacturer of the Machine | Independent variable |\n", - "| MachineHoursCurrentMeter | current usage of the machine in hours at time of sale (saledate); null or 0 means no hours have been reported for that sale | Independent variable |\n", - "| UsageBand | value (low, medium, high) calculated comparing this particular Machine-Sale hours to average usage for the fiBaseModel; e.g. 'Low' means this machine has fewer hours given its lifespan relative to the average of fiBaseModel. | Independent variable |\n", - "| Saledate | time of sale | Independent variable |\n", - "| fiModelDesc | Description of a unique machine model (see ModelID); concatenation of fiBaseModel & fiSecondaryDesc & fiModelSeries & fiModelDescriptor | Independent variable |\n", - "| State | US State in which sale occurred | Independent variable |\n", - "| Drive_System | machine configuration; typically describes whether 2 or 4 wheel drive | Independent variable |\n", - "| Enclosure | machine configuration - does the machine have an enclosed cab or not | Independent variable |\n", - "| Forks | machine configuration - attachment used for lifting | Independent variable |\n", - "| Pad_Type | machine configuration - type of treads a crawler machine uses | Independent variable |\n", - "| Ride_Control | machine configuration - optional feature on loaders to make the ride smoother | Independent variable |\n", - "| Transmission | machine configuration - describes type of transmission; typically automatic or manual | Independent variable |\n", - "| ... | ... | ... |\n", - "| SalePrice | cost of sale in USD | Target/dependent variable | \n", - "\n", - "\n", - "You can download the full version of this file directly from the [Kaggle competition page](https://www.kaggle.com/c/bluebook-for-bulldozers/download/Bnl6RAHA0enbg0UfAvGA%2Fversions%2FwBG4f35Q8mAbfkzwCeZn%2Ffiles%2FData%20Dictionary.xlsx) (account required) or view it [on Google Sheets](https://docs.google.com/spreadsheets/d/18ly-bLR8sbDJLITkWG7ozKm8l3RyieQ2Fpgix-beSYI/edit?usp=sharing).\n", - "\n", - "With all of this being known, let's get started! \n", - "\n", - "First, we'll import the dataset and start exploring. Since we know the evaluation metric we're trying to minimise, our first goal will be building a baseline model and seeing how it stacks up against the competition." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Notebook last run (end-to-end): 2024-10-21 14:31:32.217669\n" - ] - } - ], - "source": [ - "# Timestamp\n", - "import datetime\n", - "\n", - "import datetime\n", - "print(f\"Notebook last run (end-to-end): {datetime.datetime.now()}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 1. Importing the data and preparing it for modelling\n", - "\n", - "First thing is first, let's get the libraries we need imported and the data we'll need for the project.\n", - "\n", - "We'll start by importing pandas, NumPy and matplotlib." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pandas version: 2.2.2\n", - "NumPy version: 2.1.1\n", - "matplotlib version: 3.9.2\n" - ] - } - ], - "source": [ - "# Import data analysis tools \n", - "import pandas as pd\n", - "import numpy as np\n", - "import matplotlib\n", - "import matplotlib.pyplot as plt\n", - "\n", - "# Print the versions we're using (as long as your versions are equal or higher than these, the code should work)\n", - "print(f\"pandas version: {pd.__version__}\")\n", - "print(f\"NumPy version: {np.__version__}\")\n", - "print(f\"matplotlib version: {matplotlib.__version__}\") " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we've got our tools for data analysis ready, we can import the data and start to explore it.\n", - "\n", - "For this project, I've [downloaded the data from Kaggle](https://www.kaggle.com/c/bluebook-for-bulldozers/data) and stored it on the [course GitHub](https://github.com/mrdbourke/zero-to-mastery-ml/) under the file path [`../data/bluebook-for-bulldozers`](https://github.com/mrdbourke/zero-to-mastery-ml/blob/master/data/bluebook-for-bulldozers.zip).\n", - "\n", - "We can write some code to check if the files are available locally (on our computer) and if not, we can download them.\n", - "\n", - "> **Note:** If you're running this notebook on Google Colab, the code below will enable you to download the dataset programmatically. Just beware that each time Google Colab shuts down, the data will have to be redownloaded. There's also an [example Google Colab notebook](https://colab.research.google.com/drive/1hf1rTcCAQP1EN8pZ0ZIqjjEy47dwzbiv?usp=sharing) showing how to download the data programmatically." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] 'bluebook-for-bulldozers' dataset exists, feel free to proceed!\n", - "[INFO] Current dataset dir: ../data/bluebook-for-bulldozers\n" - ] - } - ], - "source": [ - "from pathlib import Path\n", - "\n", - "# Check if 'bluebook-for-bulldozers' exists in the current or parent directory\n", - "# Link to data (see the file \"bluebook-for-bulldozers\"): https://github.com/mrdbourke/zero-to-mastery-ml/tree/master/data\n", - "dataset_dir = Path(\"../data/bluebook-for-bulldozers\")\n", - "if not (dataset_dir.is_dir()):\n", - " print(f\"[INFO] Can't find existing 'bluebook-for-bulldozers' dataset in current directory or parent directory, downloading...\")\n", - "\n", - " # Download and unzip the bluebook for bulldozers dataset\n", - " !wget https://github.com/mrdbourke/zero-to-mastery-ml/raw/refs/heads/master/data/bluebook-for-bulldozers.zip\n", - " !unzip bluebook-for-bulldozers.zip\n", - "\n", - " # Ensure a data directory exists and move the downloaded dataset there\n", - " !mkdir ../data/\n", - " !mv bluebook-for-bulldozers ../data/\n", - " print(f\"[INFO] Current dataset dir: {dataset_dir}\")\n", - "\n", - " # Remove .zip file from notebook directory\n", - " !rm -rf bluebook-for-bulldozers.zip\n", - "else:\n", - " # If the target dataset directory exists, we don't need to download it\n", - " print(f\"[INFO] 'bluebook-for-bulldozers' dataset exists, feel free to proceed!\")\n", - " print(f\"[INFO] Current dataset dir: {dataset_dir}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Dataset downloaded!\n", - "\n", - "Let's check what files are available." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Files/folders available in ../data/bluebook-for-bulldozers:\n" - ] - }, - { - "data": { - "text/plain": [ - "['random_forest_benchmark_test.csv',\n", - " 'Valid.csv',\n", - " 'median_benchmark.csv',\n", - " 'Valid.zip',\n", - " 'TrainAndValid.7z',\n", - " 'Test.csv',\n", - " 'Train.7z',\n", - " 'test_predictions.csv',\n", - " 'ValidSolution.csv',\n", - " 'train_tmp.csv',\n", - " 'Machine_Appendix.csv',\n", - " 'Train.csv',\n", - " 'Valid.7z',\n", - " 'Data Dictionary.xlsx',\n", - " 'TrainAndValid.csv',\n", - " 'Train.zip',\n", - " 'TrainAndValid.zip']" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import os\n", - "\n", - "print(f\"[INFO] Files/folders available in {dataset_dir}:\")\n", - "os.listdir(dataset_dir)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can explore each of these files individually or read about them on the [Kaggle Competition page](https://www.kaggle.com/c/bluebook-for-bulldozers/data).\n", - "\n", - "For now, the main file we're interested in is `TrainAndValid.csv` (this is also a combination of `Train.csv` and `Valid.csv`), this is a combination of the training and validation datasets.\n", - "\n", - "* The training data (`Train.csv`) contains sale data from 1989 up to the end of 2011.\n", - "* The validation data (`Valid.csv`) contains sale data from January 1, 2012 - April 30, 2012.\n", - "* The test data (`Test.csv`) contains sale data from May 1, 2012 - November 2012.\n", - "\n", - "We'll use the training data to train our model to predict the sale price of bulldozers, we'll then validate its performance on the validation data to see if our model can be improved in any way. Finally, we'll evaluate our best model on the test dataset.\n", - "\n", - "But more on this later on.\n", - "\n", - "Let's import the `TrainAndValid.csv` file and turn it into a pandas DataFrame." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/var/folders/c4/qj4gdk190td18bqvjjh0p3p00000gn/T/ipykernel_21543/1127193594.py:2: DtypeWarning: Columns (13,39,40,41) have mixed types. Specify dtype option on import or set low_memory=False.\n", - " df = pd.read_csv(filepath_or_buffer=\"../data/bluebook-for-bulldozers/TrainAndValid.csv\")\n" - ] - } - ], - "source": [ - "# Import the training and validation set\n", - "df = pd.read_csv(filepath_or_buffer=\"../data/bluebook-for-bulldozers/TrainAndValid.csv\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Wonderful! We've got our DataFrame ready to explore.\n", - "\n", - "You might see a warning appear in the form:\n", - "\n", - "`DtypeWarning: Columns (13,39,40,41) have mixed types. Specify dtype option on import or set low_memory=False. df = pd.read_csv(\"../data/bluebook-for-bulldozers/TrainAndValid.csv\")`\n", - "\n", - "This is just saying that some of our columns have multiple/mixed data types. For example, a column may contain strings but also contain integers. This is okay for now and can be addressed later on if necessary.\n", - "\n", - "How about we get some information about our DataFrame?\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "RangeIndex: 412698 entries, 0 to 412697\n", - "Data columns (total 53 columns):\n", - " # Column Non-Null Count Dtype \n", - "--- ------ -------------- ----- \n", - " 0 SalesID 412698 non-null int64 \n", - " 1 SalePrice 412698 non-null float64\n", - " 2 MachineID 412698 non-null int64 \n", - " 3 ModelID 412698 non-null int64 \n", - " 4 datasource 412698 non-null int64 \n", - " 5 auctioneerID 392562 non-null float64\n", - " 6 YearMade 412698 non-null int64 \n", - " 7 MachineHoursCurrentMeter 147504 non-null float64\n", - " 8 UsageBand 73670 non-null object \n", - " 9 saledate 412698 non-null object \n", - " 10 fiModelDesc 412698 non-null object \n", - " 11 fiBaseModel 412698 non-null object \n", - " 12 fiSecondaryDesc 271971 non-null object \n", - " 13 fiModelSeries 58667 non-null object \n", - " 14 fiModelDescriptor 74816 non-null object \n", - " 15 ProductSize 196093 non-null object \n", - " 16 fiProductClassDesc 412698 non-null object \n", - " 17 state 412698 non-null object \n", - " 18 ProductGroup 412698 non-null object \n", - " 19 ProductGroupDesc 412698 non-null object \n", - " 20 Drive_System 107087 non-null object \n", - " 21 Enclosure 412364 non-null object \n", - " 22 Forks 197715 non-null object \n", - " 23 Pad_Type 81096 non-null object \n", - " 24 Ride_Control 152728 non-null object \n", - " 25 Stick 81096 non-null object \n", - " 26 Transmission 188007 non-null object \n", - " 27 Turbocharged 81096 non-null object \n", - " 28 Blade_Extension 25983 non-null object \n", - " 29 Blade_Width 25983 non-null object \n", - " 30 Enclosure_Type 25983 non-null object \n", - " 31 Engine_Horsepower 25983 non-null object \n", - " 32 Hydraulics 330133 non-null object \n", - " 33 Pushblock 25983 non-null object \n", - " 34 Ripper 106945 non-null object \n", - " 35 Scarifier 25994 non-null object \n", - " 36 Tip_Control 25983 non-null object \n", - " 37 Tire_Size 97638 non-null object \n", - " 38 Coupler 220679 non-null object \n", - " 39 Coupler_System 44974 non-null object \n", - " 40 Grouser_Tracks 44875 non-null object \n", - " 41 Hydraulics_Flow 44875 non-null object \n", - " 42 Track_Type 102193 non-null object \n", - " 43 Undercarriage_Pad_Width 102916 non-null object \n", - " 44 Stick_Length 102261 non-null object \n", - " 45 Thumb 102332 non-null object \n", - " 46 Pattern_Changer 102261 non-null object \n", - " 47 Grouser_Type 102193 non-null object \n", - " 48 Backhoe_Mounting 80712 non-null object \n", - " 49 Blade_Type 81875 non-null object \n", - " 50 Travel_Controls 81877 non-null object \n", - " 51 Differential_Type 71564 non-null object \n", - " 52 Steering_Controls 71522 non-null object \n", - "dtypes: float64(3), int64(5), object(45)\n", - "memory usage: 166.9+ MB\n" - ] - } - ], - "source": [ - "# Get info about DataFrame\n", - "df.info()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Woah! Over 400,000 entries!\n", - "\n", - "That's a much larger dataset than what we've worked with before.\n", - "\n", - "One thing you might have noticed is that the `saledate` column value is being treated as a Python object (it's okay if you didn't notice, these things take practice).\n", - "\n", - "When the `Dtype` is `object`, it's saying that it's a string.\n", - "\n", - "However, when look at it...\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0 11/16/2006 0:00\n", - "1 3/26/2004 0:00\n", - "2 2/26/2004 0:00\n", - "3 5/19/2011 0:00\n", - "4 7/23/2009 0:00\n", - "5 12/18/2008 0:00\n", - "6 8/26/2004 0:00\n", - "7 11/17/2005 0:00\n", - "8 8/27/2009 0:00\n", - "9 8/9/2007 0:00\n", - "Name: saledate, dtype: object" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df[\"saledate\"][:10]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can see that these `object`'s are in the form of dates.\n", - "\n", - "Since we're working on a **time series** problem (a machine learning problem with a time component), it's probably worth it to turn these strings into Python `datetime` objects.\n", - "\n", - "Before we do, let's try visualize our `saledate` column against our `SalePrice` column.\n", - "\n", - "To do so, we can create a scatter plot.\n", - "\n", - "And to prevent our plot from being too big, how about we visualize the first 1000 values?" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fig, ax = plt.subplots()\n", - "ax.scatter(x=df[\"saledate\"][:1000], # visualize the first 1000 values\n", - " y=df[\"SalePrice\"][:1000])\n", - "ax.set_xlabel(\"Sale Date\")\n", - "ax.set_ylabel(\"Sale Price ($)\");" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Hmm... looks like the x-axis is quite crowded.\n", - "\n", - "Maybe we can fix this by turning the `saledate` column into `datetime` format.\n", - "\n", - "Good news is that is looks like our `SalePrice` column is already in `float64` format so we can view its distribution directly from the DataFrame using a histogram plot." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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HntMJSUll3fk7q7Y2FjNnTvX0gYBAABqgyqFqgYNGuiNN97Q3Llz9Z///EeS9NOf/lQNGza0tDkAAIDa4kct/nn69GmdPn1abdu2VcOGDWUYhlV9AQAA1CpVClXffPON+vTpo7vuukv9+/fX6dOnJUmxsbEspwAAAOqkKoWqMWPGqH79+jpx4oQaNGhgbh84cKBSUlIsaw4AAKC2qNI9VR9++KE2btyoli1bumxv27atjh8/bkljAAAAtUmVrlQVFha6XKEqk5eXJ09Pzx/dFAAAQG1TpVB1//3365133jGf22w2lZaWKjExUQ899JBlzQEAANQWVfr4LzExUX369FFmZqaKi4s1YcIE7d+/X3l5edq+fbvVPQIAANR4VbpS1alTJx0+fFi9e/fWb3/7WxUWFuqRRx7R7t279dOf/tTqHgEAAGq8G75SVVJSon79+ikpKUlTpky5GT0BAADUOjd8pap+/frau3fvzegFAACg1qrSx3+PP/64/va3v1ndCwAAQK1VpRvVL168qL///e/66KOP1L1793K/+Td//nxLmgMAAKgtbihUffnllwoODlZOTo66desmSTp8+LBLjc1ms647AACAWuKGQlXbtm11+vRpbd68WdLln6VZtGiRAgICbkpzAAAAtcUN3VNlGIbL8w8++ECFhYWWNgQAAFAbVelG9TI/DFkAAAB11Q2FKpvNVu6eKe6hAgAAuMF7qgzD0BNPPGH+aPKFCxf09NNPl/v23+rVq63rEAAAoBa4oVA1bNgwl+ePP/64pc0AAADUVjcUqt56662b1QcAAECt9qNuVAcAAMBlhCoAAAAL1PhQ9fXXX+vxxx9Xs2bN5O3trdDQUGVmZprjhmFo+vTpatGihby9vRUREaEjR4647CMvL08xMTHy8fGRn5+fYmNjdf78eZeavXv36v7775eXl5eCgoKUmJhYrpdVq1apffv28vLyUmhoqDZs2HBzThoAANQ6NTpUnTt3Tvfdd5/q16+vDz74QJ9//rnmzZunJk2amDWJiYlatGiRkpKSlJGRoYYNGyoyMlIXLlwwa2JiYrR//36lpqZq3bp12rJli0aMGGGOO51O9e3bV61bt1ZWVpbmzp2rmTNnaunSpWbNp59+qsGDBys2Nla7d+9WdHS0oqOjlZOTc2smAwAA1Gg2owav4Dlp0iRt375dW7durXDc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8ZOf/MSYPXt2uV7effdd46677jI8PDyMjh07GuvXr7f+hCvgdDqN0aNHG61atTK8vLyMO++805gyZYrLG+ftOA+bN2+u8G/BsGHDatw5V6YXq+fg6NGjV/17uXnz5ttmDq43DxWpKFTV1nmwGcYVy/wCAACgSrinCgAAwAKEKgAAAAsQqgAAACxAqAIAALAAoQoAAMAChCoAAAALEKoAAAAsQKgCAACwAKEKwG0rOTlZfn5+1XLsn//854qPj7/pxxkyZIheeeWVctuPHTummTNnltteXFys4OBgZWZm3vTegLqGUAWgRjp79qxGjhypVq1aydPTU4GBgYqMjNT27dtvaR8zZ86UzWaTzWaTu7u7goODNWbMGJ0/f/6ar1u9erVefPHFm9rbnj17tGHDBj333HOVfo2Hh4fGjRuniRMn3sTOgLrJvbobAICKDBgwQMXFxXr77bd15513Kjc3V2lpafrmm29ueS8dO3bURx99pIsXL2r79u166qmn9N133+nNN98sV1tcXCwPDw81bdr0pvf12muv6fe//70aNWpkbjt69KgSEhKUnp4up9OpFStW6Oc//7mSkpLMmpiYGI0dO1b79+9Xx44db3qfQF3BlSoANU5+fr62bt2qOXPm6KGHHlLr1q3Vs2dPTZ48Wb/5zW/Muvnz5ys0NFQNGzZUUFCQnnnmmeteQfr3v/+tbt26ycvLS3feeadeeOEFXbx48ZqvcXd3V2BgoFq2bKmBAwcqJiZGa9eulXT5SlaXLl3017/+VSEhIfLy8pJU/uO/oqIiTZw4UUFBQfL09FSbNm30t7/9zRzPycnRr371KzVq1EgBAQEaMmSI/vvf/161p0uXLul///d/9fDDD7tsHzp0qHJzc7VkyRI98cQTWrhwoZo1a+ZS06RJE913331asWLFNc8bwI0hVAGocRo1aqRGjRppzZo1Kioqumqdm5ubFi1apP379+vtt9/Wpk2bNGHChKvWb926VUOHDtXo0aP1+eef680331RycrJefvnlG+rP29tbxcXF5vMvvvhC//rXv7R69WplZ2dX+JqhQ4fqn//8pxYtWqQDBw7ozTffNK8w5efn6xe/+IW6du2qzMxMpaSkKDc3V3/4wx+u2sPevXtVUFCgHj16uGzfvXu34uLi1LVrV/n7+ysyMrLC8+vZs6e2bt16Q+cN4Nr4+A9AjePu7q7k5GQNHz5cSUlJ6tatmx588EENGjRIP/vZz8y6K68EBQcH66WXXtLTTz+tN954o8L9vvDCC5o0aZKGDRsmSbrzzjv14osvasKECZoxY0alesvKytLy5cv1i1/8wtxWXFysd955R3fccUeFrzl8+LDeffddpaamKiIiwjx2mcWLF6tr164uN5z//e9/V1BQkA4fPqy77rqr3D6PHz+uevXqyd/f32X7fffdpwULFqi0tPSa52G323X8+PHrnzCASuNKFYAaacCAATp16pTWrl2rfv366eOPP1a3bt2UnJxs1nz00Ufq06ePfvKTn6hx48YaMmSIvvnmG3333XcV7nPPnj3685//bF4Ja9SokYYPH67Tp09f9TWStG/fPjVq1Eje3t7q2bOnwsPDtXjxYnO8devWVw1UkpSdna169erpwQcfvGpfmzdvdumrffv2kqT//Oc/Fb7m+++/l6enp2w2m8v2ZcuWqVevXnr++ef18ssvKzw8XP/7v/9b7vXe3t7XPGcAN44rVQBqLC8vL/3yl7/UL3/5S02bNk1//OMfNWPGDD3xxBM6duyYfv3rX2vkyJF6+eWX1bRpU23btk2xsbEqLi5WgwYNyu3v/PnzeuGFF/TII49UeKyradeundauXSt3d3fZ7XZ5eHi4jDds2PCa5+Ht7X3N8fPnz+vhhx/WnDlzyo21aNGiwtc0b95c3333nXlj/JXbX3vtNY0dO1azZ89WcHCwBg4cqA8++EB9+/Y16/Ly8q4ZBAHcOEIVgFqjQ4cOWrNmjaTLH8OVlpZq3rx5cnO7fNH93Xffvebru3XrpkOHDqlNmzY3dFwPD48bfs2VQkNDVVpaqk8++cT8+O+Hff3rX/9ScHCw3N0r92e5S5cukqTPP//c/O8fCgwM1KRJk7Rq1Spt3brVJVTl5OSoa9euN3wuAK6Oj/8A1DjffPONfvGLX+gf//iH9u7dq6NHj2rVqlVKTEzUb3/7W0lSmzZtVFJSotdee01ffvml/t//+38uywZUZPr06XrnnXf0wgsvaP/+/Tpw4IBWrFihqVOn3tTzCQ4O1rBhw/TUU09pzZo1Onr0qD7++GMzBMbFxSkvL0+DBw/Wzp079Z///EcbN27Uk08+qUuXLlW4zzvuuEPdunXTtm3bXLbHxsZqx44dKiwsVFFRkVavXq39+/ere/fuLnU/DFkAfjxCFYAap1GjRgoLC9Orr76qBx54QJ06ddK0adM0fPhw816mzp07a/78+ZozZ446deqkZcuWadasWdfcb2RkpNatW6cPP/xQ99xzj3r16qVXX31VrVu3vunntGTJEj366KN65pln1L59ew0fPlyFhYWSLt80vn37dl26dEl9+/ZVaGio4uPj5efnZ16Fq8gf//hHLVu2zGWbv7+/nnrqKfXs2VNz587VuHHj9OKLLyo6OtqsSU9PV0FBgR599NGbcq5AXWUzDMOo7iYAADfu+++/V7t27bRy5UqFh4e7jB07dkzJyckV/lTNwIED1blzZz3//PO3qFOgbuBKFQDUUt7e3nrnnXeuuUjoDxUXFys0NFRjxoy5iZ0BdRNXqgAAACzAlSoAAAALEKoAAAAsQKgCAACwAKEKAADAAoQqAAAACxCqAAAALECoAgAAsAChCgAAwAKEKgAAAAv8f4g4XKxyi22QAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# View SalePrice distribution \n", - "df.SalePrice.plot.hist(xlabel=\"Sale Price ($)\");" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 1.1 Parsing dates\n", - "\n", - "When working with time series data, it's a good idea to make sure any date data is the format of a [datetime object](https://docs.python.org/3/library/datetime.html) (a Python data type which encodes specific information about dates).\n", - "\n", - "We can tell pandas which columns to read in as dates by setting the `parse_dates` parameter in [`pd.read_csv`](https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html).\n", - "\n", - "Once we've imported our CSV with the `saledate` column parsed, we can view information about our DataFrame again with `df.info()`. " - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "RangeIndex: 412698 entries, 0 to 412697\n", - "Data columns (total 53 columns):\n", - " # Column Non-Null Count Dtype \n", - "--- ------ -------------- ----- \n", - " 0 SalesID 412698 non-null int64 \n", - " 1 SalePrice 412698 non-null float64 \n", - " 2 MachineID 412698 non-null int64 \n", - " 3 ModelID 412698 non-null int64 \n", - " 4 datasource 412698 non-null int64 \n", - " 5 auctioneerID 392562 non-null float64 \n", - " 6 YearMade 412698 non-null int64 \n", - " 7 MachineHoursCurrentMeter 147504 non-null float64 \n", - " 8 UsageBand 73670 non-null object \n", - " 9 saledate 412698 non-null datetime64[ns]\n", - " 10 fiModelDesc 412698 non-null object \n", - " 11 fiBaseModel 412698 non-null object \n", - " 12 fiSecondaryDesc 271971 non-null object \n", - " 13 fiModelSeries 58667 non-null object \n", - " 14 fiModelDescriptor 74816 non-null object \n", - " 15 ProductSize 196093 non-null object \n", - " 16 fiProductClassDesc 412698 non-null object \n", - " 17 state 412698 non-null object \n", - " 18 ProductGroup 412698 non-null object \n", - " 19 ProductGroupDesc 412698 non-null object \n", - " 20 Drive_System 107087 non-null object \n", - " 21 Enclosure 412364 non-null object \n", - " 22 Forks 197715 non-null object \n", - " 23 Pad_Type 81096 non-null object \n", - " 24 Ride_Control 152728 non-null object \n", - " 25 Stick 81096 non-null object \n", - " 26 Transmission 188007 non-null object \n", - " 27 Turbocharged 81096 non-null object \n", - " 28 Blade_Extension 25983 non-null object \n", - " 29 Blade_Width 25983 non-null object \n", - " 30 Enclosure_Type 25983 non-null object \n", - " 31 Engine_Horsepower 25983 non-null object \n", - " 32 Hydraulics 330133 non-null object \n", - " 33 Pushblock 25983 non-null object \n", - " 34 Ripper 106945 non-null object \n", - " 35 Scarifier 25994 non-null object \n", - " 36 Tip_Control 25983 non-null object \n", - " 37 Tire_Size 97638 non-null object \n", - " 38 Coupler 220679 non-null object \n", - " 39 Coupler_System 44974 non-null object \n", - " 40 Grouser_Tracks 44875 non-null object \n", - " 41 Hydraulics_Flow 44875 non-null object \n", - " 42 Track_Type 102193 non-null object \n", - " 43 Undercarriage_Pad_Width 102916 non-null object \n", - " 44 Stick_Length 102261 non-null object \n", - " 45 Thumb 102332 non-null object \n", - " 46 Pattern_Changer 102261 non-null object \n", - " 47 Grouser_Type 102193 non-null object \n", - " 48 Backhoe_Mounting 80712 non-null object \n", - " 49 Blade_Type 81875 non-null object \n", - " 50 Travel_Controls 81877 non-null object \n", - " 51 Differential_Type 71564 non-null object \n", - " 52 Steering_Controls 71522 non-null object \n", - "dtypes: datetime64[ns](1), float64(3), int64(5), object(44)\n", - "memory usage: 166.9+ MB\n" - ] - } - ], - "source": [ - "df = pd.read_csv(filepath_or_buffer=\"../data/bluebook-for-bulldozers/TrainAndValid.csv\",\n", - " low_memory=False, # set low_memory=False to prevent mixed data types warning \n", - " parse_dates=[\"saledate\"]) # can use the parse_dates parameter and specify which column to treat as a date column\n", - "\n", - "# With parse_dates... check dtype of \"saledate\"\n", - "df.info()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Nice!\n", - "\n", - "Looks like our `saledate` column is now of type [`datetime64[ns]`](https://numpy.org/doc/stable/reference/arrays.scalars.html#numpy.datetime64), a NumPy-specific datetime format with high precision.\n", - "\n", - "Since pandas works well with NumPy, we can keep it in this format.\n", - "\n", - "How about we view a few samples from our `SaleDate` column again?" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0 2006-11-16\n", - "1 2004-03-26\n", - "2 2004-02-26\n", - "3 2011-05-19\n", - "4 2009-07-23\n", - "5 2008-12-18\n", - "6 2004-08-26\n", - "7 2005-11-17\n", - "8 2009-08-27\n", - "9 2007-08-09\n", - "Name: saledate, dtype: datetime64[ns]" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df[\"saledate\"][:10]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Beautiful! That's looking much better already. \n", - "\n", - "We'll see how having our dates in this format is really helpful later on.\n", - "\n", - "For now, how about we visualize our `saledate` column against our `SalePrice` column again?" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fig, ax = plt.subplots()\n", - "ax.scatter(x=df[\"saledate\"][:1000], # visualize the first 1000 values\n", - " y=df[\"SalePrice\"][:1000])\n", - "ax.set_xlabel(\"Sale Date\")\n", - "ax.set_ylabel(\"Sale Price ($)\");" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 1.2 Sorting our DataFrame by saledate\n", - "\n", - "Now we've formatted our `saledate` column to be NumPy `datetime64[ns]` objects, we can use built-in pandas methods such as `sort_values` to sort our DataFrame by date.\n", - "\n", - "And considering this is a time series problem, sorting our DataFrame by date has the added benefit of making sure our data is sequential.\n", - "\n", - "In other words, we want to use examples from the past (example sale prices from previous dates) to try and predict future bulldozer sale prices. \n", - "\n", - "Let's use the [`pandas.DataFrame.sort_values`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.sort_values.html) method to sort our DataFrame by `saledate` in ascending order." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(205615 1989-01-17\n", - " 274835 1989-01-31\n", - " 141296 1989-01-31\n", - " 212552 1989-01-31\n", - " 62755 1989-01-31\n", - " 54653 1989-01-31\n", - " 81383 1989-01-31\n", - " 204924 1989-01-31\n", - " 135376 1989-01-31\n", - " 113390 1989-01-31\n", - " Name: saledate, dtype: datetime64[ns],\n", - " 409202 2012-04-28\n", - " 408976 2012-04-28\n", - " 411695 2012-04-28\n", - " 411319 2012-04-28\n", - " 408889 2012-04-28\n", - " 410879 2012-04-28\n", - " 412476 2012-04-28\n", - " 411927 2012-04-28\n", - " 407124 2012-04-28\n", - " 409203 2012-04-28\n", - " Name: saledate, dtype: datetime64[ns])" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Sort DataFrame in date order\n", - "df.sort_values(by=[\"saledate\"], inplace=True, ascending=True)\n", - "df.saledate.head(10), df.saledate.tail(10)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Nice!\n", - "\n", - "Looks like our older samples are now coming first and the newer samples are towards the end of the DataFrame." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 1.3 Adding extra features to our DataFrame\n", - "\n", - "One way to potentially increase the predictive power of our data is to enhance it with more features.\n", - "\n", - "This practice is known as [**feature engineering**](https://en.wikipedia.org/wiki/Feature_engineering), taking existing features and using them to create more/different features. \n", - "\n", - "There is no set in stone way to do feature engineering and often it takes quite a bit of practice/exploration/experimentation to figure out what might work and what won't.\n", - "\n", - "For now, we'll use our `saledate` column to add extra features such as:\n", - "\n", - "* Year of sale\n", - "* Month of sale\n", - "* Day of sale\n", - "* Day of week sale (e.g. Monday = 1, Tuesday = 2)\n", - "* Day of year sale (e.g. January 1st = 1, January 2nd = 2)\n", - "\n", - "Since we're going to be manipulating the data, we'll make a copy of the original DataFrame and perform our changes there.\n", - "\n", - "This will keep the original DataFrame in tact if we need it again." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "# Make a copy of the original DataFrame to perform edits on\n", - "df_tmp = df.copy()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Because we imported the data using `read_csv()` and we asked pandas to parse the dates using `parase_dates=[\"saledate\"]`, we can now access the [different datetime attributes](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DatetimeIndex.html) of the `saledate` column.\n", - "\n", - "Let's use these attributes to add a series of different feature columns to our dataset. \n", - "\n", - "After we've added these extra columns, we can remove the original `saledate` column as its information will be dispersed across these new columns." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "# Add datetime parameters for saledate\n", - "df_tmp[\"saleYear\"] = df_tmp.saledate.dt.year\n", - "df_tmp[\"saleMonth\"] = df_tmp.saledate.dt.month\n", - "df_tmp[\"saleDay\"] = df_tmp.saledate.dt.day\n", - "df_tmp[\"saleDayofweek\"] = df_tmp.saledate.dt.dayofweek\n", - "df_tmp[\"saleDayofyear\"] = df_tmp.saledate.dt.dayofyear\n", - "\n", - "# Drop original saledate column\n", - "df_tmp.drop(\"saledate\", axis=1, inplace=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We could add more of these style of columns, such as, whether it was the start or end of a quarter (the sale being at the end of a quarter may bye influenced by things such as quarterly budgets) but these will do for now.\n", - "\n", - "> **Challenge:** See what other [datetime attributes](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DatetimeIndex.html) you can add to `df_tmp` using a similar technique to what we've used above. Hint: check the bottom of the pandas.DatetimeIndex docs.\n", - "\n", - "How about we view some of our newly created columns?" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - "
SalePricesaleYearsaleMonthsaleDaysaleDayofweeksaleDayofyear
2056159500.01989117117
27483514000.01989131131
14129650000.01989131131
21255216000.01989131131
6275522000.01989131131
\n", - "
" - ], - "text/plain": [ - " SalePrice saleYear saleMonth saleDay saleDayofweek saleDayofyear\n", - "205615 9500.0 1989 1 17 1 17\n", - "274835 14000.0 1989 1 31 1 31\n", - "141296 50000.0 1989 1 31 1 31\n", - "212552 16000.0 1989 1 31 1 31\n", - "62755 22000.0 1989 1 31 1 31" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# View newly created columns\n", - "df_tmp[[\"SalePrice\", \"saleYear\", \"saleMonth\", \"saleDay\", \"saleDayofweek\", \"saleDayofyear\"]].head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Cool!\n", - "\n", - "Now we've broken our `saledate` column into columns/features, we can perform further exploratory analysis such as visualizing the `SalePrice` against the `saleMonth`.\n", - "\n", - "How about we view the first 10,000 samples (we could also randomly select 10,000 samples too) to see if reveals anything about which month has the highest sales?" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# View 10,000 samples SalePrice against saleMonth\n", - "fig, ax = plt.subplots()\n", - "ax.scatter(x=df_tmp[\"saleMonth\"][:10000], # visualize the first 10000 values\n", - " y=df_tmp[\"SalePrice\"][:10000])\n", - "ax.set_xlabel(\"Sale Month\")\n", - "ax.set_ylabel(\"Sale Price ($)\");" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Hmm... doesn't look like there's too much conclusive evidence here about which month has the highest sales value.\n", - "\n", - "How about we plot the median sale price of each month?\n", - "\n", - "We can do so by grouping on the `saleMonth` column with [`pandas.DataFrame.groupby`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.groupby.html) and then getting the median of the `SalePrice` column." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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h0ajgUajgZeXl/lxjzzyCMaPH4+oqCjMnj0bFRUV2L59e7PtAyKyD7nYARAROVKbNm0watQoLFiwAIIgYNSoUQgMDDTff+TIEdTV1WHgwIHm2zw8PNC3b1/k5ORYbKt79+7mv0NCQgAAJSUl110fdenjfHx8oFarUVJS0qTXRUTNj0kTEbm9Rx99FMnJyQCAOXPmNHo7Hh4e5r8lEgkAwGg02vQ402OteRwRORdOzxGR27vttttQW1uLuro6JCYmWtzXsWNHKBQK/Pnnn+bb6urqsGPHDsTExFj9HAqFAgaDwW4xE5Hz4ZEmInJ7MpnMPNUmk8ks7vPx8cHTTz+NKVOmICAgABEREXjnnXdQWVmJxx57zOrnaN++PY4dO4asrCyEhYVBpVJBqVTa9XUQkbiYNBFRi6BWq69631tvvQWj0YiHHnoI5eXl6N27N9auXYtWrVpZvf277roLS5cuxZAhQ3D+/HnMnz/frsUziUh8EkEQBLGDICIiInJ2XNNEREREZAUmTURERERWYNJEREREZAUmTURERERWYNJEREREZAUmTURERERWYNJEREREZAUmTURERERWYNJEREREZAUmTURERERWYNJEREREZIX/B6H/lxw8qGnwAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Group DataFrame by saleMonth and then find the median SalePrice\n", - "df_tmp.groupby([\"saleMonth\"])[\"SalePrice\"].median().plot()\n", - "plt.xlabel(\"Month\")\n", - "plt.ylabel(\"Median Sale Price ($)\");" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Ohhh it looks like the median sale prices of January and February (months 1 and 2) are quite a bit higher than the other months of the year.\n", - "\n", - "Could this be because of New Year budget spending?\n", - "\n", - "Perhaps... but this would take a bit more investigation.\n", - "\n", - "In the meantime, there are many other values we could look further into." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### TK - 1.4 Inspect values of other columns\n", - "\n", - "When first exploring a new problem, it's often a good idea to become as familiar with the data as you can.\n", - "\n", - "Of course, with a dataset that has over 400,000 samples, it's unlikely you'll ever get through every sample.\n", - "\n", - "But that's where the power of data analysis and machine learning can help.\n", - "\n", - "We can use pandas to aggregate thousands of samples into smaller more managable pieces.\n", - "\n", - "And as we'll see later on, we can use machine learning models to model the data and then later inspect which features the model thought were most important.\n", - "\n", - "How about we see which states sell the most bulldozers?" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "state\n", - "Florida 67320\n", - "Texas 53110\n", - "California 29761\n", - "Washington 16222\n", - "Georgia 14633\n", - "Maryland 13322\n", - "Mississippi 13240\n", - "Ohio 12369\n", - "Illinois 11540\n", - "Colorado 11529\n", - "Name: count, dtype: int64" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Check the different values of different columns\n", - "df_tmp.state.value_counts()[:10]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Woah! Looks like Flordia sells a fair few bulldozers.\n", - "\n", - "How about we go even further and group our samples by `state` and then find the median `SalePrice` per state?\n", - "\n", - "We also compare this to the median `SalePrice` for all samples." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA2QAAAKZCAYAAADXk+i7AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAADReElEQVR4nOzdeZxO5f/H8ffMMGMdO0O2kew7YVIhMpZkS5IYQj9b35gsKVkrpa81SlKWQmhRKLKnDAljX0pEMSjMMJgZM9fvD9/7bm4z92o44vV8PO4Hc87nOuc6630+97nOdfyMMUYAAAAAgFvO3+oKAAAAAMDdioQMAAAAACxCQgYAAAAAFiEhAwAAAACLkJABAAAAgEVIyAAAAADAIiRkAAAAAGCRTFZX4E6RkpKiEydOKGfOnPLz87O6OgAAAAAsYozRhQsXVKRIEfn7u74HRkKWQU6cOKFixYpZXQ0AAAAAt4njx4+raNGiLmNIyDJIzpw5JV1b6cHBwRbXBgAAAIBV4uLiVKxYMXuO4AoJWQaxNVMMDg4mIQMAAADg0aNMdOoBAAAAABYhIQMAAAAAi5CQAQAAAIBFeIbsFktOTlZSUpLV1QDgRubMmRUQEGB1NQAAwB2OhOwWMcYoJiZG58+ft7oqADyUO3duhYSE8G5BAABw05CQ3SK2ZKxgwYLKli0bF3jAbcwYo0uXLun06dOSpMKFC1tcIwAAcKciIbsFkpOT7clYvnz5rK4OAA9kzZpVknT69GkVLFiQ5osAAOCmoFOPW8D2zFi2bNksrgkAb9iOWZ77BAAANwsJ2S1EM0Xg34VjFgAA3GwkZAAAAABgERIyAAAAALAICRkst379evn5+dlfCTB79mzlzp3b0jp5ysq6NmjQQP3797dk3pLUtWtXy+YNAABwpyAhg0tdu3aVn5+fevXqlWZc37595efnl+EX5h06dNChQ4cydJrpOXPmjHr37q3ixYsrKChIISEhCg8P148//njT553ayJEj5efnJz8/P2XKlEklS5bUgAEDdPHiRZflvvjiC40ZM+YW1dIzSUlJGjJkiCpXrqzs2bOrSJEi6tKli06cOJFufEJCgqpVqyY/Pz9FR0e7nPaVK1fUt29f5cuXTzly5FC7du106tQph5hjx46pRYsWypYtmwoWLKhBgwbp6tWrDjHr169XjRo1FBQUpNKlS2v27Nk3ssgAAAA3hIQMbhUrVkyffvqpLl++bB925coVzZ8/X8WLF8/w+WXNmlUFCxbM8Oler127dtqxY4fmzJmjQ4cO6euvv1aDBg30999/3/R5X69ixYo6efKkjh49qrfeekszZszQiy++mG5sYmKiJClv3rzKmTPnraym/vrrL0VERKh48eJasGCBSpcurfbt29vrdOnSJW3fvl2vvvqqtm/fri+++EIHDx7U448/nu70Bg8erCJFing07wEDBmjp0qVavHixNmzYoBMnTqht27b28cnJyWrRooUSExO1adMmzZkzR7Nnz9bw4cPtMUeOHFGLFi3UsGFDRUdHq3///urRo4dWrlx5A2sFAADgBhhkiNjYWCPJxMbGphl3+fJls2/fPnP58uW0BS9edP65Pt5V7KVL7mN9EBERYVq1amUqVapkPvnkE/vwefPmmSpVqphWrVqZiIgI+/Dk5GTzxhtvmJIlS5osWbKYKlWqmMWLFztMc/ny5ea+++4zWbJkMQ0aNDCzZs0yksy5c+eMMcbMmjXL5MqVyx7/66+/mscff9wULFjQZM+e3dSqVcusWrXKYZolSpQwr7/+uunWrZvJkSOHKVasmHn//fedLte5c+eMJLN+/XqXyz9+/HhTqVIlky1bNlO0aFHTu3dvc+HCBfv46+tqjDFLliwx1atXN0FBQSY0NNSMHDnSJCUlOZ3HiBEjTNWqVR2G9ezZ04SEhDiM/+CDD0zJkiWNn5+fMcaY+vXrmxdeeMFe5sqVK2bw4MGmaNGiJjAw0Nx7771m5syZ9vG7d+82TZs2NdmzZzcFCxY0zzzzjDlz5ozL5b/eM888Y8qUKWPWr19vWrdubdauXWsGDx6c/r79Pz/99JORZH7//XeH4d98840pV66c2bt3r5FkduzY4XQa58+fN5kzZ3bYl/bv328kmaioKPv0/P39TUxMjD3mvffeM8HBwSYhIcEYY8zgwYNNxYoVHabdoUMHEx4enu58XR67AAAATrjKDa7HHTKr5cjh/NOunWNswYLOY5s1c4wtWTJtzA149tlnNWvWLPvfH330kbp165YmbuzYsZo7d66mT5+uvXv3asCAAXrmmWe0YcMGSdLx48fVtm1btWzZUtHR0erRo4deeukll/O+ePGimjdvrjVr1mjHjh1q2rSpWrZsqWPHjjnEjR8/XrVq1dKOHTvUp08f9e7dWwcPHkx3mjly5FCOHDm0ZMkSJSQkOJ23v7+/pkyZor1792rOnDlau3atBg8e7DR+48aN6tKli1544QXt27dP77//vmbPnq3XX3/d5TJeL2vWrPa7TpL066+/6vPPP9cXX3zhtGlfly5dtGDBAk2ZMkX79+/X+++/rxz/2+7nz5/XI488ourVq+vnn3/WihUrdOrUKT355JP28rNnz3bbzfuOHTvUpUsX1a9fX7ly5VLDhg311ltvKUuWLE7LxMbGys/Pz+FZu1OnTqlnz576+OOPPXo/37Zt25SUlKTGjRvbh5UrV07FixdXVFSUJCkqKkqVK1dWoUKF7DHh4eGKi4vT3r177TGpp2GLsU0DAADgVstkdQXw7/DMM89o6NCh+v333yVJP/74oz799FOtX7/eHpOQkKA33nhDq1evVlhYmCSpVKlS+uGHH/T++++rfv36eu+993Tvvfdq/PjxkqSyZctq9+7deuutt5zOu2rVqqpatar97zFjxujLL7/U119/rX79+tmHN2/eXH369JEkDRkyRBMnTtS6detUtmzZNNPMlCmTZs+erZ49e2r69OmqUaOG6tevr6eeekpVqlSxx6XuNKNkyZJ67bXX1KtXL7377rvp1nXUqFF66aWXFBERYV/+MWPGaPDgwRoxYoTTZUxt27Ztmj9/vh555BH7sMTERM2dO1cFChRIt8yhQ4e0aNEirVq1yp5wlCpVyj5+6tSpql69ut544w37sI8++kjFihXToUOHVKZMGeXKlSvddZVavXr1NGvWLIft4cqVK1c0ZMgQdezYUcHBwZIkY4y6du2qXr16qVatWjp69Kjb6cTExCgwMDBNByqFChVSTEyMPSZ1MmYbbxvnKiYuLk6XL19W1qxZPVouAACAjEJCZjVXHTcEBDj+ffq081j/6252enCR640CBQqoRYsWmj17towxatGihfLnz+8Q8+uvv+rSpUt69NFHHYYnJiaqevXqkqT9+/erTp06DuNtyZszFy9e1MiRI7V8+XKdPHlSV69e1eXLl9PcIUudSPn5+SkkJESnXayzdu3aqUWLFtq4caM2b96sb7/9VuPGjdPMmTPtHZWsXr1aY8eO1YEDBxQXF6erV6/qypUrunTpUrp3dnbu3Kkff/zR4Y5YcnKyyzKStHv3buXIkUPJyclKTExUixYtNHXqVPv4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ySM/Pz+nsWfPns2wygEAAADAncyjhGzixInKmTOnJGnSpEk3sz4AAAAAcNfwqMliRESEgoKC7P939fHG999/r5YtW6pIkSLy8/PTkiVLHMZ37dpVfn5+Dp+mTZs6xJw9e1adOnVScHCwcufOre7du9s7HbHZtWuXHnroIWXJkkXFihXTuHHj0tRl8eLFKleunLJkyaLKlSvrm2++8WpZAAAAAMBbHiVkcXFxHn+8ER8fr6pVq2ratGlOY5o2baqTJ0/aPwsWLHAY36lTJ+3du1erVq3SsmXL9P333+u5555zqHuTJk1UokQJbdu2TW+//bZGjhypGTNm2GM2bdqkjh07qnv37tqxY4dat26t1q1ba8+ePV4tDwAAAAB4w6Mmi7lz53b53FhqycnJHs+8WbNmatasmcuYoKAghYSEpDtu//79WrFihbZu3apatWpJkt555x01b95c//3vf1WkSBHNmzdPiYmJ+uijjxQYGKiKFSsqOjpaEyZMsCdukydPVtOmTTVo0CBJ0pgxY7Rq1SpNnTqVXiQBAAAA3DQe3SFbt26d1q5dq7Vr1+qjjz5SwYIFNXjwYH355Zf68ssvNXjwYBUqVEgfffRRhldw/fr1KliwoMqWLavevXvr77//to+LiopS7ty57cmYJDVu3Fj+/v7asmWLPebhhx9WYGCgPSY8PFwHDx7UuXPn7DGNGzd2mG94eLiioqKc1ishIeGG7g4CAAAAgEd3yOrXr2///+jRozVhwgR17NjRPuzxxx9X5cqVNWPGDK+fI3OladOmatu2rUJDQ3X48GG9/PLLatasmaKiohQQEKCYmBgVLFjQoUymTJmUN29excTESJJiYmIUGhrqEFOoUCH7uDx58igmJsY+LHWMbRrpGTt2rEaNGpURiwkAAADgLuX1e8iioqIc7kjZ1KpVSz/99FOGVMrmqaeesid7rVu31rJly7R161atX78+Q+fji6FDhyo2Ntb+OX78uNVVAgAAAPAv43VCVqxYMX3wwQdphs+cOVPFihXLkEo5U6pUKeXPn1+//vqrJCkkJESnT592iLl69arOnj1rf+4sJCREp06dcoix/e0uxtmza9K1Z9uCg4MdPgAAAADgDY+aLKY2ceJEtWvXTt9++63q1KkjSfrpp5/0yy+/6PPPP8/wCqb2xx9/6O+//1bhwoUlSWFhYTp//ry2bdummjVrSpLWrl2rlJQUe93CwsL0yiuvKCkpSZkzZ5YkrVq1SmXLllWePHnsMWvWrFH//v3t81q1apXCwsJu6vIAAAAAuLt5fYesefPmOnTokFq2bKmzZ8/q7NmzatmypQ4dOqTmzZt7Na2LFy8qOjpa0dHRkqQjR44oOjpax44d08WLFzVo0CBt3rxZR48e1Zo1a9SqVSuVLl1a4eHhkqTy5curadOm6tmzp3766Sf9+OOP6tevn5566ikVKVJEkvT0008rMDBQ3bt31969e7Vw4UJNnjxZkZGR9nq88MILWrFihcaPH68DBw5o5MiR+vnnn9WvXz9vVw8AAAAAeMzrO2TStWaLb7zxxg3P/Oeff1bDhg3tf9uSpIiICL333nvatWuX5syZo/Pnz6tIkSJq0qSJxowZY39JtSTNmzdP/fr1U6NGjeTv76927dppypQp9vG5cuXSd999p759+6pmzZrKnz+/hg8f7vCusgceeEDz58/XsGHD9PLLL+u+++7TkiVLVKlSpRteRgAAAABwxqeEbOPGjXr//ff122+/afHixbrnnnv08ccfKzQ0VA8++KDH02nQoIGMMU7Hr1y50u008ubNq/nz57uMqVKlijZu3Ogypn379mrfvr3b+QEAAABARvG6yeLnn3+u8PBwZc2aVdu3b1dCQoIkKTY2NkPumgEAAADA3cLrhOy1117T9OnT9cEHH9g7yZCkevXqafv27RlaOQAAAAC4k3mdkB08eFAPP/xwmuG5cuXS+fPnM6JOAAAAAHBX8DohCwkJsb8HLLUffvhBpUqVypBKAQAAAMDdwOuErGfPnnrhhRe0ZcsW+fn56cSJE5o3b54GDhyo3r1734w6AgAAAMAdyeteFl966SWlpKSoUaNGunTpkh5++GEFBQVp4MCBev75529GHQEAAADgjuR1Qubn56dXXnlFgwYN0q+//qqLFy+qQoUKypEjx82oHwAAAADcsXx6D5kkBQYGqkKFChlZFwAAAAC4q3ickD377LMexX300Uc+VwYAAAAA7iYeJ2SzZ89WiRIlVL16dRljbmadAAAAAOCu4HFC1rt3by1YsEBHjhxRt27d9Mwzzyhv3rw3s24AAAAAcEfzuNv7adOm6eTJkxo8eLCWLl2qYsWK6cknn9TKlSu5YwYAAAAAPvDqPWRBQUHq2LGjVq1apX379qli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MTExOnfunMqXL+80fs+ePSpdurSyZMmiZcuWadeuXerRo4cKFizotn53u61bt+rvv/9Oc33z7bffqkCBAqpVq5bL8klJSTp27JjD9r3TvyczEgnZXcCXk6C3B1ZcXJymTp2a5iS9aNEil/Np06aN5s6dq5SUFNWqVUtBQUFq27atRo8e7bJccnKyFi1apH379jnMz9UXSWJiot59911t3LhRkvTwww+rd+/eCgwMdFqmRo0a2r59u8OwmjVratu2bS7rd/XqVc2YMUNHjx7VuHHjdPToUR07dkwPP/ywy3K+bKtbeUGyZMkSh/XXqlUrt2VWrVqlsLAw5ciRQ++++66io6MVGRmpcuXKuSwXFRWVZvv26dPHZZldu3Zp4MCBafbD06dPOy1Tu3ZtrVmzRvHx8apbt64qVKige+65Rx988IHTMvXr19fly5fVpUsXPf300x5f4Pqy33pzAX4jF1qS78fj1atXderUKSUnJ9uHFS9e3Gm8txd1kydP1gsvvOB0+dJbrsWLF6t9+/Z69913052mq33Jl/3Ixpf91psy9erV05w5c9S+fXt7klOxYkXt3bvX5Tx+++03zZ07VwsXLlSFChUUERGhFi1aKCAgwGmZunXravLkyapTp46ka9vnP//5jzZv3uy0zJ49e9StWzctXrxYW7Zs0YQJE7R06VK3F8QNGzZUZGSkhg4dqoULF2rWrFnKkiWLXnvtNadlJkyYoM8++0yHDh1Sw4YNtXr1aj300EP6+uuvXc7r2LFjev755/XTTz/J399ftWvX1uTJkzN0n7XZv3+/xo8fr99//93h+Fi7dq3TMr58n86fP1/Dhw9X48aNZYzRunXrNHr0aD311FNpYufMmSNJ2rhxow4ePKgnn3xS0rVjpmzZsi7Pfb5sJ8m3bTVw4ECdOXNGW7Zs0YEDB3TmzBk99thj2rJli9My1apV0/bt27Vv3z517NhRnTt31sqVK7VmzRqnZb755huXdXf3ffrjjz/q6NGjDtu3S5cuTuNr166dZr9Jb1h6rl69qsTERPvf2bJlcxl/6tQpzZw5M039PvroozSxjzzyiObMmaNixYo5DD9+/Li6dOmidevWOZ3PggUL9Nprr+n48eMqW7asdu7cqVq1amnTpk1ul8lbBQoUSPM9EBwcrBo1aujNN99UqVKlMnyet4TBHW38+PEmLCzM5MuXzzzxxBMmd+7cpmXLli7LzJ8/31SoUMHkzJnT1KpVy2TOnNmEhYW5LPPYY4+ZKVOmmPvuu88sW7bMPPnkk2bgwIFu61etWjVjjDEzZ840L7/8sklJSTGVK1d2W65Tp04mMjLSlChRwkydOtXUq1fP9OnTx2WZiIgI07t3b7Np0yazadMm07dvXxMREZFu7HfffWcGDhxoChUqZAYNGmT//N///Z+5//773davc+fOZvjw4aZChQrGGGPi4uJM9erVXZbxZVt5W+aRRx4xxhiTP39+U6BAAfvH9rcrL774omnRooWZP3++mT9/vmnZsqVH27hKlSrGGGOioqLMAw88YBYuXGgeeOABl2UiIyNNu3btTOHChc3AgQNN6dKlTefOnd3Oq06dOmbXrl2mWrVq5uLFi+add94xo0ePdlnGtg9OmTLFvP7668YYY6pWrep2XkeOHDGjRo0yFStWNG3atDFffvmlSUpKclnGl/32gQceML/88ou9nsYY+351vdmzZ5vZs2eb7t27mwcffNBMmTLFTJkyxTz00EOmR48ebpfJl+Nx/PjxplChQqZGjRqmVq1aplatWm6PkQYNGpivv/7aVKxY0ezZs8e8+OKL5pVXXnEa//XXXzss3/Wf9EyfPt0YY8zIkSPT/bjiy35kjG/7rbdlbOs29f7gyf6a2jfffGOKFCliChQoYCIjI82JEyfSjbMdu+6GXW/Xrl2mYsWKpkGDBiYuLs6jOtWsWdMYY0ylSpXSDHOmUqVK5urVq/Y6HT9+3DRt2tTtvBo2bGgWLlxo/3vRokWmYcOGLst4u8/aVK5c2Xz00Udm586dZs+ePfaPK758n1apUsWcPXvW/vfZs2fdbqv777/fXL161f53UlKSqV27tssyvmwnW7y328q2j6fe190tky125MiRZsaMGcYY4/a7t2vXrqZr166mWbNmJnfu3KZdu3ambdu2Jk+ePKZ58+Yuyz711FOmQYMGZsCAAWbgwIFm4MCBZtCgQenGnjlzxuzZs8eUL1/e7Nu3z+zdu9fs3bvXREVFmbJly7qcz5o1a0zVqlVN1qxZTf78+Y2/v78pWbKkyzLGGFO7dm0zfPhw89VXX5lly5bZP+mpVauW0+m4W++VK1c28fHx9nPRjh07zJNPPum2fgsXLjSlS5f26lpk6NChZubMmebChQvmwoUL5sMPPzQDBw40ixcvNg8//LDbed6uSMjucL6cBH05sGrUqGEva4wxKSkpHiUu5cuXN7/++qtp2LCh2bx5s8M0XLGddG2xCQkJbpPG9E4ozi5koqOjzezZs03x4sUdLvw+//xzhy89Z2zrw5svEl+2la8XJL64frskJyd7tK1sdRsyZIiZO3euMcZxvbial63s+fPnTf369d3Oy3ZhkLpe7r6MK1eubFavXm1q1qxpdu3aZYwxpmLFim7nZYwxFy5cMDNnzjT33HOPCQsLM2XLljVz5sxxGu/LfuvLBbgvF1rG+HY83nfffeb8+fNup52arxd1Nn/++afTJCK15ORk069fP6/qlrou3uxHqeO92W+9LdO2bVvz888/m+rVq5uUlBTzzjvvmHbt2rmtmzHGrF692nTu3NlUrlzZjBo1yhw8eNDMmjXLlC9fPt34zp07m759+5qoqCgTFRVlnn/+efPMM8+kG2tLxG2fIkWKmIoVK9r/dicsLMykpKSYVq1amQ8++MB88803pkyZMi7L2C4gq1evbi5cuGCMMaZcuXJu5+VLounrPuvqItcZX75PK1WqZBITE+1/JyYmOtQ1PWXKlDF//vmn/e8///zTbWLgy3Yyxrdtdf/995vk5GT7sff333+7/e6oV6+eGTZsmAkNDTUnTpwwycnJbteDTaNGjczJkyftf588edI0atTIZRlnx056Zs+ebRo0aGBy5MhhGjRoYP+0bNnSfP755y7LVq9e3cTExNiXf+nSpW5/zDPG/Xdtavfee69JTk5OM/zq1avm3nvvdVnWtn2rVq1q3w89+R699957zeHDhz2uozHpfyfZjl9PfjC6XWWy+g4dbq4sWbIoICBAAQEBunjxoooWLaqjR4+6LBMUFGS/DZ6UlKRq1aq5bQ6TKdO1XalQoUJas2aNihQpor///ttt/YYPH642bdqoXr16qlOnjn777TeVLl3abbnMmTNLknLlyqVDhw6pYMGCOnXqlMsyWbJk0c8//2xvB71t2zYFBQWlG1u1alVVrVpVXbp0cdkEzJmgoCAlJCTYyx47dsxl00hb/bzdVt6WOXLkiEJDQ7Vv3750x7tqlhoQEKDjx4/bmzP8+eefLps72RQpUkSdO3fW999/r+joaCUkJDg0nUhP1qxZJV1bvtOnTytv3rz6888/3c4rW7ZsSkpKUpUqVfTqq6+qSJEibuc1efJkTZw4Ue3bt1flypX122+/qWHDhi7LrFq1SnPmzFF0dLSefPJJ/fDDDypZsqRiY2Pt+016fNlvixUrpm3btsnPz0/GGE2bNs3tMRIbG6tTp07Zn/86ffq0YmNjXZaR/jkeH3zwQY+Px5IlS7rdt68XGBgoY4zuvfdezZw5U/fcc49HnUZs3LhRPXr0UM6cOSVJFy9e1MyZM/Xggw+mG+/v768dO3YoOTnZo33Vxpf9SPJtv/W2zPvvv6/+/fvrxIkTKlKkiBo2bKjp06e7rVu5cuVUt25dPfvss2rQoIF9eJkyZZx2ujFjxgxNmzZNb731liTpwQcfdNrs9bPPPpMkXb582b5M3pg4caLi4+M1ZcoUDR8+XHFxcfamdc7UqFFD58+fV/fu3VWnTh3lzJnT3rzSlRIlSui///2vnnnmGUnSvHnzXDZXlHzfZxs1amQ/rlJ/37g61/ryffrMM8/ogQceULt27SRJX3zxhctmc5I0fvx41atXT2XLlpUk/fLLL5o8ebLLMr5sJ8m3bfWf//xHHTp00JkzZzRmzBgtXLhQr7zyissyixcv1oIFCzRnzhwVLlxYx44d06BBg9zWT5L++OMP5c+f3/53vnz59Mcff7gsU7t2bR08eNC+Dl2JiIhQRESElixZotatW3tUJxt/f38VKlRIycnJMsbosccec7suJKl169aaNWuWWrdu7bD/pdfUsVWrVnruuec0ZcoU+/hLly5pwIABatmypcv5hISE6Pz582rZsqWaNWumfPnypWn6mJ577rnH/rypp/Lnz68pU6aoQ4cOkq415c2TJ49SUlK8Os/fdqzNB3GzPffcc+bcuXNm6tSppkKFCqZOnTpOm+nZPPbYY+bcuXNm2LBhplGjRubJJ590e9dlyZIl5vz582bnzp2mfv36pkaNGmbJkiUZuCSOpk+fbs6dO2fWrl1rSpUqZUJCQsx7773nssy2bdtM5cqVTdmyZU2ZMmVMlSpVzLZt21yWKVmypAkNDU3zcWflypWmcePGpmDBgubZZ581oaGhZvXq1S7L+LKtvC3Ts2dPY4xx+HXO9nHXZGflypWmRIkSJjw83DRp0sSEhoaaVatWuSxjjDEXL140n3/+uTl06JAxxpgTJ06YlStXuiwzYsQIc+7cObNo0SJzzz33mGLFinnUPOjw4cPm8uXL5ty5c2bEiBFmwIAB5pdffnFbzltdunQxa9eudRh2+fJlY8y15mDO+LLfnjlzxnTq1MkUKlTIhISEmI4dO5ozZ864LLN06VJTsmRJEx4ebsLDw02pUqXM0qVL3S7Xzp07PRqW2pNPPmnKly9v/vOf/zg073Vl8+bN5sKFC+b33383ERERpm3btvY7cq5UqFDB7Nu3z/73vn37nDbftImIiDAPPvigefvtt820adPsH1d83Y982W+9KZOcnOzx3bDredp08PoyqZvhJiUluZxOSkqKV3cMMtJvv/3mdl+1+euvv0y/fv1MtWrVTLVq1czzzz9v/vrrL5dlrt9n27RpY6KiotzOy5dzra/fp1u3bjWTJk0ykyZNMj///LPbeGOMuXLliomOjjbR0dHmypUrHpW5Ud5sq/3795upU6eaKVOmmL1793o8j6SkJBMfH2//eGLEiBGmdu3aZuzYsebNN980devWddq82XZHuGrVqiYwMNBUqVLF3H///R412b506ZL55JNPzGuvvWZGjRpl/7jyyCOPmIsXL5revXubiIgIM3jwYFO3bl23y1SyZMk0H2fXMAkJCaZ///4mX758pkaNGqZ69eomf/78ZsCAASYhIcHtvGzWrVtnvvrqK4/K9OjRwzzyyCNmwoQJHp+fT506Zfr06WOqVatmqlatavr06WNiYmLMlStXzIEDBzyu5+2GTj3uIkeOHNGFCxdUpUoVj8usX79ecXFxatasmf3X/YwUFxenadOmpXmg3V1nIDfCdqcgV65cbmPj4+Pt/09ISNDnn3+uP/74Q6NGjXJaJiUlRZ988olatGihzZs3KyUlRWFhYQ6/vLnjy7bypYy3rly5ooMHD0qSypYtqyxZsjiNTUhIUFBQkC5dupTueHcPI6eezpUrVzzaXtHR0apatapXdzV9eVi/S5cumjt3rv3v8+fPq1WrVtqwYYPH873ZEhISdODAAUnX7o44uxucWnqd2KQ3LDVnv45HREQ4LeNr76XpdahTq1Yt/fzzz07LODtWR4wY4XJevrhy5Yr9mLDtt0lJSR4f+57s6w0bNtSyZcuUPXt2r+rmS++MderU0bp16+zHanx8vBo3buyyG/uOHTtq2LBhqlixolf186Xzi9atW2vJkiVuh90NfvzxR1WpUsV+9zguLk579uzRAw884LacNx1S+LKdJN+3lbe9LK5d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Ek67MH7//ffVoUMH7dixQz169NClS5c0cuRI/d///V+aWNsFYGJiovbv32/vIMKTL28p/WdO0ns25frxBw4c8OpCwebIkSP68ccf9eOPP2rTpk0qXry4x82oEhIS9Pfff9uT9oxWoEAB/f3338qZM6fDcrm6EPTl2PJ2/dmaEn788ccOF5hxcXHavn27y/X+8MMPa82aNerWrZtCQ0NVpEgRTZ8+3eVzRmvXrlX37t1VtmxZGWP066+/aubMmW4T1YcffljPPPOMOnbsKD8/P3366aeaO3euvv/+e6dlUjfJsjU7HjdunHbv3u20THrnQlfnQHfdfrvq4GTGjBl6++237c0C161bp4EDB6pnz54OcSdPnlThwoWddibgqhOB9Lg61/ryrK5NlSpVtHXrVvuFUkJCgu6///6b8sxM165dlS1bNnXu3FnStR97Ll686PLHHkkqXbq0vvvuO3sTQU+0adNG8fHxDk0W3T1vJV07H/3nP//R1q1b5e/vr1q1amny5MnpHtc2ZcuWTbfJrLcdubiTUfuSJ3zdVgcOHNCaNWuUkpKiRo0aub3o3rt3b5rrgO+//95t4iJda0761VdfacuWLerZs6c9AezYsaPTMi1bttTHH3+s8ePHKyoqSvny5VNcXJy+/fZbl/NasmSJQ3Lqrhnyiy++qKVLl6pSpUoOCY+7DtC2b9+url27KjExUcYYZcmSRbNmzVKNGjXSxLp6Pt7ds/MVKlTwuvmrbbpRUVE6ceKEHn30UTVp0kQnT57Ul19+6bRMet8TnvwocLsjIbvD3Xvvvfr444/TtHv35sTuaZLki759++rNN99UpkyZVL9+fR0/flwjRoxQr169XJa7//77tXXrVq/n523Pc9c/KO1s2PWeeeaZdJ/Rcvdgsac9PNnUqVNHUVFR9m2bnJxsf3i6cuXKbn+p88SN9CZlq+O0adMcfqHr06ePy3b5vl4oHD58WD/88IM2btyon376SdmyZVO9evU0fvx4p2XatGmjuXPnKiUlRbVq1VJQUJDatm2r0aNHOy3zyCOPOPzSfe7cObVv316rV692Wb9bxdv1t3PnTkVHR2v48OEOy50zZ041bNjQ5XNDv/32mwoXLqyEhARNmjRJcXFx6tOnj8v3l9WoUUNffvmlvT6///672rRp47aznPQehnf3gHzqL+9MmTKpRIkSioyM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9u3bzbx581wmGT/88IMxxpjly5en+3HFl27HfX0dx9q1a03Lli3Nm2++aYy5ltz369fPZRlP94mBAweaQYMGmSeffNKUL1/e/Oc//zGDBg2yf1yx/XiTWkpKikfn2rlz55oCBQqYe+65x+zcudNt/O7du01wcLDJly+fKVCggNsuvZ1daHrS/XXt2rXNtm3b7H9/+OGH5qGHHnIaP3LkSPP444+bI0eO2If99ttvplWrVmb48OFul+3LL780kZGRJjIy0nz11Vdu4425dtylvtDfuXOn/Vh01oW7N8f8448/bjp37mymT59u2rVrZx544AFTr149e7firjz22GPm3LlzZtiwYaZRo0bmySefdPpjwI1sJ2O831bGGHPixAkzfvx48/333xtjjPn999/dvobH9t2d2urVq12WsZ0PvPmuWL58uVm2bJmpWbOm/Ty0ZcsWj5MQ2w+p0dHRHv+Q6gtPfii8ES1atDDGGFOyZEkTGhpqSpYsaf+Ehoa6Lf/999+bRo0amdKlS9vLuyu3efNm06pVK1OtWjVTuXJl++ffjiaLd7jjx49rzJgxaV7a6qpdb//+/dW/f3/73yVKlND69etdzseX54Ska81ovvjiizTd1w8fPtxluRo1auipp57SE0884dC+21UzrubNm+v8+fMaOHCgatSoIX9/f6e36G/0xcvePKNl06RJE7333ntpXibtqv26Ny+gTm3JkiX68ccfNXv2bM2YMUPVqlXTgw8+6PKF4SEhITp//rxatmypZs2aKV++fPYmF66cOnVKq1atchuXEfPy5dmkU6dOaebMmWn2QVe9il7fy6btAWR3XWDXqFFD58+fV/fu3VWnTh3lzJnT5YvQJd+az/m6/h566CFNmDBBCQkJ2rhxo6ZNm+b2pfD58+fXlClT7E2yFi1apDx58iglJcVpM5wmTZooKipKR44c0ZNPPqlHH31Uixcvdtqz1o003/Sl23FfX8fRsGFDh05ESpUqpXfeecdlGU/3CdvLgitWrOhyedPj7++vqVOnOuyffn5+ypTJ9SVAmzZtlDlzZu3du1e///67unXrpscee8xpZx8zZszQ+PHj9eabb6pXr14eNf9N3dQuJibG3tSxdu3aKlSokMuyX3zxhVq3bq3p06dr7dq1Wrt2rVasWOE0ft68edqzZ49DM+bQ0FAtXLhQlSpVcrpc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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Group DataFrame by saleMonth and then find the median SalePrice per state as well as across the whole dataset\n", - "median_prices_by_state = df_tmp.groupby([\"state\"])[\"SalePrice\"].median() # this will return a pandas Series rather than a DataFrame\n", - "median_sale_price = df_tmp[\"SalePrice\"].median()\n", - "\n", - "# Create a plot comparing median sale price per state to median sale price overall\n", - "plt.figure(figsize=(10, 7))\n", - "plt.bar(x=median_prices_by_state.index, # Because we're working with a Series, we can use the index (state names) as the x values\n", - " height=median_prices_by_state.values)\n", - "plt.xlabel(\"State\")\n", - "plt.ylabel(\"Median Sale Price ($)\")\n", - "plt.xticks(rotation=90, fontsize=7);\n", - "plt.axhline(y=median_sale_price, \n", - " color=\"red\", \n", - " linestyle=\"--\", \n", - " label=f\"Median Sale Price: ${median_sale_price:,.0f}\")\n", - "plt.legend();" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that's a nice looking figure!\n", - "\n", - "Interestingly Florida has the most sales and the median sale price is above the overall median of all other states.\n", - "\n", - "And if you had a bulldozer and were chasing the highest sale price, the data would reveal that perhaps selling in South Dakota would be your best bet.\n", - "\n", - "Perhaps bulldozers are in higher demand in South Dakota because of a building or mining boom?\n", - "\n", - "Answering this would require a bit more research.\n", - "\n", - "But what we're doing here is slowly building up a mental model of our data. \n", - "\n", - "So that if we saw an example in the future, we could compare its values to the ones we've already seen." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 2. Model driven exploration\n", - "\n", - "We've performed a small Exploratory Data Analysis (EDA) as well as enriched it with some `datetime` attributes, now let's try to model it.\n", - "\n", - "Why model so early?\n", - "\n", - "Well, we know the evaluation metric (root mean squared log error or RMSLE) we're heading towards. \n", - "\n", - "We could spend more time doing EDA, finding more out about the data ourselves but what we'll do instead is use a machine learning model to help us do EDA whilst simultaneously working towards the best evaluation metric we can get. \n", - "\n", - "Remember, one of the biggest goals of starting any new machine learning project is reducing the time between experiments.\n", - "\n", - "Following the [Scikit-Learn machine learning map](https://scikit-learn.org/stable/machine_learning_map.html) and taking into account the fact we've got over 100,000 examples, we find a [`sklearn.linear_model.SGDRegressor()`](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.SGDRegressor.html) or a [`sklearn.ensemble.RandomForestRegressor()`](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html#sklearn-ensemble-randomforestregressor) model might be a good candidate.\n", - "\n", - "Since we're worked with the Random Forest algorithm before (on the [heart disease classification problem](https://dev.mrdbourke.com/zero-to-mastery-ml/end-to-end-heart-disease-classification/)), let's try it out on our regression problem.\n", - "\n", - "> **Note:** We're trying just one model here for now. But you can try many other kinds of models from the Scikit-Learn library, they mostly work with a similar API. There are even libraries such as [`LazyPredict`](https://github.com/shankarpandala/lazypredict) which will try many models simultaneously and return a table with the results." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "ename": "ValueError", - "evalue": "could not convert string to float: 'Low'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m/var/folders/c4/qj4gdk190td18bqvjjh0p3p00000gn/T/ipykernel_21543/2824176890.py\u001b[0m in \u001b[0;36m?\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# This won't work since we've got missing numbers and categories\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0msklearn\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mensemble\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mRandomForestRegressor\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mmodel\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mRandomForestRegressor\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn_jobs\u001b[0m\u001b[0;34m=\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[0;32m----> 5\u001b[0;31m model.fit(X=df_tmp.drop(\"SalePrice\", axis=1), # use all columns except SalePrice as X input\n\u001b[0m\u001b[1;32m 6\u001b[0m y=df_tmp.SalePrice) # use SalePrice column as y input\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/base.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(estimator, *args, **kwargs)\u001b[0m\n\u001b[1;32m 1469\u001b[0m skip_parameter_validation=(\n\u001b[1;32m 1470\u001b[0m \u001b[0mprefer_skip_nested_validation\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mglobal_skip_validation\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1471\u001b[0m )\n\u001b[1;32m 1472\u001b[0m ):\n\u001b[0;32m-> 1473\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mfit_method\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mestimator\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/ensemble/_forest.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, X, y, sample_weight)\u001b[0m\n\u001b[1;32m 359\u001b[0m \u001b[0;31m# Validate or convert input data\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 360\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0missparse\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my\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 361\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"sparse multilabel-indicator for y is not supported.\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 362\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 363\u001b[0;31m X, y = self._validate_data(\n\u001b[0m\u001b[1;32m 364\u001b[0m \u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 365\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 366\u001b[0m \u001b[0mmulti_output\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/base.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, X, y, reset, validate_separately, cast_to_ndarray, **check_params)\u001b[0m\n\u001b[1;32m 646\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;34m\"estimator\"\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mcheck_y_params\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 647\u001b[0m \u001b[0mcheck_y_params\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m**\u001b[0m\u001b[0mdefault_check_params\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mcheck_y_params\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 648\u001b[0m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcheck_array\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minput_name\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"y\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mcheck_y_params\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 649\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 650\u001b[0;31m \u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcheck_X_y\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mcheck_params\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 651\u001b[0m \u001b[0mout\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 652\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 653\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mno_val_X\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mcheck_params\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"ensure_2d\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mTrue\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[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/utils/validation.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(X, y, accept_sparse, accept_large_sparse, dtype, order, copy, force_writeable, force_all_finite, ensure_2d, allow_nd, multi_output, ensure_min_samples, ensure_min_features, y_numeric, estimator)\u001b[0m\n\u001b[1;32m 1297\u001b[0m raise ValueError(\n\u001b[1;32m 1298\u001b[0m \u001b[0;34mf\"{estimator_name} requires y to be passed, but the target y is None\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1299\u001b[0m )\n\u001b[1;32m 1300\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1301\u001b[0;31m X = check_array(\n\u001b[0m\u001b[1;32m 1302\u001b[0m \u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1303\u001b[0m \u001b[0maccept_sparse\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0maccept_sparse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1304\u001b[0m \u001b[0maccept_large_sparse\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0maccept_large_sparse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/utils/validation.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(array, accept_sparse, accept_large_sparse, dtype, order, copy, force_writeable, force_all_finite, ensure_2d, allow_nd, ensure_min_samples, ensure_min_features, estimator, input_name)\u001b[0m\n\u001b[1;32m 1009\u001b[0m )\n\u001b[1;32m 1010\u001b[0m \u001b[0marray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mxp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mastype\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1011\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1012\u001b[0m \u001b[0marray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_asarray_with_order\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0morder\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0morder\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mxp\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mxp\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1013\u001b[0;31m \u001b[0;32mexcept\u001b[0m \u001b[0mComplexWarning\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mcomplex_warning\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 1014\u001b[0m raise ValueError(\n\u001b[1;32m 1015\u001b[0m \u001b[0;34m\"Complex data not supported\\n{}\\n\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1016\u001b[0m ) from complex_warning\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/sklearn/utils/_array_api.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(array, dtype, order, copy, xp, device)\u001b[0m\n\u001b[1;32m 747\u001b[0m \u001b[0;31m# Use NumPy API to support order\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 748\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mcopy\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 749\u001b[0m \u001b[0marray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnumpy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0morder\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0morder\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 750\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 751\u001b[0;31m \u001b[0marray\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnumpy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0morder\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0morder\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\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 752\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 753\u001b[0m \u001b[0;31m# At this point array is a NumPy ndarray. We convert it to an array\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 754\u001b[0m \u001b[0;31m# container that is consistent with the input's namespace.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniforge3/envs/ai/lib/python3.11/site-packages/pandas/core/generic.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, dtype, copy)\u001b[0m\n\u001b[1;32m 2149\u001b[0m def __array__(\n\u001b[1;32m 2150\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mnpt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mDTypeLike\u001b[0m \u001b[0;34m|\u001b[0m \u001b[0;32mNone\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mbool_t\u001b[0m \u001b[0;34m|\u001b[0m \u001b[0;32mNone\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2151\u001b[0m ) -> np.ndarray:\n\u001b[1;32m 2152\u001b[0m \u001b[0mvalues\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_values\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2153\u001b[0;31m \u001b[0marr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\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 2154\u001b[0m if (\n\u001b[1;32m 2155\u001b[0m \u001b[0mastype_is_view\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0marr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2156\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0musing_copy_on_write\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[0;31mValueError\u001b[0m: could not convert string to float: 'Low'" - ] - } - ], - "source": [ - "# This won't work since we've got missing numbers and categories\n", - "from sklearn.ensemble import RandomForestRegressor\n", - "\n", - "model = RandomForestRegressor(n_jobs=-1)\n", - "model.fit(X=df_tmp.drop(\"SalePrice\", axis=1), # use all columns except SalePrice as X input\n", - " y=df_tmp.SalePrice) # use SalePrice column as y input" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Oh no!\n", - "\n", - "When we try to fit our model to the data, we get a value error similar to:\n", - "\n", - "> `ValueError: could not convert string to float: 'Low'`\n", - "\n", - "The problem here is that some of the features of our data are in string format and machine learning models love numbers.\n", - "\n", - "Not to mention some of our samples have missing values.\n", - "\n", - "And typically, machine learning models require all data to be in numerical format as well as all missing values to be filled.\n", - "\n", - "Let's start to fix this by inspecting the different datatypes in our DataFrame.\n", - "\n", - "We can do so using the [`pandas.DataFrame.info()`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.info.html) method, this will give us the different datatypes as well as how many non-null (a null value is generally a missing value) in our `df_tmp` DataFrame.\n", - "\n", - "> **Note:** There are some ML models such as [`sklearn.ensemble.HistGradientBoostingRegressor`](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.HistGradientBoostingRegressor.html), [CatBoost](https://catboost.ai/) and [XGBoost](https://xgboost.ai/) which can handle missing values, however, I'll leave exploring each of these as extra-curriculum/extensions." - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Index: 412698 entries, 205615 to 409203\n", - "Data columns (total 57 columns):\n", - " # Column Non-Null Count Dtype \n", - "--- ------ -------------- ----- \n", - " 0 SalesID 412698 non-null int64 \n", - " 1 SalePrice 412698 non-null float64\n", - " 2 MachineID 412698 non-null int64 \n", - " 3 ModelID 412698 non-null int64 \n", - " 4 datasource 412698 non-null int64 \n", - " 5 auctioneerID 392562 non-null float64\n", - " 6 YearMade 412698 non-null int64 \n", - " 7 MachineHoursCurrentMeter 147504 non-null float64\n", - " 8 UsageBand 73670 non-null object \n", - " 9 fiModelDesc 412698 non-null object \n", - " 10 fiBaseModel 412698 non-null object \n", - " 11 fiSecondaryDesc 271971 non-null object \n", - " 12 fiModelSeries 58667 non-null object \n", - " 13 fiModelDescriptor 74816 non-null object \n", - " 14 ProductSize 196093 non-null object \n", - " 15 fiProductClassDesc 412698 non-null object \n", - " 16 state 412698 non-null object \n", - " 17 ProductGroup 412698 non-null object \n", - " 18 ProductGroupDesc 412698 non-null object \n", - " 19 Drive_System 107087 non-null object \n", - " 20 Enclosure 412364 non-null object \n", - " 21 Forks 197715 non-null object \n", - " 22 Pad_Type 81096 non-null object \n", - " 23 Ride_Control 152728 non-null object \n", - " 24 Stick 81096 non-null object \n", - " 25 Transmission 188007 non-null object \n", - " 26 Turbocharged 81096 non-null object \n", - " 27 Blade_Extension 25983 non-null object \n", - " 28 Blade_Width 25983 non-null object \n", - " 29 Enclosure_Type 25983 non-null object \n", - " 30 Engine_Horsepower 25983 non-null object \n", - " 31 Hydraulics 330133 non-null object \n", - " 32 Pushblock 25983 non-null object \n", - " 33 Ripper 106945 non-null object \n", - " 34 Scarifier 25994 non-null object \n", - " 35 Tip_Control 25983 non-null object \n", - " 36 Tire_Size 97638 non-null object \n", - " 37 Coupler 220679 non-null object \n", - " 38 Coupler_System 44974 non-null object \n", - " 39 Grouser_Tracks 44875 non-null object \n", - " 40 Hydraulics_Flow 44875 non-null object \n", - " 41 Track_Type 102193 non-null object \n", - " 42 Undercarriage_Pad_Width 102916 non-null object \n", - " 43 Stick_Length 102261 non-null object \n", - " 44 Thumb 102332 non-null object \n", - " 45 Pattern_Changer 102261 non-null object \n", - " 46 Grouser_Type 102193 non-null object \n", - " 47 Backhoe_Mounting 80712 non-null object \n", - " 48 Blade_Type 81875 non-null object \n", - " 49 Travel_Controls 81877 non-null object \n", - " 50 Differential_Type 71564 non-null object \n", - " 51 Steering_Controls 71522 non-null object \n", - " 52 saleYear 412698 non-null int32 \n", - " 53 saleMonth 412698 non-null int32 \n", - " 54 saleDay 412698 non-null int32 \n", - " 55 saleDayofweek 412698 non-null int32 \n", - " 56 saleDayofyear 412698 non-null int32 \n", - "dtypes: float64(3), int32(5), int64(5), object(44)\n", - "memory usage: 174.7+ MB\n" - ] - } - ], - "source": [ - "# Check for missing values and different datatypes \n", - "df_tmp.info();" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Ok, it seems as though we've got a fair few different datatypes. \n", - "\n", - "There are `int64` types such as `MachineID`.\n", - "\n", - "There are `float64` types such as `SalePrice`.\n", - "\n", - "And there are `object` (the `object` dtype can hold any Python object, including strings) types such as `UseageBand`.\n", - "\n", - "> **Resource:** You can see a list of all the [pandas dtypes in the pandas user guide](https://pandas.pydata.org/docs/user_guide/basics.html#dtypes).\n", - "\n", - "How about we find out how many missing values are in each column?\n", - "\n", - "We can do so using [`pandas.DataFrame.isna()`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.isna.html) (`isna` stands for 'is null or NaN') which will return a boolean `True`/`False` if a value is missing (`True` if missing, `False` if not). \n", - "\n", - "Let's start by checking the missing values in the head of our DataFrame." - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - " \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", - "
SalesIDSalePriceMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandfiModelDesc...Backhoe_MountingBlade_TypeTravel_ControlsDifferential_TypeSteering_ControlssaleYearsaleMonthsaleDaysaleDayofweeksaleDayofyear
205615FalseFalseFalseFalseFalseFalseFalseTrueTrueFalse...FalseFalseFalseTrueTrueFalseFalseFalseFalseFalse
274835FalseFalseFalseFalseFalseFalseFalseTrueTrueFalse...TrueTrueTrueFalseFalseFalseFalseFalseFalseFalse
141296FalseFalseFalseFalseFalseFalseFalseTrueTrueFalse...FalseFalseFalseTrueTrueFalseFalseFalseFalseFalse
212552FalseFalseFalseFalseFalseFalseFalseTrueTrueFalse...TrueTrueTrueFalseFalseFalseFalseFalseFalseFalse
62755FalseFalseFalseFalseFalseFalseFalseTrueTrueFalse...FalseFalseFalseTrueTrueFalseFalseFalseFalseFalse
\n", - "

5 rows × 57 columns

\n", - "
" - ], - "text/plain": [ - " SalesID SalePrice MachineID ModelID datasource auctioneerID \\\n", - "205615 False False False False False False \n", - "274835 False False False False False False \n", - "141296 False False False False False False \n", - "212552 False False False False False False \n", - "62755 False False False False False False \n", - "\n", - " YearMade MachineHoursCurrentMeter UsageBand fiModelDesc ... \\\n", - "205615 False True True False ... \n", - "274835 False True True False ... \n", - "141296 False True True False ... \n", - "212552 False True True False ... \n", - "62755 False True True False ... \n", - "\n", - " Backhoe_Mounting Blade_Type Travel_Controls Differential_Type \\\n", - "205615 False False False True \n", - "274835 True True True False \n", - "141296 False False False True \n", - "212552 True True True False \n", - "62755 False False False True \n", - "\n", - " Steering_Controls saleYear saleMonth saleDay saleDayofweek \\\n", - "205615 True False False False False \n", - "274835 False False False False False \n", - "141296 True False False False False \n", - "212552 False False False False False \n", - "62755 True False False False False \n", - "\n", - " saleDayofyear \n", - "205615 False \n", - "274835 False \n", - "141296 False \n", - "212552 False \n", - "62755 False \n", - "\n", - "[5 rows x 57 columns]" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Find missing values in the head of our DataFrame \n", - "df_tmp.head().isna()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Alright it seems as though we've got some missing values in the `MachineHoursCurrentMeter` as well as the `UsageBand` and a few other columns.\n", - "\n", - "But so far we've only viewed the first few rows.\n", - "\n", - "It'll be very time consuming to go through each row one by one so how about we get the total missing values per column?\n", - "\n", - "We can do so by calling `.isna()` on the whole DataFrame and then chaining it together with `.sum()`.\n", - "\n", - "Doing so will give us the total `True`/`False` values in a given column (when summing, `True` = 1, `False` = 0)." - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "SalesID 0\n", - "SalePrice 0\n", - "MachineID 0\n", - "ModelID 0\n", - "datasource 0\n", - "auctioneerID 20136\n", - "YearMade 0\n", - "MachineHoursCurrentMeter 265194\n", - "UsageBand 339028\n", - "fiModelDesc 0\n", - "fiBaseModel 0\n", - "fiSecondaryDesc 140727\n", - "fiModelSeries 354031\n", - "fiModelDescriptor 337882\n", - "ProductSize 216605\n", - "fiProductClassDesc 0\n", - "state 0\n", - "ProductGroup 0\n", - "ProductGroupDesc 0\n", - "Drive_System 305611\n", - "Enclosure 334\n", - "Forks 214983\n", - "Pad_Type 331602\n", - "Ride_Control 259970\n", - "Stick 331602\n", - "Transmission 224691\n", - "Turbocharged 331602\n", - "Blade_Extension 386715\n", - "Blade_Width 386715\n", - "Enclosure_Type 386715\n", - "Engine_Horsepower 386715\n", - "Hydraulics 82565\n", - "Pushblock 386715\n", - "Ripper 305753\n", - "Scarifier 386704\n", - "Tip_Control 386715\n", - "Tire_Size 315060\n", - "Coupler 192019\n", - "Coupler_System 367724\n", - "Grouser_Tracks 367823\n", - "Hydraulics_Flow 367823\n", - "Track_Type 310505\n", - "Undercarriage_Pad_Width 309782\n", - "Stick_Length 310437\n", - "Thumb 310366\n", - "Pattern_Changer 310437\n", - "Grouser_Type 310505\n", - "Backhoe_Mounting 331986\n", - "Blade_Type 330823\n", - "Travel_Controls 330821\n", - "Differential_Type 341134\n", - "Steering_Controls 341176\n", - "saleYear 0\n", - "saleMonth 0\n", - "saleDay 0\n", - "saleDayofweek 0\n", - "saleDayofyear 0\n", - "dtype: int64" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Check for total missing values per column\n", - "df_tmp.isna().sum()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Woah! It looks like our DataFrame has quite a few missing values.\n", - "\n", - "Not to worry, we can work on fixing this later on.\n", - "\n", - "How about we start by tring to turn all of our data in numbers? " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### TK (change heading?) - Convert strings to categories - TK - possible option: Inspecting the datatypes in our DataFrame \n", - "\n", - "UPTOHERE - getting all values into numbers (e.g. objects -> categories)\n", - "\n", - "One way to help turn all of our data into numbers is to convert the columns with the `object` datatype into a `category` datatype using [`pandas.CategoricalDtype`](https://pandas.pydata.org/docs/reference/api/pandas.CategoricalDtype.html).\n", - "\n", - "> **Note:** There are many different ways to convert values into numbers. And often the best way will be specific to the value you're trying to convert. The method we're going to use, converting all objects (that are mostly strings) to categories is one of the faster methods as it makes a quick assumption that each unique value is its own number. \n", - "\n", - "We can check the datatype of an individual column using the `.dtype` attribute and we can get its full name using `.dtype.name`." - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(dtype('O'), 'object')" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Get the dtype of a given column\n", - "df_tmp[\"UsageBand\"].dtype, df_tmp[\"UsageBand\"].dtype.name" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Beautiful!\n", - "\n", - "Now we've got a way to check a column's datatype individually.\n", - "\n", - "There's also another group of methods to check a column's datatype directly.\n", - "\n", - "For example, using [`pd.api.types.is_object_dtype(arr_or_dtype)`](https://pandas.pydata.org/docs/reference/api/pandas.api.types.is_object_dtype.html) we can get a boolean response as to whether the input is an object or not.\n", - "\n", - "> **Note:** There are many more of these checks you can perform for other datatypes such as strings under a similar name space `pd.api.types.is_XYZ_dtype`. See the [pandas documentation](https://pandas.pydata.org/docs/reference/arrays.html) for more.\n", - "\n", - "Let's see how it works on our `df_tmp[\"UsageBand\"]` column." - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Check whether a column is an object\n", - "pd.api.types.is_object_dtype(df_tmp[\"UsageBand\"])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can also check whether a column is a string with [`pd.api.types.is_string_dtype(arr_or_dtype)`](https://pandas.pydata.org/docs/reference/api/pandas.api.types.is_string_dtype.html). " - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Check whether a column is a string\n", - "pd.api.types.is_string_dtype(df_tmp[\"state\"])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Nice!\n", - "\n", - "We can even loop through the items (columns and their labels) in our DataFrame using [`pandas.DataFrame.items()`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.items.html) (in Python dictionary terms, calling `.items()` on a DataFrame will treat the column names as the keys and the column values as the values) and print out samples of columns which have the `string` datatype.\n", - "\n", - "As an extra check, passing the sample to [`pd.api.types.infer_dtype()`](https://pandas.pydata.org/docs/reference/api/pandas.api.types.infer_dtype.html) will return the datatype of the sample.\n", - "\n", - "This will be a good way to keep exploring our data." - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "This is a key: key1\n", - "This is a value: hello\n", - "This is a key: key2\n", - "This is a value: world!\n" - ] - } - ], - "source": [ - "# Quick exampke of calling .items() on a dictionary\n", - "random_dict = {\"key1\": \"hello\",\n", - " \"key2\": \"world!\"}\n", - "\n", - "for key, value in random_dict.items():\n", - " print(f\"This is a key: {key}\")\n", - " print(f\"This is a value: {value}\")" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Column name: fiModelDesc | Column dtype: object | Example value: ['330BL'] | Example value dtype: string\n", - "Column name: fiBaseModel | Column dtype: object | Example value: ['906'] | Example value dtype: string\n", - "Column name: fiProductClassDesc | Column dtype: object | Example value: ['Wheel Loader - 100.0 to 110.0 Horsepower'] | Example value dtype: string\n", - "Column name: state | Column dtype: object | Example value: ['Washington'] | Example value dtype: string\n", - "Column name: ProductGroup | Column dtype: object | Example value: ['TTT'] | Example value dtype: string\n", - "Column name: ProductGroupDesc | Column dtype: object | Example value: ['Track Type Tractors'] | Example value dtype: string\n" - ] - } - ], - "source": [ - "# Print column names and example content of columns which contain strings\n", - "for label, content in df_tmp.items():\n", - " if pd.api.types.is_string_dtype(content):\n", - " # Check datatype of target column\n", - " column_datatype = df_tmp[label].dtype.name\n", - "\n", - " # Get random sample from column values\n", - " example_value = content.sample(1).values\n", - "\n", - " # Infer random sample datatype\n", - " example_value_dtype = pd.api.types.infer_dtype(example_value)\n", - " print(f\"Column name: {label} | Column dtype: {column_datatype} | Example value: {example_value} | Example value dtype: {example_value_dtype}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Hmm... it seems that there are many more columns in the `df_tmp` with the `object` type that didn't display when checking for the string datatype (we know there are many `object` datatype columns in our DataFrame from using `df_tmp.info()`).\n", - "\n", - "How about we try the same as above, except this time instead of `pd.api.types.is_string_dtype`, we use `pd.api.types.is_object_dtype`?\n", - "\n", - "Let's try it." - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Column name: UsageBand | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: fiModelDesc | Column dtype: object | Example value: ['560B'] | Example value dtype: string\n", - "Column name: fiBaseModel | Column dtype: object | Example value: ['310'] | Example value dtype: string\n", - "Column name: fiSecondaryDesc | Column dtype: object | Example value: ['LC'] | Example value dtype: string\n", - "Column name: fiModelSeries | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: fiModelDescriptor | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: ProductSize | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: fiProductClassDesc | Column dtype: object | Example value: ['Track Type Tractor, Dozer - 20.0 to 75.0 Horsepower'] | Example value dtype: string\n", - "Column name: state | Column dtype: object | Example value: ['Texas'] | Example value dtype: string\n", - "Column name: ProductGroup | Column dtype: object | Example value: ['TTT'] | Example value dtype: string\n", - "Column name: ProductGroupDesc | Column dtype: object | Example value: ['Wheel Loader'] | Example value dtype: string\n", - "Column name: Drive_System | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Enclosure | Column dtype: object | Example value: ['OROPS'] | Example value dtype: string\n", - "Column name: Forks | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Pad_Type | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Ride_Control | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Stick | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Transmission | Column dtype: object | Example value: ['Standard'] | Example value dtype: string\n", - "Column name: Turbocharged | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Blade_Extension | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Blade_Width | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Enclosure_Type | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Engine_Horsepower | Column dtype: object | Example value: ['No'] | Example value dtype: string\n", - "Column name: Hydraulics | Column dtype: object | Example value: ['2 Valve'] | Example value dtype: string\n", - "Column name: Pushblock | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Ripper | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Scarifier | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Tip_Control | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Tire_Size | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Coupler | Column dtype: object | Example value: ['Manual'] | Example value dtype: string\n", - "Column name: Coupler_System | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Grouser_Tracks | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Hydraulics_Flow | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Track_Type | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Undercarriage_Pad_Width | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Stick_Length | Column dtype: object | Example value: ['None or Unspecified'] | Example value dtype: string\n", - "Column name: Thumb | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Pattern_Changer | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Grouser_Type | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Backhoe_Mounting | Column dtype: object | Example value: ['None or Unspecified'] | Example value dtype: string\n", - "Column name: Blade_Type | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Travel_Controls | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Differential_Type | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "Column name: Steering_Controls | Column dtype: object | Example value: [nan] | Example value dtype: empty\n", - "\n", - "[INFO] Total number of object type columns: 44\n" - ] - } - ], - "source": [ - "# Start a count of how many object type columns there are\n", - "number_of_object_type_columns = 0\n", - "\n", - "for label, content in df_tmp.items():\n", - " # Check to see if column is of object type (this will include the string columns)\n", - " if pd.api.types.is_object_dtype(content): \n", - " # Check datatype of target column\n", - " column_datatype = df_tmp[label].dtype.name\n", - "\n", - " # Get random sample from column values\n", - " example_value = content.sample(1).values\n", - "\n", - " # Infer random sample datatype\n", - " example_value_dtype = pd.api.types.infer_dtype(example_value)\n", - " print(f\"Column name: {label} | Column dtype: {column_datatype} | Example value: {example_value} | Example value dtype: {example_value_dtype}\")\n", - "\n", - " number_of_object_type_columns += 1\n", - "\n", - "print(f\"\\n[INFO] Total number of object type columns: {number_of_object_type_columns}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Wonderful, looks like we've got sample outputs from all of the columns with the `object` datatype.\n", - "\n", - "It also looks like that many of random samples are missing values." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### TK - Converting strings to categories \n", - "\n", - "In pandas, one way to convert object/string values to numerical values is to convert them to categories or more specifically, the `pd.CategoricalDtype` datatype.\n", - "\n", - "This datatype keeps the underlying data the same (e.g. doesn't change the string) but enables easy conversion to a numeric code using [`.cat.codes`](https://pandas.pydata.org/docs/reference/api/pandas.Series.cat.codes.html).\n", - "\n", - "For example, the column `state` might have the values `'Alabama', 'Alaska', 'Arizona'...` and these could be mapped to numeric values `1, 2, 3...` respectively.\n", - "\n", - "To see this in action, let's first convert the object datatype columns to `\"category\"` datatype.\n", - "\n", - "We can do so by looping through the `.items()` of our DataFrame and reassigning each object datatype column using [`pandas.Series.astype(dtype=\"category\")`](https://pandas.pydata.org/docs/reference/api/pandas.Series.astype.html)." - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "metadata": {}, - "outputs": [], - "source": [ - "# This will turn all of the object columns into category values\n", - "for label, content in df_tmp.items(): \n", - " if pd.api.types.is_object_dtype(content):\n", - " df_tmp[label] = df_tmp[label].astype(\"category\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Wonderful!\n", - "\n", - "Now let's check if it worked by calling `.info()` on our DataFrame." - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "RangeIndex: 412698 entries, 0 to 412697\n", - "Data columns (total 57 columns):\n", - " # Column Non-Null Count Dtype \n", - "--- ------ -------------- ----- \n", - " 0 SalesID 412698 non-null int64 \n", - " 1 SalePrice 412698 non-null float64 \n", - " 2 MachineID 412698 non-null int64 \n", - " 3 ModelID 412698 non-null int64 \n", - " 4 datasource 412698 non-null int64 \n", - " 5 auctioneerID 392562 non-null float64 \n", - " 6 YearMade 412698 non-null int64 \n", - " 7 MachineHoursCurrentMeter 147504 non-null float64 \n", - " 8 UsageBand 73670 non-null category\n", - " 9 fiModelDesc 412698 non-null category\n", - " 10 fiBaseModel 412698 non-null category\n", - " 11 fiSecondaryDesc 271971 non-null category\n", - " 12 fiModelSeries 58667 non-null category\n", - " 13 fiModelDescriptor 74816 non-null category\n", - " 14 ProductSize 196093 non-null category\n", - " 15 fiProductClassDesc 412698 non-null category\n", - " 16 state 412698 non-null category\n", - " 17 ProductGroup 412698 non-null category\n", - " 18 ProductGroupDesc 412698 non-null category\n", - " 19 Drive_System 107087 non-null category\n", - " 20 Enclosure 412364 non-null category\n", - " 21 Forks 197715 non-null category\n", - " 22 Pad_Type 81096 non-null category\n", - " 23 Ride_Control 152728 non-null category\n", - " 24 Stick 81096 non-null category\n", - " 25 Transmission 188007 non-null category\n", - " 26 Turbocharged 81096 non-null category\n", - " 27 Blade_Extension 25983 non-null category\n", - " 28 Blade_Width 25983 non-null category\n", - " 29 Enclosure_Type 25983 non-null category\n", - " 30 Engine_Horsepower 25983 non-null category\n", - " 31 Hydraulics 330133 non-null category\n", - " 32 Pushblock 25983 non-null category\n", - " 33 Ripper 106945 non-null category\n", - " 34 Scarifier 25994 non-null category\n", - " 35 Tip_Control 25983 non-null category\n", - " 36 Tire_Size 97638 non-null category\n", - " 37 Coupler 220679 non-null category\n", - " 38 Coupler_System 44974 non-null category\n", - " 39 Grouser_Tracks 44875 non-null category\n", - " 40 Hydraulics_Flow 44875 non-null category\n", - " 41 Track_Type 102193 non-null category\n", - " 42 Undercarriage_Pad_Width 102916 non-null category\n", - " 43 Stick_Length 102261 non-null category\n", - " 44 Thumb 102332 non-null category\n", - " 45 Pattern_Changer 102261 non-null category\n", - " 46 Grouser_Type 102193 non-null category\n", - " 47 Backhoe_Mounting 80712 non-null category\n", - " 48 Blade_Type 81875 non-null category\n", - " 49 Travel_Controls 81877 non-null category\n", - " 50 Differential_Type 71564 non-null category\n", - " 51 Steering_Controls 71522 non-null category\n", - " 52 saleYear 412698 non-null int64 \n", - " 53 saleMonth 412698 non-null int64 \n", - " 54 saleDay 412698 non-null int64 \n", - " 55 saleDayofweek 412698 non-null int64 \n", - " 56 saleDayofyear 412698 non-null int64 \n", - "dtypes: category(44), float64(3), int64(10)\n", - "memory usage: 60.1 MB\n" - ] - } - ], - "source": [ - "df_tmp.info()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "It looks like it worked!\n", - "\n", - "All of the object datatype columns now have the category datatype.\n", - "\n", - "We can inspect this on a single column using `pandas.Series.dtype`." - ] - }, - { - "cell_type": "code", - "execution_count": 60, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "CategoricalDtype(categories=['Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California',\n", - " 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia',\n", - " 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas',\n", - " 'Kentucky', 'Louisiana', 'Maine', 'Maryland',\n", - " 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi',\n", - " 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire',\n", - " 'New Jersey', 'New Mexico', 'New York', 'North Carolina',\n", - " 'North Dakota', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania',\n", - " 'Puerto Rico', 'Rhode Island', 'South Carolina',\n", - " 'South Dakota', 'Tennessee', 'Texas', 'Unspecified', 'Utah',\n", - " 'Vermont', 'Virginia', 'Washington', 'Washington DC',\n", - " 'West Virginia', 'Wisconsin', 'Wyoming'],\n", - ", ordered=False, categories_dtype=object)" - ] - }, - "execution_count": 60, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Check the datatype of a single column\n", - "df_tmp.state.dtype" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Excellent, notice how the column is now of type `pd.CategoricalDtype`.\n", - "\n", - "We can also access these categories using [`pandas.Series.cat.categories`](https://pandas.pydata.org/docs/reference/api/pandas.Series.cat.categories.html)." - ] - }, - { - "cell_type": "code", - "execution_count": 61, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Index(['Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado',\n", - " 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho',\n", - " 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana',\n", - " 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota',\n", - " 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada',\n", - " 'New Hampshire', 'New Jersey', 'New Mexico', 'New York',\n", - " 'North Carolina', 'North Dakota', 'Ohio', 'Oklahoma', 'Oregon',\n", - " 'Pennsylvania', 'Puerto Rico', 'Rhode Island', 'South Carolina',\n", - " 'South Dakota', 'Tennessee', 'Texas', 'Unspecified', 'Utah', 'Vermont',\n", - " 'Virginia', 'Washington', 'Washington DC', 'West Virginia', 'Wisconsin',\n", - " 'Wyoming'],\n", - " dtype='object')" - ] - }, - "execution_count": 61, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Get the category names of a given column\n", - "df_tmp.state.cat.categories" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, we can get the category codes (the numeric values representing the category) using [`pandas.Series.cat.codes`](https://pandas.pydata.org/docs/reference/api/pandas.Series.cat.codes.html)." - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "205615 43\n", - "274835 8\n", - "141296 8\n", - "212552 8\n", - "62755 8\n", - " ..\n", - "410879 4\n", - "412476 4\n", - "411927 4\n", - "407124 4\n", - "409203 4\n", - "Length: 412698, dtype: int8" - ] - }, - "execution_count": 42, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Inspect the category codes\n", - "df_tmp.state.cat.codes" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This gives us a numeric representation of our object/string datatype columns." - ] - }, - { - "cell_type": "code", - "execution_count": 64, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Target state category number 43 maps to: Texas\n" - ] - } - ], - "source": [ - "# Get example string using category number\n", - "target_state_cat_number = 43\n", - "target_state_cat_value = df_tmp.state.cat.categories[target_state_cat_number] \n", - "print(f\"[INFO] Target state category number {target_state_cat_number} maps to: {target_state_cat_value}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "UPTOHERE - filling missing values, perhaps it's better to create a separate section for this... we don't necessarily need to save the updated values either?\n", - "TK - Could do:\n", - "- try to fit model (doesn't work)\n", - "- still have missing values\n", - "- save values with categories updated\n", - "- fill missing values\n", - "- fit model (works)\n", - "- what's wrong with this?\n", - "- import valid/train datasets separately + update to numerical + fill missing values with Scikit-Learn (as an alternative) \n", - "- fit model... \n", - "\n", - "All of our data is categorical and thus we can now turn the categories into numbers, however it's still missing values..." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### TK - Saving our preprocessed data (part 1)\n", - "\n", - "We've updated our dataset to turn object datatypes into categories.\n", - "\n", - "However, it still contains missing values.\n", - "\n", - "Before we get to those, how about we save our current DataFrame to file so we could import it again later if necessary.\n", - "\n", - "Saving and updating your dataset as you go is common practice in machine learning problems. As your problem changes and evolves, the dataset you're working with will likely change too.\n", - "\n", - "Making checkpoints of your dataset is similar to making checkpoints of your code." - ] - }, - { - "cell_type": "code", - "execution_count": 68, - "metadata": {}, - "outputs": [], - "source": [ - "# Save preprocessed data to file\n", - "df_tmp.to_csv(\"../data/bluebook-for-bulldozers/TrainAndValid_object_values_as_categories.csv\",\n", - " index=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we've saved our preprocessed data to file, we can re-import it and make sure it's in the same format." - ] - }, - { - "cell_type": "code", - "execution_count": 137, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - " \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", - "
SalesIDSalePriceMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandfiModelDesc...Backhoe_MountingBlade_TypeTravel_ControlsDifferential_TypeSteering_ControlssaleYearsaleMonthsaleDaysaleDayofweeksaleDayofyear
016467709500.01126363843413218.01974NaNNaNTD20...None or UnspecifiedStraightNone or UnspecifiedNaNNaN1989117117
1182151414000.011940891015013299.01980NaNNaNA66...NaNNaNNaNStandardConventional1989131131
2150513850000.01473654413913299.01978NaNNaND7G...None or UnspecifiedStraightNone or UnspecifiedNaNNaN1989131131
3167117416000.01327630859113299.01980NaNNaNA62...NaNNaNNaNStandardConventional1989131131
4132905622000.01336053408913299.01984NaNNaND3B...None or UnspecifiedPATLeverNaNNaN1989131131
\n", - "

5 rows × 57 columns

\n", - "
" - ], - "text/plain": [ - " SalesID SalePrice MachineID ModelID datasource auctioneerID YearMade \\\n", - "0 1646770 9500.0 1126363 8434 132 18.0 1974 \n", - "1 1821514 14000.0 1194089 10150 132 99.0 1980 \n", - "2 1505138 50000.0 1473654 4139 132 99.0 1978 \n", - "3 1671174 16000.0 1327630 8591 132 99.0 1980 \n", - "4 1329056 22000.0 1336053 4089 132 99.0 1984 \n", - "\n", - " MachineHoursCurrentMeter UsageBand fiModelDesc ... Backhoe_Mounting \\\n", - "0 NaN NaN TD20 ... None or Unspecified \n", - "1 NaN NaN A66 ... NaN \n", - "2 NaN NaN D7G ... None or Unspecified \n", - "3 NaN NaN A62 ... NaN \n", - "4 NaN NaN D3B ... None or Unspecified \n", - "\n", - " Blade_Type Travel_Controls Differential_Type Steering_Controls \\\n", - "0 Straight None or Unspecified NaN NaN \n", - "1 NaN NaN Standard Conventional \n", - "2 Straight None or Unspecified NaN NaN \n", - "3 NaN NaN Standard Conventional \n", - "4 PAT Lever NaN NaN \n", - "\n", - " saleYear saleMonth saleDay saleDayofweek saleDayofyear \n", - "0 1989 1 17 1 17 \n", - "1 1989 1 31 1 31 \n", - "2 1989 1 31 1 31 \n", - "3 1989 1 31 1 31 \n", - "4 1989 1 31 1 31 \n", - "\n", - "[5 rows x 57 columns]" - ] - }, - "execution_count": 137, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Import preprocessed data to file\n", - "df_tmp = pd.read_csv(\"../data/bluebook-for-bulldozers/TrainAndValid_object_values_as_categories.csv\",\n", - " low_memory=False)\n", - "\n", - "df_tmp.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Excellent, looking at the tale end (the far right side) our processed DataFrame has the columns we added to it (the extra data features) but it's still missing values.\n", - "\n", - "But if we check `df_tmp.info()`..." - ] - }, - { - "cell_type": "code", - "execution_count": 138, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "RangeIndex: 412698 entries, 0 to 412697\n", - "Data columns (total 57 columns):\n", - " # Column Non-Null Count Dtype \n", - "--- ------ -------------- ----- \n", - " 0 SalesID 412698 non-null int64 \n", - " 1 SalePrice 412698 non-null float64\n", - " 2 MachineID 412698 non-null int64 \n", - " 3 ModelID 412698 non-null int64 \n", - " 4 datasource 412698 non-null int64 \n", - " 5 auctioneerID 392562 non-null float64\n", - " 6 YearMade 412698 non-null int64 \n", - " 7 MachineHoursCurrentMeter 147504 non-null float64\n", - " 8 UsageBand 73670 non-null object \n", - " 9 fiModelDesc 412698 non-null object \n", - " 10 fiBaseModel 412698 non-null object \n", - " 11 fiSecondaryDesc 271971 non-null object \n", - " 12 fiModelSeries 58667 non-null object \n", - " 13 fiModelDescriptor 74816 non-null object \n", - " 14 ProductSize 196093 non-null object \n", - " 15 fiProductClassDesc 412698 non-null object \n", - " 16 state 412698 non-null object \n", - " 17 ProductGroup 412698 non-null object \n", - " 18 ProductGroupDesc 412698 non-null object \n", - " 19 Drive_System 107087 non-null object \n", - " 20 Enclosure 412364 non-null object \n", - " 21 Forks 197715 non-null object \n", - " 22 Pad_Type 81096 non-null object \n", - " 23 Ride_Control 152728 non-null object \n", - " 24 Stick 81096 non-null object \n", - " 25 Transmission 188007 non-null object \n", - " 26 Turbocharged 81096 non-null object \n", - " 27 Blade_Extension 25983 non-null object \n", - " 28 Blade_Width 25983 non-null object \n", - " 29 Enclosure_Type 25983 non-null object \n", - " 30 Engine_Horsepower 25983 non-null object \n", - " 31 Hydraulics 330133 non-null object \n", - " 32 Pushblock 25983 non-null object \n", - " 33 Ripper 106945 non-null object \n", - " 34 Scarifier 25994 non-null object \n", - " 35 Tip_Control 25983 non-null object \n", - " 36 Tire_Size 97638 non-null object \n", - " 37 Coupler 220679 non-null object \n", - " 38 Coupler_System 44974 non-null object \n", - " 39 Grouser_Tracks 44875 non-null object \n", - " 40 Hydraulics_Flow 44875 non-null object \n", - " 41 Track_Type 102193 non-null object \n", - " 42 Undercarriage_Pad_Width 102916 non-null object \n", - " 43 Stick_Length 102261 non-null object \n", - " 44 Thumb 102332 non-null object \n", - " 45 Pattern_Changer 102261 non-null object \n", - " 46 Grouser_Type 102193 non-null object \n", - " 47 Backhoe_Mounting 80712 non-null object \n", - " 48 Blade_Type 81875 non-null object \n", - " 49 Travel_Controls 81877 non-null object \n", - " 50 Differential_Type 71564 non-null object \n", - " 51 Steering_Controls 71522 non-null object \n", - " 52 saleYear 412698 non-null int64 \n", - " 53 saleMonth 412698 non-null int64 \n", - " 54 saleDay 412698 non-null int64 \n", - " 55 saleDayofweek 412698 non-null int64 \n", - " 56 saleDayofyear 412698 non-null int64 \n", - "dtypes: float64(3), int64(10), object(44)\n", - "memory usage: 179.5+ MB\n" - ] - } - ], - "source": [ - "df_tmp.info()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We notice that all of the `category` datatype columns are back to the `object` datatype.\n", - "\n", - "This is strange since we already converted the `object` datatype columns to `category`.\n", - "\n", - "Well then why did they change back?\n", - "\n", - "This happens because of the limitations of the CSV (`.csv`) file format, it doesn't preserve data types, rather it stores all the values as strings.\n", - "\n", - "So when we read in a CSV, pandas defaults to interpreting strings as `object` datatypes.\n", - "\n", - "Not to worry though, we can easily convert them to the `category` datatype as we did before.\n", - "\n", - "> **Note:** If you'd like to retain the datatypes when saving your data, you can use file formats such as [`parquet`](https://pandas.pydata.org/docs/user_guide/io.html#parquet) (Apache Parquet) and [`feather`](https://pandas.pydata.org/docs/user_guide/io.html#feather). These filetypes have several advantages over CSV in terms of processing speeds and storage size. However, data stored in these formats is not human-readable so you won't be able to open the files and inspect them without specific tools. For more on different file formats in pandas, see the [IO tools documentation page](https://pandas.pydata.org/docs/user_guide/io.html#)." - ] - }, - { - "cell_type": "code", - "execution_count": 139, - "metadata": {}, - "outputs": [], - "source": [ - "for label, content in df_tmp.items():\n", - " if pd.api.types.is_object_dtype(content):\n", - " # Turn object columns into category datatype\n", - " df_tmp[label] = df_tmp[label].astype(\"category\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now if we wanted to preserve the datatypes of our data, we can save to `parquet` or `feather` format.\n", - "\n", - "Let's try using `parquet` format.\n", - "\n", - "To do so, we can use the [`pandas.DataFrame.to_parquet()`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_parquet.html) method.\n", - "\n", - "Files in the `parquet` format typically have the file extension of `.parquet`." - ] - }, - { - "cell_type": "code", - "execution_count": 155, - "metadata": {}, - "outputs": [], - "source": [ - "# To save to parquet format requires pyarrow or fastparquet (or both)\n", - "# Can install via `pip install pyarrow fastparquet`\n", - "df_tmp.to_parquet(path=\"../data/bluebook-for-bulldozers/TrainAndValid_object_values_as_categories.parquet\", \n", - " engine=\"auto\") # \"auto\" will automatically use pyarrow or fastparquet, defaulting to pyarrow first" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Wonderful! Now let's try importing our DataFrame from the `parquet` format and check it using `df_tmp.info()`." - ] - }, - { - "cell_type": "code", - "execution_count": 157, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "RangeIndex: 412698 entries, 0 to 412697\n", - "Data columns (total 59 columns):\n", - " # Column Non-Null Count Dtype \n", - "--- ------ -------------- ----- \n", - " 0 SalesID 412698 non-null int64 \n", - " 1 SalePrice 412698 non-null float64 \n", - " 2 MachineID 412698 non-null int64 \n", - " 3 ModelID 412698 non-null int64 \n", - " 4 datasource 412698 non-null int64 \n", - " 5 auctioneerID 412698 non-null float64 \n", - " 6 YearMade 412698 non-null int64 \n", - " 7 MachineHoursCurrentMeter 412698 non-null float64 \n", - " 8 UsageBand 73670 non-null category\n", - " 9 fiModelDesc 412698 non-null category\n", - " 10 fiBaseModel 412698 non-null category\n", - " 11 fiSecondaryDesc 271971 non-null category\n", - " 12 fiModelSeries 58667 non-null category\n", - " 13 fiModelDescriptor 74816 non-null category\n", - " 14 ProductSize 196093 non-null category\n", - " 15 fiProductClassDesc 412698 non-null category\n", - " 16 state 412698 non-null category\n", - " 17 ProductGroup 412698 non-null category\n", - " 18 ProductGroupDesc 412698 non-null category\n", - " 19 Drive_System 107087 non-null category\n", - " 20 Enclosure 412364 non-null category\n", - " 21 Forks 197715 non-null category\n", - " 22 Pad_Type 81096 non-null category\n", - " 23 Ride_Control 152728 non-null category\n", - " 24 Stick 81096 non-null category\n", - " 25 Transmission 188007 non-null category\n", - " 26 Turbocharged 81096 non-null category\n", - " 27 Blade_Extension 25983 non-null category\n", - " 28 Blade_Width 25983 non-null category\n", - " 29 Enclosure_Type 25983 non-null category\n", - " 30 Engine_Horsepower 25983 non-null category\n", - " 31 Hydraulics 330133 non-null category\n", - " 32 Pushblock 25983 non-null category\n", - " 33 Ripper 106945 non-null category\n", - " 34 Scarifier 25994 non-null category\n", - " 35 Tip_Control 25983 non-null category\n", - " 36 Tire_Size 97638 non-null category\n", - " 37 Coupler 220679 non-null category\n", - " 38 Coupler_System 44974 non-null category\n", - " 39 Grouser_Tracks 44875 non-null category\n", - " 40 Hydraulics_Flow 44875 non-null category\n", - " 41 Track_Type 102193 non-null category\n", - " 42 Undercarriage_Pad_Width 102916 non-null category\n", - " 43 Stick_Length 102261 non-null category\n", - " 44 Thumb 102332 non-null category\n", - " 45 Pattern_Changer 102261 non-null category\n", - " 46 Grouser_Type 102193 non-null category\n", - " 47 Backhoe_Mounting 80712 non-null category\n", - " 48 Blade_Type 81875 non-null category\n", - " 49 Travel_Controls 81877 non-null category\n", - " 50 Differential_Type 71564 non-null category\n", - " 51 Steering_Controls 71522 non-null category\n", - " 52 saleYear 412698 non-null int64 \n", - " 53 saleMonth 412698 non-null int64 \n", - " 54 saleDay 412698 non-null int64 \n", - " 55 saleDayofweek 412698 non-null int64 \n", - " 56 saleDayofyear 412698 non-null int64 \n", - " 57 auctioneerID_is_missing 412698 non-null int64 \n", - " 58 MachineHoursCurrentMeter_is_missing 412698 non-null int64 \n", - "dtypes: category(44), float64(3), int64(12)\n", - "memory usage: 66.4 MB\n" - ] - } - ], - "source": [ - "# Read in df_tmp from parquet format\n", - "df_tmp = pd.read_parquet(path=\"../data/bluebook-for-bulldozers/TrainAndValid_object_values_as_categories.parquet\",\n", - " engine=\"auto\")\n", - "\n", - "# Using parquet format, datatypes are preserved\n", - "df_tmp.info()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Nice! Looks like using the `parquet` format preserved all of our datatypes.\n", - "\n", - "For more on the `parquet` and `feather` formats, be sure to check out the [pandas IO (input/output) documentation](https://pandas.pydata.org/docs/user_guide/io.html#parquet)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### TK - Finding and filling missing values\n", - "\n", - "Let's remind ourselves of the missing values by getting the top 20 columns with the most missing values." - ] - }, - { - "cell_type": "code", - "execution_count": 146, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Blade_Width 386715\n", - "Engine_Horsepower 386715\n", - "Tip_Control 386715\n", - "Pushblock 386715\n", - "Blade_Extension 386715\n", - "Enclosure_Type 386715\n", - "Scarifier 386704\n", - "Hydraulics_Flow 367823\n", - "Grouser_Tracks 367823\n", - "Coupler_System 367724\n", - "fiModelSeries 354031\n", - "Steering_Controls 341176\n", - "Differential_Type 341134\n", - "UsageBand 339028\n", - "fiModelDescriptor 337882\n", - "Backhoe_Mounting 331986\n", - "Stick 331602\n", - "Turbocharged 331602\n", - "Pad_Type 331602\n", - "Blade_Type 330823\n", - "dtype: int64" - ] - }, - "execution_count": 146, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Check missing values\n", - "df_tmp.isna().sum().sort_values(ascending=False)[:20]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Ok, it seems like there are a fair few columns with missing values and there are several datatypes across these columns (numerical, categorical).\n", - "\n", - "How about we break the problem down and work on filling each datatype separately?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### TK - Filling missing numerical values\n", - "\n", - "There's no set way to fill missing values in your dataset.\n", - "\n", - "And unless you're filling the missing samples with newly discovered actual data, every way you fill your dataset's missing values will introduce some sort of noise or bias. \n", - "\n", - "We'll start by filling the missing numerical values in ourdataet.\n", - "\n", - "To do this, we'll first find the numeric datatype columns.\n", - "\n", - "We can do by looping through the columns in our DataFrame and calling [`pd.api.types.is_numeric_dtype(arr_or_dtype)`](https://pandas.pydata.org/docs/reference/api/pandas.api.types.is_numeric_dtype.html) on them." - ] - }, - { - "cell_type": "code", - "execution_count": 147, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Column name: SalesID | Column dtype: int64 | Example value: [1146304] | Example value dtype: integer\n", - "Column name: SalePrice | Column dtype: float64 | Example value: [13000.] | Example value dtype: floating\n", - "Column name: MachineID | Column dtype: int64 | Example value: [1408211] | Example value dtype: integer\n", - "Column name: ModelID | Column dtype: int64 | Example value: [3856] | Example value dtype: integer\n", - "Column name: datasource | Column dtype: int64 | Example value: [136] | Example value dtype: integer\n", - "Column name: auctioneerID | Column dtype: float64 | Example value: [1.] | Example value dtype: floating\n", - "Column name: YearMade | Column dtype: int64 | Example value: [2003] | Example value dtype: integer\n", - "Column name: MachineHoursCurrentMeter | Column dtype: float64 | Example value: [nan] | Example value dtype: floating\n", - "Column name: saleYear | Column dtype: int64 | Example value: [2010] | Example value dtype: integer\n", - "Column name: saleMonth | Column dtype: int64 | Example value: [11] | Example value dtype: integer\n", - "Column name: saleDay | Column dtype: int64 | Example value: [3] | Example value dtype: integer\n", - "Column name: saleDayofweek | Column dtype: int64 | Example value: [4] | Example value dtype: integer\n", - "Column name: saleDayofyear | Column dtype: int64 | Example value: [330] | Example value dtype: integer\n" - ] - } - ], - "source": [ - "# Find numeric columns \n", - "for label, content in df_tmp.items():\n", - " if pd.api.types.is_numeric_dtype(content):\n", - " # Check datatype of target column\n", - " column_datatype = df_tmp[label].dtype.name\n", - "\n", - " # Get random sample from column values\n", - " example_value = content.sample(1).values\n", - "\n", - " # Infer random sample datatype\n", - " example_value_dtype = pd.api.types.infer_dtype(example_value)\n", - " print(f\"Column name: {label} | Column dtype: {column_datatype} | Example value: {example_value} | Example value dtype: {example_value_dtype}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Beautiful! Looks like we've got a mixture of `int64` and `float64` numerical datatypes.\n", - "\n", - "Now how about we find out which numeric columns are missing values?\n", - "\n", - "We can do so by using `pandas.isnull(obj).sum()` to detect and sum the missing values in a given array-like object (in our case, the data in a target column).\n", - "\n", - "Let's loop through our DataFrame columns, find the numeric datatypes and check if they have any missing values." - ] - }, - { - "cell_type": "code", - "execution_count": 148, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Column name: SalesID | Has missing values: False\n", - "Column name: SalePrice | Has missing values: False\n", - "Column name: MachineID | Has missing values: False\n", - "Column name: ModelID | Has missing values: False\n", - "Column name: datasource | Has missing values: False\n", - "Column name: auctioneerID | Has missing values: True\n", - "Column name: YearMade | Has missing values: False\n", - "Column name: MachineHoursCurrentMeter | Has missing values: True\n", - "Column name: saleYear | Has missing values: False\n", - "Column name: saleMonth | Has missing values: False\n", - "Column name: saleDay | Has missing values: False\n", - "Column name: saleDayofweek | Has missing values: False\n", - "Column name: saleDayofyear | Has missing values: False\n" - ] - } - ], - "source": [ - "# Check for which numeric columns have null values\n", - "for label, content in df_tmp.items():\n", - " if pd.api.types.is_numeric_dtype(content):\n", - " if pd.isnull(content).sum():\n", - " print(f\"Column name: {label} | Has missing values: {True}\")\n", - " else:\n", - " print(f\"Column name: {label} | Has missing values: {False}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Okay, it looks like our `auctioneerID` and `MachineHoursCurrentMeter` columns have missing numeric values.\n", - "\n", - "As previously discussed, there are many ways to fill missing values.\n", - "\n", - "For missing numeric values, some potential options are:\n", - "\n", - "| **Method** | **Pros** | **Cons** |\n", - "|-----|-----|-----|\n", - "| **Fill with mean of column** | - Easy to calculate/implement
- Retains overall data distribution | - Averages out variation
- Affected by outliers (e.g. if one value is much higher/lower than others) |\n", - "| **Fill with median of column** | - Easy to calculate/implement
- Robust to outliers
- Preserves center of data | - Ignores data distribution shape |\n", - "| **Fill with mode of column** | - Easy to calculate/implement
- More useful for categorical-like data | - May not make sense for continuous/numerical data |\n", - "| **Fill with 0 (or another constant)** | - Simple to implement
- Useful in certain contexts like counts | - Introduces bias (e.g. if 0 was a value that meant something)
- Skews data (e.g. if many missing values, replacing all with 0 makes it look like that's the most common value) |\n", - "| **Forward/Backward fill (use previous/future values to fill future/previous values)** | - Maintains temporal continuity (for time series) | - Assumes data is continuous, which may not be valid |\n", - "| **Use a calculation from other columns** | - Takes existing information and reinterprets it | - Can result in unlikely outputs if calculations are not continuous | \n", - "| **Interpolate (e.g. like dragging a cell in Excel/Google Sheets)** | - Captures trends
- Suitable for ordered data | - Can introduce errors
- May assume linearity (data continues in a straight line) |\n", - "| **Drop missing values** | - Ensures complete data (only use samples with all information)
- Useful for small datasets | - Can result in data loss (e.g. if many missing values are scattered across columns, data size can be dramatically reduced)
- Reduces dataset size |\n", - "\n", - "Which method you choose will be dataset and problem dependant and will likely require several phases of experimentation to see what works and what doesn't.\n", - "\n", - "For now, we'll fill our missing numeric values with the median value of the target column.\n", - "\n", - "We'll also add a binary column (0 or 1) with rows reflecting whether or not a value was missing.\n", - "\n", - "For example, `MachineHoursCurrentMeter_is_missing` will be a column with rows which have a value of `0` if that row's `MachineHoursCurrentMeter` column was *not* missing and `1` if it was.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 149, - "metadata": {}, - "outputs": [], - "source": [ - "# Fill missing numeric values with the median of the target column\n", - "for label, content in df_tmp.items():\n", - " if pd.api.types.is_numeric_dtype(content):\n", - " if pd.isnull(content).sum():\n", - " \n", - " # Add a binary column which tells if the data was missing our not\n", - " df_tmp[label+\"_is_missing\"] = pd.isnull(content).astype(int) # this will add a 0 or 1 value to rows with missing values (e.g. 0 = not missing, 1 = missing)\n", - "\n", - " # Fill missing numeric values with median since it's more robust than the mean\n", - " df_tmp[label] = content.fillna(content.median())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Why add a binary column indicating whether the data was missing or not?\n", - "\n", - "We can easily fill all of the missing numeric values in our dataset with the median. \n", - "\n", - "However, a numeric value may be missing for a reason. \n", - "\n", - "Adding a binary column which indicates whether the value was missing or not helps to retain this information. It also means we can inspect these rows later on." - ] - }, - { - "cell_type": "code", - "execution_count": 150, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - " \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", - "
SalesIDSalePriceMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandfiModelDesc...Travel_ControlsDifferential_TypeSteering_ControlssaleYearsaleMonthsaleDaysaleDayofweeksaleDayofyearauctioneerID_is_missingMachineHoursCurrentMeter_is_missing
185062155927239000.048081435421321.020020.0NaN420D...NaNNaNNaN2005616316701
32362125654222000.01451409324713221.019850.0NaN880D...NaNNaNNaN19941010028301
100005170731521000.01439450158831321.019930.0NaN217S...NaNNaNNaN2000929427301
131755127159310500.0138084931121329.010000.0NaN1845C...NaNNaNNaN2002621417201
19690131462582500.089824741571321.019880.0NaND9N...None or UnspecifiedNaNNaN19921214034901
\n", - "

5 rows × 59 columns

\n", - "
" - ], - "text/plain": [ - " SalesID SalePrice MachineID ModelID datasource auctioneerID \\\n", - "185062 1559272 39000.0 480814 3542 132 1.0 \n", - "32362 1256542 22000.0 1451409 3247 132 21.0 \n", - "100005 1707315 21000.0 1439450 15883 132 1.0 \n", - "131755 1271593 10500.0 1380849 3112 132 9.0 \n", - "19690 1314625 82500.0 898247 4157 132 1.0 \n", - "\n", - " YearMade MachineHoursCurrentMeter UsageBand fiModelDesc ... \\\n", - "185062 2002 0.0 NaN 420D ... \n", - "32362 1985 0.0 NaN 880D ... \n", - "100005 1993 0.0 NaN 217S ... \n", - "131755 1000 0.0 NaN 1845C ... \n", - "19690 1988 0.0 NaN D9N ... \n", - "\n", - " Travel_Controls Differential_Type Steering_Controls saleYear \\\n", - "185062 NaN NaN NaN 2005 \n", - "32362 NaN NaN NaN 1994 \n", - "100005 NaN NaN NaN 2000 \n", - "131755 NaN NaN NaN 2002 \n", - "19690 None or Unspecified NaN NaN 1992 \n", - "\n", - " saleMonth saleDay saleDayofweek saleDayofyear auctioneerID_is_missing \\\n", - "185062 6 16 3 167 0 \n", - "32362 10 10 0 283 0 \n", - "100005 9 29 4 273 0 \n", - "131755 6 21 4 172 0 \n", - "19690 12 14 0 349 0 \n", - "\n", - " MachineHoursCurrentMeter_is_missing \n", - "185062 1 \n", - "32362 1 \n", - "100005 1 \n", - "131755 1 \n", - "19690 1 \n", - "\n", - "[5 rows x 59 columns]" - ] - }, - "execution_count": 150, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Show rows where MachineHoursCurrentMeter_is_missing == 1\n", - "df_tmp[df_tmp[\"MachineHoursCurrentMeter_is_missing\"] == 1].sample(5)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Missing numeric values filled!\n", - "\n", - "How about we check again whether or not the numeric columns have missing values?" - ] - }, - { - "cell_type": "code", - "execution_count": 151, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Column name: SalesID | Has missing values: False\n", - "Column name: SalePrice | Has missing values: False\n", - "Column name: MachineID | Has missing values: False\n", - "Column name: ModelID | Has missing values: False\n", - "Column name: datasource | Has missing values: False\n", - "Column name: auctioneerID | Has missing values: False\n", - "Column name: YearMade | Has missing values: False\n", - "Column name: MachineHoursCurrentMeter | Has missing values: False\n", - "Column name: saleYear | Has missing values: False\n", - "Column name: saleMonth | Has missing values: False\n", - "Column name: saleDay | Has missing values: False\n", - "Column name: saleDayofweek | Has missing values: False\n", - "Column name: saleDayofyear | Has missing values: False\n", - "Column name: auctioneerID_is_missing | Has missing values: False\n", - "Column name: MachineHoursCurrentMeter_is_missing | Has missing values: False\n" - ] - } - ], - "source": [ - "# Check for which numeric columns have null values\n", - "for label, content in df_tmp.items():\n", - " if pd.api.types.is_numeric_dtype(content):\n", - " if pd.isnull(content).sum():\n", - " print(f\"Column name: {label} | Has missing values: {True}\")\n", - " else:\n", - " print(f\"Column name: {label} | Has missing values: {False}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Woohoo! Numeric missing values filled!\n", - "\n", - "And thanks to our binary `_is_missing` columns, we can even check how many were missing." - ] - }, - { - "cell_type": "code", - "execution_count": 152, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "auctioneerID_is_missing\n", - "0 392562\n", - "1 20136\n", - "Name: count, dtype: int64" - ] - }, - "execution_count": 152, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Check to see how many examples in the auctioneerID were missing\n", - "df_tmp.auctioneerID_is_missing.value_counts()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### TK - Filling missing categorical values \n", - "\n", - "UPTOHERE \n", - "- filling missing categorical variables\n", - "- save the data again with numeric + filled values\n", - "- fit model \n", - "- eval model\n", - "- discuss the mistake (mixing train + val datasets) + how to fix it\n", - "- continue into splitting data section\n", - "\n", - "Now we've filled the numeric values, we'll do the same with the categorical values whilst ensuring that they are all numerical too.\n", - "\n", - "Let's first investigate the columns which *aren't* numeric (we've already worked with these). " - ] - }, - { - "cell_type": "code", - "execution_count": 169, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Columns which are not numeric:\n", - "Column name: UsageBand | Column dtype: category\n", - "Column name: fiModelDesc | Column dtype: category\n", - "Column name: fiBaseModel | Column dtype: category\n", - "Column name: fiSecondaryDesc | Column dtype: category\n", - "Column name: fiModelSeries | Column dtype: category\n", - "Column name: fiModelDescriptor | Column dtype: category\n", - "Column name: ProductSize | Column dtype: category\n", - "Column name: fiProductClassDesc | Column dtype: category\n", - "Column name: state | Column dtype: category\n", - "Column name: ProductGroup | Column dtype: category\n", - "Column name: ProductGroupDesc | Column dtype: category\n", - "Column name: Drive_System | Column dtype: category\n", - "Column name: Enclosure | Column dtype: category\n", - "Column name: Forks | Column dtype: category\n", - "Column name: Pad_Type | Column dtype: category\n", - "Column name: Ride_Control | Column dtype: category\n", - "Column name: Stick | Column dtype: category\n", - "Column name: Transmission | Column dtype: category\n", - "Column name: Turbocharged | Column dtype: category\n", - "Column name: Blade_Extension | Column dtype: category\n", - "Column name: Blade_Width | Column dtype: category\n", - "Column name: Enclosure_Type | Column dtype: category\n", - "Column name: Engine_Horsepower | Column dtype: category\n", - "Column name: Hydraulics | Column dtype: category\n", - "Column name: Pushblock | Column dtype: category\n", - "Column name: Ripper | Column dtype: category\n", - "Column name: Scarifier | Column dtype: category\n", - "Column name: Tip_Control | Column dtype: category\n", - "Column name: Tire_Size | Column dtype: category\n", - "Column name: Coupler | Column dtype: category\n", - "Column name: Coupler_System | Column dtype: category\n", - "Column name: Grouser_Tracks | Column dtype: category\n", - "Column name: Hydraulics_Flow | Column dtype: category\n", - "Column name: Track_Type | Column dtype: category\n", - "Column name: Undercarriage_Pad_Width | Column dtype: category\n", - "Column name: Stick_Length | Column dtype: category\n", - "Column name: Thumb | Column dtype: category\n", - "Column name: Pattern_Changer | Column dtype: category\n", - "Column name: Grouser_Type | Column dtype: category\n", - "Column name: Backhoe_Mounting | Column dtype: category\n", - "Column name: Blade_Type | Column dtype: category\n", - "Column name: Travel_Controls | Column dtype: category\n", - "Column name: Differential_Type | Column dtype: category\n", - "Column name: Steering_Controls | Column dtype: category\n" - ] - } - ], - "source": [ - "# Check columns which aren't numeric\n", - "print(f\"[INFO] Columns which are not numeric:\")\n", - "for label, content in df_tmp.items():\n", - " if not pd.api.types.is_numeric_dtype(content):\n", - " print(f\"Column name: {label} | Column dtype: {df_tmp[label].dtype.name}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Okay, we've got plenty of category type columns.\n", - "\n", - "Let's now write some code to fill the missing categorical values as well as ensure they are numerical (non-string). \n", - "\n", - "To do so, we'll:\n", - "\n", - "1. Create a blank column to category dictionary, we'll use this to store categorical value names (e.g. their string name) as well as their categorical code. We'll end with a dictionary of dictionaries in the form `{\"column_name\": {category_code: \"category_value\"...}...}`.\n", - "2. Loop through the items in the DataFrame.\n", - "3. Check if the column is numeric or not.\n", - "4. Add a binary column in the form `ORIGINAL_COLUMN_NAME_is_missing` with a `0` or `1` value for if the row had a missing value.\n", - "5. Ensure the column values are in the `pd.Categorical` datatype and get their category codes with `pd.Series.cat.codes` (we'll add `1` to these values since pandas defaults to assigning `-1` to `NaN` values, we'll use `0` instead).\n", - "6. Turn the column categories and column category codes from 5 into a dictionary with Python's [`dict(zip(category_names, category_codes))`](https://docs.python.org/3.3/library/functions.html#zip) and save this to the blank dictionary from 1 with the target column name as key.\n", - "7. Set the target column value to the numerical category values from 5.\n", - "\n", - "Phew!\n", - "\n", - "That's a fair few steps but nothing we can't handle.\n", - "\n", - "Let's do it!" - ] - }, - { - "cell_type": "code", - "execution_count": 171, - "metadata": {}, - "outputs": [], - "source": [ - "# 1. Create a dictionary to store column to category values (e.g. we turn our category types into numbers but we keep a record so we can go back)\n", - "column_to_category_dict = {} \n", - "\n", - "# 2. Turn categorical variables into numbers\n", - "for label, content in df_tmp.items():\n", - "\n", - " # 3. Check columns which *aren't* numeric\n", - " if not pd.api.types.is_numeric_dtype(content):\n", - "\n", - " # 4. Add binary column to inidicate whether sample had missing value\n", - " df_tmp[label+\"_is_missing\"] = pd.isnull(content).astype(int)\n", - "\n", - " # 5. Ensure content is categorical and get its category codes\n", - " content_categories = pd.Categorical(content)\n", - " content_category_codes = content_categories.codes + 1 # prevents -1 (the default for NaN values) from being used for missing values (we'll treat missing values as 0)\n", - "\n", - " # 6. Add column key to dictionary with code: category mapping per column\n", - " column_to_category_dict[label] = dict(zip(content_category_codes, content_categories))\n", - " \n", - " # 7. Set the column to the numerical values (the category code value) \n", - " df_tmp[label] = content_category_codes " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Ho ho! No errors!\n", - "\n", - "Let's check out a few random samples of our DataFrame." - ] - }, - { - "cell_type": "code", - "execution_count": 174, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - " \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", - "
SalesIDSalePriceMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandfiModelDesc...Undercarriage_Pad_Width_is_missingStick_Length_is_missingThumb_is_missingPattern_Changer_is_missingGrouser_Type_is_missingBackhoe_Mounting_is_missingBlade_Type_is_missingTravel_Controls_is_missingDifferential_Type_is_missingSteering_Controls_is_missing
157621168764762500.01451688116301327.019960.002769...0000011111
24770149116334500.01177842410713299.019860.002178...1111100011
351574243292611500.01256467360331361.020051712.034259...1111111111
396421632034551000.0187729958891491.020060.003374...1111111100
378776265565816000.0185247148971491.019964436.024615...1111100011
\n", - "

5 rows × 103 columns

\n", - "
" - ], - "text/plain": [ - " SalesID SalePrice MachineID ModelID datasource auctioneerID \\\n", - "157621 1687647 62500.0 1451688 11630 132 7.0 \n", - "24770 1491163 34500.0 1177842 4107 132 99.0 \n", - "351574 2432926 11500.0 1256467 36033 136 1.0 \n", - "396421 6320345 51000.0 1877299 5889 149 1.0 \n", - "378776 2655658 16000.0 1852471 4897 149 1.0 \n", - "\n", - " YearMade MachineHoursCurrentMeter UsageBand fiModelDesc ... \\\n", - "157621 1996 0.0 0 2769 ... \n", - "24770 1986 0.0 0 2178 ... \n", - "351574 2005 1712.0 3 4259 ... \n", - "396421 2006 0.0 0 3374 ... \n", - "378776 1996 4436.0 2 4615 ... \n", - "\n", - " Undercarriage_Pad_Width_is_missing Stick_Length_is_missing \\\n", - "157621 0 0 \n", - "24770 1 1 \n", - "351574 1 1 \n", - "396421 1 1 \n", - "378776 1 1 \n", - "\n", - " Thumb_is_missing Pattern_Changer_is_missing Grouser_Type_is_missing \\\n", - "157621 0 0 0 \n", - "24770 1 1 1 \n", - "351574 1 1 1 \n", - "396421 1 1 1 \n", - "378776 1 1 1 \n", - "\n", - " Backhoe_Mounting_is_missing Blade_Type_is_missing \\\n", - "157621 1 1 \n", - "24770 0 0 \n", - "351574 1 1 \n", - "396421 1 1 \n", - "378776 0 0 \n", - "\n", - " Travel_Controls_is_missing Differential_Type_is_missing \\\n", - "157621 1 1 \n", - "24770 0 1 \n", - "351574 1 1 \n", - "396421 1 0 \n", - "378776 0 1 \n", - "\n", - " Steering_Controls_is_missing \n", - "157621 1 \n", - "24770 1 \n", - "351574 1 \n", - "396421 0 \n", - "378776 1 \n", - "\n", - "[5 rows x 103 columns]" - ] - }, - "execution_count": 174, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df_tmp.sample(5)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Beautiful! Looks like our data is all in numerical form.\n", - "\n", - "How about we investigate an item from our `column_to_category_dict`?\n", - "\n", - "This will show the mapping from numerical value to category (most likely a string) value." - ] - }, - { - "cell_type": "code", - "execution_count": 184, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0 -> nan\n", - "1 -> High\n", - "2 -> Low\n", - "3 -> Medium\n" - ] - } - ], - "source": [ - "# Check the UsageBand (measure of bulldozer usage)\n", - "for key, value in sorted(column_to_category_dict[\"UsageBand\"].items()): # note: calling sorted() on dictionary.items() sorts the dictionary by keys \n", - " print(f\"{key} -> {value}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "> **Note:** Categorical values do not necessarily have order. They are strictly a mapping from number to value. In this case, our categorical values are mapped in numerical order. If you feel that the order of a value may influence a model in a negative way (e.g. `1 -> High` is *lower* than `3 -> Medium` but should be *higher*), you may want to look into ordering the values in a particular way or using a different numerical encoding technique such as [one-hot encoding](https://en.wikipedia.org/wiki/One-hot).\n", - "\n", - "And we can do the same for the `state` column values." - ] - }, - { - "cell_type": "code", - "execution_count": 182, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1 -> Alabama\n", - "2 -> Alaska\n", - "3 -> Arizona\n", - "4 -> Arkansas\n", - "5 -> California\n", - "6 -> Colorado\n", - "7 -> Connecticut\n", - "8 -> Delaware\n", - "9 -> Florida\n", - "10 -> Georgia\n" - ] - } - ], - "source": [ - "# Check the first 10 state column values\n", - "for key, value in sorted(column_to_category_dict[\"state\"].items())[:10]:\n", - " print(f\"{key} -> {value}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Beautiful!\n", - "\n", - "How about we check to see all of the missing values have been filled?" - ] - }, - { - "cell_type": "code", - "execution_count": 188, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Total missing values: 0 - Woohoo! Let's build a model!\n" - ] - } - ], - "source": [ - "# Check total number of missing values\n", - "total_missing_values = df_tmp.isna().sum().sum()\n", - "\n", - "if total_missing_values == 0:\n", - " print(f\"[INFO] Total missing values: {total_missing_values} - Woohoo! Let's build a model!\")\n", - "else:\n", - " print(f\"[INFO] Uh ohh... total missing values: {total_missing_values} - Perhaps we might have to retrace our steps to fill the values?\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### TK - Saving our preprocessed data (part 2)\n", - "\n", - "One more step before we train new model!\n", - "\n", - "Let's save our work so far so we could re-import our preprocessed dataset if we wanted to.\n", - "\n", - "We'll save it to the `parquet` format again, this time with a suffix to show we've filled the missing values." - ] - }, - { - "cell_type": "code", - "execution_count": 190, - "metadata": {}, - "outputs": [], - "source": [ - "# Save preprocessed data with object values as categories as well as missing values filled\n", - "df_tmp.to_parquet(path=\"../data/bluebook-for-bulldozers/TrainAndValid_object_values_as_categories_and_missing_values_filled.parquet\",\n", - " engine=\"auto\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And to make sure it worked, we can re-import it." - ] - }, - { - "cell_type": "code", - "execution_count": 191, - "metadata": {}, - "outputs": [], - "source": [ - "# Read in preprocessed dataset\n", - "df_tmp = pd.read_parquet(path=\"../data/bluebook-for-bulldozers/TrainAndValid_object_values_as_categories_and_missing_values_filled.parquet\",\n", - " engine=\"auto\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Does it have any missing values?" - ] - }, - { - "cell_type": "code", - "execution_count": 192, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Total missing values: 0 - Woohoo! Let's build a model!\n" - ] - } - ], - "source": [ - "# Check total number of missing values\n", - "total_missing_values = df_tmp.isna().sum().sum()\n", - "\n", - "if total_missing_values == 0:\n", - " print(f\"[INFO] Total missing values: {total_missing_values} - Woohoo! Let's build a model!\")\n", - "else:\n", - " print(f\"[INFO] Uh ohh... total missing values: {total_missing_values} - Perhaps we might have to retrace our steps to fill the values?\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Checkpoint reached!\n", - "\n", - "We've turned all of our data into numbers as well as filled the missing values, time to try fitting a model to it again." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### TK - Fitting a machine learning model to our preprocessed data\n", - "\n", - "UPTOHERE \n", - "- fitting a model to the data... (could fit to a subset for quicker times...)\n", - "- what's wrong with it? (fitting and evaluting on the same data)\n", - "\n", - "Now all of our data is numeric and there are no missing values, we should be able to fit a machine learning model to it!\n", - "\n", - "Let's reinstantiate our trusty [`sklearn.ensemble.RandomForestRegressor()`](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html) model.\n", - "\n", - "Since our dataset has a substantial amount of rows (~400k+), let's first make sure the model will work on a smaller sample of 1000 or so.\n", - "\n", - "> **Note:** It's common practice on machine learning problems to see if your experiments will work on smaller scale problems (e.g. smaller amounts of data) before scaling them up to the full dataset. This practice enables you to try many different kinds of experiments with faster runtimes. The benefit of this is that you can figure out what doesn't work before spending more time on what does.\n", - "\n", - "Our `X` values (features) will be every column except the `\"SalePrice\"` column.\n", - "\n", - "And our `y` values (labels) will be the entirety of the `\"SalePrice\"` column.\n", - "\n", - "\n", - "We'll time how long our smaller experiment takes using the [magic function `%%time`](https://jakevdp.github.io/PythonDataScienceHandbook/01.07-timing-and-profiling.html) and placing it at the top of the notebook cell.\n", - "\n", - "> **Note:** You can find out more about the `%%time` magic command by typing `%%time?` (note the question mark on the end) in a notebook cell.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 204, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 1.01 s, sys: 68.6 ms, total: 1.07 s\n", - "Wall time: 387 ms\n" - ] - }, - { - "data": { - "text/html": [ - "
RandomForestRegressor(n_jobs=-1)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" - ], - "text/plain": [ - "RandomForestRegressor(n_jobs=-1)" - ] - }, - "execution_count": 204, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "\n", - "# Sample 1000 samples with random state 42 for reproducibility\n", - "df_tmp_sample_1k = df_tmp.sample(n=1000, random_state=42)\n", - "\n", - "# Instantiate a model\n", - "model = RandomForestRegressor(n_jobs=-1) # use -1 to utilise all available processors\n", - "\n", - "# Create features and labels\n", - "X_sample_1k = df_tmp_sample_1k.drop(\"SalePrice\", axis=1) # use all columns except SalePrice as X values\n", - "y_sample_1k = df_tmp_sample_1k[\"SalePrice\"] # use SalePrice as y values (target variable)\n", - "\n", - "# Fit the model to the sample data\n", - "model.fit(X=X_sample_1k, \n", - " y=y_sample_1k) " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Woah! It looks like things worked!\n", - "\n", - "And quite quick too (since we're only using a relatively small number of rows).\n", - "\n", - "How about we score our model?\n", - "\n", - "We can do so using the built-in method `score()`. By default, `sklearn.ensemble.RandomForestRegressor` uses [coefficient of determination](https://en.wikipedia.org/wiki/Coefficient_of_determination) ($R^2$ or R-squared) as the evaluation metric (higher is better, with a score of 1.0 being perfect)." - ] - }, - { - "cell_type": "code", - "execution_count": 205, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Model score on 1000 samples: 0.9552290424939952\n" - ] - } - ], - "source": [ - "# Evaluate the model\n", - "model_sample_1k_score = model.score(X=X_sample_1k,\n", - " y=y_sample_1k)\n", - "\n", - "print(f\"[INFO] Model score on {len(df_tmp_sample_1k)} samples: {model_sample_1k_score}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Wow, it looks like our model got a pretty good score on only 1000 samples (the best possible score it could achieve would've been 1.0). \n", - "\n", - "How about we try our model on the whole dataset?" - ] - }, - { - "cell_type": "code", - "execution_count": 206, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 9min 5s, sys: 3.05 s, total: 9min 8s\n", - "Wall time: 1min 11s\n" - ] - }, - { - "data": { - "text/html": [ - "
RandomForestRegressor(n_jobs=-1)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" - ], - "text/plain": [ - "RandomForestRegressor(n_jobs=-1)" - ] - }, - "execution_count": 206, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "\n", - "# Instantiate model\n", - "model = RandomForestRegressor(n_jobs=-1) # note: this could take quite a while depending on your machine (it took ~1.5 minutes on my MacBook Pro M1 Pro with 10 cores)\n", - "\n", - "# Create features and labels with entire dataset\n", - "X_all = df_tmp.drop(\"SalePrice\", axis=1)\n", - "y_all = df_tmp[\"SalePrice\"]\n", - "\n", - "# Fit the model\n", - "model.fit(X=X_all, \n", - " y=y_all)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Ok, that took a little bit longer than fitting on 1000 samples (but that's too be expected, as many more calculations had to be made).\n", - "\n", - "There's a reason we used `n_jobs=-1` too.\n", - "\n", - "If we stuck with the default of `n_jobs=None` (the same as `n_jobs=1`), it would've taken much longer.\n", - "\n", - "| Configuration (MacBook Pro M1 Pro, 10 Cores) | CPU Times (User) | CPU Times (Sys) | CPU Times (Total) | Wall Time |\n", - "|-----|-----|-----|-----|-----|\n", - "| `n_jobs=-1` (all cores) | 9min 14s | 3.85s | 9min 18s | 1min 15s |\n", - "| `n_jobs=None` (default) | 7min 14s | 1.75s | 7min 16s | 7min 25s |\n", - "\n", - "And as we've discussed many times, one of the main goals when starting a machine learning project is to reduce your time between experiments.\n", - "\n", - "How about we score the model trained on all of the data?" - ] - }, - { - "cell_type": "code", - "execution_count": 207, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Model score on 412698 samples: 0.98752722160166\n" - ] - } - ], - "source": [ - "# Evaluate the model\n", - "model_sample_all_score = model.score(X=X_all,\n", - " y=y_all)\n", - "\n", - "print(f\"[INFO] Model score on {len(df_tmp)} samples: {model_sample_all_score}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "An even better score!\n", - "\n", - "Oh wait...\n", - "\n", - "Oh no...\n", - "\n", - "I think we've got an error... (you might've noticed it already)\n", - "\n", - "Why might this metric be unreliable?\n", - "\n", - "Hint: Compare the data we trained on versus the data we evaluated on." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### TK - A big (but fixable) mistake \n", - "\n", - "One of the hard things about bugs in machine learning projects is that they are often silent.\n", - "\n", - "For example, our model seems to have fit the data with no issues and then evaluated with a good score.\n", - "\n", - "So what's wrong?\n", - "\n", - "It seems we've stumbled across one of the most common bugs in machine learning and that's **data leakage** (data from the training set leaking into the validation/testing sets).\n", - "\n", - "We've evaluated our model on the same data it was trained on.\n", - "\n", - "This isn't the model's fault either.\n", - "\n", - "It's our fault.\n", - "\n", - "Right back at the start we imported a file called `TrainAndValid.csv`, this contains both the training and validation data.\n", - "\n", - "And while we preprocessed it to make sure there were no missing values and the samples were all numeric, we never split the data into separate training and validation splits.\n", - "\n", - "The right workflow would've been to train the model on the training split and then evaluate it on the *unseen* validation split.\n", - "\n", - "Our evaluation scores above are quite good but they can't necessarily be trusted to be replicated on unseen data (data in the real world) because they've been obtained by evaluating the model on data its already seen. \n", - "\n", - "This would be the equivalent of a final exam at university containing all of the same questions as the practice exam without any changes. \n", - "\n", - "Not to worry, we can fix this!\n", - "\n", - "How?\n", - "\n", - "We can import the training and validation datasets separately via `Train.csv` and `Valid.csv` respectively.\n", - "\n", - "Or we could import `TrainAndValid.csv` and perform the appropriate splits according the original [Kaggle competition page](https://www.kaggle.com/c/bluebook-for-bulldozers/data) (training data includes all samples prior to 2012 and validation data includes samples from January 1 2012 to April 30 2012).\n", - "\n", - "In both methods, we'll have to perform the same preprocessing steps we've done so far.\n", - "\n", - "Except because the validation data is supposed to remain as *unseen* data, we'll only use information from the training set to preprocess the validation set (and not mix the two). \n", - "\n", - "We'll work on this in the next section.\n", - "\n", - "The takeaway?\n", - "\n", - "Always (if possible) **create appropriate data splits at the start of a project**.\n", - "\n", - "Because it's one thing to train a machine learning model but if you can't evaluate it properly (on unseen data), how can you know how it'll perform (or may perform) in the real world on new and unseen data?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3. TK - Splitting data into train/valid sets\n", - "\n", - "UPTOHERE \n", - "* TK - trying to fit a model forced us to prepare our dataset in a way that it could be used with a model but caused us to make the mistake of mixing the training/validation data (perhaps this was on purpose...)\n", - "* TK - can just import the Train/Valid CSVs separately and fill with Scikit-Learn imputers\n", - "\n", - "* Good new is, we get to practice preprocessing our data again. This time with separate training and validation splits. Last time we used pandas to make ensure our data was all numeric and had no missing values. But using pandas in this way can be a bit of an issue with larger scale datasets or when new data is introduced. How about this time we use Scikit-Learn and make a reproducible pipeline for our data preprocessing needs?\n", - "\n", - "* Next steps:\n", - "- import train/validation data separately\n", - "- create scikit-learn data filling pipeline for fitting to training data (turn all data numeric + fill missing values) \n", - "- use this preprocessing pipeline for applying to to validation data (e.g. `fit_transform` on train data -> only `transform` on validation data)\n", - "- eval + improve on validation data\n", - "\n", - "* We imported the `TrainAndValid.csv` and filled missing values/evaluated on it already " - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - " \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", - "
SalesIDSalePriceMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandfiModelDesc...Undercarriage_Pad_Width_is_missingStick_Length_is_missingThumb_is_missingPattern_Changer_is_missingGrouser_Type_is_missingBackhoe_Mounting_is_missingBlade_Type_is_missingTravel_Controls_is_missingDifferential_Type_is_missingSteering_Controls_is_missing
016467709500.01126363843413218.019740.004593...TrueTrueTrueTrueTrueFalseFalseFalseTrueTrue
1182151414000.011940891015013299.019800.001820...TrueTrueTrueTrueTrueTrueTrueTrueFalseFalse
2150513850000.01473654413913299.019780.002348...TrueTrueTrueTrueTrueFalseFalseFalseTrueTrue
3167117416000.01327630859113299.019800.001819...TrueTrueTrueTrueTrueTrueTrueTrueFalseFalse
4132905622000.01336053408913299.019840.002119...TrueTrueTrueTrueTrueFalseFalseFalseTrueTrue
\n", - "

5 rows × 103 columns

\n", - "
" - ], - "text/plain": [ - " SalesID SalePrice MachineID ModelID datasource auctioneerID YearMade \\\n", - "0 1646770 9500.0 1126363 8434 132 18.0 1974 \n", - "1 1821514 14000.0 1194089 10150 132 99.0 1980 \n", - "2 1505138 50000.0 1473654 4139 132 99.0 1978 \n", - "3 1671174 16000.0 1327630 8591 132 99.0 1980 \n", - "4 1329056 22000.0 1336053 4089 132 99.0 1984 \n", - "\n", - " MachineHoursCurrentMeter UsageBand fiModelDesc ... \\\n", - "0 0.0 0 4593 ... \n", - "1 0.0 0 1820 ... \n", - "2 0.0 0 2348 ... \n", - "3 0.0 0 1819 ... \n", - "4 0.0 0 2119 ... \n", - "\n", - " Undercarriage_Pad_Width_is_missing Stick_Length_is_missing \\\n", - "0 True True \n", - "1 True True \n", - "2 True True \n", - "3 True True \n", - "4 True True \n", - "\n", - " Thumb_is_missing Pattern_Changer_is_missing Grouser_Type_is_missing \\\n", - "0 True True True \n", - "1 True True True \n", - "2 True True True \n", - "3 True True True \n", - "4 True True True \n", - "\n", - " Backhoe_Mounting_is_missing Blade_Type_is_missing \\\n", - "0 False False \n", - "1 True True \n", - "2 False False \n", - "3 True True \n", - "4 False False \n", - "\n", - " Travel_Controls_is_missing Differential_Type_is_missing \\\n", - "0 False True \n", - "1 True False \n", - "2 False True \n", - "3 True False \n", - "4 False True \n", - "\n", - " Steering_Controls_is_missing \n", - "0 True \n", - "1 False \n", - "2 True \n", - "3 False \n", - "4 True \n", - "\n", - "[5 rows x 103 columns]" - ] - }, - "execution_count": 45, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df_tmp.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "According to the [Kaggle data page](https://www.kaggle.com/c/bluebook-for-bulldozers/data), the validation set and test set are split according to dates.\n", - "\n", - "This makes sense since we're working on a time series problem.\n", - "\n", - "E.g. using past events to try and predict future events.\n", - "\n", - "Knowing this, randomly splitting our data into train and test sets using something like `train_test_split()` wouldn't work.\n", - "\n", - "Instead, we split our data into training, validation and test sets using the date each sample occured.\n", - "\n", - "In our case:\n", - "* Training = all samples up until 2011\n", - "* Valid = all samples form January 1, 2012 - April 30, 2012\n", - "* Test = all samples from May 1, 2012 - November 2012\n", - "\n", - "For more on making good training, validation and test sets, check out the post [How (and why) to create a good validation set](https://www.fast.ai/2017/11/13/validation-sets/) by Rachel Thomas." - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2009 43849\n", - "2008 39767\n", - "2011 35197\n", - "2010 33390\n", - "2007 32208\n", - "2006 21685\n", - "2005 20463\n", - "2004 19879\n", - "2001 17594\n", - "2000 17415\n", - "2002 17246\n", - "2003 15254\n", - "1998 13046\n", - "1999 12793\n", - "2012 11573\n", - "1997 9785\n", - "1996 8829\n", - "1995 8530\n", - "1994 7929\n", - "1993 6303\n", - "1992 5519\n", - "1991 5109\n", - "1989 4806\n", - "1990 4529\n", - "Name: saleYear, dtype: int64" - ] - }, - "execution_count": 46, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df_tmp.saleYear.value_counts()" - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(11573, 401125)" - ] - }, - "execution_count": 47, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Split data into training and validation\n", - "df_val = df_tmp[df_tmp.saleYear == 2012]\n", - "df_train = df_tmp[df_tmp.saleYear != 2012]\n", - "\n", - "len(df_val), len(df_train)" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "((401125, 102), (401125,), (11573, 102), (11573,))" - ] - }, - "execution_count": 48, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Split data into X & y\n", - "X_train, y_train = df_train.drop(\"SalePrice\", axis=1), df_train.SalePrice\n", - "X_valid, y_valid = df_val.drop(\"SalePrice\", axis=1), df_val.SalePrice\n", - "\n", - "X_train.shape, y_train.shape, X_valid.shape, y_valid.shape" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Building an evaluation function\n", - "\n", - "According to Kaggle for the Bluebook for Bulldozers competition, [the evaluation function](https://www.kaggle.com/c/bluebook-for-bulldozers/overview/evaluation) they use is root mean squared log error (RMSLE).\n", - "\n", - "**RMSLE** = generally you don't care as much if you're off by $10 as much as you'd care if you were off by 10%, you care more about ratios rather than differences. **MAE** (mean absolute error) is more about exact differences.\n", - "\n", - "It's important to understand the evaluation metric you're going for.\n", - "\n", - "Since Scikit-Learn doesn't have a function built-in for RMSLE, we'll create our own.\n", - "\n", - "We can do this by taking the square root of Scikit-Learn's [mean_squared_log_error](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.mean_squared_log_error.html#sklearn.metrics.mean_squared_log_error) (MSLE). MSLE is the same as taking the log of mean squared error (MSE).\n", - "\n", - "We'll also calculate the MAE and R^2 for fun.\n", - "\n", - "TK - use RMSLE from scikit-learn, see: https://scikit-learn.org/1.5/modules/generated/sklearn.metrics.root_mean_squared_log_error.html#sklearn.metrics.root_mean_squared_log_error " - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "metadata": {}, - "outputs": [], - "source": [ - "# Create evaluation function (the competition uses Root Mean Square Log Error)\n", - "from sklearn.metrics import mean_squared_log_error, mean_absolute_error\n", - "\n", - "# TK - can now use RMSLE from sckit-learn, see: https://scikit-learn.org/1.5/modules/generated/sklearn.metrics.root_mean_squared_log_error.html#sklearn.metrics.root_mean_squared_log_error \n", - "def rmsle(y_test, y_preds):\n", - " return np.sqrt(mean_squared_log_error(y_test, y_preds))\n", - "\n", - "# Create function to evaluate our model\n", - "def show_scores(model):\n", - " train_preds = model.predict(X_train)\n", - " val_preds = model.predict(X_valid)\n", - " scores = {\"Training MAE\": mean_absolute_error(y_train, train_preds),\n", - " \"Valid MAE\": mean_absolute_error(y_valid, val_preds),\n", - " \"Training RMSLE\": rmsle(y_train, train_preds),\n", - " \"Valid RMSLE\": rmsle(y_valid, val_preds),\n", - " \"Training R^2\": model.score(X_train, y_train),\n", - " \"Valid R^2\": model.score(X_valid, y_valid)}\n", - " return scores" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Testing our model on a subset (to tune the hyperparameters)\n", - "\n", - "Retraing an entire model would take far too long to continuing experimenting as fast as we want to.\n", - "\n", - "So what we'll do is take a sample of the training set and tune the hyperparameters on that before training a larger model.\n", - "\n", - "If you're experiments are taking longer than 10-seconds (give or take how long you have to wait), you should be trying to speed things up. You can speed things up by sampling less data or using a faster computer." - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": {}, - "outputs": [], - "source": [ - "# This takes too long...\n", - "\n", - "# %%time\n", - "# # Retrain a model on training data\n", - "# model.fit(X_train, y_train)\n", - "# show_scores(model)" - ] - }, - { - "cell_type": "code", - "execution_count": 51, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "401125" - ] - }, - "execution_count": 51, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(X_train)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Depending on your computer (mine is a MacBook Pro), making calculations on ~400,000 rows may take a while...\n", - "\n", - "Let's alter the number of samples each `n_estimator` in the [`RandomForestRegressor`](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html) see's using the `max_samples` parameter." - ] - }, - { - "cell_type": "code", - "execution_count": 52, - "metadata": {}, - "outputs": [], - "source": [ - "# Change max samples in RandomForestRegressor\n", - "model = RandomForestRegressor(n_jobs=-1,\n", - " max_samples=10000)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Setting `max_samples` to 10000 means every `n_estimator` (default 100) in our `RandomForestRegressor` will only see 10000 random samples from our DataFrame instead of the entire 400,000.\n", - "\n", - "In other words, we'll be looking at 40x less samples which means we'll get faster computation speeds but we should expect our results to worsen (simple the model has less samples to learn patterns from)." - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 32.5 s, sys: 68 ms, total: 32.6 s\n", - "Wall time: 2.31 s\n" - ] - }, - { - "data": { - "text/html": [ - "
RandomForestRegressor(max_samples=10000, n_jobs=-1)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" - ], - "text/plain": [ - "RandomForestRegressor(max_samples=10000, n_jobs=-1)" - ] - }, - "execution_count": 53, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "# Cutting down the max number of samples each tree can see improves training time\n", - "model.fit(X_train, y_train)" - ] - }, - { - "cell_type": "code", - "execution_count": 54, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'Training MAE': 5567.491987510129,\n", - " 'Valid MAE': 7182.652944785276,\n", - " 'Training RMSLE': 0.25773885441307287,\n", - " 'Valid RMSLE': 0.2940155702000724,\n", - " 'Training R^2': 0.8599287949488105,\n", - " 'Valid R^2': 0.8311803212160184}" - ] - }, - "execution_count": 54, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "show_scores(model)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Beautiful, that took far less time than the model with all the data.\n", - "\n", - "With this, let's try tune some hyperparameters." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Hyperparameter tuning with RandomizedSearchCV\n", - "\n", - "You can increase `n_iter` to try more combinations of hyperparameters but in our case, we'll try 20 and see where it gets us.\n", - "\n", - "Remember, we're trying to reduce the amount of time it takes between experiments." - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Fitting 5 folds for each of 20 candidates, totalling 100 fits\n", - "CPU times: user 3min 9s, sys: 3.28 s, total: 3min 12s\n", - "Wall time: 3min 12s\n" - ] - }, - { - "data": { - "text/html": [ - "
RandomizedSearchCV(cv=5, estimator=RandomForestRegressor(), n_iter=20,\n",
-       "                   param_distributions={'max_depth': [None, 3, 5, 10],\n",
-       "                                        'max_features': [0.5, 1.0, 'sqrt'],\n",
-       "                                        'max_samples': [10000],\n",
-       "                                        'min_samples_leaf': array([ 1,  3,  5,  7,  9, 11, 13, 15, 17, 19]),\n",
-       "                                        'min_samples_split': array([ 2,  4,  6,  8, 10, 12, 14, 16, 18]),\n",
-       "                                        'n_estimators': array([10, 20, 30, 40, 50, 60, 70, 80, 90])},\n",
-       "                   verbose=True)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" - ], - "text/plain": [ - "RandomizedSearchCV(cv=5, estimator=RandomForestRegressor(), n_iter=20,\n", - " param_distributions={'max_depth': [None, 3, 5, 10],\n", - " 'max_features': [0.5, 1.0, 'sqrt'],\n", - " 'max_samples': [10000],\n", - " 'min_samples_leaf': array([ 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]),\n", - " 'min_samples_split': array([ 2, 4, 6, 8, 10, 12, 14, 16, 18]),\n", - " 'n_estimators': array([10, 20, 30, 40, 50, 60, 70, 80, 90])},\n", - " verbose=True)" - ] - }, - "execution_count": 56, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "from sklearn.model_selection import RandomizedSearchCV\n", - "\n", - "# Different RandomForestClassifier hyperparameters\n", - "rf_grid = {\"n_estimators\": np.arange(10, 100, 10),\n", - " \"max_depth\": [None, 3, 5, 10],\n", - " \"min_samples_split\": np.arange(2, 20, 2),\n", - " \"min_samples_leaf\": np.arange(1, 20, 2),\n", - " \"max_features\": [0.5, 1.0, \"sqrt\"], # Note: \"max_features='auto'\" is equivalent to \"max_features=1.0\", as of Scikit-Learn version 1.1\n", - " \"max_samples\": [10000]}\n", - "\n", - "rs_model = RandomizedSearchCV(RandomForestRegressor(),\n", - " param_distributions=rf_grid,\n", - " n_iter=20,\n", - " cv=5,\n", - " verbose=True)\n", - "\n", - "rs_model.fit(X_train, y_train)" - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'n_estimators': 30,\n", - " 'min_samples_split': 2,\n", - " 'min_samples_leaf': 3,\n", - " 'max_samples': 10000,\n", - " 'max_features': 1.0,\n", - " 'max_depth': None}" - ] - }, - "execution_count": 57, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Find the best parameters from the RandomizedSearch \n", - "rs_model.best_params_" - ] - }, - { - "cell_type": "code", - "execution_count": 58, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'Training MAE': 5725.976315602646,\n", - " 'Valid MAE': 7294.5625641579545,\n", - " 'Training RMSLE': 0.26348401446113984,\n", - " 'Valid RMSLE': 0.2960739319152716,\n", - " 'Training R^2': 0.8513015231223766,\n", - " 'Valid R^2': 0.82379444657151}" - ] - }, - "execution_count": 58, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Evaluate the RandomizedSearch model\n", - "show_scores(rs_model)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Train a model with the best parameters\n", - "\n", - "In a model I prepared earlier, I tried 100 different combinations of hyperparameters (setting `n_iter` to 100 in `RandomizedSearchCV`) and found the best results came from the ones you see below.\n", - "\n", - "**Note:** This kind of search on my computer (`n_iter` = 100) took ~2-hours. So it's kind of a set and come back later experiment.\n", - "\n", - "We'll instantiate a new model with these discovered hyperparameters and reset the `max_samples` back to its original value." - ] - }, - { - "cell_type": "code", - "execution_count": 59, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 8min 54s, sys: 471 ms, total: 8min 54s\n", - "Wall time: 35.4 s\n" - ] - }, - { - "data": { - "text/html": [ - "
RandomForestRegressor(max_features=0.5, min_samples_split=14, n_estimators=90,\n",
-       "                      n_jobs=-1)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" - ], - "text/plain": [ - "RandomForestRegressor(max_features=0.5, min_samples_split=14, n_estimators=90,\n", - " n_jobs=-1)" - ] - }, - "execution_count": 59, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "# Most ideal hyperparameters\n", - "ideal_model = RandomForestRegressor(n_estimators=90,\n", - " min_samples_leaf=1,\n", - " min_samples_split=14,\n", - " max_features=0.5,\n", - " n_jobs=-1,\n", - " max_samples=None)\n", - "ideal_model.fit(X_train, y_train)" - ] - }, - { - "cell_type": "code", - "execution_count": 60, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'Training MAE': 2930.02086721936,\n", - " 'Valid MAE': 5942.019241517711,\n", - " 'Training RMSLE': 0.1434641550675688,\n", - " 'Valid RMSLE': 0.2451178900180815,\n", - " 'Training R^2': 0.9595925460436532,\n", - " 'Valid R^2': 0.8822734761669947}" - ] - }, - "execution_count": 60, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "show_scores(ideal_model)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With these new hyperparameters as well as using all the samples, we can see an improvement to our models performance.\n", - "\n", - "You can make a faster model by altering some of the hyperparameters. Particularly by lowering `n_estimators` since each increase in `n_estimators` is basically building another small model.\n", - "\n", - "However, lowering of `n_estimators` or altering of other hyperparameters may lead to poorer results." - ] - }, - { - "cell_type": "code", - "execution_count": 61, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 3min 45s, sys: 304 ms, total: 3min 45s\n", - "Wall time: 15.9 s\n" - ] - }, - { - "data": { - "text/html": [ - "
RandomForestRegressor(max_features=0.5, min_samples_leaf=3, n_estimators=40,\n",
-       "                      n_jobs=-1)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" - ], - "text/plain": [ - "RandomForestRegressor(max_features=0.5, min_samples_leaf=3, n_estimators=40,\n", - " n_jobs=-1)" - ] - }, - "execution_count": 61, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "# Faster model\n", - "fast_model = RandomForestRegressor(n_estimators=40,\n", - " min_samples_leaf=3,\n", - " max_features=0.5,\n", - " n_jobs=-1)\n", - "fast_model.fit(X_train, y_train)" - ] - }, - { - "cell_type": "code", - "execution_count": 62, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'Training MAE': 2548.9560499523304,\n", - " 'Valid MAE': 5923.285839919034,\n", - " 'Training RMSLE': 0.12974340722269298,\n", - " 'Valid RMSLE': 0.2440897497981412,\n", - " 'Training R^2': 0.9670593150524459,\n", - " 'Valid R^2': 0.8818131128042139}" - ] - }, - "execution_count": 62, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "show_scores(fast_model)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Make predictions on test data\n", - "\n", - "Now we've got a trained model, it's time to make predictions on the test data.\n", - "\n", - "Remember what we've done.\n", - "\n", - "Our model is trained on data prior to 2011. However, the test data is from May 1 2012 to November 2012.\n", - "\n", - "So what we're doing is trying to use the patterns our model has learned in the training data to predict the sale price of a Bulldozer with characteristics it's never seen before but are assumed to be similar to that of those in the training data." - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - " \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", - "
SalesIDMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandsaledatefiModelDesc...Undercarriage_Pad_WidthStick_LengthThumbPattern_ChangerGrouser_TypeBackhoe_MountingBlade_TypeTravel_ControlsDifferential_TypeSteering_Controls
0122782910063093168121319993688.0Low2012-05-03580G...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
11227844102281772711213100028555.0High2012-05-10936...NaNNaNNaNNaNNaNNaNNaNNaNStandardConventional
21227847103156022805121320046038.0Medium2012-05-10EC210BLC...None or Unspecified9' 6\"ManualNone or UnspecifiedDoubleNaNNaNNaNNaNNaN
31227848562041269121320068940.0High2012-05-10330CL...None or UnspecifiedNone or UnspecifiedManualYesTripleNaNNaNNaNNaNNaN
41227863105388722312121320052286.0Low2012-05-10650K...NaNNaNNaNNaNNaNNone or UnspecifiedPATNone or UnspecifiedNaNNaN
\n", - "

5 rows × 52 columns

\n", - "
" - ], - "text/plain": [ - " SalesID MachineID ModelID datasource auctioneerID YearMade \\\n", - "0 1227829 1006309 3168 121 3 1999 \n", - "1 1227844 1022817 7271 121 3 1000 \n", - "2 1227847 1031560 22805 121 3 2004 \n", - "3 1227848 56204 1269 121 3 2006 \n", - "4 1227863 1053887 22312 121 3 2005 \n", - "\n", - " MachineHoursCurrentMeter UsageBand saledate fiModelDesc ... \\\n", - "0 3688.0 Low 2012-05-03 580G ... \n", - "1 28555.0 High 2012-05-10 936 ... \n", - "2 6038.0 Medium 2012-05-10 EC210BLC ... \n", - "3 8940.0 High 2012-05-10 330CL ... \n", - "4 2286.0 Low 2012-05-10 650K ... \n", - "\n", - " Undercarriage_Pad_Width Stick_Length Thumb Pattern_Changer \\\n", - "0 NaN NaN NaN NaN \n", - "1 NaN NaN NaN NaN \n", - "2 None or Unspecified 9' 6\" Manual None or Unspecified \n", - "3 None or Unspecified None or Unspecified Manual Yes \n", - "4 NaN NaN NaN NaN \n", - "\n", - " Grouser_Type Backhoe_Mounting Blade_Type Travel_Controls \\\n", - "0 NaN NaN NaN NaN \n", - "1 NaN NaN NaN NaN \n", - "2 Double NaN NaN NaN \n", - "3 Triple NaN NaN NaN \n", - "4 NaN None or Unspecified PAT None or Unspecified \n", - "\n", - " Differential_Type Steering_Controls \n", - "0 NaN NaN \n", - "1 Standard Conventional \n", - "2 NaN NaN \n", - "3 NaN NaN \n", - "4 NaN NaN \n", - "\n", - "[5 rows x 52 columns]" - ] - }, - "execution_count": 63, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df_test = pd.read_csv(\"../data/bluebook-for-bulldozers/Test.csv\",\n", - " parse_dates=[\"saledate\"])\n", - "df_test.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 64, - "metadata": {}, - "outputs": [ - { - "ename": "ValueError", - "evalue": "The feature names should match those that were passed during fit.\nFeature names unseen at fit time:\n- saledate\nFeature names seen at fit time, yet now missing:\n- Backhoe_Mounting_is_missing\n- Blade_Extension_is_missing\n- Blade_Type_is_missing\n- Blade_Width_is_missing\n- Coupler_System_is_missing\n- ...\n", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m/home/daniel/code/zero-to-mastery-ml/section-3-structured-data-projects/end-to-end-bluebook-bulldozer-price-regression.ipynb Cell 93\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[39m# Let's see how the model goes predicting on the test data\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m model\u001b[39m.\u001b[39;49mpredict(df_test)\n", - "File \u001b[0;32m~/code/pytorch/env/lib/python3.8/site-packages/sklearn/ensemble/_forest.py:984\u001b[0m, in \u001b[0;36mForestRegressor.predict\u001b[0;34m(self, X)\u001b[0m\n\u001b[1;32m 982\u001b[0m check_is_fitted(\u001b[39mself\u001b[39m)\n\u001b[1;32m 983\u001b[0m \u001b[39m# Check data\u001b[39;00m\n\u001b[0;32m--> 984\u001b[0m X \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_validate_X_predict(X)\n\u001b[1;32m 986\u001b[0m \u001b[39m# Assign chunk of trees to jobs\u001b[39;00m\n\u001b[1;32m 987\u001b[0m n_jobs, _, _ \u001b[39m=\u001b[39m _partition_estimators(\u001b[39mself\u001b[39m\u001b[39m.\u001b[39mn_estimators, \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mn_jobs)\n", - "File \u001b[0;32m~/code/pytorch/env/lib/python3.8/site-packages/sklearn/ensemble/_forest.py:599\u001b[0m, in \u001b[0;36mBaseForest._validate_X_predict\u001b[0;34m(self, X)\u001b[0m\n\u001b[1;32m 596\u001b[0m \u001b[39m\"\"\"\u001b[39;00m\n\u001b[1;32m 597\u001b[0m \u001b[39mValidate X whenever one tries to predict, apply, predict_proba.\"\"\"\u001b[39;00m\n\u001b[1;32m 598\u001b[0m check_is_fitted(\u001b[39mself\u001b[39m)\n\u001b[0;32m--> 599\u001b[0m X \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_validate_data(X, dtype\u001b[39m=\u001b[39;49mDTYPE, accept_sparse\u001b[39m=\u001b[39;49m\u001b[39m\"\u001b[39;49m\u001b[39mcsr\u001b[39;49m\u001b[39m\"\u001b[39;49m, reset\u001b[39m=\u001b[39;49m\u001b[39mFalse\u001b[39;49;00m)\n\u001b[1;32m 600\u001b[0m \u001b[39mif\u001b[39;00m issparse(X) \u001b[39mand\u001b[39;00m (X\u001b[39m.\u001b[39mindices\u001b[39m.\u001b[39mdtype \u001b[39m!=\u001b[39m np\u001b[39m.\u001b[39mintc \u001b[39mor\u001b[39;00m X\u001b[39m.\u001b[39mindptr\u001b[39m.\u001b[39mdtype \u001b[39m!=\u001b[39m np\u001b[39m.\u001b[39mintc):\n\u001b[1;32m 601\u001b[0m \u001b[39mraise\u001b[39;00m \u001b[39mValueError\u001b[39;00m(\u001b[39m\"\u001b[39m\u001b[39mNo support for np.int64 index based sparse matrices\u001b[39m\u001b[39m\"\u001b[39m)\n", - "File \u001b[0;32m~/code/pytorch/env/lib/python3.8/site-packages/sklearn/base.py:579\u001b[0m, in \u001b[0;36mBaseEstimator._validate_data\u001b[0;34m(self, X, y, reset, validate_separately, cast_to_ndarray, **check_params)\u001b[0m\n\u001b[1;32m 508\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39m_validate_data\u001b[39m(\n\u001b[1;32m 509\u001b[0m \u001b[39mself\u001b[39m,\n\u001b[1;32m 510\u001b[0m X\u001b[39m=\u001b[39m\u001b[39m\"\u001b[39m\u001b[39mno_validation\u001b[39m\u001b[39m\"\u001b[39m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 515\u001b[0m \u001b[39m*\u001b[39m\u001b[39m*\u001b[39mcheck_params,\n\u001b[1;32m 516\u001b[0m ):\n\u001b[1;32m 517\u001b[0m \u001b[39m\"\"\"Validate input data and set or check the `n_features_in_` attribute.\u001b[39;00m\n\u001b[1;32m 518\u001b[0m \n\u001b[1;32m 519\u001b[0m \u001b[39m Parameters\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 577\u001b[0m \u001b[39m validated.\u001b[39;00m\n\u001b[1;32m 578\u001b[0m \u001b[39m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 579\u001b[0m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_check_feature_names(X, reset\u001b[39m=\u001b[39;49mreset)\n\u001b[1;32m 581\u001b[0m \u001b[39mif\u001b[39;00m y \u001b[39mis\u001b[39;00m \u001b[39mNone\u001b[39;00m \u001b[39mand\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_get_tags()[\u001b[39m\"\u001b[39m\u001b[39mrequires_y\u001b[39m\u001b[39m\"\u001b[39m]:\n\u001b[1;32m 582\u001b[0m \u001b[39mraise\u001b[39;00m \u001b[39mValueError\u001b[39;00m(\n\u001b[1;32m 583\u001b[0m \u001b[39mf\u001b[39m\u001b[39m\"\u001b[39m\u001b[39mThis \u001b[39m\u001b[39m{\u001b[39;00m\u001b[39mself\u001b[39m\u001b[39m.\u001b[39m\u001b[39m__class__\u001b[39m\u001b[39m.\u001b[39m\u001b[39m__name__\u001b[39m\u001b[39m}\u001b[39;00m\u001b[39m estimator \u001b[39m\u001b[39m\"\u001b[39m\n\u001b[1;32m 584\u001b[0m \u001b[39m\"\u001b[39m\u001b[39mrequires y to be passed, but the target y is None.\u001b[39m\u001b[39m\"\u001b[39m\n\u001b[1;32m 585\u001b[0m )\n", - "File \u001b[0;32m~/code/pytorch/env/lib/python3.8/site-packages/sklearn/base.py:506\u001b[0m, in \u001b[0;36mBaseEstimator._check_feature_names\u001b[0;34m(self, X, reset)\u001b[0m\n\u001b[1;32m 501\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mnot\u001b[39;00m missing_names \u001b[39mand\u001b[39;00m \u001b[39mnot\u001b[39;00m unexpected_names:\n\u001b[1;32m 502\u001b[0m message \u001b[39m+\u001b[39m\u001b[39m=\u001b[39m (\n\u001b[1;32m 503\u001b[0m \u001b[39m\"\u001b[39m\u001b[39mFeature names must be in the same order as they were in fit.\u001b[39m\u001b[39m\\n\u001b[39;00m\u001b[39m\"\u001b[39m\n\u001b[1;32m 504\u001b[0m )\n\u001b[0;32m--> 506\u001b[0m \u001b[39mraise\u001b[39;00m \u001b[39mValueError\u001b[39;00m(message)\n", - "\u001b[0;31mValueError\u001b[0m: The feature names should match those that were passed during fit.\nFeature names unseen at fit time:\n- saledate\nFeature names seen at fit time, yet now missing:\n- Backhoe_Mounting_is_missing\n- Blade_Extension_is_missing\n- Blade_Type_is_missing\n- Blade_Width_is_missing\n- Coupler_System_is_missing\n- ...\n" - ] - } - ], - "source": [ - "# Let's see how the model goes predicting on the test data\n", - "model.predict(df_test)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Ahhh... the test data isn't in the same format of our other data, so we have to fix it. Let's create a function to preprocess our data." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Preprocessing the test data\n", - "\n", - "Our model has been trained on data formatted in the same way as the training data.\n", - "\n", - "This means in order to make predictions on the test data, we need to take the same steps we used to preprocess the training data to preprocess the test data.\n", - "\n", - "Remember: Whatever you do to the training data, you have to do to the test data.\n", - "\n", - "Let's create a function for doing so (by copying the preprocessing steps we used above)." - ] - }, - { - "cell_type": "code", - "execution_count": 65, - "metadata": {}, - "outputs": [], - "source": [ - "def preprocess_data(df):\n", - " # Add datetime parameters for saledate\n", - " df[\"saleYear\"] = df.saledate.dt.year\n", - " df[\"saleMonth\"] = df.saledate.dt.month\n", - " df[\"saleDay\"] = df.saledate.dt.day\n", - " df[\"saleDayofweek\"] = df.saledate.dt.dayofweek\n", - " df[\"saleDayofyear\"] = df.saledate.dt.dayofyear\n", - "\n", - " # Drop original saledate\n", - " df.drop(\"saledate\", axis=1, inplace=True)\n", - " \n", - " # Fill numeric rows with the median\n", - " for label, content in df.items():\n", - " if pd.api.types.is_numeric_dtype(content):\n", - " if pd.isnull(content).sum():\n", - " df[label+\"_is_missing\"] = pd.isnull(content)\n", - " df[label] = content.fillna(content.median())\n", - " \n", - " # Turn categorical variables into numbers\n", - " if not pd.api.types.is_numeric_dtype(content):\n", - " df[label+\"_is_missing\"] = pd.isnull(content)\n", - " # We add the +1 because pandas encodes missing categories as -1\n", - " df[label] = pd.Categorical(content).codes+1 \n", - " \n", - " return df" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Question:** Where would this function break?\n", - "\n", - "**Hint:** What if the test data had different missing values to the training data?\n", - "\n", - "Now we've got a function for preprocessing data, let's preprocess the test dataset into the same format as our training dataset." - ] - }, - { - "cell_type": "code", - "execution_count": 66, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - " \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", - "
SalesIDMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandfiModelDescfiBaseModel...Undercarriage_Pad_Width_is_missingStick_Length_is_missingThumb_is_missingPattern_Changer_is_missingGrouser_Type_is_missingBackhoe_Mounting_is_missingBlade_Type_is_missingTravel_Controls_is_missingDifferential_Type_is_missingSteering_Controls_is_missing
0122782910063093168121319993688.02499180...TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
11227844102281772711213100028555.01831292...TrueTrueTrueTrueTrueTrueTrueTrueFalseFalse
21227847103156022805121320046038.031177404...FalseFalseFalseFalseFalseTrueTrueTrueTrueTrue
31227848562041269121320068940.01287113...FalseFalseFalseFalseFalseTrueTrueTrueTrueTrue
41227863105388722312121320052286.02566196...TrueTrueTrueTrueTrueFalseFalseFalseTrueTrue
\n", - "

5 rows × 101 columns

\n", - "
" - ], - "text/plain": [ - " SalesID MachineID ModelID datasource auctioneerID YearMade \\\n", - "0 1227829 1006309 3168 121 3 1999 \n", - "1 1227844 1022817 7271 121 3 1000 \n", - "2 1227847 1031560 22805 121 3 2004 \n", - "3 1227848 56204 1269 121 3 2006 \n", - "4 1227863 1053887 22312 121 3 2005 \n", - "\n", - " MachineHoursCurrentMeter UsageBand fiModelDesc fiBaseModel ... \\\n", - "0 3688.0 2 499 180 ... \n", - "1 28555.0 1 831 292 ... \n", - "2 6038.0 3 1177 404 ... \n", - "3 8940.0 1 287 113 ... \n", - "4 2286.0 2 566 196 ... \n", - "\n", - " Undercarriage_Pad_Width_is_missing Stick_Length_is_missing \\\n", - "0 True True \n", - "1 True True \n", - "2 False False \n", - "3 False False \n", - "4 True True \n", - "\n", - " Thumb_is_missing Pattern_Changer_is_missing Grouser_Type_is_missing \\\n", - "0 True True True \n", - "1 True True True \n", - "2 False False False \n", - "3 False False False \n", - "4 True True True \n", - "\n", - " Backhoe_Mounting_is_missing Blade_Type_is_missing \\\n", - "0 True True \n", - "1 True True \n", - "2 True True \n", - "3 True True \n", - "4 False False \n", - "\n", - " Travel_Controls_is_missing Differential_Type_is_missing \\\n", - "0 True True \n", - "1 True False \n", - "2 True True \n", - "3 True True \n", - "4 False True \n", - "\n", - " Steering_Controls_is_missing \n", - "0 True \n", - "1 False \n", - "2 True \n", - "3 True \n", - "4 True \n", - "\n", - "[5 rows x 101 columns]" - ] - }, - "execution_count": 66, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df_test = preprocess_data(df_test)\n", - "df_test.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 67, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - " \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", - "
SalesIDMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandfiModelDescfiBaseModel...Undercarriage_Pad_Width_is_missingStick_Length_is_missingThumb_is_missingPattern_Changer_is_missingGrouser_Type_is_missingBackhoe_Mounting_is_missingBlade_Type_is_missingTravel_Controls_is_missingDifferential_Type_is_missingSteering_Controls_is_missing
016467701126363843413218.019740.0045931744...TrueTrueTrueTrueTrueFalseFalseFalseTrueTrue
1182151411940891015013299.019800.001820559...TrueTrueTrueTrueTrueTrueTrueTrueFalseFalse
215051381473654413913299.019780.002348713...TrueTrueTrueTrueTrueFalseFalseFalseTrueTrue
316711741327630859113299.019800.001819558...TrueTrueTrueTrueTrueTrueTrueTrueFalseFalse
413290561336053408913299.019840.002119683...TrueTrueTrueTrueTrueFalseFalseFalseTrueTrue
\n", - "

5 rows × 102 columns

\n", - "
" - ], - "text/plain": [ - " SalesID MachineID ModelID datasource auctioneerID YearMade \\\n", - "0 1646770 1126363 8434 132 18.0 1974 \n", - "1 1821514 1194089 10150 132 99.0 1980 \n", - "2 1505138 1473654 4139 132 99.0 1978 \n", - "3 1671174 1327630 8591 132 99.0 1980 \n", - "4 1329056 1336053 4089 132 99.0 1984 \n", - "\n", - " MachineHoursCurrentMeter UsageBand fiModelDesc fiBaseModel ... \\\n", - "0 0.0 0 4593 1744 ... \n", - "1 0.0 0 1820 559 ... \n", - "2 0.0 0 2348 713 ... \n", - "3 0.0 0 1819 558 ... \n", - "4 0.0 0 2119 683 ... \n", - "\n", - " Undercarriage_Pad_Width_is_missing Stick_Length_is_missing \\\n", - "0 True True \n", - "1 True True \n", - "2 True True \n", - "3 True True \n", - "4 True True \n", - "\n", - " Thumb_is_missing Pattern_Changer_is_missing Grouser_Type_is_missing \\\n", - "0 True True True \n", - "1 True True True \n", - "2 True True True \n", - "3 True True True \n", - "4 True True True \n", - "\n", - " Backhoe_Mounting_is_missing Blade_Type_is_missing \\\n", - "0 False False \n", - "1 True True \n", - "2 False False \n", - "3 True True \n", - "4 False False \n", - "\n", - " Travel_Controls_is_missing Differential_Type_is_missing \\\n", - "0 False True \n", - "1 True False \n", - "2 False True \n", - "3 True False \n", - "4 False True \n", - "\n", - " Steering_Controls_is_missing \n", - "0 True \n", - "1 False \n", - "2 True \n", - "3 False \n", - "4 True \n", - "\n", - "[5 rows x 102 columns]" - ] - }, - "execution_count": 67, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "X_train.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 68, - "metadata": {}, - "outputs": [ - { - "ename": "ValueError", - "evalue": "The feature names should match those that were passed during fit.\nFeature names seen at fit time, yet now missing:\n- auctioneerID_is_missing\n", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m/home/daniel/code/zero-to-mastery-ml/section-3-structured-data-projects/end-to-end-bluebook-bulldozer-price-regression.ipynb Cell 100\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[39m# Make predictions on the test dataset using the best model\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m test_preds \u001b[39m=\u001b[39m ideal_model\u001b[39m.\u001b[39;49mpredict(df_test)\n", - "File \u001b[0;32m~/code/pytorch/env/lib/python3.8/site-packages/sklearn/ensemble/_forest.py:984\u001b[0m, in \u001b[0;36mForestRegressor.predict\u001b[0;34m(self, X)\u001b[0m\n\u001b[1;32m 982\u001b[0m check_is_fitted(\u001b[39mself\u001b[39m)\n\u001b[1;32m 983\u001b[0m \u001b[39m# Check data\u001b[39;00m\n\u001b[0;32m--> 984\u001b[0m X \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_validate_X_predict(X)\n\u001b[1;32m 986\u001b[0m \u001b[39m# Assign chunk of trees to jobs\u001b[39;00m\n\u001b[1;32m 987\u001b[0m n_jobs, _, _ \u001b[39m=\u001b[39m _partition_estimators(\u001b[39mself\u001b[39m\u001b[39m.\u001b[39mn_estimators, \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mn_jobs)\n", - "File \u001b[0;32m~/code/pytorch/env/lib/python3.8/site-packages/sklearn/ensemble/_forest.py:599\u001b[0m, in \u001b[0;36mBaseForest._validate_X_predict\u001b[0;34m(self, X)\u001b[0m\n\u001b[1;32m 596\u001b[0m \u001b[39m\"\"\"\u001b[39;00m\n\u001b[1;32m 597\u001b[0m \u001b[39mValidate X whenever one tries to predict, apply, predict_proba.\"\"\"\u001b[39;00m\n\u001b[1;32m 598\u001b[0m check_is_fitted(\u001b[39mself\u001b[39m)\n\u001b[0;32m--> 599\u001b[0m X \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_validate_data(X, dtype\u001b[39m=\u001b[39;49mDTYPE, accept_sparse\u001b[39m=\u001b[39;49m\u001b[39m\"\u001b[39;49m\u001b[39mcsr\u001b[39;49m\u001b[39m\"\u001b[39;49m, reset\u001b[39m=\u001b[39;49m\u001b[39mFalse\u001b[39;49;00m)\n\u001b[1;32m 600\u001b[0m \u001b[39mif\u001b[39;00m issparse(X) \u001b[39mand\u001b[39;00m (X\u001b[39m.\u001b[39mindices\u001b[39m.\u001b[39mdtype \u001b[39m!=\u001b[39m np\u001b[39m.\u001b[39mintc \u001b[39mor\u001b[39;00m X\u001b[39m.\u001b[39mindptr\u001b[39m.\u001b[39mdtype \u001b[39m!=\u001b[39m np\u001b[39m.\u001b[39mintc):\n\u001b[1;32m 601\u001b[0m \u001b[39mraise\u001b[39;00m \u001b[39mValueError\u001b[39;00m(\u001b[39m\"\u001b[39m\u001b[39mNo support for np.int64 index based sparse matrices\u001b[39m\u001b[39m\"\u001b[39m)\n", - "File \u001b[0;32m~/code/pytorch/env/lib/python3.8/site-packages/sklearn/base.py:579\u001b[0m, in \u001b[0;36mBaseEstimator._validate_data\u001b[0;34m(self, X, y, reset, validate_separately, cast_to_ndarray, **check_params)\u001b[0m\n\u001b[1;32m 508\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39m_validate_data\u001b[39m(\n\u001b[1;32m 509\u001b[0m \u001b[39mself\u001b[39m,\n\u001b[1;32m 510\u001b[0m X\u001b[39m=\u001b[39m\u001b[39m\"\u001b[39m\u001b[39mno_validation\u001b[39m\u001b[39m\"\u001b[39m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 515\u001b[0m \u001b[39m*\u001b[39m\u001b[39m*\u001b[39mcheck_params,\n\u001b[1;32m 516\u001b[0m ):\n\u001b[1;32m 517\u001b[0m \u001b[39m\"\"\"Validate input data and set or check the `n_features_in_` attribute.\u001b[39;00m\n\u001b[1;32m 518\u001b[0m \n\u001b[1;32m 519\u001b[0m \u001b[39m Parameters\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 577\u001b[0m \u001b[39m validated.\u001b[39;00m\n\u001b[1;32m 578\u001b[0m \u001b[39m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 579\u001b[0m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_check_feature_names(X, reset\u001b[39m=\u001b[39;49mreset)\n\u001b[1;32m 581\u001b[0m \u001b[39mif\u001b[39;00m y \u001b[39mis\u001b[39;00m \u001b[39mNone\u001b[39;00m \u001b[39mand\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_get_tags()[\u001b[39m\"\u001b[39m\u001b[39mrequires_y\u001b[39m\u001b[39m\"\u001b[39m]:\n\u001b[1;32m 582\u001b[0m \u001b[39mraise\u001b[39;00m \u001b[39mValueError\u001b[39;00m(\n\u001b[1;32m 583\u001b[0m \u001b[39mf\u001b[39m\u001b[39m\"\u001b[39m\u001b[39mThis \u001b[39m\u001b[39m{\u001b[39;00m\u001b[39mself\u001b[39m\u001b[39m.\u001b[39m\u001b[39m__class__\u001b[39m\u001b[39m.\u001b[39m\u001b[39m__name__\u001b[39m\u001b[39m}\u001b[39;00m\u001b[39m estimator \u001b[39m\u001b[39m\"\u001b[39m\n\u001b[1;32m 584\u001b[0m \u001b[39m\"\u001b[39m\u001b[39mrequires y to be passed, but the target y is None.\u001b[39m\u001b[39m\"\u001b[39m\n\u001b[1;32m 585\u001b[0m )\n", - "File \u001b[0;32m~/code/pytorch/env/lib/python3.8/site-packages/sklearn/base.py:506\u001b[0m, in \u001b[0;36mBaseEstimator._check_feature_names\u001b[0;34m(self, X, reset)\u001b[0m\n\u001b[1;32m 501\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mnot\u001b[39;00m missing_names \u001b[39mand\u001b[39;00m \u001b[39mnot\u001b[39;00m unexpected_names:\n\u001b[1;32m 502\u001b[0m message \u001b[39m+\u001b[39m\u001b[39m=\u001b[39m (\n\u001b[1;32m 503\u001b[0m \u001b[39m\"\u001b[39m\u001b[39mFeature names must be in the same order as they were in fit.\u001b[39m\u001b[39m\\n\u001b[39;00m\u001b[39m\"\u001b[39m\n\u001b[1;32m 504\u001b[0m )\n\u001b[0;32m--> 506\u001b[0m \u001b[39mraise\u001b[39;00m \u001b[39mValueError\u001b[39;00m(message)\n", - "\u001b[0;31mValueError\u001b[0m: The feature names should match those that were passed during fit.\nFeature names seen at fit time, yet now missing:\n- auctioneerID_is_missing\n" - ] - } - ], - "source": [ - "# Make predictions on the test dataset using the best model\n", - "test_preds = ideal_model.predict(df_test)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We've found an error and it's because our test dataset (after preprocessing) has 101 columns where as, our training dataset (`X_train`) has 102 columns (after preprocessing).\n", - "\n", - "Let's find the difference." - ] - }, - { - "cell_type": "code", - "execution_count": 69, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'auctioneerID_is_missing'}" - ] - }, - "execution_count": 69, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# We can find how the columns differ using sets\n", - "set(X_train.columns) - set(df_test.columns)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In this case, it's because the test dataset wasn't missing any `auctioneerID` fields.\n", - "\n", - "To fix it, we'll add a column to the test dataset called `auctioneerID_is_missing` and fill it with `False`, since none of the `auctioneerID` fields are missing in the test dataset." - ] - }, - { - "cell_type": "code", - "execution_count": 70, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - " \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", - "
SalesIDMachineIDModelIDdatasourceauctioneerIDYearMadeMachineHoursCurrentMeterUsageBandfiModelDescfiBaseModel...Stick_Length_is_missingThumb_is_missingPattern_Changer_is_missingGrouser_Type_is_missingBackhoe_Mounting_is_missingBlade_Type_is_missingTravel_Controls_is_missingDifferential_Type_is_missingSteering_Controls_is_missingauctioneerID_is_missing
0122782910063093168121319993688.02499180...TrueTrueTrueTrueTrueTrueTrueTrueTrueFalse
11227844102281772711213100028555.01831292...TrueTrueTrueTrueTrueTrueTrueFalseFalseFalse
21227847103156022805121320046038.031177404...FalseFalseFalseFalseTrueTrueTrueTrueTrueFalse
31227848562041269121320068940.01287113...FalseFalseFalseFalseTrueTrueTrueTrueTrueFalse
41227863105388722312121320052286.02566196...TrueTrueTrueTrueFalseFalseFalseTrueTrueFalse
\n", - "

5 rows × 102 columns

\n", - "
" - ], - "text/plain": [ - " SalesID MachineID ModelID datasource auctioneerID YearMade \\\n", - "0 1227829 1006309 3168 121 3 1999 \n", - "1 1227844 1022817 7271 121 3 1000 \n", - "2 1227847 1031560 22805 121 3 2004 \n", - "3 1227848 56204 1269 121 3 2006 \n", - "4 1227863 1053887 22312 121 3 2005 \n", - "\n", - " MachineHoursCurrentMeter UsageBand fiModelDesc fiBaseModel ... \\\n", - "0 3688.0 2 499 180 ... \n", - "1 28555.0 1 831 292 ... \n", - "2 6038.0 3 1177 404 ... \n", - "3 8940.0 1 287 113 ... \n", - "4 2286.0 2 566 196 ... \n", - "\n", - " Stick_Length_is_missing Thumb_is_missing Pattern_Changer_is_missing \\\n", - "0 True True True \n", - "1 True True True \n", - "2 False False False \n", - "3 False False False \n", - "4 True True True \n", - "\n", - " Grouser_Type_is_missing Backhoe_Mounting_is_missing \\\n", - "0 True True \n", - "1 True True \n", - "2 False True \n", - "3 False True \n", - "4 True False \n", - "\n", - " Blade_Type_is_missing Travel_Controls_is_missing \\\n", - "0 True True \n", - "1 True True \n", - "2 True True \n", - "3 True True \n", - "4 False False \n", - "\n", - " Differential_Type_is_missing Steering_Controls_is_missing \\\n", - "0 True True \n", - "1 False False \n", - "2 True True \n", - "3 True True \n", - "4 True True \n", - "\n", - " auctioneerID_is_missing \n", - "0 False \n", - "1 False \n", - "2 False \n", - "3 False \n", - "4 False \n", - "\n", - "[5 rows x 102 columns]" - ] - }, - "execution_count": 70, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Match test dataset columns to training dataset\n", - "df_test[\"auctioneerID_is_missing\"] = False\n", - "df_test.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There's one more step we have to do before we can make predictions on the test data.\n", - "\n", - "And that's to line up the columns (the features) in our test dataset to match the columns in our training dataset.\n", - "\n", - "As in, the order of the columnns in the training dataset, should match the order of the columns in our test dataset.\n", - "\n", - "> **Note:** As of Scikit-Learn 1.2, the order of columns that were fit on should match the order of columns that are predicted on." - ] - }, - { - "cell_type": "code", - "execution_count": 71, - "metadata": {}, - "outputs": [], - "source": [ - "# Match column order from X_train to df_test (to predict on columns, they should be in the same order they were fit on)\n", - "df_test = df_test[X_train.columns]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now the test dataset column names and column order matches the training dataset, we should be able to make predictions on it using our trained model. " - ] - }, - { - "cell_type": "code", - "execution_count": 72, - "metadata": {}, - "outputs": [], - "source": [ - "# Make predictions on the test dataset using the best model\n", - "test_preds = ideal_model.predict(df_test)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "When looking at the [Kaggle submission requirements](https://www.kaggle.com/c/bluebook-for-bulldozers/overview/evaluation), we see that if we wanted to make a submission, the data is required to be in a certain format. Namely, a DataFrame containing the `SalesID` and the predicted `SalePrice` of the bulldozer.\n", - "\n", - "Let's make it." - ] - }, - { - "cell_type": "code", - "execution_count": 73, - "metadata": {}, - "outputs": [ - { - "data": { - "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", - "
SalesIDSalePrice
0122782918198.663455
1122784415747.746682
2122784748390.264848
3122784865840.504704
4122786358180.230933
.........
12452664317143613.653622
12453664317313335.788097
12454664318413009.453670
12455664318617151.096779
12456664319629025.076618
\n", - "

12457 rows × 2 columns

\n", - "
" - ], - "text/plain": [ - " SalesID SalePrice\n", - "0 1227829 18198.663455\n", - "1 1227844 15747.746682\n", - "2 1227847 48390.264848\n", - "3 1227848 65840.504704\n", - "4 1227863 58180.230933\n", - "... ... ...\n", - "12452 6643171 43613.653622\n", - "12453 6643173 13335.788097\n", - "12454 6643184 13009.453670\n", - "12455 6643186 17151.096779\n", - "12456 6643196 29025.076618\n", - "\n", - "[12457 rows x 2 columns]" - ] - }, - "execution_count": 73, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Create DataFrame compatible with Kaggle submission requirements\n", - "df_preds = pd.DataFrame()\n", - "df_preds[\"SalesID\"] = df_test[\"SalesID\"]\n", - "df_preds[\"SalePrice\"] = test_preds\n", - "df_preds" - ] - }, - { - "cell_type": "code", - "execution_count": 74, - "metadata": {}, - "outputs": [], - "source": [ - "# Export to csv...\n", - "# TK - update this to export to Parquet? Or CSV is enough...?\n", - "#df_preds.to_csv(\"../data/bluebook-for-bulldozers/predictions.csv\",\n", - "# index=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## TK - Add a section where we create a purely custom sample using the available columns, e.g. a custom bulldozer sale built into an app -> model outputs price prediction" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Feature Importance\n", - "\n", - "Since we've built a model which is able to make predictions. The people you share these predictions with (or yourself) might be curious of what parts of the data led to these predictions.\n", - "\n", - "This is where **feature importance** comes in. Feature importance seeks to figure out which different attributes of the data were most important when it comes to predicting the **target variable**.\n", - "\n", - "In our case, after our model learned the patterns in the data, which bulldozer sale attributes were most important for predicting its overall sale price?\n", - "\n", - "Beware: the default feature importances for random forests can lead to non-ideal results.\n", - "\n", - "To find which features were most important of a machine learning model, a good idea is to search something like \"\\[MODEL NAME\\] feature importance\".\n", - "\n", - "Doing this for our `RandomForestRegressor` leads us to find the `feature_importances_` attribute.\n", - "\n", - "Let's check it out." - ] - }, - { - "cell_type": "code", - "execution_count": 75, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([3.46627679e-02, 1.56764228e-02, 4.37926114e-02, 1.67650333e-03,\n", - " 3.34502142e-03, 1.97197187e-01, 3.06340515e-03, 9.77673001e-04,\n", - " 4.36749162e-02, 4.29037954e-02, 6.72975373e-02, 4.75148666e-03,\n", - " 1.53850682e-02, 1.55090204e-01, 4.45514872e-02, 5.95084780e-03,\n", - " 3.10028046e-03, 3.63841539e-03, 3.19638601e-03, 8.14915664e-02,\n", - " 6.53889246e-04, 5.94194750e-05, 1.41170245e-03, 2.27382622e-04,\n", - " 1.14398876e-03, 1.34339699e-04, 1.22607934e-03, 1.20989969e-02,\n", - " 1.44058495e-04, 1.35266062e-03, 3.36823266e-03, 3.42373542e-03,\n", - " 4.15153438e-03, 7.64328000e-04, 2.33613372e-03, 6.31647990e-03,\n", - " 9.15661618e-04, 1.20935454e-02, 1.89512094e-03, 2.06103870e-03,\n", - " 1.05929984e-03, 8.74105415e-04, 2.29493677e-03, 5.64128997e-04,\n", - " 7.38134764e-04, 3.60958405e-04, 2.88470991e-04, 2.15278313e-03,\n", - " 9.99457824e-04, 2.60780750e-04, 2.25566970e-04, 7.31244555e-02,\n", - " 3.78194598e-03, 5.69220059e-03, 2.90964527e-03, 9.93488783e-03,\n", - " 2.56180192e-04, 1.47457488e-03, 3.42954304e-04, 0.00000000e+00,\n", - " 0.00000000e+00, 1.91457326e-03, 1.34351415e-03, 5.69871181e-03,\n", - " 2.39504831e-02, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n", - " 0.00000000e+00, 5.97282251e-05, 7.01667140e-06, 3.59081182e-04,\n", - " 2.73656952e-05, 1.78603144e-04, 6.52558655e-05, 2.63920230e-04,\n", - " 3.48499839e-05, 1.21327449e-03, 1.78540890e-03, 9.39776578e-04,\n", - " 6.85501348e-05, 2.29510723e-03, 9.72534799e-04, 2.28851486e-03,\n", - " 1.43734099e-03, 9.74602815e-04, 3.39223163e-03, 1.66720737e-04,\n", - " 1.11866001e-02, 1.45338897e-03, 2.03979079e-03, 5.52949060e-05,\n", - " 9.35368656e-05, 5.93897732e-05, 7.88358813e-05, 6.16130828e-05,\n", - " 8.52025865e-05, 3.58013480e-04, 1.26474014e-04, 1.53885294e-04,\n", - " 8.63610944e-05, 1.87067289e-04])" - ] - }, - "execution_count": 75, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Find feature importance of our best model\n", - "ideal_model.feature_importances_" - ] - }, - { - "cell_type": "code", - "execution_count": 76, - "metadata": {}, - "outputs": [], - "source": [ - "# Install Seaborn package in current environment (if you don't have it)\n", - "# import sys\n", - "# !conda install --yes --prefix {sys.prefix} seaborn" - ] - }, - { - "cell_type": "code", - "execution_count": 77, - "metadata": {}, - "outputs": [], - "source": [ - "import seaborn as sns\n", - "\n", - "# Helper function for plotting feature importance\n", - "def plot_features(columns, importances, n=20):\n", - " df = (pd.DataFrame({\"features\": columns,\n", - " \"feature_importance\": importances})\n", - " .sort_values(\"feature_importance\", ascending=False)\n", - " .reset_index(drop=True))\n", - " \n", - " sns.barplot(x=\"feature_importance\",\n", - " y=\"features\",\n", - " data=df[:n],\n", - " orient=\"h\")" - ] - }, - { - "cell_type": "code", - "execution_count": 78, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "plot_features(X_train.columns, ideal_model.feature_importances_)" - ] - }, - { - "cell_type": "code", - "execution_count": 79, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1.0000000000000002" - ] - }, - "execution_count": 79, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sum(ideal_model.feature_importances_)" - ] - }, - { - "cell_type": "code", - "execution_count": 80, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "216605" - ] - }, - "execution_count": 80, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.ProductSize.isna().sum()" - ] - }, - { - "cell_type": "code", - "execution_count": 81, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Medium 64342\n", - "Large / Medium 51297\n", - "Small 27057\n", - "Mini 25721\n", - "Large 21396\n", - "Compact 6280\n", - "Name: ProductSize, dtype: int64" - ] - }, - "execution_count": 81, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.ProductSize.value_counts()" - ] - }, - { - "cell_type": "code", - "execution_count": 82, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "None or Unspecified 77111\n", - "Yes 3985\n", - "Name: Turbocharged, dtype: int64" - ] - }, - "execution_count": 82, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.Turbocharged.value_counts()" - ] - }, - { - "cell_type": "code", - "execution_count": 83, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "None or Unspecified 85074\n", - "Manual 9678\n", - "Hydraulic 7580\n", - "Name: Thumb, dtype: int64" - ] - }, - "execution_count": 83, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.Thumb.value_counts()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Extensions and Extra-curriculum\n", - "\n", - "* Extra-curriculum: read pandas io tools for info on parquet/feather data formats - [IO tools documentation page](https://pandas.pydata.org/docs/user_guide/io.html#). \n", - "\n", - "* See all of the pandas dtypes in the pandas user guide: https://pandas.pydata.org/docs/user_guide/basics.html#dtypes \n", - "* > **Note:** There are some ML models such as [`sklearn.ensemble.HistGradientBoostingRegressor`](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.HistGradientBoostingRegressor.html), [CatBoost](https://catboost.ai/) and [XGBoost](https://xgboost.ai/) which can handle missing values, however, I'll leave exploring each of these as extra-curriculum/extensions." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -}