{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "cd314cdb-71b4-4707-b78f-1268e6162be0",
   "metadata": {},
   "source": [
    "# Workshop Machine Learning: Theorie"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4a2f43de-ec81-4e42-9b80-85dbd67a4a67",
   "metadata": {},
   "source": [
    "Voer de volgende cel uit om de trainingsdata te downloaden die je hieronder nodig hebt."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "dc8b1fb7-285f-4f15-8409-9b31a3f54cf9",
   "metadata": {},
   "outputs": [],
   "source": [
    "!wget -q -O melbourne_data.csv \"https://www.dropbox.com/scl/fi/h7195dod2je5dd6zjk9do/melbourne_data.csv?rlkey=6za8a5aqqv8gvxap0d875qrtb&dl=1\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6b4cc657-c085-4496-9987-fc9ec56e20b5",
   "metadata": {
    "jp-MarkdownHeadingCollapsed": true
   },
   "source": [
    "## Inleiding\n",
    "\n",
    "Er zijn veel verschillende soorten modellen die gebruikt worden binnen data science. Denk hierbij aan bijvoorbeeld: **neurale netwerken**, **naive bayes classifiers**, **lineaire** en **logistische regressie**, en **k-nearest neighbors**, om er een paar te noemen. Al deze modellen hebben voor- en nadelen en het ligt aan het soort probleem welk model het meest geschikt is. Tijdens deze workshop beginnen we met één van de meest simpele modellen: de **decision tree** ook wel **beslisboom** genoemd. Geavanceerdere modellen kunnen nauwkeuriger zijn, maar decision trees zijn makkelijk te begrijpen en vormen de basis voor enkele van de meest krachtige modellen in data science.\n",
    "\n",
    "Tijdens deze workshop ga je modellen trainen om de prijzen van huizen te kunnen voorspellen op basis van kenmerken van die huizen.\n",
    "\n",
    "### Hoe werkt een decision tree?\n",
    "\n",
    "Hieronder zie je een grafische weergave van een decision tree.\n",
    "\n",
    "![](https://www.dropbox.com/scl/fi/y64da5mph8bq52k49269m/decision_tree.png?rlkey=3na1h47ewtjhhxcjyu62nbuug&dl=1)\n",
    "\n",
    "Dit model voorspelt de prijs van een huis op basis van twee kenmerken, namelijk het aantal slaapkamers en de perceelgrootte.\n",
    "\n",
    "Je voorspelt de prijs van een huis door de decision tree te volgen en telkens de route te kiezen die bij de eigenschappen van dat huis past. De voorspelde prijs vind je onderaan in de boom. Het blauwe vak onderaan waar we de voorspelling doen heet een **leaf** of **blad**.\n",
    "\n",
    "De kenmerken die het model gebruikt om te komen tot een beslissing, noemen we in machine learning jargon **features**. De afgebeelde decision tree is een simpel voorbeeld. Het is niet ongebruikelijk dat een decision tree veel meer dan twee features in overweging neemt.\n",
    "\n",
    "We gebruiken data om te bepalen hoe we het beste de splitsingen kunnen maken en de voorspelde prijs in elk blad vast te stellen. Dit proces van het vastleggen van patronen uit data heet **fitten** of **trainen** van het model. De data die we gebruiken om het model te fitten heet de **trainingsdata**.\n",
    "\n",
    "De details van hoe het model precies gefit wordt (bijvoorbeeld hoe de data wordt gesplitst) zijn best complex. Gelukkig hoeven we dit niet met de hand te doen. De scikit-learn bibliotheek bevat algoritmes (voor decision trees en vele andere soorten modellen) die dit fitten voor ons doen. Het enige wat we hoeven te doen is de juiste methode aanroepen en data meegeven om het model te fitten. Zodra het model gefit is, kun je het toepassen op nieuwe data om prijzen van andere huizen te voorspellen.\n",
    "\n",
    "Het probleem met een decision tree zoals hierboven is dat het veel factoren die de prijs beïnvloeden, zoals het aantal badkamers, locatie, enz., niet meeneemt. Je kunt meer factoren meenemen door een boom te gebruiken met meer **splitsingen**. We spreken dan van **diepere** bomen.\n",
    "\n",
    "Nu duidelijk is hoe een decision tree werkt kunnen we gaan kijken naar de data waarmee we een dergelijk model kunnen fitten."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b36c0f30-5430-4693-b1f4-9aef85493425",
   "metadata": {},
   "source": [
    "## Dataverkenning\n",
    "\n",
    "De eerste stap in elk machine learning project is om vertrouwd te raken met de data. We gebruiken hiervoor de Pandas bibliotheek welke we eerst in Python moeten importeren. Pandas biedt allerlei functies om data te verkennen en manipuleren. In Python importeren we `pandas` meestal als `pd`. Dat doen we met de volgende opdracht:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "64abdcbc-5860-4ab6-a7e2-bdc61d1caac2",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "19c30129-7773-4464-a81b-b435b368708c",
   "metadata": {},
   "source": [
    "De belangrijkste datastructuur in de Pandas bibliotheek is het `DataFrame`. Een `DataFrame` bevat het soort data dat je als een tabel kunt zien. Dit lijkt op een blad in Excel of een tabel in een SQL-database.\n",
    "\n",
    "Pandas heeft krachtige methodes voor het verkennen en manipuleren van dit soort data.\n",
    "\n",
    "Als voorbeeld bekijken we data met kenmerken en prijzen van huizen in Melbourne, Australië. In de praktische oefeningen ga je zelf aan de slag op een nieuwe dataset met huizenprijzen in Iowa, de VS.\n",
    "\n",
    "De voorbeelddata (Melbourne) staat in het bestand **`melbourne_data.csv`**.\n",
    "\n",
    "We laden en verkennen de data met de volgende opdrachten:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "a84a67d3-f37a-4a08-96d7-d46abb0d1a4b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Rooms</th>\n",
       "      <th>Price</th>\n",
       "      <th>Distance</th>\n",
       "      <th>Postcode</th>\n",
       "      <th>Bedroom2</th>\n",
       "      <th>Bathroom</th>\n",
       "      <th>Car</th>\n",
       "      <th>Landsize</th>\n",
       "      <th>BuildingArea</th>\n",
       "      <th>YearBuilt</th>\n",
       "      <th>Lattitude</th>\n",
       "      <th>Longtitude</th>\n",
       "      <th>Propertycount</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>count</th>\n",
       "      <td>13580.000000</td>\n",
       "      <td>1.358000e+04</td>\n",
       "      <td>13580.000000</td>\n",
       "      <td>13580.000000</td>\n",
       "      <td>13580.000000</td>\n",
       "      <td>13580.000000</td>\n",
       "      <td>13518.000000</td>\n",
       "      <td>13580.000000</td>\n",
       "      <td>7130.000000</td>\n",
       "      <td>8205.000000</td>\n",
       "      <td>13580.000000</td>\n",
       "      <td>13580.000000</td>\n",
       "      <td>13580.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>mean</th>\n",
       "      <td>2.937997</td>\n",
       "      <td>1.075684e+06</td>\n",
       "      <td>10.137776</td>\n",
       "      <td>3105.301915</td>\n",
       "      <td>2.914728</td>\n",
       "      <td>1.534242</td>\n",
       "      <td>1.610075</td>\n",
       "      <td>558.416127</td>\n",
       "      <td>151.967650</td>\n",
       "      <td>1964.684217</td>\n",
       "      <td>-37.809203</td>\n",
       "      <td>144.995216</td>\n",
       "      <td>7454.417378</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>std</th>\n",
       "      <td>0.955748</td>\n",
       "      <td>6.393107e+05</td>\n",
       "      <td>5.868725</td>\n",
       "      <td>90.676964</td>\n",
       "      <td>0.965921</td>\n",
       "      <td>0.691712</td>\n",
       "      <td>0.962634</td>\n",
       "      <td>3990.669241</td>\n",
       "      <td>541.014538</td>\n",
       "      <td>37.273762</td>\n",
       "      <td>0.079260</td>\n",
       "      <td>0.103916</td>\n",
       "      <td>4378.581772</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>min</th>\n",
       "      <td>1.000000</td>\n",
       "      <td>8.500000e+04</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>3000.000000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>1196.000000</td>\n",
       "      <td>-38.182550</td>\n",
       "      <td>144.431810</td>\n",
       "      <td>249.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25%</th>\n",
       "      <td>2.000000</td>\n",
       "      <td>6.500000e+05</td>\n",
       "      <td>6.100000</td>\n",
       "      <td>3044.000000</td>\n",
       "      <td>2.000000</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>177.000000</td>\n",
       "      <td>93.000000</td>\n",
       "      <td>1940.000000</td>\n",
       "      <td>-37.856822</td>\n",
       "      <td>144.929600</td>\n",
       "      <td>4380.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>50%</th>\n",
       "      <td>3.000000</td>\n",
       "      <td>9.030000e+05</td>\n",
       "      <td>9.200000</td>\n",
       "      <td>3084.000000</td>\n",
       "      <td>3.000000</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>2.000000</td>\n",
       "      <td>440.000000</td>\n",
       "      <td>126.000000</td>\n",
       "      <td>1970.000000</td>\n",
       "      <td>-37.802355</td>\n",
       "      <td>145.000100</td>\n",
       "      <td>6555.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>75%</th>\n",
       "      <td>3.000000</td>\n",
       "      <td>1.330000e+06</td>\n",
       "      <td>13.000000</td>\n",
       "      <td>3148.000000</td>\n",
       "      <td>3.000000</td>\n",
       "      <td>2.000000</td>\n",
       "      <td>2.000000</td>\n",
       "      <td>651.000000</td>\n",
       "      <td>174.000000</td>\n",
       "      <td>1999.000000</td>\n",
       "      <td>-37.756400</td>\n",
       "      <td>145.058305</td>\n",
       "      <td>10331.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>max</th>\n",
       "      <td>10.000000</td>\n",
       "      <td>9.000000e+06</td>\n",
       "      <td>48.100000</td>\n",
       "      <td>3977.000000</td>\n",
       "      <td>20.000000</td>\n",
       "      <td>8.000000</td>\n",
       "      <td>10.000000</td>\n",
       "      <td>433014.000000</td>\n",
       "      <td>44515.000000</td>\n",
       "      <td>2018.000000</td>\n",
       "      <td>-37.408530</td>\n",
       "      <td>145.526350</td>\n",
       "      <td>21650.000000</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              Rooms         Price      Distance      Postcode      Bedroom2  \\\n",
       "count  13580.000000  1.358000e+04  13580.000000  13580.000000  13580.000000   \n",
       "mean       2.937997  1.075684e+06     10.137776   3105.301915      2.914728   \n",
       "std        0.955748  6.393107e+05      5.868725     90.676964      0.965921   \n",
       "min        1.000000  8.500000e+04      0.000000   3000.000000      0.000000   \n",
       "25%        2.000000  6.500000e+05      6.100000   3044.000000      2.000000   \n",
       "50%        3.000000  9.030000e+05      9.200000   3084.000000      3.000000   \n",
       "75%        3.000000  1.330000e+06     13.000000   3148.000000      3.000000   \n",
       "max       10.000000  9.000000e+06     48.100000   3977.000000     20.000000   \n",
       "\n",
       "           Bathroom           Car       Landsize  BuildingArea    YearBuilt  \\\n",
       "count  13580.000000  13518.000000   13580.000000   7130.000000  8205.000000   \n",
       "mean       1.534242      1.610075     558.416127    151.967650  1964.684217   \n",
       "std        0.691712      0.962634    3990.669241    541.014538    37.273762   \n",
       "min        0.000000      0.000000       0.000000      0.000000  1196.000000   \n",
       "25%        1.000000      1.000000     177.000000     93.000000  1940.000000   \n",
       "50%        1.000000      2.000000     440.000000    126.000000  1970.000000   \n",
       "75%        2.000000      2.000000     651.000000    174.000000  1999.000000   \n",
       "max        8.000000     10.000000  433014.000000  44515.000000  2018.000000   \n",
       "\n",
       "          Lattitude    Longtitude  Propertycount  \n",
       "count  13580.000000  13580.000000   13580.000000  \n",
       "mean     -37.809203    144.995216    7454.417378  \n",
       "std        0.079260      0.103916    4378.581772  \n",
       "min      -38.182550    144.431810     249.000000  \n",
       "25%      -37.856822    144.929600    4380.000000  \n",
       "50%      -37.802355    145.000100    6555.000000  \n",
       "75%      -37.756400    145.058305   10331.000000  \n",
       "max      -37.408530    145.526350   21650.000000  "
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# sla de bestandslocatie op in een variabele\n",
    "melbourne_file_path = 'melbourne_data.csv'\n",
    "\n",
    "# lees de data in en sla het op in een DataFrame genaamd melbourne_data\n",
    "melbourne_data = pd.read_csv(melbourne_file_path) \n",
    "\n",
    "# print een samenvatting van de data in melbourne_data\n",
    "melbourne_data.describe()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3e551fcf-4218-4acf-9630-1d0a1e703c1e",
   "metadata": {},
   "source": [
    "### Databeschrijving interpreteren\n",
    "\n",
    "De resultaten tonen 8 getallen voor elke kolom in de oorspronkelijke dataset. Het eerste getal, de **count**, laat zien hoeveel rijen niet-lege waarden hebben.\n",
    "\n",
    "Missende waarden ontstaan door allerlei redenen. Bijvoorbeeld, de grootte van de tweede slaapkamer wordt niet geregistreerd bij een huis met maar één slaapkamer. We komen later nog terug op het onderwerp missende data.\n",
    "\n",
    "Het tweede getal is het gemiddelde, oftewel **mean**. Daaronder zie je **std**, de standaarddeviatie, die aangeeft hoe verspreid de waarden zijn.\n",
    "\n",
    "De **min**, **25%**, **50%**, **75%** en **max** waarden kun je als volgt interpreteren: Stel je voor dat je elke kolom sorteert van laagste naar hoogste waarde. De eerste (kleinste) waarde is de **min**. Als je een kwart van de lijst doorloopt, vind je een getal dat groter is dan 25% van de waarden en kleiner dan 75% van de waarden. Dat is de **25%** waarde (uitgesproken als \"25e percentiel\"). De 50e en 75e percentielen worden op dezelfde manier bepaald, en de **max** is het grootste getal.\n",
    "\n",
    "### Oefeningen\n",
    "\n",
    "Maak nu oefening 1 t/m 3."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "39b107d2-8fba-482d-949a-f259d23d96d7",
   "metadata": {},
   "source": [
    "## Een eerste machine learning model\n",
    "\n",
    "### Data kiezen voor modellering\n",
    "\n",
    "Je dataset had te veel variabelen om allemaal in één keer te begrijpen, of zelfs om netjes uit te printen. Hoe kun je deze enorme hoeveelheid data terugbrengen tot iets dat je beter begrijpt?\n",
    "\n",
    "We beginnen met het kiezen van een paar variabelen op basis van intuïtie. Er zijn statistische technieken om automatisch variabelen te selecteren, maar voor nu maken we een handmatige selectie.\n",
    "\n",
    "Om variabelen/kolommen te kunnen kiezen, willen we eerst een lijst zien van alle kolommen die überhaupt in de dataset voorkomen. Dat doe je met de `columns` eigenschap van de `DataFrame` (zie de regel code hieronder)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "90a78db1-e5d8-44ed-9195-0fd12e332f64",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Index(['Suburb', 'Address', 'Rooms', 'Type', 'Price', 'Method', 'SellerG',\n",
       "       'Date', 'Distance', 'Postcode', 'Bedroom2', 'Bathroom', 'Car',\n",
       "       'Landsize', 'BuildingArea', 'YearBuilt', 'CouncilArea', 'Lattitude',\n",
       "       'Longtitude', 'Regionname', 'Propertycount'],\n",
       "      dtype='object')"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "melbourne_data.columns"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ccd417b9-52f4-4ec3-93dd-46d4d3118a7a",
   "metadata": {},
   "source": [
    "De Melbourne data heeft wat missende waarden (voor sommige huizen zijn bepaalde waardes niet ingevuld). Er zijn verschillende manieren om hiermee om te gaan. Voor nu nemen we de eenvoudigste optie en laten we de huizen met missende waarden weg. De code die dit doet is deze:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "69803c72-d550-4774-925e-6cf74725a838",
   "metadata": {},
   "outputs": [],
   "source": [
    "melbourne_data = melbourne_data.dropna(axis=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ee3dbad5-f41c-4ac8-bfd2-bb8f0608a4e7",
   "metadata": {},
   "source": [
    "### Subsets van je data selecteren\n",
    "\n",
    "Er zijn veel manieren om met Pandas een subset van je data te selecteren, maar we richten ons nu op twee methoden:\n",
    "\n",
    "* Puntnotatie, die we gebruiken om de \"doelvariabele\" (het kenmerk dat de prijs bevat) te selecteren.\n",
    "* Selecteren met een kolomlijst, die we gebruiken om de features te selecteren.\n",
    "\n",
    "### De doelvariabele selecteren\n",
    "\n",
    "Je kunt een variabele eruit halen met puntnotatie. Deze enkele kolom wordt opgeslagen in een `Series`, wat eigenlijk een `DataFrame` is met maar één kolom.\n",
    "\n",
    "We gebruiken puntnotatie om de kolom te selecteren die we willen voorspellen, genaamd de doelvariabele. Deze wordt gewoonlijk `y` genoemd. De code om de huizenprijzen in de Melbourne data op te slaan is:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "34c51c4a-a0e5-4262-8b34-dc918f86feae",
   "metadata": {},
   "outputs": [],
   "source": [
    "y = melbourne_data.Price"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c211ce10-a97d-4a7a-b4ee-6f230ee27a42",
   "metadata": {},
   "source": [
    "### Features kiezen\n",
    "\n",
    "De kolommen die in ons model worden ingevoerd (en later worden gebruikt om voorspellingen te doen) worden **features** genoemd. In ons geval zijn dat de kolommen die worden gebruikt om de huizenprijs te bepalen. Soms gebruik je alle kolommen behalve het doel als features. Andere keren ben je beter af met minder features.\n",
    "\n",
    "Voor nu trainen we een model met slechts een paar features. Later zul je zien hoe je iteratief modellen kunt vergelijken met verschillende features.\n",
    "\n",
    "We selecteren meerdere features door een lijst van kolomnamen tussen haakjes te plaatsen. Elk item in die lijst moet een string zijn (met aanhalingstekens).\n",
    "\n",
    "Een voorbeeld:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "89055fba-dcfc-40fc-bfe8-d76dc9738963",
   "metadata": {},
   "outputs": [],
   "source": [
    "melbourne_features = ['Rooms', 'Bathroom', 'Landsize', 'Lattitude', 'Longtitude']"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "638ae641-1cf6-4d00-8ecc-1db0b0c356ea",
   "metadata": {},
   "source": [
    "Deze data wordt gewoonlijk `X` genoemd."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "58bf0388-f0e5-473a-bf99-49bde284ed95",
   "metadata": {},
   "outputs": [],
   "source": [
    "X = melbourne_data[melbourne_features]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "791de9cc-131a-4512-ae69-94fbbecd5072",
   "metadata": {},
   "source": [
    "Laten we ter controle de data bekijken die we gaan gebruiken om huizenprijzen te voorspellen. We kunnen hiervoor zoals hierboven de `describe` methode gebruiken."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "b829bc2f-e37b-495c-ba48-131ebed3c9bc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Rooms</th>\n",
       "      <th>Bathroom</th>\n",
       "      <th>Landsize</th>\n",
       "      <th>Lattitude</th>\n",
       "      <th>Longtitude</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>count</th>\n",
       "      <td>6196.000000</td>\n",
       "      <td>6196.000000</td>\n",
       "      <td>6196.000000</td>\n",
       "      <td>6196.000000</td>\n",
       "      <td>6196.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>mean</th>\n",
       "      <td>2.931407</td>\n",
       "      <td>1.576340</td>\n",
       "      <td>471.006940</td>\n",
       "      <td>-37.807904</td>\n",
       "      <td>144.990201</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>std</th>\n",
       "      <td>0.971079</td>\n",
       "      <td>0.711362</td>\n",
       "      <td>897.449881</td>\n",
       "      <td>0.075850</td>\n",
       "      <td>0.099165</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>min</th>\n",
       "      <td>1.000000</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>-38.164920</td>\n",
       "      <td>144.542370</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25%</th>\n",
       "      <td>2.000000</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>152.000000</td>\n",
       "      <td>-37.855438</td>\n",
       "      <td>144.926198</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>50%</th>\n",
       "      <td>3.000000</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>373.000000</td>\n",
       "      <td>-37.802250</td>\n",
       "      <td>144.995800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>75%</th>\n",
       "      <td>4.000000</td>\n",
       "      <td>2.000000</td>\n",
       "      <td>628.000000</td>\n",
       "      <td>-37.758200</td>\n",
       "      <td>145.052700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>max</th>\n",
       "      <td>8.000000</td>\n",
       "      <td>8.000000</td>\n",
       "      <td>37000.000000</td>\n",
       "      <td>-37.457090</td>\n",
       "      <td>145.526350</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "             Rooms     Bathroom      Landsize    Lattitude   Longtitude\n",
       "count  6196.000000  6196.000000   6196.000000  6196.000000  6196.000000\n",
       "mean      2.931407     1.576340    471.006940   -37.807904   144.990201\n",
       "std       0.971079     0.711362    897.449881     0.075850     0.099165\n",
       "min       1.000000     1.000000      0.000000   -38.164920   144.542370\n",
       "25%       2.000000     1.000000    152.000000   -37.855438   144.926198\n",
       "50%       3.000000     1.000000    373.000000   -37.802250   144.995800\n",
       "75%       4.000000     2.000000    628.000000   -37.758200   145.052700\n",
       "max       8.000000     8.000000  37000.000000   -37.457090   145.526350"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X.describe()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3d750baa-ed9b-49e4-a7f5-7669066c44a9",
   "metadata": {},
   "source": [
    "Een andere optie is de `head` methode, die de eerste paar rijen laat zien."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "e0abb810-66ad-4df9-9754-db97f1636475",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Rooms</th>\n",
       "      <th>Bathroom</th>\n",
       "      <th>Landsize</th>\n",
       "      <th>Lattitude</th>\n",
       "      <th>Longtitude</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>2</td>\n",
       "      <td>1.0</td>\n",
       "      <td>156.0</td>\n",
       "      <td>-37.8079</td>\n",
       "      <td>144.9934</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>3</td>\n",
       "      <td>2.0</td>\n",
       "      <td>134.0</td>\n",
       "      <td>-37.8093</td>\n",
       "      <td>144.9944</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>4</td>\n",
       "      <td>1.0</td>\n",
       "      <td>120.0</td>\n",
       "      <td>-37.8072</td>\n",
       "      <td>144.9941</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>3</td>\n",
       "      <td>2.0</td>\n",
       "      <td>245.0</td>\n",
       "      <td>-37.8024</td>\n",
       "      <td>144.9993</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>2</td>\n",
       "      <td>1.0</td>\n",
       "      <td>256.0</td>\n",
       "      <td>-37.8060</td>\n",
       "      <td>144.9954</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   Rooms  Bathroom  Landsize  Lattitude  Longtitude\n",
       "1      2       1.0     156.0   -37.8079    144.9934\n",
       "2      3       2.0     134.0   -37.8093    144.9944\n",
       "4      4       1.0     120.0   -37.8072    144.9941\n",
       "6      3       2.0     245.0   -37.8024    144.9993\n",
       "7      2       1.0     256.0   -37.8060    144.9954"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f86a8e02-f414-46e1-b1cb-5f0aff708538",
   "metadata": {},
   "source": [
    "Visueel je data controleren met deze commando's is belangrijk. Je zult vaak verrassingen in de dataset tegenkomen die nadere inspectie vereisen.\n",
    "\n",
    "### Een model trainen\n",
    "\n",
    "Je gebruikt de scikit-learn bibliotheek om je modellen te maken. In code wordt naar deze bibliotheek verwezen als `sklearn`, zoals ook hieronder gebeurt. Scikit-learn is veruit de populairste bibliotheek voor het trainen van modellen op basis van tabulaire data.\n",
    "\n",
    "De stappen om een model te bouwen en te gebruiken zijn:\n",
    "\n",
    "* **Definiëren**: Welk type model wordt het? Een decision tree? Een ander type model? Je specificeert hier ook eventuele parameters van het model.\n",
    "* **Fitten**: Patronen vastleggen uit de gegeven data.\n",
    "* **Voorspellen**: Precies zoals het klinkt.\n",
    "* **Evalueren**: Bepalen hoe nauwkeurig de voorspellingen van het model zijn.\n",
    "\n",
    "Hier is een voorbeeld van het definiëren van een decision tree model met scikit-learn en het fitten met de features en doelvariabele."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "574b85d4-aae8-4248-939b-57d8fc0618dc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style>#sk-container-id-1 {\n",
       "  /* Definition of color scheme common for light and dark mode */\n",
       "  --sklearn-color-text: black;\n",
       "  --sklearn-color-line: gray;\n",
       "  /* Definition of color scheme for unfitted estimators */\n",
       "  --sklearn-color-unfitted-level-0: #fff5e6;\n",
       "  --sklearn-color-unfitted-level-1: #f6e4d2;\n",
       "  --sklearn-color-unfitted-level-2: #ffe0b3;\n",
       "  --sklearn-color-unfitted-level-3: chocolate;\n",
       "  /* Definition of color scheme for fitted estimators */\n",
       "  --sklearn-color-fitted-level-0: #f0f8ff;\n",
       "  --sklearn-color-fitted-level-1: #d4ebff;\n",
       "  --sklearn-color-fitted-level-2: #b3dbfd;\n",
       "  --sklearn-color-fitted-level-3: cornflowerblue;\n",
       "\n",
       "  /* Specific color for light theme */\n",
       "  --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
       "  --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, white)));\n",
       "  --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
       "  --sklearn-color-icon: #696969;\n",
       "\n",
       "  @media (prefers-color-scheme: dark) {\n",
       "    /* Redefinition of color scheme for dark theme */\n",
       "    --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
       "    --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, #111)));\n",
       "    --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
       "    --sklearn-color-icon: #878787;\n",
       "  }\n",
       "}\n",
       "\n",
       "#sk-container-id-1 {\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 pre {\n",
       "  padding: 0;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 input.sk-hidden--visually {\n",
       "  border: 0;\n",
       "  clip: rect(1px 1px 1px 1px);\n",
       "  clip: rect(1px, 1px, 1px, 1px);\n",
       "  height: 1px;\n",
       "  margin: -1px;\n",
       "  overflow: hidden;\n",
       "  padding: 0;\n",
       "  position: absolute;\n",
       "  width: 1px;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-dashed-wrapped {\n",
       "  border: 1px dashed var(--sklearn-color-line);\n",
       "  margin: 0 0.4em 0.5em 0.4em;\n",
       "  box-sizing: border-box;\n",
       "  padding-bottom: 0.4em;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-container {\n",
       "  /* jupyter's `normalize.less` sets `[hidden] { display: none; }`\n",
       "     but bootstrap.min.css set `[hidden] { display: none !important; }`\n",
       "     so we also need the `!important` here to be able to override the\n",
       "     default hidden behavior on the sphinx rendered scikit-learn.org.\n",
       "     See: https://github.com/scikit-learn/scikit-learn/issues/21755 */\n",
       "  display: inline-block !important;\n",
       "  position: relative;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-text-repr-fallback {\n",
       "  display: none;\n",
       "}\n",
       "\n",
       "div.sk-parallel-item,\n",
       "div.sk-serial,\n",
       "div.sk-item {\n",
       "  /* draw centered vertical line to link estimators */\n",
       "  background-image: linear-gradient(var(--sklearn-color-text-on-default-background), var(--sklearn-color-text-on-default-background));\n",
       "  background-size: 2px 100%;\n",
       "  background-repeat: no-repeat;\n",
       "  background-position: center center;\n",
       "}\n",
       "\n",
       "/* Parallel-specific style estimator block */\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item::after {\n",
       "  content: \"\";\n",
       "  width: 100%;\n",
       "  border-bottom: 2px solid var(--sklearn-color-text-on-default-background);\n",
       "  flex-grow: 1;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel {\n",
       "  display: flex;\n",
       "  align-items: stretch;\n",
       "  justify-content: center;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  position: relative;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item {\n",
       "  display: flex;\n",
       "  flex-direction: column;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item:first-child::after {\n",
       "  align-self: flex-end;\n",
       "  width: 50%;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item:last-child::after {\n",
       "  align-self: flex-start;\n",
       "  width: 50%;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item:only-child::after {\n",
       "  width: 0;\n",
       "}\n",
       "\n",
       "/* Serial-specific style estimator block */\n",
       "\n",
       "#sk-container-id-1 div.sk-serial {\n",
       "  display: flex;\n",
       "  flex-direction: column;\n",
       "  align-items: center;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  padding-right: 1em;\n",
       "  padding-left: 1em;\n",
       "}\n",
       "\n",
       "\n",
       "/* Toggleable style: style used for estimator/Pipeline/ColumnTransformer box that is\n",
       "clickable and can be expanded/collapsed.\n",
       "- Pipeline and ColumnTransformer use this feature and define the default style\n",
       "- Estimators will overwrite some part of the style using the `sk-estimator` class\n",
       "*/\n",
       "\n",
       "/* Pipeline and ColumnTransformer style (default) */\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable {\n",
       "  /* Default theme specific background. It is overwritten whether we have a\n",
       "  specific estimator or a Pipeline/ColumnTransformer */\n",
       "  background-color: var(--sklearn-color-background);\n",
       "}\n",
       "\n",
       "/* Toggleable label */\n",
       "#sk-container-id-1 label.sk-toggleable__label {\n",
       "  cursor: pointer;\n",
       "  display: block;\n",
       "  width: 100%;\n",
       "  margin-bottom: 0;\n",
       "  padding: 0.5em;\n",
       "  box-sizing: border-box;\n",
       "  text-align: center;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 label.sk-toggleable__label-arrow:before {\n",
       "  /* Arrow on the left of the label */\n",
       "  content: \"▸\";\n",
       "  float: left;\n",
       "  margin-right: 0.25em;\n",
       "  color: var(--sklearn-color-icon);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 label.sk-toggleable__label-arrow:hover:before {\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       "/* Toggleable content - dropdown */\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content {\n",
       "  max-height: 0;\n",
       "  max-width: 0;\n",
       "  overflow: hidden;\n",
       "  text-align: left;\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content pre {\n",
       "  margin: 0.2em;\n",
       "  border-radius: 0.25em;\n",
       "  color: var(--sklearn-color-text);\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content.fitted pre {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 input.sk-toggleable__control:checked~div.sk-toggleable__content {\n",
       "  /* Expand drop-down */\n",
       "  max-height: 200px;\n",
       "  max-width: 100%;\n",
       "  overflow: auto;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {\n",
       "  content: \"▾\";\n",
       "}\n",
       "\n",
       "/* Pipeline/ColumnTransformer-specific style */\n",
       "\n",
       "#sk-container-id-1 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-label.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Estimator-specific style */\n",
       "\n",
       "/* Colorize estimator box */\n",
       "#sk-container-id-1 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-estimator.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-label label.sk-toggleable__label,\n",
       "#sk-container-id-1 div.sk-label label {\n",
       "  /* The background is the default theme color */\n",
       "  color: var(--sklearn-color-text-on-default-background);\n",
       "}\n",
       "\n",
       "/* On hover, darken the color of the background */\n",
       "#sk-container-id-1 div.sk-label:hover label.sk-toggleable__label {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "/* Label box, darken color on hover, fitted */\n",
       "#sk-container-id-1 div.sk-label.fitted:hover label.sk-toggleable__label.fitted {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Estimator label */\n",
       "\n",
       "#sk-container-id-1 div.sk-label label {\n",
       "  font-family: monospace;\n",
       "  font-weight: bold;\n",
       "  display: inline-block;\n",
       "  line-height: 1.2em;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-label-container {\n",
       "  text-align: center;\n",
       "}\n",
       "\n",
       "/* Estimator-specific */\n",
       "#sk-container-id-1 div.sk-estimator {\n",
       "  font-family: monospace;\n",
       "  border: 1px dotted var(--sklearn-color-border-box);\n",
       "  border-radius: 0.25em;\n",
       "  box-sizing: border-box;\n",
       "  margin-bottom: 0.5em;\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-estimator.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "/* on hover */\n",
       "#sk-container-id-1 div.sk-estimator:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-estimator.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Specification for estimator info (e.g. \"i\" and \"?\") */\n",
       "\n",
       "/* Common style for \"i\" and \"?\" */\n",
       "\n",
       ".sk-estimator-doc-link,\n",
       "a:link.sk-estimator-doc-link,\n",
       "a:visited.sk-estimator-doc-link {\n",
       "  float: right;\n",
       "  font-size: smaller;\n",
       "  line-height: 1em;\n",
       "  font-family: monospace;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  border-radius: 1em;\n",
       "  height: 1em;\n",
       "  width: 1em;\n",
       "  text-decoration: none !important;\n",
       "  margin-left: 1ex;\n",
       "  /* unfitted */\n",
       "  border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-unfitted-level-1);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link.fitted,\n",
       "a:link.sk-estimator-doc-link.fitted,\n",
       "a:visited.sk-estimator-doc-link.fitted {\n",
       "  /* fitted */\n",
       "  border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-1);\n",
       "}\n",
       "\n",
       "/* On hover */\n",
       "div.sk-estimator:hover .sk-estimator-doc-link:hover,\n",
       ".sk-estimator-doc-link:hover,\n",
       "div.sk-label-container:hover .sk-estimator-doc-link:hover,\n",
       ".sk-estimator-doc-link:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "div.sk-estimator.fitted:hover .sk-estimator-doc-link.fitted:hover,\n",
       ".sk-estimator-doc-link.fitted:hover,\n",
       "div.sk-label-container:hover .sk-estimator-doc-link.fitted:hover,\n",
       ".sk-estimator-doc-link.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "/* Span, style for the box shown on hovering the info icon */\n",
       ".sk-estimator-doc-link span {\n",
       "  display: none;\n",
       "  z-index: 9999;\n",
       "  position: relative;\n",
       "  font-weight: normal;\n",
       "  right: .2ex;\n",
       "  padding: .5ex;\n",
       "  margin: .5ex;\n",
       "  width: min-content;\n",
       "  min-width: 20ex;\n",
       "  max-width: 50ex;\n",
       "  color: var(--sklearn-color-text);\n",
       "  box-shadow: 2pt 2pt 4pt #999;\n",
       "  /* unfitted */\n",
       "  background: var(--sklearn-color-unfitted-level-0);\n",
       "  border: .5pt solid var(--sklearn-color-unfitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link.fitted span {\n",
       "  /* fitted */\n",
       "  background: var(--sklearn-color-fitted-level-0);\n",
       "  border: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link:hover span {\n",
       "  display: block;\n",
       "}\n",
       "\n",
       "/* \"?\"-specific style due to the `<a>` HTML tag */\n",
       "\n",
       "#sk-container-id-1 a.estimator_doc_link {\n",
       "  float: right;\n",
       "  font-size: 1rem;\n",
       "  line-height: 1em;\n",
       "  font-family: monospace;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  border-radius: 1rem;\n",
       "  height: 1rem;\n",
       "  width: 1rem;\n",
       "  text-decoration: none;\n",
       "  /* unfitted */\n",
       "  color: var(--sklearn-color-unfitted-level-1);\n",
       "  border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 a.estimator_doc_link.fitted {\n",
       "  /* fitted */\n",
       "  border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-1);\n",
       "}\n",
       "\n",
       "/* On hover */\n",
       "#sk-container-id-1 a.estimator_doc_link:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 a.estimator_doc_link.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "</style><div id=\"sk-container-id-1\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>DecisionTreeRegressor(random_state=1)</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-1\" type=\"checkbox\" checked><label for=\"sk-estimator-id-1\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;&nbsp;DecisionTreeRegressor<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.5/modules/generated/sklearn.tree.DecisionTreeRegressor.html\">?<span>Documentation for DecisionTreeRegressor</span></a><span class=\"sk-estimator-doc-link fitted\">i<span>Fitted</span></span></label><div class=\"sk-toggleable__content fitted\"><pre>DecisionTreeRegressor(random_state=1)</pre></div> </div></div></div></div>"
      ],
      "text/plain": [
       "DecisionTreeRegressor(random_state=1)"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.tree import DecisionTreeRegressor\n",
    "\n",
    "# Model definiëren. We geven een nummer voor random_state om telkens dezelfde resultaten bij elke run te krijgen\n",
    "melbourne_model = DecisionTreeRegressor(random_state=1)\n",
    "\n",
    "# Model fitten\n",
    "melbourne_model.fit(X, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "50af5a47-4b69-4c1a-80fd-d83f6fd25f9f",
   "metadata": {},
   "source": [
    "Veel machine learning modellen laten wat willekeur toe tijdens het trainen. Door een nummer voor `random_state` te specificeren, zorg je ervoor dat je bij elke run dezelfde resultaten krijgt. Je kunt elk nummer gebruiken; de kwaliteit van het model hangt niet significant af van de exacte waarde die je kiest.\n",
    "\n",
    "We hebben nu een gefit model dat we kunnen gebruiken om voorspellingen te doen.\n",
    "\n",
    "In de praktijk wil je voorspellingen doen voor nieuwe huizen die op de markt komen, in plaats van de huizen waarvoor we al prijzen hebben. In dit geval gebruiken we echter de eerste paar rijen van de trainingsdata. Dit doet we nu alleen om te laten zien hoe de `predict` methode werkt."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "2b29307e-a4a7-497f-9a58-acd9ad2b8262",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Voorspellingen maken voor de volgende 5 huizen:\n",
      "   Rooms  Bathroom  Landsize  Lattitude  Longtitude\n",
      "1      2       1.0     156.0   -37.8079    144.9934\n",
      "2      3       2.0     134.0   -37.8093    144.9944\n",
      "4      4       1.0     120.0   -37.8072    144.9941\n",
      "6      3       2.0     245.0   -37.8024    144.9993\n",
      "7      2       1.0     256.0   -37.8060    144.9954\n",
      "De voorspellingen zijn\n",
      "[1035000. 1465000. 1600000. 1876000. 1636000.]\n"
     ]
    }
   ],
   "source": [
    "print(\"Voorspellingen maken voor de volgende 5 huizen:\")\n",
    "print(X.head())\n",
    "\n",
    "print(\"De voorspellingen zijn\")\n",
    "print(melbourne_model.predict(X.head()))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "590bb8c3-134a-4c70-97c3-fa4cff61bd17",
   "metadata": {},
   "source": [
    "### Oefeningen\n",
    "\n",
    "Maak nu oefening 4 t/m 9."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cae9bf6f-96af-4a0c-8474-7b545be03ee1",
   "metadata": {},
   "source": [
    "## Het valideren van je model\n",
    "\n",
    "Je hebt een model gebouwd. Maar hoe goed voorspelt het model?\n",
    "\n",
    "Je zult bijna elk model dat je traint willen evalueren. In de meeste (maar niet alle) toepassingen is de relevante maatstaf voor modelkwaliteit de voorspellende nauwkeurigheid. Met andere woorden, zullen de voorspellingen van het model dicht bij de werkelijke waarden liggen?\n",
    "\n",
    "Veel beginners maken een grote fout bij het kwantificeren van de nauwkeurigheid van hun model: Ze doen voorspellingen met hun trainingsdata en vergelijken die voorspellingen met de doelwaarden in de trainingsdata. Je zult zo zien wat het probleem is met deze aanpak is en hoe je dit kunt oplossen.\n",
    "\n",
    "Laten we eerst echter nadenken over hoe we de nauwkeurigheid zouden kunnen kwantificeren.\n",
    "\n",
    "Wat we willen is de modelkwaliteit in een begrijpelijke maatstaf samenvatten. Als je de voorspelde en de werkelijke woningwaarden van 10.000 huizen vergelijkt, zul je waarschijnlijk een mix van goede en slechte voorspellingen vinden. Door deze lijst van 10.000 voorspelde en werkelijke waarden bladeren is ondoenlijk. We willen dit samenvatten in een enkele metriek.\n",
    "\n",
    "Er zijn veel verschillende metrieken voor het samenvatten van modelkwaliteit, maar voor ons probleem kunnen we gebruik maken van de zogenaamd **Mean Absolute Error** (ook wel **MAE** genoemd). Laten we deze metriek stap voor stap bekijken, te beginnen met het laatste woord, **Error** (fout).\n",
    "\n",
    "De voorspellingsfout voor elk huis is:\n",
    "\n",
    "$$\\text{error} = |\\text{actual} - \\text{predicted}|$$\n",
    "\n",
    "Dus, als een huis $\\$150.000$ kost en je voorspelt dat het $\\$100.000$ zou kosten, dan is de fout $\\$50.000$. Let op dat in de formule hierboven we telkens de _absolute_ waarde nemen van het verschil tussen $\\text{actual}$ en $\\text{predicted}$. Dus als het model had voorspeld dat datzelfde huis van $\\$150.000$ $\\$200.000$ zou kosten, dan is de fout ook $\\$50.000$.\n",
    "\n",
    "Met de MAE-metriek nemen we het gemiddelde van al die absolute fouten. Dit gemiddelde is onze uiteindelijke maatstaf voor modelkwaliteit. In eenvoudige taal zouden we kunnen zeggen dat de MAE het volgende uitdrukt:\n",
    "\n",
    "\"Gemiddeld zitten onze voorspellingen er ongeveer X naast.\"\n",
    "\n",
    "Om MAE te berekenen, hebben we eerst een model nodig zoals we dat hierboven gefit hebben.\n",
    "\n",
    "Zodra we een model hebben, berekenen we de mean absolute error als volgt:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "a0e6b9d4-9fd9-4dff-9b80-89dcfc813b3f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1115.7467183128902"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.metrics import mean_absolute_error\n",
    "\n",
    "predicted_home_prices = melbourne_model.predict(X)\n",
    "mean_absolute_error(y, predicted_home_prices)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4c07c7e1-26a9-4472-864b-3a431c315477",
   "metadata": {},
   "source": [
    "### Het probleem met op deze wijze de MAE score bepalen\n",
    "\n",
    "De MAE metriek zoals we die zojuist hebben berekend, zou een \"in-sample\" score genoemd kunnen worden. We gebruikten een enkele \"sample\" van huizen voor zowel het trainen van het model als het evalueren ervan. \n",
    "\n",
    "Dat dit een verkeerde aanpak is maakt het volgende voorbeeld duidelijk:\n",
    "\n",
    "Stel je voor dat, in de vastgoedmarkt, de kleur van de deur niet gerelateerd is aan de woningprijs. Echter, in de data die je gebruikte om het model te trainen, waren alle huizen met groene deuren erg duur. Het model moet patronen vinden die de woningprijzen voorspellen, dus het zal dit patroon zien en altijd hoge prijzen voorspellen voor huizen met groene deuren.\n",
    "\n",
    "Omdat dit patroon werd afgeleid van de trainingsdata, lijkt het model accuraat in de trainingsdata. Maar omdat dit patroon niet geldt wanneer het model nieuwe data ziet, is het model zeer onnauwkeurig in de praktijk. Anders gezegd: We willen dat het model goed **generaliseert**.\n",
    "\n",
    "Aangezien de praktische waarde van modellen voortkomt uit het maken van voorspellingen op nieuwe data, meten we de prestaties op data die niet werd gebruikt om het model te bouwen. De meest voor de hand liggende manier om dit te doen is om een deel van de data apart te houden van het modeltrainingsproces en deze te gebruiken om de nauwkeurigheid van het model op data die het nog niet heeft gezien te testen. Deze apart gehouden data wordt **validatiedata** genoemd.\n",
    "\n",
    "### Hoe dit te doen in Python\n",
    "\n",
    "De scikit-learn bibliotheek heeft een functie `train_test_split` om de data op te splitsen in twee stukken. We gebruiken een deel van die data als trainingsdata om het model te fitten, en we gebruiken de andere data als validatiedata om de `mean_absolute_error` te berekenen.\n",
    "\n",
    "De code is als volgt:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "a4e6d44c-0a4e-4fe4-936f-4d957cbc931e",
   "metadata": {
    "jp-MarkdownHeadingCollapsed": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "270372.6621476221\n"
     ]
    }
   ],
   "source": [
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "# splits data in trainings- en validatiedata, voor zowel features als target\n",
    "train_X, val_X, train_y, val_y = train_test_split(X, y, random_state=0)\n",
    "# Definieer model\n",
    "melbourne_model = DecisionTreeRegressor()\n",
    "# Pas model aan\n",
    "melbourne_model.fit(train_X, train_y)\n",
    "\n",
    "# krijg voorspelde prijzen op validatiedata\n",
    "val_predictions = melbourne_model.predict(val_X)\n",
    "print(mean_absolute_error(val_y, val_predictions))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f7409b71-7a02-4ee9-8200-315ab57b883b",
   "metadata": {},
   "source": [
    "### Vergelijk deze MAE met de \"in-sample\" MAE\n",
    "\n",
    "Als je deze MAE vergelijkt met de MAE berekend op de \"in-sample\" data dan zie je een enorm verschil.\n",
    "\n",
    "Dit is het verschil tussen een model dat bijna helemaal correct is, en een model dat onbruikbaar is voor de meeste praktische doeleinden. Ter referentie: de gemiddelde woningwaarde in de validatiedata is 1.1 miljoen dollar. Dus de fout in nieuwe data is ongeveer een kwart van de gemiddelde woningwaarde.\n",
    "\n",
    "Later zullen we zien hoe we dit model kunnen verbeteren.\n",
    "\n",
    "### Oefeningen\n",
    "\n",
    "Maak nu oefening 10 t/m 14."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f8f9eaa7-cd21-4ac6-b0ac-fd87f6f7a096",
   "metadata": {},
   "source": [
    "## Het model optimaliseren\n",
    "\n",
    "Om je modellen nauwkeuriger te maken zijn de concepten **underfitting** en **overfitting** erg belangrijk.\n",
    "\n",
    "### Experimenteren met verschillende modellen\n",
    "\n",
    "Nu je een betrouwbare manier hebt om de nauwkeurigheid van een model te meten, kun je experimenteren met alternatieve modellen en zien welke de beste voorspellingen geeft. Maar welke alternatieven heb je voor modellen?\n",
    "\n",
    "In [de documentatie van scikit-learn](https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeRegressor.html) zie je dat het decision tree-model veel opties heeft (meer dan je voorlopig nodig hebt). De belangrijkste opties bepalen de diepte van de boom. In de inleiding leerde je dat de diepte van een boom aangeeft hoeveel splitsingen hij maakt voordat hij een voorspelling doet. \n",
    "\n",
    "Hier het voorbeeld van een relatief ondiepe boom:\n",
    "\n",
    "![](https://www.dropbox.com/scl/fi/y64da5mph8bq52k49269m/decision_tree.png?rlkey=3na1h47ewtjhhxcjyu62nbuug&dl=1)\n",
    "\n",
    "In de praktijk is het niet ongebruikelijk dat een boom 10 splitsingen heeft tussen de bovenste laag (alle huizen) en een blad. Naarmate de boom dieper wordt, wordt de dataset steeds opgedeeld in bladeren met minder huizen. Als een boom slechts 1 splitsing had, verdeelt deze de data in 2 groepen. Als elke groep opnieuw wordt gesplitst, krijgen we 4 groepen huizen. Splitsen we die opnieuw, dan ontstaan er 8 groepen, enzovoorts. Bij 10 niveaus hebben we $2^{10}$ groepen huizen, oftewel 1024 bladeren.\n",
    "\n",
    "Wanneer we huizen verdelen over veel bladeren, hebben we ook minder huizen per blad. Bladeren met heel weinig huizen zullen voorspellingen doen die dicht bij de werkelijke waarden van die huizen liggen, maar deze voorspellingen kunnen erg onbetrouwbaar zijn voor nieuwe data (omdat elke voorspelling is gebaseerd op slechts een paar huizen).\n",
    "\n",
    "### Overfitting en Underfitting\n",
    "\n",
    "Men spreek van **overfitting** wanneer een model bijna perfect aansluit op de trainingsdata, maar slecht presteert bij validatie of nieuwe data. Dit gebeurt als een decision tree te diep is. De boom memoriseert dan als het ware de trainingsdata maar is niet in staat om te generaliseren. Aan de andere kant, als de boom heel ondiep is, verdeelt hij de huizen niet in duidelijke groepen. Wanneer een model belangrijke patronen in de data juist niet vastlegt, noemen we dat **underfitting**.\n",
    "\n",
    "Bij extreme underfitting verdeelt een boom huizen slechts in 2 of 4 groepen, waardoor er een grote variatie binnen elke groep blijft. Dit resulteert in slechte voorspellingen, zelfs op de trainingsdata (en natuurlijk ook bij validatie). \n",
    "\n",
    "Omdat we ons richten op nauwkeurigheid bij nieuwe data (ingeschat via validatiedata), zoeken we naar het optimale punt tussen underfitting en overfitting. Visueel is dit het laagste punt van de (rode) validatiecurve in de onderstaande grafiek.\n",
    "\n",
    "![](https://www.dropbox.com/scl/fi/nr7zxxnlfazjowlyf3xdm/underoverfitting.png?rlkey=a11ywpooc0i1w4gyruow73h63&dl=1)\n",
    "\n",
    "### Het vinden van een balans\n",
    "\n",
    "Een goede manier om overfitting zoveel mogelijk te voorkomen, is het beperken van het aantal bladeren. Of meer algemeen: door de _complexiteit_ van het model te beperken. Het argument `max_leaf_nodes` in `DecisionTreeRegressor` biedt een eenvoudige manier om dit voor elkaar te krijgen. Hoe meer bladeren (hoe complexer het model), hoe verder we verschuiven van underfitting naar overfitting.\n",
    "\n",
    "We kunnen een hulpfunctie gebruiken om MAE-scores (Mean Absolute Error) voor verschillende waarden van `max_leaf_nodes` te vergelijken:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "53c5ea04-1da5-41f3-bc92-eb18accdb121",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_mae(max_leaf_nodes, train_X, val_X, train_y, val_y):\n",
    "    model = DecisionTreeRegressor(max_leaf_nodes=max_leaf_nodes, random_state=0)\n",
    "    model.fit(train_X, train_y)\n",
    "    preds_val = model.predict(val_X)\n",
    "    mae = mean_absolute_error(val_y, preds_val)\n",
    "    return mae"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b467f550-26db-4c2c-b38a-80d2837b7b13",
   "metadata": {},
   "source": [
    "We gebruiken een for-loop om de nauwkeurigheid van modellen te vergelijken bij verschillende waarden voor `max_leaf_nodes`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "392d7ca0-fb5e-4dca-961e-c0abbe74c899",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Max leaf nodes: 5  \t\t Mean Absolute Error:  385696.54278937966\n",
      "Max leaf nodes: 50  \t\t Mean Absolute Error:  279794.61143891385\n",
      "Max leaf nodes: 500  \t\t Mean Absolute Error:  261718.1134423186\n",
      "Max leaf nodes: 5000  \t\t Mean Absolute Error:  271320.97310092533\n"
     ]
    }
   ],
   "source": [
    "# Vergelijk MAE met verschillende waarden voor max_leaf_nodes\n",
    "for max_leaf_nodes in [5, 50, 500, 5000]:\n",
    "    my_mae = get_mae(max_leaf_nodes, train_X, val_X, train_y, val_y)\n",
    "    print(f\"Max leaf nodes: {max_leaf_nodes}  \\t\\t Mean Absolute Error:  {my_mae}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0c9fb0e6-26ca-47f5-a1d6-dd13df37840a",
   "metadata": {},
   "source": [
    "Van de gegeven opties is 500 het optimale aantal bladeren. Argumenten zoals `max_leaf_nodes` worden ook wel **hyperparameters** genoemd. Het manipuleren van dergelijke argumenten wordt dan ook wel **hyperparameter tuning** genoemd. Verschillende modellen hebben verschillende hyperparameters.\n",
    "\n",
    "### Samengevat\n",
    "\n",
    "Laten we het bovenstaande nogmaals beknopt samenvatten.\n",
    "\n",
    "Modellen kunnen last hebben van:\n",
    "\n",
    "* **Overfitting**: het leren van willekeurige patronen die niet herhaald worden in nieuwe data, wat leidt tot minder nauwkeurige voorspellingen.\n",
    "* **Underfitting**: het niet leren van relevante patronen, wat eveneens leidt tot minder nauwkeurige voorspellingen.\n",
    "\n",
    "We gebruiken validatiedata (die niet wordt gebruikt bij het trainen van het model) om de nauwkeurigheid van een model te meten. Dit stelt ons in staat om meerdere modellen te vergelijken en de beste te kiezen.\n",
    "\n",
    "### Oefeningen\n",
    "\n",
    "Maak nu oefening 15 en 16."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5cfef80a-7ea2-480f-8ed3-05b4a549d49d",
   "metadata": {},
   "source": [
    "## Random Forests\n",
    "\n",
    "### Inleiding\n",
    "\n",
    "Decision trees brengen een lastig dilemma met zich mee. Een diepe boom met veel bladeren zal **overfitten**, omdat elke voorspelling is gebaseerd op historische data van slechts een paar huizen in een blad. Maar een ondiepe boom met weinig bladeren zal slecht presteren omdat deze niet genoeg onderscheid maakt in de ruwe data.\n",
    "\n",
    "Zelfs de meest geavanceerde modelleringstechnieken van vandaag hebben te maken met deze spanning tussen **underfitting** en **overfitting**. Veel modellen bevatten echter slimme ideeën die tot betere prestaties kunnen leiden. We kijken nu naar het *random forest* als voorbeeld.\n",
    "\n",
    "Het random forest gebruikt niet één decision tree om tot een beslissing te komen, maar heel veel beslisbomen (vandaar het woord _forest_ oftewel _bos_). Een random forest maakt een voorspelling door het gemiddelde te nemen van de voorspellingen van elke individuele boom. Het heeft over het algemeen een veel betere voorspellende nauwkeurigheid dan een enkele beslissingsboom en werkt goed met standaardinstellingen. Als je verder gaat met modelleren, kun je modellen ontdekken met nog betere prestaties, maar veel daarvan vereisen dat je de juiste parameters zorgvuldig instelt."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "29d10010-ed0a-4ee4-b482-73e6d8f8d529",
   "metadata": {},
   "source": [
    "We bouwen een random forest-model op een vergelijkbare manier als we eerder een decision tree bouwden in scikit-learn, maar deze keer gebruiken we de klasse `RandomForestRegressor` in plaats van `DecisionTreeRegressor`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "847d0ad0-c5b4-458e-b822-4815b32cfc81",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "207190.6873773146\n"
     ]
    }
   ],
   "source": [
    "from sklearn.ensemble import RandomForestRegressor\n",
    "\n",
    "forest_model = RandomForestRegressor(random_state=1)\n",
    "forest_model.fit(train_X, train_y)\n",
    "\n",
    "melb_preds = forest_model.predict(val_X)\n",
    "print(mean_absolute_error(val_y, melb_preds))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "48f09575-1813-4e34-9ec8-aae51114236f",
   "metadata": {},
   "source": [
    "Er is waarschijnlijk nog wel ruimte voor verdere verbetering, maar dit is al een grote verbetering ten opzichte van de beste foutmarge van een enkele decision tree! Er zijn [parameters waarmee je de prestaties van een random forest kunt aanpassen](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html), net zoals we eerder de maximale diepte van een enkele beslissingsboom aanpasten. Het mooie van random forest-modellen is echter dat ze over het algemeen redelijk goed presteren, zelfs zonder verdere aanpassingen.\n",
    "\n",
    "### Oefeningen\n",
    "\n",
    "Maak nu oefening 17."
   ]
  }
 ],
 "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.12.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
