{ "nbformat": 4, "nbformat_minor": 2, "metadata": { "colab": { "name": "lesson_2-R.ipynb", "provenance": [], "collapsed_sections": [], "toc_visible": true }, "kernelspec": { "name": "ir", "display_name": "R" }, "language_info": { "name": "R" }, "coopTranslator": { "original_hash": "f3c335f9940cfd76528b3ef918b9b342", "translation_date": "2025-09-06T11:57:13+00:00", "source_file": "2-Regression/2-Data/solution/R/lesson_2-R.ipynb", "language_code": "nl" } }, "cells": [ { "cell_type": "markdown", "source": [ "# Bouw een regressiemodel: data voorbereiden en visualiseren\n", "\n", "## **Lineaire regressie voor pompoenen - Les 2**\n", "#### Introductie\n", "\n", "Nu je beschikt over de tools die je nodig hebt om te beginnen met het bouwen van machine learning-modellen met Tidymodels en de Tidyverse, ben je klaar om vragen te stellen over je data. Het is erg belangrijk om te begrijpen hoe je de juiste vragen stelt om de mogelijkheden van je dataset optimaal te benutten wanneer je met data werkt en ML-oplossingen toepast.\n", "\n", "In deze les leer je:\n", "\n", "- Hoe je je data voorbereidt voor het bouwen van modellen.\n", "\n", "- Hoe je `ggplot2` gebruikt voor datavisualisatie.\n", "\n", "De vraag die je beantwoord wilt hebben, bepaalt welk type ML-algoritmes je zult gebruiken. En de kwaliteit van het antwoord dat je terugkrijgt, hangt sterk af van de aard van je data.\n", "\n", "Laten we dit zien door een praktische oefening te doen.\n", "\n", "\n", "
\n",
" \n",
"
\n",
"\n",
"> Een opfrisser: De pipe-operator (`%>%`) voert bewerkingen uit in logische volgorde door een object door te geven aan een functie of expressie. Je kunt de pipe-operator zien als \"en dan\" in je code.\n"
],
"metadata": {
"id": "REWcIv9yX29v"
}
},
{
"cell_type": "markdown",
"source": [
"## 2. Controleer op ontbrekende gegevens\n",
"\n",
"Een van de meest voorkomende problemen waarmee datawetenschappers te maken hebben, is incomplete of ontbrekende gegevens. R vertegenwoordigt ontbrekende of onbekende waarden met een speciale sentinelwaarde: `NA` (Not Available).\n",
"\n",
"Hoe kunnen we weten of het gegevensframe ontbrekende waarden bevat?\n",
"
\n",
"- Een eenvoudige manier is om de basis R-functie `anyNA` te gebruiken, die de logische objecten `TRUE` of `FALSE` retourneert.\n"
],
"metadata": {
"id": "Zxfb3AM5YbUe"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"pumpkins %>% \n",
" anyNA()"
],
"outputs": [],
"metadata": {
"id": "G--DQutAYltj"
}
},
{
"cell_type": "markdown",
"source": [
"Geweldig, het lijkt erop dat er wat gegevens ontbreken! Dat is een goed startpunt.\n",
"\n",
"- Een andere manier is om de functie `is.na()` te gebruiken, die aangeeft welke individuele kolomelementen ontbreken met een logische `TRUE`.\n"
],
"metadata": {
"id": "mU-7-SB6YokF"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"pumpkins %>% \n",
" is.na() %>% \n",
" head(n = 7)"
],
"outputs": [],
"metadata": {
"id": "W-DxDOR4YxSW"
}
},
{
"cell_type": "markdown",
"source": [
"Oké, het is gelukt, maar met een grote dataset zoals deze zou het inefficiënt en praktisch onmogelijk zijn om alle rijen en kolommen afzonderlijk te controleren😴.\n",
"\n",
"- Een meer intuïtieve manier zou zijn om de som van de ontbrekende waarden per kolom te berekenen:\n"
],
"metadata": {
"id": "xUWxipKYY0o7"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"pumpkins %>% \n",
" is.na() %>% \n",
" colSums()"
],
"outputs": [],
"metadata": {
"id": "ZRBWV6P9ZArL"
}
},