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.
685 lines
30 KiB
685 lines
30 KiB
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Bygg en logistisk regresjonsmodell - Leksjon 4\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"#### **[Quiz før leksjon](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/15/)**\n",
|
|
"\n",
|
|
"#### Introduksjon\n",
|
|
"\n",
|
|
"I denne siste leksjonen om regresjon, en av de grunnleggende *klassiske* ML-teknikkene, skal vi se nærmere på logistisk regresjon. Du kan bruke denne teknikken for å oppdage mønstre og forutsi binære kategorier. Er dette godteri sjokolade eller ikke? Er denne sykdommen smittsom eller ikke? Vil denne kunden velge dette produktet eller ikke?\n",
|
|
"\n",
|
|
"I denne leksjonen vil du lære:\n",
|
|
"\n",
|
|
"- Teknikker for logistisk regresjon\n",
|
|
"\n",
|
|
"✅ Fordyp deg i hvordan du arbeider med denne typen regresjon i dette [Learn-modulet](https://learn.microsoft.com/training/modules/introduction-classification-models/?WT.mc_id=academic-77952-leestott)\n",
|
|
"\n",
|
|
"## Forutsetning\n",
|
|
"\n",
|
|
"Etter å ha jobbet med gresskar-dataene, er vi nå kjent nok med dem til å innse at det finnes én binær kategori vi kan jobbe med: `Color`.\n",
|
|
"\n",
|
|
"La oss bygge en logistisk regresjonsmodell for å forutsi, gitt noen variabler, *hvilken farge et gitt gresskar sannsynligvis har* (oransje 🎃 eller hvit 👻).\n",
|
|
"\n",
|
|
"> Hvorfor snakker vi om binær klassifisering i en leksjonsgruppe om regresjon? Kun av språklig bekvemmelighet, ettersom logistisk regresjon [egentlig er en klassifiseringsmetode](https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression), om enn en lineær-basert en. Lær om andre måter å klassifisere data på i neste leksjonsgruppe.\n",
|
|
"\n",
|
|
"For denne leksjonen trenger vi følgende pakker:\n",
|
|
"\n",
|
|
"- `tidyverse`: [tidyverse](https://www.tidyverse.org/) er en [samling av R-pakker](https://www.tidyverse.org/packages) designet for å gjøre datavitenskap raskere, enklere og morsommere!\n",
|
|
"\n",
|
|
"- `tidymodels`: [tidymodels](https://www.tidymodels.org/) er et [rammeverk av pakker](https://www.tidymodels.org/packages/) for modellering og maskinlæring.\n",
|
|
"\n",
|
|
"- `janitor`: [janitor-pakken](https://github.com/sfirke/janitor) gir enkle verktøy for å undersøke og rense rotete data.\n",
|
|
"\n",
|
|
"- `ggbeeswarm`: [ggbeeswarm-pakken](https://github.com/eclarke/ggbeeswarm) gir metoder for å lage beeswarm-stil grafer ved hjelp av ggplot2.\n",
|
|
"\n",
|
|
"Du kan installere dem slik:\n",
|
|
"\n",
|
|
"`install.packages(c(\"tidyverse\", \"tidymodels\", \"janitor\", \"ggbeeswarm\"))`\n",
|
|
"\n",
|
|
"Alternativt kan skriptet nedenfor sjekke om du har de nødvendige pakkene for å fullføre dette modulen og installere dem for deg 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ørsmålet**\n",
|
|
"\n",
|
|
"For vårt formål vil vi uttrykke dette som en binær: 'Hvit' eller 'Ikke Hvit'. Det finnes også en kategori for 'stripete' i datasettet vårt, men det er få forekomster av den, så vi kommer ikke til å bruke den. Den forsvinner uansett når vi fjerner nullverdier fra datasettet.\n",
|
|
"\n",
|
|
"> 🎃 Artig fakta: Vi kaller noen ganger hvite gresskar for 'spøkelsesgresskar'. De er ikke så lette å skjære ut, så de er ikke like populære som de oransje, men de ser kule ut! Så vi kunne også omformulert spørsmålet vårt til: 'Spøkelse' eller 'Ikke Spøkelse'. 👻\n",
|
|
"\n",
|
|
"## **Om logistisk regresjon**\n",
|
|
"\n",
|
|
"Logistisk regresjon skiller seg fra lineær regresjon, som du har lært om tidligere, på noen viktige måter.\n",
|
|
"\n",
|
|
"#### **Binær klassifisering**\n",
|
|
"\n",
|
|
"Logistisk regresjon tilbyr ikke de samme funksjonene som lineær regresjon. Førstnevnte gir en prediksjon om en `binær kategori` (\"oransje eller ikke oransje\"), mens sistnevnte er i stand til å forutsi `kontinuerlige verdier`, for eksempel gitt opprinnelsen til et gresskar og tidspunktet for innhøsting, *hvor mye prisen vil stige*.\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"### Andre klassifiseringer\n",
|
|
"\n",
|
|
"Det finnes andre typer logistisk regresjon, inkludert multinomial og ordinal:\n",
|
|
"\n",
|
|
"- **Multinomial**, som innebærer å ha mer enn én kategori - \"Oransje, Hvite og Stripete\".\n",
|
|
"\n",
|
|
"- **Ordinal**, som innebærer ordnede kategorier, nyttig hvis vi ønsker å ordne resultatene våre logisk, som gresskarene våre som er ordnet etter et begrenset antall størrelser (mini,sm,med,lg,xl,xxl).\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"#### **Variabler TRENGER IKKE å korrelere**\n",
|
|
"\n",
|
|
"Husker du hvordan lineær regresjon fungerte bedre med mer korrelerte variabler? Logistisk regresjon er det motsatte - variablene trenger ikke å være i samsvar. Dette fungerer for disse dataene som har noe svake korrelasjoner.\n",
|
|
"\n",
|
|
"#### **Du trenger mye rene data**\n",
|
|
"\n",
|
|
"Logistisk regresjon gir mer nøyaktige resultater hvis du bruker mer data; vårt lille datasett er ikke optimalt for denne oppgaven, så husk det.\n",
|
|
"\n",
|
|
"✅ Tenk på hvilke typer data som egner seg godt for logistisk regresjon\n",
|
|
"\n",
|
|
"## Øvelse - rydd opp i dataene\n",
|
|
"\n",
|
|
"Først, rydd opp i dataene litt, fjern nullverdier og velg kun noen av kolonnene:\n",
|
|
"\n",
|
|
"1. Legg til 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 alltid ta en titt på din nye dataframe ved å bruke [*glimpse()*](https://pillar.r-lib.org/reference/glimpse.html)-funksjonen 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": [
|
|
"La oss bekrefte at vi faktisk skal jobbe med et binært klassifiseringsproblem:\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",
|
|
"Nå har du lastet opp gresskar-dataene igjen og renset dem slik at du har et datasett som inneholder noen få variabler, inkludert Farge. La oss visualisere dataframen i notatboken ved hjelp av ggplot-biblioteket.\n",
|
|
"\n",
|
|
"Ggplot-biblioteket tilbyr noen smarte måter å visualisere dataene dine på. For eksempel kan du sammenligne distribusjoner av dataene for hver Sort og Farge i et kategorisk plot.\n",
|
|
"\n",
|
|
"1. Lag et slikt plot ved å bruke geombar-funksjonen, med gresskar-dataene våre, og spesifiser en fargekartlegging for hver gresskarkategori (oransje eller hvit):\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 å observere dataene kan du se hvordan Farge-dataene henger sammen med Variant.\n",
|
|
"\n",
|
|
"✅ Gitt dette kategoriske diagrammet, hvilke interessante utforskninger kan du se for deg?\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Databehandling: funksjonskoding\n",
|
|
"\n",
|
|
"Datasettet vårt med gresskar inneholder strengverdier for alle kolonnene. Å jobbe med kategoriske data er intuitivt for mennesker, men ikke for maskiner. Maskinlæringsalgoritmer fungerer godt med tall. Derfor er koding et veldig viktig steg i databehandlingsfasen, siden det lar oss gjøre kategoriske data om til numeriske data uten å miste informasjon. God koding fører til å bygge en god modell.\n",
|
|
"\n",
|
|
"For funksjonskoding finnes det to hovedtyper av kodere:\n",
|
|
"\n",
|
|
"1. Ordinal koder: denne passer godt for ordinale variabler, som er kategoriske variabler der dataene følger en logisk rekkefølge, som kolonnen `item_size` i datasettet vårt. Den lager en mapping slik at hver kategori representeres av et tall, som er rekkefølgen til kategorien i kolonnen.\n",
|
|
"\n",
|
|
"2. Kategorisk koder: denne passer godt for nominelle variabler, som er kategoriske variabler der dataene ikke følger en logisk rekkefølge, som alle funksjonene som er forskjellige fra `item_size` i datasettet vårt. Det er en one-hot encoding, som betyr at hver kategori representeres av en binær kolonne: den kodede variabelen er lik 1 hvis gresskaret tilhører den sorten, og 0 ellers.\n",
|
|
"\n",
|
|
"Tidymodels tilbyr enda en praktisk pakke: [recipes](https://recipes.tidymodels.org/) - en pakke for databehandling. Vi definerer en `recipe` som spesifiserer at alle prediktorkolonner skal kodes til et sett med heltall, `prep` den for å estimere de nødvendige mengdene og statistikkene som trengs for operasjonene, og til slutt `bake` for å bruke beregningene på nye data.\n",
|
|
"\n",
|
|
"> Vanligvis brukes recipes som en forbehandler for modellering, der den definerer hvilke steg som skal brukes på et datasett for å gjøre det klart for modellering. I så fall er det **sterkt anbefalt** at du bruker en `workflow()` i stedet for å manuelt estimere en oppskrift med prep og bake. Vi skal se alt dette om et øyeblikk.\n",
|
|
">\n",
|
|
"> Men for nå bruker vi recipes + prep + bake for å spesifisere hvilke steg som skal brukes på et datasett for å gjøre det klart for dataanalyse, og deretter hente ut de forhåndsbehandlede dataene med de anvendte stegene.\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": [
|
|
"✅ Hva er fordelene med å bruke en ordinal encoder for Item Size-kolonnen?\n",
|
|
"\n",
|
|
"### Analyser forholdet mellom variabler\n",
|
|
"\n",
|
|
"Nå som vi har forhåndsprosesseret dataene våre, kan vi analysere forholdet mellom funksjonene og etiketten for å få en idé om hvor godt modellen vil kunne forutsi etiketten basert på funksjonene. Den beste måten å utføre denne typen analyse på er å visualisere dataene. \n",
|
|
"Vi skal igjen bruke ggplot geom_boxplot_-funksjonen for å visualisere forholdet mellom Item Size, Variety og Color i et kategorisk diagram. For å bedre visualisere dataene vil vi bruke den kodede Item Size-kolonnen og den ukodede Variety-kolonnen.\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": [
|
|
"#### Bruk et swarm-plot\n",
|
|
"\n",
|
|
"Siden Color er en binær kategori (Hvit eller Ikke), krever det 'en [spesialisert tilnærming](https://github.com/rstudio/cheatsheets/blob/main/data-visualization.pdf) til visualisering'.\n",
|
|
"\n",
|
|
"Prøv et `swarm-plot` for å vise fordelingen av farge med hensyn til item_size.\n",
|
|
"\n",
|
|
"Vi skal bruke [ggbeeswarm-pakken](https://github.com/eclarke/ggbeeswarm), som gir metoder for å lage beeswarm-lignende plott ved hjelp av ggplot2. Beeswarm-plott er en måte å plotte punkter som normalt ville overlappet, slik at de i stedet plasseres ved siden av hverandre.\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": [
|
|
"Nå som vi har en idé om forholdet mellom de binære kategoriene for farge og den større gruppen av størrelser, la oss utforske logistisk regresjon for å bestemme den sannsynlige fargen på et gitt gresskar.\n",
|
|
"\n",
|
|
"## Bygg modellen din\n",
|
|
"\n",
|
|
"Velg variablene du vil bruke i klassifiseringsmodellen din, og del dataene inn i trenings- og testsett. [rsample](https://rsample.tidymodels.org/), en pakke i Tidymodels, gir infrastruktur for effektiv datadeling og resampling:\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 nå klare til å trene en modell ved å tilpasse treningsfunksjonene til treningsetiketten (farge).\n",
|
|
"\n",
|
|
"Vi starter med å lage en oppskrift som spesifiserer forbehandlingsstegene som skal utføres på dataene våre for å gjøre dem klare for modellering, dvs. koding av kategoriske variabler til et sett med heltall. Akkurat som `baked_pumpkins`, lager vi en `pumpkins_recipe`, men vi bruker ikke `prep` og `bake`, siden dette vil bli inkludert i en arbeidsflyt, som du vil se om noen få steg.\n",
|
|
"\n",
|
|
"Det finnes ganske mange måter å spesifisere en logistisk regresjonsmodell i Tidymodels. Se `?logistic_reg()`. For nå vil vi spesifisere en logistisk regresjonsmodell via standardmotoren `stats::glm()`.\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": [
|
|
"Nå som vi har en oppskrift og en modellspecifikasjon, trenger vi en måte å samle dem sammen i et objekt som først vil forhåndsbehandle dataene (prep+bake i bakgrunnen), tilpasse modellen på de forhåndsbehandlede dataene og også tillate eventuelle etterbehandlingsaktiviteter.\n",
|
|
"\n",
|
|
"I Tidymodels kalles dette praktiske objektet en [`workflow`](https://workflows.tidymodels.org/) og holder på en praktisk måte dine modelleringskomponenter.\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": [
|
|
"Etter at en arbeidsflyt har blitt *spesifisert*, kan en modell `trenings` ved hjelp av [`fit()`](https://tidymodels.github.io/parsnip/reference/fit.html)-funksjonen. Arbeidsflyten vil estimere en oppskrift og forhåndsbehandle dataene før trening, så vi slipper å gjøre det manuelt ved hjelp av 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 koeffisientene som ble lært under treningen.\n",
|
|
"\n",
|
|
"Nå som vi har trent modellen med treningsdataene, kan vi gjøre prediksjoner på testdataene ved hjelp av [parsnip::predict()](https://parsnip.tidymodels.org/reference/predict.model_fit.html). La oss starte med å bruke modellen til å forutsi etiketter for testsettet og sannsynlighetene for hver etikett. Når sannsynligheten er større enn 0,5, er den predikerte klassen `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": [
|
|
"Veldig bra! Dette gir litt mer innsikt i hvordan logistisk regresjon fungerer.\n",
|
|
"\n",
|
|
"### Bedre forståelse gjennom en forvirringsmatrise\n",
|
|
"\n",
|
|
"Å sammenligne hver prediksjon med dens tilsvarende \"sanne verdi\" er ikke en særlig effektiv måte å avgjøre hvor godt modellen predikerer. Heldigvis har Tidymodels noen flere triks i ermet: [`yardstick`](https://yardstick.tidymodels.org/) - en pakke som brukes til å måle modellers effektivitet ved hjelp av ytelsesmetrikker.\n",
|
|
"\n",
|
|
"En ytelsesmetrikk som er knyttet til klassifiseringsproblemer er [`forvirringsmatrisen`](https://wikipedia.org/wiki/Confusion_matrix). En forvirringsmatrise beskriver hvor godt en klassifiseringsmodell presterer. Den viser hvor mange eksempler i hver klasse som ble korrekt klassifisert av en modell. I vårt tilfelle vil den vise hvor mange oransje gresskar som ble klassifisert som oransje, og hvor mange hvite gresskar som ble klassifisert som hvite; forvirringsmatrisen viser også hvor mange som ble klassifisert i **feil** kategorier.\n",
|
|
"\n",
|
|
"Funksjonen [**`conf_mat()`**](https://tidymodels.github.io/yardstick/reference/conf_mat.html) fra yardstick beregner denne krysstabuleringen av observerte og predikerte 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": [
|
|
"La oss tolke forvirringsmatrisen. Modellen vår blir bedt om å klassifisere gresskar i to binære kategorier, kategorien `hvit` og kategorien `ikke-hvit`.\n",
|
|
"\n",
|
|
"- Hvis modellen din forutsier et gresskar som hvitt og det faktisk tilhører kategorien 'hvit', kaller vi det en `sann positiv` (true positive), vist med tallet øverst til venstre.\n",
|
|
"\n",
|
|
"- Hvis modellen din forutsier et gresskar som ikke hvitt og det faktisk tilhører kategorien 'hvit', kaller vi det en `falsk negativ` (false negative), vist med tallet nederst til venstre.\n",
|
|
"\n",
|
|
"- Hvis modellen din forutsier et gresskar som hvitt og det faktisk tilhører kategorien 'ikke-hvit', kaller vi det en `falsk positiv` (false positive), vist med tallet øverst til høyre.\n",
|
|
"\n",
|
|
"- Hvis modellen din forutsier et gresskar som ikke hvitt og det faktisk tilhører kategorien 'ikke-hvit', kaller vi det en `sann negativ` (true negative), vist med tallet nederst til høyre.\n",
|
|
"\n",
|
|
"| Sannhet |\n",
|
|
"|:-------:|\n",
|
|
"\n",
|
|
"| | | |\n",
|
|
"|---------------|--------|-------|\n",
|
|
"| **Forutsagt** | HVIT | ORANSJE |\n",
|
|
"| HVIT | TP | FP |\n",
|
|
"| ORANSJE | FN | TN |\n",
|
|
"\n",
|
|
"Som du kanskje har gjettet, er det å foretrekke å ha et høyere antall sanne positive og sanne negative, og et lavere antall falske positive og falske negative, noe som indikerer at modellen presterer bedre.\n",
|
|
"\n",
|
|
"Forvirringsmatrisen er nyttig fordi den gir opphav til andre måleparametere som kan hjelpe oss med å evaluere ytelsen til en klassifiseringsmodell bedre. La oss gå gjennom noen av dem:\n",
|
|
"\n",
|
|
"🎓 Presisjon: `TP/(TP + FP)` definert som andelen av forutsagte positive som faktisk er positive. Også kalt [positiv prediktiv verdi](https://en.wikipedia.org/wiki/Positive_predictive_value \"Positive predictive value\").\n",
|
|
"\n",
|
|
"🎓 Gjenkalling: `TP/(TP + FN)` definert som andelen positive resultater av antall prøver som faktisk var positive. Også kjent som `sensitivitet`.\n",
|
|
"\n",
|
|
"🎓 Spesifisitet: `TN/(TN + FP)` definert som andelen negative resultater av antall prøver som faktisk var negative.\n",
|
|
"\n",
|
|
"🎓 Nøyaktighet: `TP + TN/(TP + TN + FP + FN)` Prosentandelen av etiketter som er korrekt forutsagt for en prøve.\n",
|
|
"\n",
|
|
"🎓 F-mål: Et vektet gjennomsnitt av presisjon og gjenkalling, der det beste er 1 og det dårligste er 0.\n",
|
|
"\n",
|
|
"La oss beregne disse måleparametrene!\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 modellen\n",
|
|
"\n",
|
|
"La oss gjøre en visualisering til for å se den såkalte [`ROC-kurven`](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 brukes ofte for å få en oversikt over resultatene til en klassifiserer når det gjelder sanne vs. falske positive. ROC-kurver viser vanligvis `True Positive Rate`/Sensitivitet på Y-aksen og `False Positive Rate`/1-Spesifisitet på X-aksen. Derfor er kurvens bratthet og avstanden mellom midtlinjen og kurven viktig: du ønsker en kurve som raskt går opp og over linjen. I vårt tilfelle er det falske positive i starten, og deretter går linjen opp og over på riktig måte.\n",
|
|
"\n",
|
|
"Til slutt, la oss bruke `yardstick::roc_auc()` for å beregne det faktiske arealet under kurven (AUC). En måte å tolke AUC på er som sannsynligheten for at modellen rangerer et tilfeldig positivt eksempel høyere enn et tilfeldig 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 rundt `0.975`. Gitt at AUC varierer fra 0 til 1, ønsker du en høy score, siden en modell som er 100 % korrekt i sine prediksjoner vil ha en AUC på 1; i dette tilfellet er modellen *ganske bra*.\n",
|
|
"\n",
|
|
"I fremtidige leksjoner om klassifiseringer vil du lære hvordan du kan forbedre modellens resultater (for eksempel ved å håndtere ubalanserte data i dette tilfellet).\n",
|
|
"\n",
|
|
"## 🚀Utfordring\n",
|
|
"\n",
|
|
"Det er mye mer å utforske når det gjelder logistisk regresjon! Men den beste måten å lære på er å eksperimentere. Finn et datasett som egner seg for denne typen analyse og bygg en modell med det. Hva lærer du? Tips: prøv [Kaggle](https://www.kaggle.com/search?q=logistic+regression+datasets) for interessante datasett.\n",
|
|
"\n",
|
|
"## Gjennomgang og Selvstudium\n",
|
|
"\n",
|
|
"Les de første sidene av [denne artikkelen fra Stanford](https://web.stanford.edu/~jurafsky/slp3/5.pdf) om noen praktiske bruksområder for logistisk regresjon. Tenk på oppgaver som egner seg bedre for den ene eller den andre typen regresjonsoppgaver vi har studert så langt. Hva ville fungert best?\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"\n---\n\n**Ansvarsfraskrivelse**: \nDette dokumentet er oversatt ved hjelp av AI-oversettelsestjenesten [Co-op Translator](https://github.com/Azure/co-op-translator). Selv om vi tilstreber nøyaktighet, vennligst vær oppmerksom på at automatiske oversettelser kan inneholde feil eller unøyaktigheter. Det originale dokumentet på sitt opprinnelige språk bør anses som den autoritative kilden. For kritisk informasjon anbefales profesjonell menneskelig oversettelse. Vi er ikke ansvarlige for eventuelle misforståelser eller feiltolkninger som oppstår ved bruk av denne oversettelsen.\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-06T11:46:44+00:00",
|
|
"source_file": "2-Regression/4-Logistic/solution/R/lesson_4-R.ipynb",
|
|
"language_code": "no"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 1
|
|
} |