{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Byg en logistisk regressionsmodel - Lektion 4\n", "\n", "![Infografik om logistisk vs. lineær regression](../../../../../../2-Regression/4-Logistic/images/linear-vs-logistic.png)\n", "\n", "#### **[Quiz før lektionen](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/15/)**\n", "\n", "#### Introduktion\n", "\n", "I denne sidste lektion om regression, en af de grundlæggende *klassiske* ML-teknikker, vil vi tage et kig på logistisk regression. Du kan bruge denne teknik til at finde mønstre og forudsige binære kategorier. Er dette slik chokolade eller ej? Er denne sygdom smitsom eller ej? Vil denne kunde vælge dette produkt eller ej?\n", "\n", "I denne lektion vil du lære:\n", "\n", "- Teknikker til logistisk regression\n", "\n", "✅ Uddyb din forståelse af at arbejde med denne type regression i dette [Learn-modul](https://learn.microsoft.com/training/modules/introduction-classification-models/?WT.mc_id=academic-77952-leestott)\n", "\n", "## Forudsætning\n", "\n", "Efter at have arbejdet med græskardataene, er vi nu tilstrækkeligt bekendte med dem til at indse, at der er én binær kategori, vi kan arbejde med: `Color`.\n", "\n", "Lad os bygge en logistisk regressionsmodel for at forudsige, givet nogle variabler, *hvilken farve et givet græskar sandsynligvis har* (orange 🎃 eller hvid 👻).\n", "\n", "> Hvorfor taler vi om binær klassifikation i en lektion, der handler om regression? Kun for sproglig bekvemmelighed, da logistisk regression [faktisk er en klassifikationsmetode](https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression), omend en lineær-baseret en. Lær om andre måder at klassificere data på i den næste lektion.\n", "\n", "Til denne lektion skal vi bruge følgende pakker:\n", "\n", "- `tidyverse`: [tidyverse](https://www.tidyverse.org/) er en [samling af R-pakker](https://www.tidyverse.org/packages), der er designet til at gøre datavidenskab hurtigere, nemmere 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", "- `janitor`: [janitor-pakken](https://github.com/sfirke/janitor) tilbyder simple værktøjer til at undersøge og rense beskidte data.\n", "\n", "- `ggbeeswarm`: [ggbeeswarm-pakken](https://github.com/eclarke/ggbeeswarm) giver metoder til at lave beeswarm-stil plots ved hjælp af ggplot2.\n", "\n", "Du kan installere dem som:\n", "\n", "`install.packages(c(\"tidyverse\", \"tidymodels\", \"janitor\", \"ggbeeswarm\"))`\n", "\n", "Alternativt kan scriptet nedenfor kontrollere, om du har de nødvendige pakker til at fuldføre dette modul, og installere dem for dig, hvis de mangler.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "suppressWarnings(if (!require(\"pacman\"))install.packages(\"pacman\"))\n", "\n", "pacman::p_load(tidyverse, tidymodels, janitor, ggbeeswarm)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **Definer spørgsmålet**\n", "\n", "For vores formål vil vi udtrykke dette som en binær: 'Hvid' eller 'Ikke Hvid'. Der er også en 'stribet' kategori i vores datasæt, men der er få eksempler på den, så vi vil ikke bruge den. Den forsvinder alligevel, når vi fjerner null-værdier fra datasættet.\n", "\n", "> 🎃 Sjovt faktum, vi kalder nogle gange hvide græskar for 'spøgelsesgræskar'. De er ikke særlig nemme at skære i, så de er ikke lige så populære som de orange, men de ser seje ud! Så vi kunne også omformulere vores spørgsmål som: 'Spøgelse' eller 'Ikke Spøgelse'. 👻\n", "\n", "## **Om logistisk regression**\n", "\n", "Logistisk regression adskiller sig fra lineær regression, som du tidligere har lært om, på nogle vigtige måder.\n", "\n", "#### **Binær klassifikation**\n", "\n", "Logistisk regression tilbyder ikke de samme funktioner som lineær regression. Førstnævnte giver en forudsigelse om en `binær kategori` (\"orange eller ikke orange\"), mens sidstnævnte er i stand til at forudsige `kontinuerlige værdier`, for eksempel givet oprindelsen af et græskar og tidspunktet for høsten, *hvor meget prisen vil stige*.\n", "\n", "![Infografik af Dasani Madipalli](../../../../../../2-Regression/4-Logistic/images/pumpkin-classifier.png)\n", "\n", "### Andre klassifikationer\n", "\n", "Der findes andre typer af logistisk regression, herunder multinomial og ordinal:\n", "\n", "- **Multinomial**, som involverer mere end én kategori - \"Orange, Hvid og Stribet\".\n", "\n", "- **Ordinal**, som involverer ordnede kategorier, nyttigt hvis vi ønskede at ordne vores resultater logisk, som vores græskar, der er ordnet efter et begrænset antal størrelser (mini,sm,med,lg,xl,xxl).\n", "\n", "![Multinomial vs ordinal regression](../../../../../../2-Regression/4-Logistic/images/multinomial-vs-ordinal.png)\n", "\n", "#### **Variabler BEHØVER IKKE at korrelere**\n", "\n", "Kan du huske, hvordan lineær regression fungerede bedre med mere korrelerede variabler? Logistisk regression er det modsatte - variablerne behøver ikke at være i overensstemmelse. Det fungerer for disse data, som har forholdsvis svage korrelationer.\n", "\n", "#### **Du har brug for en masse rene data**\n", "\n", "Logistisk regression vil give mere præcise resultater, hvis du bruger flere data; vores lille datasæt er ikke optimalt til denne opgave, så husk det.\n", "\n", "✅ Tænk over, hvilke typer data der egner sig godt til logistisk regression\n", "\n", "## Øvelse - ryd op i dataene\n", "\n", "Først skal du rydde lidt op i dataene, fjerne null-værdier og kun vælge nogle af kolonnerne:\n", "\n", "1. Tilføj følgende kode:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Load the core tidyverse packages\n", "library(tidyverse)\n", "\n", "# Import the data and clean column names\n", "pumpkins <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/2-Regression/data/US-pumpkins.csv\") %>% \n", " clean_names()\n", "\n", "# Select desired columns\n", "pumpkins_select <- pumpkins %>% \n", " select(c(city_name, package, variety, origin, item_size, color)) \n", "\n", "# Drop rows containing missing values and encode color as factor (category)\n", "pumpkins_select <- pumpkins_select %>% \n", " drop_na() %>% \n", " mutate(color = factor(color))\n", "\n", "# View the first few rows\n", "pumpkins_select %>% \n", " slice_head(n = 5)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Du kan altid tage et kig på din nye dataframe ved at bruge [*glimpse()*](https://pillar.r-lib.org/reference/glimpse.html)-funktionen som vist nedenfor:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "pumpkins_select %>% \n", " glimpse()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lad os bekræfte, at vi faktisk vil arbejde med et binært klassifikationsproblem:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Subset distinct observations in outcome column\n", "pumpkins_select %>% \n", " distinct(color)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Visualisering - kategorisk plot\n", "Du har nu igen indlæst græskardataene og renset dem, så du har et datasæt med nogle få variabler, herunder Farve. Lad os visualisere dataframen i notebooken ved hjælp af ggplot-biblioteket.\n", "\n", "Ggplot-biblioteket tilbyder nogle smarte måder at visualisere dine data på. For eksempel kan du sammenligne fordelingen af data for hver Sort og Farve i et kategorisk plot.\n", "\n", "1. Opret et sådant plot ved at bruge geombar-funktionen, anvend vores græskardata, og angiv en farvemapping for hver græskarkategori (orange eller hvid):\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "# Specify colors for each value of the hue variable\n", "palette <- c(ORANGE = \"orange\", WHITE = \"wheat\")\n", "\n", "# Create the bar plot\n", "ggplot(pumpkins_select, aes(y = variety, fill = color)) +\n", " geom_bar(position = \"dodge\") +\n", " scale_fill_manual(values = palette) +\n", " labs(y = \"Variety\", fill = \"Color\") +\n", " theme_minimal()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ved at observere dataene kan du se, hvordan Farve-dataene relaterer sig til Sort.\n", "\n", "✅ Givet dette kategoriske plot, hvilke interessante undersøgelser kan du forestille dig?\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Databehandling: funktionkodning\n", "\n", "Vores græskar-datasæt indeholder strengværdier for alle dets kolonner. At arbejde med kategoriske data er intuitivt for mennesker, men ikke for maskiner. Maskinlæringsalgoritmer fungerer godt med tal. Derfor er kodning et meget vigtigt trin i databehandlingsfasen, da det gør det muligt for os at omdanne kategoriske data til numeriske data uden at miste nogen information. God kodning fører til opbygning af en god model.\n", "\n", "Der er to hovedtyper af kodere til funktionkodning:\n", "\n", "1. Ordinal koder: Den passer godt til ordinale variabler, som er kategoriske variabler, hvor deres data følger en logisk rækkefølge, som kolonnen `item_size` i vores datasæt. Den skaber en mapping, så hver kategori repræsenteres af et tal, som er rækkefølgen af kategorien i kolonnen.\n", "\n", "2. Kategorisk koder: Den passer godt til nominelle variabler, som er kategoriske variabler, hvor deres data ikke følger en logisk rækkefølge, som alle funktionerne bortset fra `item_size` i vores datasæt. Det er en one-hot kodning, hvilket betyder, at hver kategori repræsenteres af en binær kolonne: den kodede variabel er lig med 1, hvis græskarret tilhører den pågældende sort, og 0 ellers.\n", "\n", "Tidymodels tilbyder endnu en smart pakke: [recipes](https://recipes.tidymodels.org/) - en pakke til databehandling. Vi vil definere en `recipe`, der angiver, at alle forudsigende kolonner skal kodes til et sæt heltal, `prep` den for at estimere de nødvendige mængder og statistikker, der kræves af enhver operation, og til sidst `bake` for at anvende beregningerne på nye data.\n", "\n", "> Normalt bruges recipes 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 dette tilfælde er det **stærkt anbefalet**, at du bruger en `workflow()` i stedet for manuelt at estimere en recipe ved hjælp af prep og bake. Vi vil se alt dette om lidt.\n", ">\n", "> Men lige nu bruger vi recipes + prep + bake til at angive, hvilke trin der skal anvendes på et datasæt for at gøre det klar til dataanalyse og derefter udtrække de forbehandlede data med de anvendte trin.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Preprocess and extract data to allow some data analysis\n", "baked_pumpkins <- recipe(color ~ ., data = pumpkins_select) %>%\n", " # Define ordering for item_size column\n", " step_mutate(item_size = ordered(item_size, levels = c('sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo'))) %>%\n", " # Convert factors to numbers using the order defined above (Ordinal encoding)\n", " step_integer(item_size, zero_based = F) %>%\n", " # Encode all other predictors using one hot encoding\n", " step_dummy(all_nominal(), -all_outcomes(), one_hot = TRUE) %>%\n", " prep(data = pumpkin_select) %>%\n", " bake(new_data = NULL)\n", "\n", "# Display the first few rows of preprocessed data\n", "baked_pumpkins %>% \n", " slice_head(n = 5)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "✅ Hvad er fordelene ved at bruge en ordinal encoder til Item Size-kolonnen?\n", "\n", "### Analysér forholdet mellem variabler\n", "\n", "Nu hvor vi har forbehandlet vores data, kan vi analysere forholdet mellem funktionerne og etiketten for at få en idé om, hvor godt modellen vil kunne forudsige etiketten baseret på funktionerne. Den bedste måde at udføre denne type analyse på er ved at plotte dataene. \n", "Vi vil igen bruge ggplot geom_boxplot_-funktionen til at visualisere forholdet mellem Item Size, Variety og Color i et kategorisk plot. For at plotte dataene bedre vil vi bruge den kodede Item Size-kolonne og den ukodede Variety-kolonne.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Define the color palette\n", "palette <- c(ORANGE = \"orange\", WHITE = \"wheat\")\n", "\n", "# We need the encoded Item Size column to use it as the x-axis values in the plot\n", "pumpkins_select_plot<-pumpkins_select\n", "pumpkins_select_plot$item_size <- baked_pumpkins$item_size\n", "\n", "# Create the grouped box plot\n", "ggplot(pumpkins_select_plot, aes(x = `item_size`, y = color, fill = color)) +\n", " geom_boxplot() +\n", " facet_grid(variety ~ ., scales = \"free_x\") +\n", " scale_fill_manual(values = palette) +\n", " labs(x = \"Item Size\", y = \"\") +\n", " theme_minimal() +\n", " theme(strip.text = element_text(size = 12)) +\n", " theme(axis.text.x = element_text(size = 10)) +\n", " theme(axis.title.x = element_text(size = 12)) +\n", " theme(axis.title.y = element_blank()) +\n", " theme(legend.position = \"bottom\") +\n", " guides(fill = guide_legend(title = \"Color\")) +\n", " theme(panel.spacing = unit(0.5, \"lines\"))+\n", " theme(strip.text.y = element_text(size = 4, hjust = 0)) \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Brug et swarm-plot\n", "\n", "Da Farve er en binær kategori (Hvid eller Ikke-hvid), kræver det 'en [specialiseret tilgang](https://github.com/rstudio/cheatsheets/blob/main/data-visualization.pdf) til visualisering'.\n", "\n", "Prøv et `swarm-plot` for at vise fordelingen af farve i forhold til item_size.\n", "\n", "Vi vil bruge [ggbeeswarm-pakken](https://github.com/eclarke/ggbeeswarm), som tilbyder metoder til at skabe beeswarm-stil plots ved hjælp af ggplot2. Beeswarm-plots er en måde at plotte punkter, der normalt ville overlappe, så de i stedet placeres ved siden af hinanden.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Create beeswarm plots of color and item_size\n", "baked_pumpkins %>% \n", " mutate(color = factor(color)) %>% \n", " ggplot(mapping = aes(x = color, y = item_size, color = color)) +\n", " geom_quasirandom() +\n", " scale_color_brewer(palette = \"Dark2\", direction = -1) +\n", " theme(legend.position = \"none\")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nu hvor vi har en idé om forholdet mellem de binære farvekategorier og den større gruppe af størrelser, lad os undersøge logistisk regression for at bestemme en given græskars sandsynlige farve.\n", "\n", "## Byg din model\n", "\n", "Vælg de variabler, du vil bruge i din klassifikationsmodel, og opdel dataene i trænings- og testdatasæt. [rsample](https://rsample.tidymodels.org/), en pakke i Tidymodels, tilbyder infrastruktur til effektiv dataopdeling og genprøvning:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Split data into 80% for training and 20% for testing\n", "set.seed(2056)\n", "pumpkins_split <- pumpkins_select %>% \n", " initial_split(prop = 0.8)\n", "\n", "# Extract the data in each split\n", "pumpkins_train <- training(pumpkins_split)\n", "pumpkins_test <- testing(pumpkins_split)\n", "\n", "# Print out the first 5 rows of the training set\n", "pumpkins_train %>% \n", " slice_head(n = 5)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "🙌 Vi er nu klar til at træne en model ved at tilpasse træningsfunktionerne til træningsetiketten (farve).\n", "\n", "Vi starter med at oprette en opskrift, der angiver de forbehandlingsskridt, der skal udføres på vores data for at gøre dem klar til modellering, dvs.: kodning af kategoriske variabler til et sæt heltal. Ligesom `baked_pumpkins` opretter vi en `pumpkins_recipe`, men vi `prep` og `bake` ikke, da det vil blive samlet i en arbejdsgang, som du vil se om få trin.\n", "\n", "Der er en del måder at specificere en logistisk regressionsmodel i Tidymodels. Se `?logistic_reg()`. For nu vil vi specificere en logistisk regressionsmodel via den standard `stats::glm()` motor.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Create a recipe that specifies preprocessing steps for modelling\n", "pumpkins_recipe <- recipe(color ~ ., data = pumpkins_train) %>% \n", " step_mutate(item_size = ordered(item_size, levels = c('sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo'))) %>%\n", " step_integer(item_size, zero_based = F) %>% \n", " step_dummy(all_nominal(), -all_outcomes(), one_hot = TRUE)\n", "\n", "# Create a logistic model specification\n", "log_reg <- logistic_reg() %>% \n", " set_engine(\"glm\") %>% \n", " set_mode(\"classification\")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nu hvor vi har en opskrift og en modelspecifikation, skal vi finde en måde at samle dem i et objekt, der først forbehandler dataene (prep+bake bag kulisserne), tilpasser modellen på de forbehandlede data og også giver mulighed for potentielle efterbehandlingsaktiviteter.\n", "\n", "I Tidymodels kaldes dette praktiske objekt en [`workflow`](https://workflows.tidymodels.org/) og holder bekvemt dine modelkomponenter.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Bundle modelling components in a workflow\n", "log_reg_wf <- workflow() %>% \n", " add_recipe(pumpkins_recipe) %>% \n", " add_model(log_reg)\n", "\n", "# Print out the workflow\n", "log_reg_wf\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Efter en arbejdsgang er blevet *specificeret*, kan en model `trænes` ved hjælp af [`fit()`](https://tidymodels.github.io/parsnip/reference/fit.html)-funktionen. Arbejdsgangen vil estimere en opskrift og forbehandle dataene før træning, så vi ikke behøver manuelt at gøre det ved hjælp af prep og bake.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Train the model\n", "wf_fit <- log_reg_wf %>% \n", " fit(data = pumpkins_train)\n", "\n", "# Print the trained workflow\n", "wf_fit\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Modellen viser de koefficienter, der er lært under træningen.\n", "\n", "Nu hvor vi har trænet modellen med træningsdataene, kan vi lave forudsigelser på testdataene ved hjælp af [parsnip::predict()](https://parsnip.tidymodels.org/reference/predict.model_fit.html). Lad os starte med at bruge modellen til at forudsige etiketter for vores testdatasæt og sandsynlighederne for hver etiket. Når sandsynligheden er mere end 0.5, er den forudsagte klasse `WHITE`, ellers `ORANGE`.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Make predictions for color and corresponding probabilities\n", "results <- pumpkins_test %>% select(color) %>% \n", " bind_cols(wf_fit %>% \n", " predict(new_data = pumpkins_test)) %>%\n", " bind_cols(wf_fit %>%\n", " predict(new_data = pumpkins_test, type = \"prob\"))\n", "\n", "# Compare predictions\n", "results %>% \n", " slice_head(n = 10)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Meget flot! Dette giver nogle flere indsigter i, hvordan logistisk regression fungerer.\n", "\n", "### Bedre forståelse via en forvirringsmatrix\n", "\n", "At sammenligne hver forudsigelse med dens tilsvarende \"ground truth\" faktiske værdi er ikke en særlig effektiv måde at afgøre, hvor godt modellen forudsiger. Heldigvis har Tidymodels nogle flere tricks i ærmet: [`yardstick`](https://yardstick.tidymodels.org/) - en pakke, der bruges til at måle effektiviteten af modeller ved hjælp af præstationsmålinger.\n", "\n", "En præstationsmåling, der er forbundet med klassifikationsproblemer, er [`forvirringsmatrix`](https://wikipedia.org/wiki/Confusion_matrix). En forvirringsmatrix beskriver, hvor godt en klassifikationsmodel præsterer. En forvirringsmatrix opstiller, hvor mange eksempler i hver klasse der blev korrekt klassificeret af en model. I vores tilfælde vil den vise dig, hvor mange orange græskar der blev klassificeret som orange, og hvor mange hvide græskar der blev klassificeret som hvide; forvirringsmatrixen viser også, hvor mange der blev klassificeret i de **forkerte** kategorier.\n", "\n", "Funktionen [**`conf_mat()`**](https://tidymodels.github.io/yardstick/reference/conf_mat.html) fra yardstick beregner denne krydstabulering af observerede og forudsagte klasser.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Confusion matrix for prediction results\n", "conf_mat(data = results, truth = color, estimate = .pred_class)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lad os fortolke forvirringsmatricen. Vores model skal klassificere græskar mellem to binære kategorier, kategorien `hvid` og kategorien `ikke-hvid`.\n", "\n", "- Hvis din model forudsiger et græskar som hvidt, og det faktisk tilhører kategorien 'hvid', kalder vi det en `true positive`, vist ved tallet øverst til venstre.\n", "\n", "- Hvis din model forudsiger et græskar som ikke-hvidt, og det faktisk tilhører kategorien 'hvid', kalder vi det en `false negative`, vist ved tallet nederst til venstre.\n", "\n", "- Hvis din model forudsiger et græskar som hvidt, og det faktisk tilhører kategorien 'ikke-hvid', kalder vi det en `false positive`, vist ved tallet øverst til højre.\n", "\n", "- Hvis din model forudsiger et græskar som ikke-hvidt, og det faktisk tilhører kategorien 'ikke-hvid', kalder vi det en `true negative`, vist ved tallet nederst til højre.\n", "\n", "| Sandhed |\n", "|:--------:|\n", "\n", "| | | |\n", "|---------------|--------|-------|\n", "| **Forudsagt** | HVID | ORANGE |\n", "| HVID | TP | FP |\n", "| ORANGE | FN | TN |\n", "\n", "Som du måske har gættet, er det at foretrække at have et større antal true positives og true negatives og et lavere antal false positives og false negatives, hvilket indikerer, at modellen præsterer bedre.\n", "\n", "Forvirringsmatricen er nyttig, da den giver anledning til andre metrikker, der kan hjælpe os med bedre at evaluere ydeevnen af en klassifikationsmodel. Lad os gennemgå nogle af dem:\n", "\n", "🎓 Præcision: `TP/(TP + FP)` defineret som andelen af forudsagte positive, der faktisk er positive. Også kaldet [positiv prædiktiv værdi](https://en.wikipedia.org/wiki/Positive_predictive_value \"Positive predictive value\").\n", "\n", "🎓 Recall: `TP/(TP + FN)` defineret som andelen af positive resultater ud af antallet af prøver, der faktisk var positive. Også kendt som `sensitivitet`.\n", "\n", "🎓 Specificitet: `TN/(TN + FP)` defineret som andelen af negative resultater ud af antallet af prøver, der faktisk var negative.\n", "\n", "🎓 Nøjagtighed: `TP + TN/(TP + TN + FP + FN)` Procentdelen af etiketter, der er korrekt forudsagt for en prøve.\n", "\n", "🎓 F-mål: Et vægtet gennemsnit af præcision og recall, hvor det bedste er 1 og det værste er 0.\n", "\n", "Lad os beregne disse metrikker!\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Combine metric functions and calculate them all at once\n", "eval_metrics <- metric_set(ppv, recall, spec, f_meas, accuracy)\n", "eval_metrics(data = results, truth = color, estimate = .pred_class)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Visualiser ROC-kurven for denne model\n", "\n", "Lad os lave endnu en visualisering for at se den såkaldte [`ROC-kurve`](https://en.wikipedia.org/wiki/Receiver_operating_characteristic):\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Make a roc_curve\n", "results %>% \n", " roc_curve(color, .pred_ORANGE) %>% \n", " autoplot()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "ROC-kurver bruges ofte til at få et overblik over en klassifikators output i forhold til dens sande vs. falske positiver. ROC-kurver viser typisk `True Positive Rate`/Sensitivitet på Y-aksen og `False Positive Rate`/1-Specificitet på X-aksen. Derfor er kurvens hældning og afstanden mellem midterlinjen og kurven vigtige: du ønsker en kurve, der hurtigt bevæger sig opad og væk fra linjen. I vores tilfælde er der falske positiver i starten, og derefter bevæger linjen sig korrekt opad og væk.\n", "\n", "Til sidst kan vi bruge `yardstick::roc_auc()` til at beregne det faktiske areal under kurven (Area Under the Curve). En måde at fortolke AUC på er som sandsynligheden for, at modellen rangerer et tilfældigt positivt eksempel højere end et tilfældigt negativt eksempel.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Calculate area under curve\n", "results %>% \n", " roc_auc(color, .pred_ORANGE)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Resultatet er omkring `0.975`. Da AUC spænder fra 0 til 1, ønsker du en høj score, da en model, der er 100% korrekt i sine forudsigelser, vil have en AUC på 1; i dette tilfælde er modellen *ret god*.\n", "\n", "I fremtidige lektioner om klassifikationer vil du lære, hvordan du kan forbedre modellens resultater (såsom at håndtere ubalancerede data i dette tilfælde).\n", "\n", "## 🚀Udfordring\n", "\n", "Der er meget mere at udforske omkring logistisk regression! Men den bedste måde at lære på er at eksperimentere. Find et datasæt, der egner sig til denne type analyse, og byg en model med det. Hvad lærer du? tip: prøv [Kaggle](https://www.kaggle.com/search?q=logistic+regression+datasets) for interessante datasæt.\n", "\n", "## Gennemgang & Selvstudie\n", "\n", "Læs de første par sider af [denne artikel fra Stanford](https://web.stanford.edu/~jurafsky/slp3/5.pdf) om nogle praktiske anvendelser af logistisk regression. Tænk over opgaver, der er bedre egnet til den ene eller den anden type regressionsopgaver, som vi har studeret indtil nu. Hvad ville fungere bedst?\n" ] }, { "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 er ikke ansvarlige for eventuelle misforståelser eller fejltolkninger, der opstår som følge af brugen af denne oversættelse.\n" ] } ], "metadata": { "anaconda-cloud": "", "kernelspec": { "display_name": "R", "langauge": "R", "name": "ir" }, "language_info": { "codemirror_mode": "r", "file_extension": ".r", "mimetype": "text/x-r-source", "name": "R", "pygments_lexer": "r", "version": "3.4.1" }, "coopTranslator": { "original_hash": "feaf125f481a89c468fa115bf2aed580", "translation_date": "2025-09-04T06:49:26+00:00", "source_file": "2-Regression/4-Logistic/solution/R/lesson_4-R.ipynb", "language_code": "da" } }, "nbformat": 4, "nbformat_minor": 1 }