
{
"cell_type": "markdown",
"source": [
"Veel beter! Er ontbreken wat gegevens, maar misschien maakt dat niet uit voor de taak die voor ons ligt. Laten we eens kijken wat verder onderzoek oplevert.\n",
"\n",
"> Naast de geweldige sets pakketten en functies, heeft R een zeer goede documentatie. Gebruik bijvoorbeeld `help(colSums)` of `?colSums` om meer te weten te komen over de functie.\n"
],
"metadata": {
"id": "9gv-crB6ZD1Y"
}
},
{
"cell_type": "markdown",
"source": [
"## 3. Dplyr: Een Grammatica voor Datamanipulatie\n",
"\n",
"
\n",
" \n",
"
\n"
],
"metadata": {
"id": "i5o33MQBZWWw"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::select()\n",
"\n",
"`select()` is een functie in het pakket `dplyr` waarmee je kolommen kunt kiezen om te behouden of uit te sluiten.\n",
"\n",
"Om je data frame eenvoudiger te maken om mee te werken, kun je meerdere kolommen verwijderen met behulp van `select()`, waarbij je alleen de kolommen behoudt die je nodig hebt.\n",
"\n",
"Bijvoorbeeld, in deze oefening zullen we ons richten op de kolommen `Package`, `Low Price`, `High Price` en `Date`. Laten we deze kolommen selecteren.\n"
],
"metadata": {
"id": "x3VGMAGBZiUr"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Select desired columns\n",
"pumpkins <- pumpkins %>% \n",
" select(Package, `Low Price`, `High Price`, Date)\n",
"\n",
"\n",
"# Print data set\n",
"pumpkins %>% \n",
" slice_head(n = 5)"
],
"outputs": [],
"metadata": {
"id": "F_FgxQnVZnM0"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::mutate()\n",
"\n",
"`mutate()` is een functie in het pakket `dplyr` waarmee je kolommen kunt aanmaken of aanpassen, terwijl de bestaande kolommen behouden blijven.\n",
"\n",
"De algemene structuur van mutate is:\n",
"\n",
"`data %>% mutate(new_column_name = what_it_contains)`\n",
"\n",
"Laten we `mutate` in de praktijk gebruiken met de `Date`-kolom door de volgende bewerkingen uit te voeren:\n",
"\n",
"1. Converteer de datums (momenteel van het type karakter) naar een maandformaat (dit zijn Amerikaanse datums, dus het formaat is `MM/DD/YYYY`).\n",
"\n",
"2. Haal de maand uit de datums en sla deze op in een nieuwe kolom.\n",
"\n",
"In R maakt het pakket [lubridate](https://lubridate.tidyverse.org/) het eenvoudiger om met datum-tijdgegevens te werken. Dus laten we `dplyr::mutate()`, `lubridate::mdy()`, `lubridate::month()` gebruiken om bovenstaande doelen te bereiken. We kunnen de Date-kolom verwijderen, aangezien we deze niet meer nodig hebben in de volgende bewerkingen.\n"
],
"metadata": {
"id": "2KKo0Ed9Z1VB"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Load lubridate\n",
"library(lubridate)\n",
"\n",
"pumpkins <- pumpkins %>% \n",
" # Convert the Date column to a date object\n",
" mutate(Date = mdy(Date)) %>% \n",
" # Extract month from Date\n",
" mutate(Month = month(Date)) %>% \n",
" # Drop Date column\n",
" select(-Date)\n",
"\n",
"# View the first few rows\n",
"pumpkins %>% \n",
" slice_head(n = 7)"
],
"outputs": [],
"metadata": {
"id": "5joszIVSZ6xe"
}
},