You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
727 lines
27 KiB
727 lines
27 KiB
{
|
|
"nbformat": 4,
|
|
"nbformat_minor": 2,
|
|
"metadata": {
|
|
"colab": {
|
|
"name": "lesson_10-R.ipynb",
|
|
"provenance": [],
|
|
"collapsed_sections": []
|
|
},
|
|
"kernelspec": {
|
|
"name": "ir",
|
|
"display_name": "R"
|
|
},
|
|
"language_info": {
|
|
"name": "R"
|
|
},
|
|
"coopTranslator": {
|
|
"original_hash": "2621e24705e8100893c9bf84e0fc8aef",
|
|
"translation_date": "2025-09-04T08:51:53+00:00",
|
|
"source_file": "4-Classification/1-Introduction/solution/R/lesson_10-R.ipynb",
|
|
"language_code": "da"
|
|
}
|
|
},
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"# Byg en klassifikationsmodel: Lækre asiatiske og indiske retter\n"
|
|
],
|
|
"metadata": {
|
|
"id": "ItETB4tSFprR"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"## Introduktion til klassifikation: Rens, forbered og visualisér dine data\n",
|
|
"\n",
|
|
"I disse fire lektioner vil du udforske et grundlæggende fokus inden for klassisk maskinlæring - *klassifikation*. Vi vil gennemgå brugen af forskellige klassifikationsalgoritmer med et datasæt om alle de fantastiske køkkener fra Asien og Indien. Håber du er sulten!\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/pinch.png\"\n",
|
|
" width=\"600\"/>\n",
|
|
" <figcaption>Fejr pan-asiatiske køkkener i disse lektioner! Billede af Jen Looper</figcaption>\n",
|
|
"\n",
|
|
"\n",
|
|
"<!---->\n",
|
|
"\n",
|
|
"Klassifikation er en form for [supervised learning](https://wikipedia.org/wiki/Supervised_learning), der har meget til fælles med regressionsteknikker. I klassifikation træner du en model til at forudsige, hvilken `kategori` et element tilhører. Hvis maskinlæring handler om at forudsige værdier eller navne på ting ved hjælp af datasæt, falder klassifikation generelt i to grupper: *binær klassifikation* og *multiklassifikation*.\n",
|
|
"\n",
|
|
"Husk:\n",
|
|
"\n",
|
|
"- **Lineær regression** hjalp dig med at forudsige forhold mellem variabler og lave præcise forudsigelser om, hvor et nyt datapunkt ville falde i forhold til den linje. For eksempel kunne du forudsige en numerisk værdi som *hvad prisen på et græskar ville være i september vs. december*.\n",
|
|
"\n",
|
|
"- **Logistisk regression** hjalp dig med at opdage \"binære kategorier\": ved denne pris, *er dette græskar orange eller ikke-orange*?\n",
|
|
"\n",
|
|
"Klassifikation bruger forskellige algoritmer til at bestemme andre måder at fastslå en datapunkts label eller klasse. Lad os arbejde med dette køkkendatasæt for at se, om vi ved at observere en gruppe ingredienser kan bestemme dets oprindelseskøkken.\n",
|
|
"\n",
|
|
"### [**Quiz før lektionen**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/19/)\n",
|
|
"\n",
|
|
"### **Introduktion**\n",
|
|
"\n",
|
|
"Klassifikation er en af de grundlæggende aktiviteter for maskinlæringsforskere og dataspecialister. Fra simpel klassifikation af en binær værdi (\"er denne e-mail spam eller ej?\") til kompleks billedklassifikation og segmentering ved hjælp af computer vision, er det altid nyttigt at kunne sortere data i klasser og stille spørgsmål til det.\n",
|
|
"\n",
|
|
"For at udtrykke processen på en mere videnskabelig måde skaber din klassifikationsmetode en prædiktiv model, der gør det muligt for dig at kortlægge forholdet mellem inputvariabler og outputvariabler.\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/binary-multiclass.png\"\n",
|
|
" width=\"600\"/>\n",
|
|
" <figcaption>Binære vs. multiklasseproblemer, som klassifikationsalgoritmer skal håndtere. Infografik af Jen Looper</figcaption>\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Før vi starter processen med at rense vores data, visualisere dem og forberede dem til vores ML-opgaver, lad os lære lidt om de forskellige måder, hvorpå maskinlæring kan bruges til at klassificere data.\n",
|
|
"\n",
|
|
"Afledt fra [statistik](https://wikipedia.org/wiki/Statistical_classification) bruger klassifikation med klassisk maskinlæring funktioner som `smoker`, `weight` og `age` til at bestemme *sandsynligheden for at udvikle X sygdom*. Som en supervised learning-teknik, der ligner de regressionøvelser, du tidligere har udført, er dine data mærkede, og ML-algoritmerne bruger disse mærker til at klassificere og forudsige klasser (eller 'funktioner') i et datasæt og tildele dem til en gruppe eller et resultat.\n",
|
|
"\n",
|
|
"✅ Tag et øjeblik til at forestille dig et datasæt om køkkener. Hvad ville en multiklassemodel kunne svare på? Hvad ville en binær model kunne svare på? Hvad hvis du ville bestemme, om et givent køkken sandsynligvis ville bruge bukkehorn? Hvad hvis du ville se, om du, givet en pose med stjerneanis, artiskokker, blomkål og peberrod, kunne lave en typisk indisk ret?\n",
|
|
"\n",
|
|
"### **Hej 'classifier'**\n",
|
|
"\n",
|
|
"Det spørgsmål, vi ønsker at stille til dette køkkendatasæt, er faktisk et **multiklasse-spørgsmål**, da vi har flere potentielle nationale køkkener at arbejde med. Givet en gruppe ingredienser, hvilken af disse mange klasser passer dataene til?\n",
|
|
"\n",
|
|
"Tidymodels tilbyder flere forskellige algoritmer til at klassificere data, afhængigt af hvilken type problem du ønsker at løse. I de næste to lektioner vil du lære om flere af disse algoritmer.\n",
|
|
"\n",
|
|
"#### **Forudsætninger**\n",
|
|
"\n",
|
|
"Til denne lektion skal vi bruge følgende pakker til at rense, forberede og visualisere vores data:\n",
|
|
"\n",
|
|
"- `tidyverse`: [tidyverse](https://www.tidyverse.org/) er en [samling af R-pakker](https://www.tidyverse.org/packages), der gør datavidenskab hurtigere, lettere og sjovere!\n",
|
|
"\n",
|
|
"- `tidymodels`: [tidymodels](https://www.tidymodels.org/) er en [samling af pakker](https://www.tidymodels.org/packages/) til modellering og maskinlæring.\n",
|
|
"\n",
|
|
"- `DataExplorer`: [DataExplorer-pakken](https://cran.r-project.org/web/packages/DataExplorer/vignettes/dataexplorer-intro.html) er designet til at forenkle og automatisere EDA-processen og rapportgenerering.\n",
|
|
"\n",
|
|
"- `themis`: [themis-pakken](https://themis.tidymodels.org/) tilbyder ekstra opskridt til at håndtere ubalancerede data.\n",
|
|
"\n",
|
|
"Du kan installere dem som:\n",
|
|
"\n",
|
|
"`install.packages(c(\"tidyverse\", \"tidymodels\", \"DataExplorer\", \"here\"))`\n",
|
|
"\n",
|
|
"Alternativt tjekker scriptet nedenfor, om du har de nødvendige pakker til at gennemføre dette modul, og installerer dem for dig, hvis de mangler.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "ri5bQxZ-Fz_0"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"suppressWarnings(if (!require(\"pacman\"))install.packages(\"pacman\"))\r\n",
|
|
"\r\n",
|
|
"pacman::p_load(tidyverse, tidymodels, DataExplorer, themis, here)"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "KIPxa4elGAPI"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Vi vil senere indlæse disse fantastiske pakker og gøre dem tilgængelige i vores nuværende R-session. (Dette er kun for illustration, `pacman::p_load()` har allerede gjort det for dig)\n"
|
|
],
|
|
"metadata": {
|
|
"id": "YkKAxOJvGD4C"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"## Øvelse - Rens og balancér dine data\n",
|
|
"\n",
|
|
"Den første opgave, inden du går i gang med dette projekt, er at rense og **balancere** dine data for at opnå bedre resultater.\n",
|
|
"\n",
|
|
"Lad os tage et kig på dataene! 🕵️\n"
|
|
],
|
|
"metadata": {
|
|
"id": "PFkQDlk0GN5O"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Import data\r\n",
|
|
"df <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/4-Classification/data/cuisines.csv\")\r\n",
|
|
"\r\n",
|
|
"# View the first 5 rows\r\n",
|
|
"df %>% \r\n",
|
|
" slice_head(n = 5)\r\n"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "Qccw7okxGT0S"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Interessant! Ud fra udseendet er den første kolonne en slags `id`-kolonne. Lad os få lidt mere information om dataene.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "XrWnlgSrGVmR"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Basic information about the data\r\n",
|
|
"df %>%\r\n",
|
|
" introduce()\r\n",
|
|
"\r\n",
|
|
"# Visualize basic information above\r\n",
|
|
"df %>% \r\n",
|
|
" plot_intro(ggtheme = theme_light())"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "4UcGmxRxGieA"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Fra outputtet kan vi straks se, at vi har `2448` rækker og `385` kolonner og `0` manglende værdier. Vi har også 1 diskret kolonne, *cuisine*.\n",
|
|
"\n",
|
|
"## Øvelse - læring om køkkener\n",
|
|
"\n",
|
|
"Nu begynder arbejdet at blive mere interessant. Lad os undersøge fordelingen af data pr. køkken.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "AaPubl__GmH5"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Count observations per cuisine\r\n",
|
|
"df %>% \r\n",
|
|
" count(cuisine) %>% \r\n",
|
|
" arrange(n)\r\n",
|
|
"\r\n",
|
|
"# Plot the distribution\r\n",
|
|
"theme_set(theme_light())\r\n",
|
|
"df %>% \r\n",
|
|
" count(cuisine) %>% \r\n",
|
|
" ggplot(mapping = aes(x = n, y = reorder(cuisine, -n))) +\r\n",
|
|
" geom_col(fill = \"midnightblue\", alpha = 0.7) +\r\n",
|
|
" ylab(\"cuisine\")"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "FRsBVy5eGrrv"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Der findes et begrænset antal køkkener, men fordelingen af data er ujævn. Det kan du rette op på! Før du gør det, så udforsk lidt mere.\n",
|
|
"\n",
|
|
"Lad os derefter tildele hvert køkken til sin egen tibble og finde ud af, hvor meget data der er tilgængeligt (rækker, kolonner) pr. køkken.\n",
|
|
"\n",
|
|
"> En [tibble](https://tibble.tidyverse.org/) er en moderne dataramme.\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/dplyr_filter.jpg\"\n",
|
|
" width=\"600\"/>\n",
|
|
" <figcaption>Kunstværk af @allison_horst</figcaption>\n"
|
|
],
|
|
"metadata": {
|
|
"id": "vVvyDb1kG2in"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Create individual tibble for the cuisines\r\n",
|
|
"thai_df <- df %>% \r\n",
|
|
" filter(cuisine == \"thai\")\r\n",
|
|
"japanese_df <- df %>% \r\n",
|
|
" filter(cuisine == \"japanese\")\r\n",
|
|
"chinese_df <- df %>% \r\n",
|
|
" filter(cuisine == \"chinese\")\r\n",
|
|
"indian_df <- df %>% \r\n",
|
|
" filter(cuisine == \"indian\")\r\n",
|
|
"korean_df <- df %>% \r\n",
|
|
" filter(cuisine == \"korean\")\r\n",
|
|
"\r\n",
|
|
"\r\n",
|
|
"# Find out how much data is available per cuisine\r\n",
|
|
"cat(\" thai df:\", dim(thai_df), \"\\n\",\r\n",
|
|
" \"japanese df:\", dim(japanese_df), \"\\n\",\r\n",
|
|
" \"chinese_df:\", dim(chinese_df), \"\\n\",\r\n",
|
|
" \"indian_df:\", dim(indian_df), \"\\n\",\r\n",
|
|
" \"korean_df:\", dim(korean_df))"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "0TvXUxD3G8Bk"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"## **Øvelse - Opdagelse af topingredienser efter køkken ved hjælp af dplyr**\n",
|
|
"\n",
|
|
"Nu kan du dykke dybere ned i dataene og finde ud af, hvad der er de typiske ingredienser for hvert køkken. Du bør rense gentagne data, der skaber forvirring mellem køkkener, så lad os lære om dette problem.\n",
|
|
"\n",
|
|
"Opret en funktion `create_ingredient()` i R, der returnerer en ingrediens-dataramme. Denne funktion starter med at fjerne en ubrugelig kolonne og sortere ingredienser efter deres antal.\n",
|
|
"\n",
|
|
"Den grundlæggende struktur for en funktion i R er:\n",
|
|
"\n",
|
|
"`myFunction <- function(arglist){`\n",
|
|
"\n",
|
|
"**`...`**\n",
|
|
"\n",
|
|
"**`return`**`(value)`\n",
|
|
"\n",
|
|
"`}`\n",
|
|
"\n",
|
|
"En overskuelig introduktion til R-funktioner kan findes [her](https://skirmer.github.io/presentations/functions_with_r.html#1).\n",
|
|
"\n",
|
|
"Lad os komme i gang! Vi vil gøre brug af [dplyr-verber](https://dplyr.tidyverse.org/), som vi har lært i vores tidligere lektioner. Som en opsummering:\n",
|
|
"\n",
|
|
"- `dplyr::select()`: hjælper dig med at vælge, hvilke **kolonner** du vil beholde eller udelade.\n",
|
|
"\n",
|
|
"- `dplyr::pivot_longer()`: hjælper dig med at \"forlænge\" data, hvilket øger antallet af rækker og reducerer antallet af kolonner.\n",
|
|
"\n",
|
|
"- `dplyr::group_by()` og `dplyr::summarise()`: hjælper dig med at finde opsummeringsstatistikker for forskellige grupper og sætte dem i en pæn tabel.\n",
|
|
"\n",
|
|
"- `dplyr::filter()`: skaber et datasæt, der kun indeholder rækker, der opfylder dine betingelser.\n",
|
|
"\n",
|
|
"- `dplyr::mutate()`: hjælper dig med at oprette eller ændre kolonner.\n",
|
|
"\n",
|
|
"Tjek denne [*kunst*-fyldte learnr-tutorial](https://allisonhorst.shinyapps.io/dplyr-learnr/#section-welcome) af Allison Horst, der introducerer nogle nyttige datahåndteringsfunktioner i dplyr *(en del af Tidyverse)*.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "K3RF5bSCHC76"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Creates a functions that returns the top ingredients by class\r\n",
|
|
"\r\n",
|
|
"create_ingredient <- function(df){\r\n",
|
|
" \r\n",
|
|
" # Drop the id column which is the first colum\r\n",
|
|
" ingredient_df = df %>% select(-1) %>% \r\n",
|
|
" # Transpose data to a long format\r\n",
|
|
" pivot_longer(!cuisine, names_to = \"ingredients\", values_to = \"count\") %>% \r\n",
|
|
" # Find the top most ingredients for a particular cuisine\r\n",
|
|
" group_by(ingredients) %>% \r\n",
|
|
" summarise(n_instances = sum(count)) %>% \r\n",
|
|
" filter(n_instances != 0) %>% \r\n",
|
|
" # Arrange by descending order\r\n",
|
|
" arrange(desc(n_instances)) %>% \r\n",
|
|
" mutate(ingredients = factor(ingredients) %>% fct_inorder())\r\n",
|
|
" \r\n",
|
|
" \r\n",
|
|
" return(ingredient_df)\r\n",
|
|
"} # End of function"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "uB_0JR82HTPa"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Nu kan vi bruge funktionen til at få en idé om de ti mest populære ingredienser efter køkken. Lad os prøve den med `thai_df`.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "h9794WF8HWmc"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Call create_ingredient and display popular ingredients\r\n",
|
|
"thai_ingredient_df <- create_ingredient(df = thai_df)\r\n",
|
|
"\r\n",
|
|
"thai_ingredient_df %>% \r\n",
|
|
" slice_head(n = 10)"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "agQ-1HrcHaEA"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"I det foregående afsnit brugte vi `geom_col()`, lad os se, hvordan du også kan bruge `geom_bar` til at lave søjlediagrammer. Brug `?geom_bar` for yderligere læsning.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "kHu9ffGjHdcX"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Make a bar chart for popular thai cuisines\r\n",
|
|
"thai_ingredient_df %>% \r\n",
|
|
" slice_head(n = 10) %>% \r\n",
|
|
" ggplot(aes(x = n_instances, y = ingredients)) +\r\n",
|
|
" geom_bar(stat = \"identity\", width = 0.5, fill = \"steelblue\") +\r\n",
|
|
" xlab(\"\") + ylab(\"\")"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "fb3Bx_3DHj6e"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Lad os gøre det samme for de japanske data\n"
|
|
],
|
|
"metadata": {
|
|
"id": "RHP_xgdkHnvM"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Get popular ingredients for Japanese cuisines and make bar chart\r\n",
|
|
"create_ingredient(df = japanese_df) %>% \r\n",
|
|
" slice_head(n = 10) %>%\r\n",
|
|
" ggplot(aes(x = n_instances, y = ingredients)) +\r\n",
|
|
" geom_bar(stat = \"identity\", width = 0.5, fill = \"darkorange\", alpha = 0.8) +\r\n",
|
|
" xlab(\"\") + ylab(\"\")\r\n"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "019v8F0XHrRU"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Hvad med de kinesiske køkkener?\n"
|
|
],
|
|
"metadata": {
|
|
"id": "iIGM7vO8Hu3v"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Get popular ingredients for Chinese cuisines and make bar chart\r\n",
|
|
"create_ingredient(df = chinese_df) %>% \r\n",
|
|
" slice_head(n = 10) %>%\r\n",
|
|
" ggplot(aes(x = n_instances, y = ingredients)) +\r\n",
|
|
" geom_bar(stat = \"identity\", width = 0.5, fill = \"cyan4\", alpha = 0.8) +\r\n",
|
|
" xlab(\"\") + ylab(\"\")"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "lHd9_gd2HyzU"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [],
|
|
"metadata": {
|
|
"id": "ir8qyQbNH1c7"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Get popular ingredients for Indian cuisines and make bar chart\r\n",
|
|
"create_ingredient(df = indian_df) %>% \r\n",
|
|
" slice_head(n = 10) %>%\r\n",
|
|
" ggplot(aes(x = n_instances, y = ingredients)) +\r\n",
|
|
" geom_bar(stat = \"identity\", width = 0.5, fill = \"#041E42FF\", alpha = 0.8) +\r\n",
|
|
" xlab(\"\") + ylab(\"\")"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "ApukQtKjH5FO"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Til sidst, plot de koreanske ingredienser.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "qv30cwY1H-FM"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Get popular ingredients for Korean cuisines and make bar chart\r\n",
|
|
"create_ingredient(df = korean_df) %>% \r\n",
|
|
" slice_head(n = 10) %>%\r\n",
|
|
" ggplot(aes(x = n_instances, y = ingredients)) +\r\n",
|
|
" geom_bar(stat = \"identity\", width = 0.5, fill = \"#852419FF\", alpha = 0.8) +\r\n",
|
|
" xlab(\"\") + ylab(\"\")"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "lumgk9cHIBie"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Fra data-visualiseringerne kan vi nu udelade de mest almindelige ingredienser, der skaber forvirring mellem forskellige køkkener, ved hjælp af `dplyr::select()`.\n",
|
|
"\n",
|
|
"Alle elsker ris, hvidløg og ingefær!\n"
|
|
],
|
|
"metadata": {
|
|
"id": "iO4veMXuIEta"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Drop id column, rice, garlic and ginger from our original data set\r\n",
|
|
"df_select <- df %>% \r\n",
|
|
" select(-c(1, rice, garlic, ginger))\r\n",
|
|
"\r\n",
|
|
"# Display new data set\r\n",
|
|
"df_select %>% \r\n",
|
|
" slice_head(n = 5)"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "iHJPiG6rIUcK"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"## Forbehandling af data med opskrifter 👩🍳👨🍳 - Håndtering af ubalancerede data ⚖️\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/recipes.png\"\n",
|
|
" width=\"600\"/>\n",
|
|
" <figcaption>Illustration af @allison_horst</figcaption>\n",
|
|
"\n",
|
|
"Da denne lektion handler om køkkener, er vi nødt til at sætte `recipes` i kontekst.\n",
|
|
"\n",
|
|
"Tidymodels tilbyder endnu en smart pakke: `recipes` - en pakke til forbehandling af data.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "kkFd-JxdIaL6"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Lad os tage et kig på fordelingen af vores køkkener igen.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "6l2ubtTPJAhY"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Distribution of cuisines\r\n",
|
|
"old_label_count <- df_select %>% \r\n",
|
|
" count(cuisine) %>% \r\n",
|
|
" arrange(desc(n))\r\n",
|
|
"\r\n",
|
|
"old_label_count"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "1e-E9cb7JDVi"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Som du kan se, er der en ret ulige fordeling i antallet af køkkener. Koreanske køkkener er næsten 3 gange så mange som thailandske køkkener. Ubalance i data har ofte en negativ effekt på modellens ydeevne. Tænk på en binær klassifikation. Hvis størstedelen af dine data tilhører én klasse, vil en ML-model oftere forudsige denne klasse, simpelthen fordi der er mere data til rådighed for den. At balancere data tager skæve data og hjælper med at fjerne denne ubalance. Mange modeller fungerer bedst, når antallet af observationer er lige, og har derfor en tendens til at kæmpe med ubalancerede data.\n",
|
|
"\n",
|
|
"Der er primært to måder at håndtere ubalancerede datasæt på:\n",
|
|
"\n",
|
|
"- tilføje observationer til minoritetsklassen: `Over-sampling`, f.eks. ved brug af en SMOTE-algoritme\n",
|
|
"\n",
|
|
"- fjerne observationer fra majoritetsklassen: `Under-sampling`\n",
|
|
"\n",
|
|
"Lad os nu demonstrere, hvordan man håndterer ubalancerede datasæt ved hjælp af en `recipe`. En recipe kan betragtes som en køreplan, der beskriver, hvilke trin der skal anvendes på et datasæt for at gøre det klar til dataanalyse.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "soAw6826JKx9"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Load themis package for dealing with imbalanced data\r\n",
|
|
"library(themis)\r\n",
|
|
"\r\n",
|
|
"# Create a recipe for preprocessing data\r\n",
|
|
"cuisines_recipe <- recipe(cuisine ~ ., data = df_select) %>% \r\n",
|
|
" step_smote(cuisine)\r\n",
|
|
"\r\n",
|
|
"cuisines_recipe"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "HS41brUIJVJy"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Lad os gennemgå vores forbehandlingsskridt.\n",
|
|
"\n",
|
|
"- Kaldet til `recipe()` med en formel fortæller opskriften *rollerne* for variablerne ved at bruge `df_select`-data som reference. For eksempel er kolonnen `cuisine` blevet tildelt rollen som `outcome`, mens de øvrige kolonner er blevet tildelt rollen som `predictor`.\n",
|
|
"\n",
|
|
"- [`step_smote(cuisine)`](https://themis.tidymodels.org/reference/step_smote.html) opretter en *specifikation* af et opskriftstrin, der syntetisk genererer nye eksempler af minoritetsklassen ved hjælp af nærmeste naboer til disse tilfælde.\n",
|
|
"\n",
|
|
"Hvis vi nu ønskede at se de forbehandlede data, skulle vi [**`prep()`**](https://recipes.tidymodels.org/reference/prep.html) og [**`bake()`**](https://recipes.tidymodels.org/reference/bake.html) vores opskrift.\n",
|
|
"\n",
|
|
"`prep()`: estimerer de nødvendige parametre fra et træningssæt, som senere kan anvendes på andre datasæt.\n",
|
|
"\n",
|
|
"`bake()`: tager en forberedt opskrift og anvender operationerne på et hvilket som helst datasæt.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "Yb-7t7XcJaC8"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Prep and bake the recipe\r\n",
|
|
"preprocessed_df <- cuisines_recipe %>% \r\n",
|
|
" prep() %>% \r\n",
|
|
" bake(new_data = NULL) %>% \r\n",
|
|
" relocate(cuisine)\r\n",
|
|
"\r\n",
|
|
"# Display data\r\n",
|
|
"preprocessed_df %>% \r\n",
|
|
" slice_head(n = 5)\r\n",
|
|
"\r\n",
|
|
"# Quick summary stats\r\n",
|
|
"preprocessed_df %>% \r\n",
|
|
" introduce()"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "9QhSgdpxJl44"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Lad os nu tjekke fordelingen af vores køkkener og sammenligne dem med de ubalancerede data.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "dmidELh_LdV7"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Distribution of cuisines\r\n",
|
|
"new_label_count <- preprocessed_df %>% \r\n",
|
|
" count(cuisine) %>% \r\n",
|
|
" arrange(desc(n))\r\n",
|
|
"\r\n",
|
|
"list(new_label_count = new_label_count,\r\n",
|
|
" old_label_count = old_label_count)"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "aSh23klBLwDz"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Mums! Dataen er dejlig ren, balanceret og meget lækker 😋!\n",
|
|
"\n",
|
|
"> Normalt bruges en opskrift typisk som en forprocessor til modellering, hvor den definerer, hvilke trin der skal anvendes på et datasæt for at gøre det klar til modellering. I det tilfælde bruges en `workflow()` typisk (som vi allerede har set i vores tidligere lektioner) i stedet for manuelt at estimere en opskrift.\n",
|
|
">\n",
|
|
"> Derfor behøver du normalt ikke at **`prep()`** og **`bake()`** opskrifter, når du bruger tidymodels, men de er nyttige funktioner at have i dit værktøjssæt for at bekræfte, at opskrifterne gør, hvad du forventer, som i vores tilfælde.\n",
|
|
">\n",
|
|
"> Når du **`bake()`** en forberedt opskrift med **`new_data = NULL`**, får du de data, du leverede, da du definerede opskriften tilbage, men med de forbehandlingstrin, der er blevet anvendt.\n",
|
|
"\n",
|
|
"Lad os nu gemme en kopi af disse data til brug i fremtidige lektioner:\n"
|
|
],
|
|
"metadata": {
|
|
"id": "HEu80HZ8L7ae"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Save preprocessed data\r\n",
|
|
"write_csv(preprocessed_df, \"../../../data/cleaned_cuisines_R.csv\")"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "cBmCbIgrMOI6"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Denne friske CSV-fil kan nu findes i rodmappen for data.\n",
|
|
"\n",
|
|
"**🚀Udfordring**\n",
|
|
"\n",
|
|
"Dette pensum indeholder flere interessante datasæt. Gennemgå `data`-mapperne og se, om nogle af dem indeholder datasæt, der kunne være passende til binær eller multi-klasse klassifikation? Hvilke spørgsmål ville du stille til dette datasæt?\n",
|
|
"\n",
|
|
"## [**Quiz efter forelæsning**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/20/)\n",
|
|
"\n",
|
|
"## **Gennemgang & Selvstudie**\n",
|
|
"\n",
|
|
"- Tjek [pakken themis](https://github.com/tidymodels/themis). Hvilke andre teknikker kunne vi bruge til at håndtere ubalancerede data?\n",
|
|
"\n",
|
|
"- Tidy models [referencehjemmeside](https://www.tidymodels.org/start/).\n",
|
|
"\n",
|
|
"- H. Wickham og G. Grolemund, [*R for Data Science: Visualize, Model, Transform, Tidy, and Import Data*](https://r4ds.had.co.nz/).\n",
|
|
"\n",
|
|
"#### TAK TIL:\n",
|
|
"\n",
|
|
"[`Allison Horst`](https://twitter.com/allison_horst/) for at skabe de fantastiske illustrationer, der gør R mere indbydende og engagerende. Find flere illustrationer i hendes [galleri](https://www.google.com/url?q=https://github.com/allisonhorst/stats-illustrations&sa=D&source=editors&ust=1626380772530000&usg=AOvVaw3zcfyCizFQZpkSLzxiiQEM).\n",
|
|
"\n",
|
|
"[Cassie Breviu](https://www.twitter.com/cassieview) og [Jen Looper](https://www.twitter.com/jenlooper) for at skabe den originale Python-version af dette modul ♥️\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/r_learners_sm.jpeg\"\n",
|
|
" width=\"600\"/>\n",
|
|
" <figcaption>Kunstværk af @allison_horst</figcaption>\n"
|
|
],
|
|
"metadata": {
|
|
"id": "WQs5621pMGwf"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"\n---\n\n**Ansvarsfraskrivelse**: \nDette dokument er blevet oversat ved hjælp af AI-oversættelsestjenesten [Co-op Translator](https://github.com/Azure/co-op-translator). Selvom vi bestræber os på nøjagtighed, skal du være opmærksom på, at automatiserede oversættelser kan indeholde fejl eller unøjagtigheder. Det originale dokument på dets oprindelige sprog bør betragtes som den autoritative kilde. For kritisk information anbefales professionel menneskelig oversættelse. Vi påtager os intet ansvar for misforståelser eller fejltolkninger, der måtte opstå som følge af brugen af denne oversættelse.\n"
|
|
]
|
|
}
|
|
]
|
|
} |