
{
"cell_type": "markdown",
"source": [
"Woohoo! 🤩\n",
"\n",
"Laten we een nieuwe kolom `Price` maken, die de gemiddelde prijs van een pompoen weergeeft. Nu gaan we het gemiddelde nemen van de kolommen `Low Price` en `High Price` om de nieuwe kolom Price in te vullen.\n",
"
\n"
],
"metadata": {
"id": "nIgLjNMCZ-6Y"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Create a new column Price\n",
"pumpkins <- pumpkins %>% \n",
" mutate(Price = (`Low Price` + `High Price`)/2)\n",
"\n",
"# View the first few rows of the data\n",
"pumpkins %>% \n",
" slice_head(n = 5)"
],
"outputs": [],
"metadata": {
"id": "Zo0BsqqtaJw2"
}
},
{
"cell_type": "markdown",
"source": [
"Yeees!💪\n",
"\n",
"\"Maar wacht!\", zul je zeggen na het snel doorlopen van de hele dataset met `View(pumpkins)`, \"Er is hier iets vreemds!\"🤔\n",
"\n",
"Als je naar de kolom `Package` kijkt, worden pompoenen in veel verschillende configuraties verkocht. Sommige worden verkocht in `1 1/9 bushel` maten, andere in `1/2 bushel` maten, sommige per pompoen, sommige per pond, en sommige in grote dozen met verschillende breedtes.\n",
"\n",
"Laten we dit verifiëren:\n"
],
"metadata": {
"id": "p77WZr-9aQAR"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Verify the distinct observations in Package column\n",
"pumpkins %>% \n",
" distinct(Package)"
],
"outputs": [],
"metadata": {
"id": "XISGfh0IaUy6"
}
},
{
"cell_type": "markdown",
"source": [
"Geweldig!👏\n",
"\n",
"Pompoenen lijken erg moeilijk consistent te wegen, dus laten we ze filteren door alleen pompoenen te selecteren met de string *bushel* in de kolom `Package` en dit in een nieuw gegevensframe `new_pumpkins` te plaatsen.\n",
"
\n"
],
"metadata": {
"id": "7sMjiVujaZxY"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::filter() en stringr::str_detect()\n",
"\n",
"[`dplyr::filter()`](https://dplyr.tidyverse.org/reference/filter.html): maakt een subset van de data die alleen **rijen** bevat die voldoen aan jouw voorwaarden, in dit geval pompoenen met de string *bushel* in de `Package`-kolom.\n",
"\n",
"[stringr::str_detect()](https://stringr.tidyverse.org/reference/str_detect.html): detecteert de aanwezigheid of afwezigheid van een patroon in een string.\n",
"\n",
"De [`stringr`](https://github.com/tidyverse/stringr)-package biedt eenvoudige functies voor veelvoorkomende bewerkingen met strings.\n"
],
"metadata": {
"id": "L8Qfcs92ageF"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Retain only pumpkins with \"bushel\"\n",
"new_pumpkins <- pumpkins %>% \n",
" filter(str_detect(Package, \"bushel\"))\n",
"\n",
"# Get the dimensions of the new data\n",
"dim(new_pumpkins)\n",
"\n",
"# View a few rows of the new data\n",
"new_pumpkins %>% \n",
" slice_head(n = 5)"
],
"outputs": [],
"metadata": {
"id": "hy_SGYREampd"
}
},
{
"cell_type": "markdown",
"source": [
"Je kunt zien dat we het hebben teruggebracht tot ongeveer 415 rijen met gegevens over pompoenen per schepel.🤩\n",
"
\n"
],
"metadata": {
"id": "VrDwF031avlR"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::case_when()\n",
"\n",
"**Maar wacht! Er is nog iets te doen**\n",
"\n",
"Heb je gemerkt dat de hoeveelheid per bushel per rij verschilt? Je moet de prijzen normaliseren zodat je de prijs per bushel laat zien, en niet per 1 1/9 of 1/2 bushel. Tijd om wat rekenwerk te doen om dit te standaardiseren.\n",
"\n",
"We gebruiken de functie [`case_when()`](https://dplyr.tidyverse.org/reference/case_when.html) om de kolom Price te *muteren* op basis van bepaalde voorwaarden. `case_when` stelt je in staat om meerdere `if_else()`-verklaringen te vectoriseren.\n"
],
"metadata": {
"id": "mLpw2jH4a0tx"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Convert the price if the Package contains fractional bushel values\n",
"new_pumpkins <- new_pumpkins %>% \n",
" mutate(Price = case_when(\n",
" str_detect(Package, \"1 1/9\") ~ Price/(1 + 1/9),\n",
" str_detect(Package, \"1/2\") ~ Price/(1/2),\n",
" TRUE ~ Price))\n",
"\n",
"# View the first few rows of the data\n",
"new_pumpkins %>% \n",
" slice_head(n = 30)"
],
"outputs": [],
"metadata": {
"id": "P68kLVQmbM6I"
}
},
{
"cell_type": "markdown",
"source": [
"Nu kunnen we de prijs per eenheid analyseren op basis van hun bushel-meting. Al deze studie over bushels van pompoenen laat echter zien hoe `belangrijk` het is om `de aard van je gegevens te begrijpen`!\n",
"\n",
"> ✅ Volgens [The Spruce Eats](https://www.thespruceeats.com/how-much-is-a-bushel-1389308) hangt het gewicht van een bushel af van het type product, omdat het een volumemeting is. \"Een bushel tomaten, bijvoorbeeld, zou 56 pond moeten wegen... Bladeren en groenten nemen meer ruimte in met minder gewicht, dus een bushel spinazie weegt slechts 20 pond.\" Het is allemaal behoorlijk ingewikkeld! Laten we ons niet druk maken over het omrekenen van bushels naar ponden, en in plaats daarvan de prijs per bushel bepalen. Al deze studie over bushels van pompoenen laat echter zien hoe belangrijk het is om de aard van je gegevens te begrijpen!\n",
">\n",
"> ✅ Is het je opgevallen dat pompoenen die per halve bushel worden verkocht erg duur zijn? Kun je achterhalen waarom? Hint: kleine pompoenen zijn veel duurder dan grote, waarschijnlijk omdat er veel meer van zijn per bushel, gezien de ongebruikte ruimte die wordt ingenomen door één grote holle taartpompoen.\n"
],
"metadata": {
"id": "pS2GNPagbSdb"
}
},
{
"cell_type": "markdown",
"source": [
"Belangrijkste regels: \n",
"1. Verplaats de kolom `Month` naar de eerste positie, vóór de kolom `Package`. \n",
"2. Gebruik de functie `dplyr::relocate()` om de kolomvolgorde te wijzigen. \n"
],
"metadata": {
"id": "qql1SowfbdnP"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Create a new data frame new_pumpkins\n",
"new_pumpkins <- new_pumpkins %>% \n",
" relocate(Month, .before = Package)\n",
"\n",
"new_pumpkins %>% \n",
" slice_head(n = 7)"
],
"outputs": [],
"metadata": {
"id": "JJ1x6kw8bixF"
}
},
{
"cell_type": "markdown",
"source": [
"Goed gedaan!👌 Je hebt nu een schoon en overzichtelijk dataset waarop je je nieuwe regressiemodel kunt bouwen!\n",
"
\n"
],
"metadata": {
"id": "y8TJ0Za_bn5Y"
}
},
{
"cell_type": "markdown",
"source": [
"## 4. Gegevensvisualisatie met ggplot2\n",
"\n",
"
\n",
" \n",
"
\n"
],
"metadata": {
"id": "Ml7SDCLQcPvE"
}
},
{
"cell_type": "markdown",
"source": [
"### **Hoe maken we het nuttig?**\n",
"\n",
"Om grafieken nuttige gegevens te laten weergeven, moet je de gegevens meestal op een bepaalde manier groeperen. Bijvoorbeeld, in ons geval zou het vinden van de gemiddelde prijs van pompoenen per maand meer inzicht geven in de onderliggende patronen in onze gegevens. Dit brengt ons bij nog een **dplyr**-overzicht:\n",
"\n",
"#### `dplyr::group_by() %>% summarize()`\n",
"\n",
"Groepsaggregatie in R kan eenvoudig worden berekend met\n",
"\n",
"`dplyr::group_by() %>% summarize()`\n",
"\n",
"- `dplyr::group_by()` verandert de analyseeenheid van de volledige dataset naar individuele groepen, zoals per maand.\n",
"\n",
"- `dplyr::summarize()` maakt een nieuw data frame met één kolom voor elke groeperingsvariabele en één kolom voor elke samenvattende statistiek die je hebt gespecificeerd.\n",
"\n",
"Bijvoorbeeld, we kunnen `dplyr::group_by() %>% summarize()` gebruiken om de pompoenen te groeperen op basis van de **Maand**-kolommen en vervolgens de **gemiddelde prijs** voor elke maand te berekenen.\n"
],
"metadata": {
"id": "jMakvJZIcVkh"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Find the average price of pumpkins per month\r\n",
"new_pumpkins %>%\r\n",
" group_by(Month) %>% \r\n",
" summarise(mean_price = mean(Price))"
],
"outputs": [],
"metadata": {
"id": "6kVSUa2Bcilf"
}
},
{
"cell_type": "markdown",
"source": [
"Bondig!✨\n",
"\n",
"Categorische kenmerken zoals maanden worden beter weergegeven met een staafdiagram 📊. De lagen die verantwoordelijk zijn voor staafdiagrammen zijn `geom_bar()` en `geom_col()`. Raadpleeg `?geom_bar` voor meer informatie.\n",
"\n",
"Laten we er een maken!\n"
],
"metadata": {
"id": "Kds48GUBcj3W"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Find the average price of pumpkins per month then plot a bar chart\r\n",
"new_pumpkins %>%\r\n",
" group_by(Month) %>% \r\n",
" summarise(mean_price = mean(Price)) %>% \r\n",
" ggplot(aes(x = Month, y = mean_price)) +\r\n",
" geom_col(fill = \"midnightblue\", alpha = 0.7) +\r\n",
" ylab(\"Pumpkin Price\")"
],
"outputs": [],
"metadata": {
"id": "VNbU1S3BcrxO"
}
},
{
"cell_type": "markdown",
"source": [
"🤩🤩Dit is een nuttigere datavisualisatie! Het lijkt erop dat de hoogste prijs voor pompoenen in september en oktober voorkomt. Komt dat overeen met jouw verwachting? Waarom wel of niet?\n",
"\n",
"Gefeliciteerd met het afronden van de tweede les 👏! Je hebt je gegevens voorbereid voor het bouwen van een model en vervolgens meer inzichten ontdekt met behulp van visualisaties!\n"
],
"metadata": {
"id": "zDm0VOzzcuzR"
}
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Disclaimer**: \nDit document is vertaald met behulp van de AI-vertalingsservice [Co-op Translator](https://github.com/Azure/co-op-translator). Hoewel we streven naar nauwkeurigheid, willen we u erop wijzen dat geautomatiseerde vertalingen fouten of onnauwkeurigheden kunnen bevatten. Het originele document in de oorspronkelijke taal moet worden beschouwd als de gezaghebbende bron. Voor kritieke informatie wordt professionele menselijke vertaling aanbevolen. Wij zijn niet aansprakelijk voor misverstanden of verkeerde interpretaties die voortvloeien uit het gebruik van deze vertaling.\n"
]
}
]
}