{ "nbformat": 4, "nbformat_minor": 2, "metadata": { "colab": { "name": "lesson_3-R.ipynb", "provenance": [], "collapsed_sections": [], "toc_visible": true }, "kernelspec": { "name": "ir", "display_name": "R" }, "language_info": { "name": "R" }, "coopTranslator": { "original_hash": "5015d65d61ba75a223bfc56c273aa174", "translation_date": "2025-09-06T13:19:40+00:00", "source_file": "2-Regression/3-Linear/solution/R/lesson_3-R.ipynb", "language_code": "sv" } }, "cells": [ { "cell_type": "markdown", "source": [], "metadata": { "id": "EgQw8osnsUV-" } }, { "cell_type": "markdown", "source": [ "## Linjär och Polynomisk Regression för Pumpapris - Lektion 3\n", "

\n", " \n", "

Infografik av Dasani Madipalli
\n", "\n", "\n", "\n", "\n", "#### Introduktion\n", "\n", "Hittills har du utforskat vad regression är med hjälp av exempeldata från pumpapris-datasetet som vi kommer att använda genom hela denna lektion. Du har också visualiserat det med hjälp av `ggplot2`.💪\n", "\n", "Nu är du redo att fördjupa dig i regression för maskininlärning. I denna lektion kommer du att lära dig mer om två typer av regression: *grundläggande linjär regression* och *polynomisk regression*, tillsammans med lite av matematiken bakom dessa tekniker.\n", "\n", "> Genom hela denna kurs antar vi minimal kunskap om matematik och strävar efter att göra det tillgängligt för studenter från andra områden. Håll utkik efter anteckningar, 🧮 matematiska inslag, diagram och andra lärverktyg som hjälper till att förstå.\n", "\n", "#### Förberedelse\n", "\n", "Som en påminnelse, du laddar denna data för att kunna ställa frågor om den.\n", "\n", "- När är den bästa tiden att köpa pumpor?\n", "\n", "- Vilket pris kan jag förvänta mig för en låda med miniatyrpumpor?\n", "\n", "- Bör jag köpa dem i halv-bushelkorgar eller i 1 1/9 bushel-lådor? Låt oss gräva djupare i denna data.\n", "\n", "I föregående lektion skapade du en `tibble` (en modern omarbetning av data frame) och fyllde den med en del av den ursprungliga datasetet, där du standardiserade prissättningen per bushel. Genom att göra det kunde du dock bara samla in cirka 400 datapunkter och endast för höstmånaderna. Kanske kan vi få lite mer detaljer om datans natur genom att städa upp den mer? Vi får se... 🕵️‍♀️\n", "\n", "För denna uppgift behöver vi följande paket:\n", "\n", "- `tidyverse`: [tidyverse](https://www.tidyverse.org/) är en [samling av R-paket](https://www.tidyverse.org/packages) designade för att göra dataanalys snabbare, enklare och roligare!\n", "\n", "- `tidymodels`: [tidymodels](https://www.tidymodels.org/) är ett [ramverk av paket](https://www.tidymodels.org/packages/) för modellering och maskininlärning.\n", "\n", "- `janitor`: [janitor-paketet](https://github.com/sfirke/janitor) erbjuder enkla verktyg för att undersöka och städa smutsig data.\n", "\n", "- `corrplot`: [corrplot-paketet](https://cran.r-project.org/web/packages/corrplot/vignettes/corrplot-intro.html) erbjuder ett visuellt utforskande verktyg för korrelationsmatriser som stödjer automatisk omordning av variabler för att hjälpa till att upptäcka dolda mönster bland variabler.\n", "\n", "Du kan installera dem med:\n", "\n", "`install.packages(c(\"tidyverse\", \"tidymodels\", \"janitor\", \"corrplot\"))`\n", "\n", "Skriptet nedan kontrollerar om du har de paket som krävs för att slutföra denna modul och installerar dem åt dig om de saknas.\n" ], "metadata": { "id": "WqQPS1OAsg3H" } }, { "cell_type": "code", "execution_count": null, "source": [ "suppressWarnings(if (!require(\"pacman\")) install.packages(\"pacman\"))\n", "\n", "pacman::p_load(tidyverse, tidymodels, janitor, corrplot)" ], "outputs": [], "metadata": { "id": "tA4C2WN3skCf", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "c06cd805-5534-4edc-f72b-d0d1dab96ac0" } }, { "cell_type": "markdown", "source": [ "Vi kommer senare att ladda dessa fantastiska paket och göra dem tillgängliga i vår nuvarande R-session. (Detta är bara för illustration, `pacman::p_load()` har redan gjort det åt dig)\n", "\n", "## 1. En linjär regressionslinje\n", "\n", "Som du lärde dig i Lektion 1 är målet med en linjär regressionsövning att kunna rita en *linje* *som* *passar bäst* för att:\n", "\n", "- **Visa samband mellan variabler**. Visa relationen mellan variabler.\n", "\n", "- **Göra förutsägelser**. Göra exakta förutsägelser om var en ny datapunkt skulle hamna i förhållande till den linjen.\n", "\n", "För att rita denna typ av linje använder vi en statistisk teknik som kallas **Minsta kvadratmetoden**. Termen `minsta kvadrat` betyder att alla datapunkter runt regressionslinjen kvadreras och sedan summeras. Idealiskt sett är den slutliga summan så liten som möjligt, eftersom vi vill ha ett lågt antal fel, eller `minsta kvadrat`. Därför är den linje som passar bäst den linje som ger oss det lägsta värdet för summan av de kvadrerade felen - därav namnet *minsta kvadratmetoden*.\n", "\n", "Vi gör detta eftersom vi vill modellera en linje som har den minsta kumulativa avvikelsen från alla våra datapunkter. Vi kvadrerar också termerna innan vi summerar dem eftersom vi är intresserade av deras storlek snarare än deras riktning.\n", "\n", "> **🧮 Visa mig matematiken**\n", ">\n", "> Denna linje, kallad *linjen som passar bäst*, kan uttryckas med [en ekvation](https://en.wikipedia.org/wiki/Simple_linear_regression):\n", ">\n", "> Y = a + bX\n", ">\n", "> `X` är den '`förklarande variabeln` eller `prediktorn`'. `Y` är den '`beroende variabeln` eller `utfallet`'. Lutningen på linjen är `b` och `a` är skärningspunkten med y-axeln, vilket hänvisar till värdet av `Y` när `X = 0`.\n", ">\n", "\n", "> ![](../../../../../../2-Regression/3-Linear/solution/images/slope.png \"lutning = $y/x$\")\n", " Infografik av Jen Looper\n", ">\n", "> Först, beräkna lutningen `b`.\n", ">\n", "> Med andra ord, och med hänvisning till vår pumpadata och den ursprungliga frågan: \"förutsäg priset på en pumpa per skäppa beroende på månad\", skulle `X` hänvisa till priset och `Y` hänvisa till försäljningsmånaden.\n", ">\n", "> ![](../../../../../../2-Regression/3-Linear/solution/images/calculation.png)\n", " Infografik av Jen Looper\n", "> \n", "> Beräkna värdet av Y. Om du betalar runt \\$4, måste det vara april!\n", ">\n", "> Matematiken som beräknar linjen måste visa lutningen på linjen, som också beror på skärningspunkten, eller var `Y` befinner sig när `X = 0`.\n", ">\n", "> Du kan se metoden för att beräkna dessa värden på webbplatsen [Math is Fun](https://www.mathsisfun.com/data/least-squares-regression.html). Besök också [denna Minsta kvadrat-kalkylator](https://www.mathsisfun.com/data/least-squares-calculator.html) för att se hur värdena påverkar linjen.\n", "\n", "Inte så skrämmande, eller hur? 🤓\n", "\n", "#### Korrelation\n", "\n", "Ett annat begrepp att förstå är **Korrelationskoefficienten** mellan givna X- och Y-variabler. Med hjälp av ett spridningsdiagram kan du snabbt visualisera denna koefficient. Ett diagram med datapunkter som är snyggt uppradade har hög korrelation, men ett diagram med datapunkter spridda överallt mellan X och Y har låg korrelation.\n", "\n", "En bra linjär regressionsmodell är en som har en hög (närmare 1 än 0) korrelationskoefficient med hjälp av Minsta kvadratmetoden och en regressionslinje.\n" ], "metadata": { "id": "cdX5FRpvsoP5" } }, { "cell_type": "markdown", "source": [ "## **2. En dans med data: skapa en data frame som ska användas för modellering**\n", "\n", "

\n", " \n", "

Konstverk av @allison_horst
\n", "\n", "\n", "\n" ], "metadata": { "id": "WdUKXk7Bs8-V" } }, { "cell_type": "markdown", "source": [ "Ladda upp nödvändiga bibliotek och dataset. Konvertera data till en data frame som innehåller ett urval av data:\n", "\n", "- Ta endast med pumpor som är prissatta per skäppa\n", "\n", "- Konvertera datumet till en månad\n", "\n", "- Beräkna priset som ett genomsnitt av högsta och lägsta pris\n", "\n", "- Konvertera priset för att återspegla prissättningen per skäppmängd\n", "\n", "> Vi gick igenom dessa steg i [föregående lektion](https://github.com/microsoft/ML-For-Beginners/blob/main/2-Regression/2-Data/solution/lesson_2-R.ipynb).\n" ], "metadata": { "id": "fMCtu2G2s-p8" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Load the core Tidyverse packages\n", "library(tidyverse)\n", "library(lubridate)\n", "\n", "# Import the pumpkins data\n", "pumpkins <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/2-Regression/data/US-pumpkins.csv\")\n", "\n", "\n", "# Get a glimpse and dimensions of the data\n", "glimpse(pumpkins)\n", "\n", "\n", "# Print the first 50 rows of the data set\n", "pumpkins %>% \n", " slice_head(n = 5)" ], "outputs": [], "metadata": { "id": "ryMVZEEPtERn" } }, { "cell_type": "markdown", "source": [ "I äkta äventyrsanda, låt oss utforska [`janitor-paketet`](../../../../../../2-Regression/3-Linear/solution/R/github.com/sfirke/janitor) som erbjuder enkla funktioner för att undersöka och rengöra smutsiga data. Till exempel, låt oss titta på kolumnnamnen för våra data:\n" ], "metadata": { "id": "xcNxM70EtJjb" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Return column names\n", "pumpkins %>% \n", " names()" ], "outputs": [], "metadata": { "id": "5XtpaIigtPfW" } }, { "cell_type": "markdown", "source": [ "🤔 Vi kan göra bättre. Låt oss göra dessa kolumnnamn `friendR` genom att konvertera dem till [snake_case](https://en.wikipedia.org/wiki/Snake_case)-konventionen med hjälp av `janitor::clean_names`. För att ta reda på mer om denna funktion: `?clean_names`\n" ], "metadata": { "id": "IbIqrMINtSHe" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Clean names to the snake_case convention\n", "pumpkins <- pumpkins %>% \n", " clean_names(case = \"snake\")\n", "\n", "# Return column names\n", "pumpkins %>% \n", " names()" ], "outputs": [], "metadata": { "id": "a2uYvclYtWvX" } }, { "cell_type": "markdown", "source": [ "Mycket tidyR 🧹! Nu, en dans med datan med hjälp av `dplyr`, precis som i den förra lektionen! 💃\n" ], "metadata": { "id": "HfhnuzDDtaDd" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Select desired columns\n", "pumpkins <- pumpkins %>% \n", " select(variety, city_name, package, low_price, high_price, date)\n", "\n", "\n", "\n", "# Extract the month from the dates to a new column\n", "pumpkins <- pumpkins %>%\n", " mutate(date = mdy(date),\n", " month = month(date)) %>% \n", " select(-date)\n", "\n", "\n", "\n", "# Create a new column for average Price\n", "pumpkins <- pumpkins %>% \n", " mutate(price = (low_price + high_price)/2)\n", "\n", "\n", "# Retain only pumpkins with the string \"bushel\"\n", "new_pumpkins <- pumpkins %>% \n", " filter(str_detect(string = package, pattern = \"bushel\"))\n", "\n", "\n", "# Normalize the pricing so that you show the pricing per bushel, not per 1 1/9 or 1/2 bushel\n", "new_pumpkins <- new_pumpkins %>% \n", " mutate(price = case_when(\n", " str_detect(package, \"1 1/9\") ~ price/(1.1),\n", " str_detect(package, \"1/2\") ~ price*2,\n", " TRUE ~ price))\n", "\n", "# Relocate column positions\n", "new_pumpkins <- new_pumpkins %>% \n", " relocate(month, .before = variety)\n", "\n", "\n", "# Display the first 5 rows\n", "new_pumpkins %>% \n", " slice_head(n = 5)" ], "outputs": [], "metadata": { "id": "X0wU3gQvtd9f" } }, { "cell_type": "markdown", "source": [ "Bra jobbat! 👌 Du har nu en ren och prydlig datamängd som du kan använda för att bygga din nya regressionsmodell!\n", "\n", "Vad sägs om ett spridningsdiagram?\n" ], "metadata": { "id": "UpaIwaxqth82" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Set theme\n", "theme_set(theme_light())\n", "\n", "# Make a scatter plot of month and price\n", "new_pumpkins %>% \n", " ggplot(mapping = aes(x = month, y = price)) +\n", " geom_point(size = 1.6)\n" ], "outputs": [], "metadata": { "id": "DXgU-j37tl5K" } }, { "cell_type": "markdown", "source": [ "Ett spridningsdiagram påminner oss om att vi bara har månadsdata från augusti till december. Vi behöver troligen mer data för att kunna dra slutsatser på ett linjärt sätt.\n", "\n", "Låt oss titta på våra modelleringsdata igen:\n" ], "metadata": { "id": "Ve64wVbwtobI" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Display first 5 rows\n", "new_pumpkins %>% \n", " slice_head(n = 5)" ], "outputs": [], "metadata": { "id": "HFQX2ng1tuSJ" } }, { "cell_type": "markdown", "source": [ "Vad händer om vi ville förutsäga `price` för en pumpa baserat på kolumnerna `city` eller `package`, som är av typen text? Eller ännu enklare, hur skulle vi kunna hitta korrelationen (som kräver att båda dess indata är numeriska) mellan till exempel `package` och `price`? 🤷🤷\n", "\n", "Maskininlärningsmodeller fungerar bäst med numeriska egenskaper snarare än textvärden, så du behöver vanligtvis konvertera kategoriska egenskaper till numeriska representationer.\n", "\n", "Detta innebär att vi måste hitta ett sätt att omforma våra prediktorer för att göra dem enklare för en modell att använda effektivt, en process som kallas `feature engineering`.\n" ], "metadata": { "id": "7hsHoxsStyjJ" } }, { "cell_type": "markdown", "source": [ "## 3. Förbereda data för modellering med recipes 👩‍🍳👨‍🍳\n", "\n", "Aktiviteter som omformar prediktorvärden för att göra dem enklare för en modell att använda effektivt kallas `feature engineering`.\n", "\n", "Olika modeller har olika krav på förbehandling. Till exempel kräver minsta kvadratmetoden `kodning av kategoriska variabler` såsom månad, sort och stad_namn. Detta innebär helt enkelt att `översätta` en kolumn med `kategoriska värden` till en eller flera `numeriska kolumner` som ersätter den ursprungliga.\n", "\n", "Till exempel, anta att din data innehåller följande kategoriska variabel:\n", "\n", "| stad |\n", "|:-------:|\n", "| Denver |\n", "| Nairobi |\n", "| Tokyo |\n", "\n", "Du kan använda *ordinal kodning* för att ersätta varje kategori med ett unikt heltalsvärde, som detta:\n", "\n", "| stad |\n", "|:----:|\n", "| 0 |\n", "| 1 |\n", "| 2 |\n", "\n", "Och det är precis vad vi ska göra med vår data!\n", "\n", "I det här avsnittet ska vi utforska ett annat fantastiskt Tidymodels-paket: [recipes](https://tidymodels.github.io/recipes/) - som är utformat för att hjälpa dig att förbehandla din data **innan** du tränar din modell. Kärnan i en recipe är ett objekt som definierar vilka steg som ska tillämpas på en dataset för att göra den redo för modellering.\n", "\n", "Nu ska vi skapa en recipe som förbereder vår data för modellering genom att ersätta varje observation i prediktorkolumnerna med ett unikt heltal:\n" ], "metadata": { "id": "AD5kQbcvt3Xl" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Specify a recipe\n", "pumpkins_recipe <- recipe(price ~ ., data = new_pumpkins) %>% \n", " step_integer(all_predictors(), zero_based = TRUE)\n", "\n", "\n", "# Print out the recipe\n", "pumpkins_recipe" ], "outputs": [], "metadata": { "id": "BNaFKXfRt9TU" } }, { "cell_type": "markdown", "source": [ "Fantastiskt! 👏 Vi har precis skapat vårt första recept som specificerar ett utfall (pris) och dess motsvarande prediktorer, och att alla prediktorkolumner ska kodas om till en uppsättning heltal 🙌! Låt oss snabbt bryta ner det:\n", "\n", "- Anropet till `recipe()` med en formel berättar för receptet vilka *roller* variablerna har, med hjälp av `new_pumpkins`-data som referens. Till exempel har kolumnen `price` tilldelats rollen `outcome`, medan resten av kolumnerna har tilldelats rollen `predictor`.\n", "\n", "- `step_integer(all_predictors(), zero_based = TRUE)` specificerar att alla prediktorer ska konverteras till en uppsättning heltal, där numreringen börjar på 0.\n", "\n", "Vi är säkra på att du kanske tänker något i stil med: \"Det här är så häftigt!! Men vad händer om jag behöver bekräfta att recepten gör exakt det jag förväntar mig? 🤔\"\n", "\n", "Det är en fantastisk tanke! Du förstår, när ditt recept är definierat kan du uppskatta de parametrar som krävs för att faktiskt förbehandla datan och sedan extrahera den bearbetade datan. Du behöver vanligtvis inte göra detta när du använder Tidymodels (vi kommer att se den normala konventionen om en liten stund -> `workflows`), men det kan vara användbart när du vill göra någon form av rimlighetskontroll för att bekräfta att recepten gör det du förväntar dig.\n", "\n", "För detta behöver du två ytterligare verb: `prep()` och `bake()`, och som alltid hjälper våra små R-vänner från [`Allison Horst`](https://github.com/allisonhorst/stats-illustrations) dig att förstå detta bättre!\n", "\n", "

\n", " \n", "

Konstverk av @allison_horst
\n", "\n", "\n", "\n" ], "metadata": { "id": "KEiO0v7kuC9O" } }, { "cell_type": "markdown", "source": [ "[`prep()`](https://recipes.tidymodels.org/reference/prep.html): beräknar de nödvändiga parametrarna från en träningsuppsättning som senare kan tillämpas på andra datamängder. Till exempel, för en given prediktorkolumn, vilken observation kommer att tilldelas heltalet 0, 1, 2 osv.\n", "\n", "[`bake()`](https://recipes.tidymodels.org/reference/bake.html): tar ett förberett recept och tillämpar operationerna på vilken datamängd som helst.\n", "\n", "Med det sagt, låt oss förbereda och tillämpa våra recept för att verkligen bekräfta att bakom kulisserna kommer prediktorkolumnerna först att kodas innan en modell anpassas.\n" ], "metadata": { "id": "Q1xtzebuuTCP" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Prep the recipe\n", "pumpkins_prep <- prep(pumpkins_recipe)\n", "\n", "# Bake the recipe to extract a preprocessed new_pumpkins data\n", "baked_pumpkins <- bake(pumpkins_prep, new_data = NULL)\n", "\n", "# Print out the baked data set\n", "baked_pumpkins %>% \n", " slice_head(n = 10)" ], "outputs": [], "metadata": { "id": "FGBbJbP_uUUn" } }, { "cell_type": "markdown", "source": [ "Woo-hoo!🥳 Den bearbetade datan `baked_pumpkins` har alla sina prediktorer kodade, vilket bekräftar att de förbehandlingssteg som definierats som vårt recept fungerar som förväntat. Detta gör det svårare för dig att läsa men mycket mer begripligt för Tidymodels! Ta lite tid att ta reda på vilken observation som har mappats till ett motsvarande heltal.\n", "\n", "Det är också värt att nämna att `baked_pumpkins` är en data frame som vi kan utföra beräkningar på.\n", "\n", "Till exempel, låt oss försöka hitta en bra korrelation mellan två punkter i din data för att potentiellt bygga en bra prediktiv modell. Vi kommer att använda funktionen `cor()` för detta. Skriv `?cor()` för att ta reda på mer om funktionen.\n" ], "metadata": { "id": "1dvP0LBUueAW" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Find the correlation between the city_name and the price\n", "cor(baked_pumpkins$city_name, baked_pumpkins$price)\n", "\n", "# Find the correlation between the package and the price\n", "cor(baked_pumpkins$package, baked_pumpkins$price)\n" ], "outputs": [], "metadata": { "id": "3bQzXCjFuiSV" } }, { "cell_type": "markdown", "source": [ "Som det visar sig finns det bara en svag korrelation mellan Stad och Pris. Däremot finns det en något bättre korrelation mellan Paket och dess Pris. Det är väl logiskt, eller hur? Vanligtvis, ju större lådan med varor, desto högre pris.\n", "\n", "När vi ändå håller på, låt oss också försöka visualisera en korrelationsmatris för alla kolumner med hjälp av paketet `corrplot`.\n" ], "metadata": { "id": "BToPWbgjuoZw" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Load the corrplot package\n", "library(corrplot)\n", "\n", "# Obtain correlation matrix\n", "corr_mat <- cor(baked_pumpkins %>% \n", " # Drop columns that are not really informative\n", " select(-c(low_price, high_price)))\n", "\n", "# Make a correlation plot between the variables\n", "corrplot(corr_mat, method = \"shade\", shade.col = NA, tl.col = \"black\", tl.srt = 45, addCoef.col = \"black\", cl.pos = \"n\", order = \"original\")" ], "outputs": [], "metadata": { "id": "ZwAL3ksmutVR" } }, { "cell_type": "markdown", "source": [ "🤩🤩 Mycket bättre.\n", "\n", "En bra fråga att ställa om dessa data är: '`Vilket pris kan jag förvänta mig för ett visst pumpapaket?`' Låt oss sätta igång!\n", "\n", "> Note: När du **`bake()`** det förberedda receptet **`pumpkins_prep`** med **`new_data = NULL`**, extraherar du den bearbetade (dvs. kodade) träningsdatan. Om du hade en annan dataset, till exempel en testuppsättning, och ville se hur ett recept skulle förbehandla den, skulle du helt enkelt baka **`pumpkins_prep`** med **`new_data = test_set`**\n", "\n", "## 4. Bygg en linjär regressionsmodell\n", "\n", "

\n", " \n", "

Infografik av Dasani Madipalli
\n", "\n", "\n", "\n" ], "metadata": { "id": "YqXjLuWavNxW" } }, { "cell_type": "markdown", "source": [ "Nu när vi har skapat ett recept och faktiskt bekräftat att datan kommer att förbehandlas korrekt, låt oss nu bygga en regressionsmodell för att besvara frågan: `Vilket pris kan jag förvänta mig för ett givet pumpapaket?`\n", "\n", "#### Träna en linjär regressionsmodell med träningsuppsättningen\n", "\n", "Som du kanske redan har räknat ut är kolumnen *price* den `beroende` variabeln medan kolumnen *package* är den `oberoende` variabeln.\n", "\n", "För att göra detta kommer vi först att dela upp datan så att 80% går till träningsuppsättningen och 20% till testuppsättningen, sedan definiera ett recept som kommer att koda den oberoende kolumnen till en uppsättning heltal, och därefter bygga en modellspecifikation. Vi kommer inte att förbereda och baka vårt recept eftersom vi redan vet att det kommer att förbehandla datan som förväntat.\n" ], "metadata": { "id": "Pq0bSzCevW-h" } }, { "cell_type": "code", "execution_count": null, "source": [ "set.seed(2056)\n", "# Split the data into training and test sets\n", "pumpkins_split <- new_pumpkins %>% \n", " initial_split(prop = 0.8)\n", "\n", "\n", "# Extract training and test data\n", "pumpkins_train <- training(pumpkins_split)\n", "pumpkins_test <- testing(pumpkins_split)\n", "\n", "\n", "\n", "# Create a recipe for preprocessing the data\n", "lm_pumpkins_recipe <- recipe(price ~ package, data = pumpkins_train) %>% \n", " step_integer(all_predictors(), zero_based = TRUE)\n", "\n", "\n", "\n", "# Create a linear model specification\n", "lm_spec <- linear_reg() %>% \n", " set_engine(\"lm\") %>% \n", " set_mode(\"regression\")" ], "outputs": [], "metadata": { "id": "CyoEh_wuvcLv" } }, { "cell_type": "markdown", "source": [ "Bra jobbat! Nu när vi har ett recept och en modellspecifikation behöver vi hitta ett sätt att kombinera dem till ett objekt som först förbehandlar data (prep+bake bakom kulisserna), tränar modellen på den förbehandlade datan och även möjliggör eventuella efterbehandlingsaktiviteter. Hur låter det för din sinnesro!🤩\n", "\n", "I Tidymodels kallas detta praktiska objekt för en [`workflow`](https://workflows.tidymodels.org/) och innehåller smidigt dina modelleringskomponenter! Det är vad vi skulle kalla *pipelines* i *Python*.\n", "\n", "Så låt oss paketera allt i ett workflow!📦\n" ], "metadata": { "id": "G3zF_3DqviFJ" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Hold modelling components in a workflow\n", "lm_wf <- workflow() %>% \n", " add_recipe(lm_pumpkins_recipe) %>% \n", " add_model(lm_spec)\n", "\n", "# Print out the workflow\n", "lm_wf" ], "outputs": [], "metadata": { "id": "T3olroU3v-WX" } }, { "cell_type": "markdown", "source": [ "Dessutom kan ett arbetsflöde anpassas/tränas på ungefär samma sätt som en modell kan.\n" ], "metadata": { "id": "zd1A5tgOwEPX" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Train the model\n", "lm_wf_fit <- lm_wf %>% \n", " fit(data = pumpkins_train)\n", "\n", "# Print the model coefficients learned \n", "lm_wf_fit" ], "outputs": [], "metadata": { "id": "NhJagFumwFHf" } }, { "cell_type": "markdown", "source": [ "Från modellens output kan vi se de koefficienter som lärdes under träningen. De representerar koefficienterna för den bästa linjen som ger oss det lägsta totala felet mellan den faktiska och den förutspådda variabeln.\n", "\n", "#### Utvärdera modellens prestanda med hjälp av testuppsättningen\n", "\n", "Det är dags att se hur modellen presterade 📏! Hur gör vi detta?\n", "\n", "Nu när vi har tränat modellen kan vi använda den för att göra förutsägelser för test_set med `parsnip::predict()`. Därefter kan vi jämföra dessa förutsägelser med de faktiska etikettvärdena för att utvärdera hur bra (eller inte!) modellen fungerar.\n", "\n", "Låt oss börja med att göra förutsägelser för testuppsättningen och sedan binda kolumnerna till testuppsättningen.\n" ], "metadata": { "id": "_4QkGtBTwItF" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Make predictions for the test set\n", "predictions <- lm_wf_fit %>% \n", " predict(new_data = pumpkins_test)\n", "\n", "\n", "# Bind predictions to the test set\n", "lm_results <- pumpkins_test %>% \n", " select(c(package, price)) %>% \n", " bind_cols(predictions)\n", "\n", "\n", "# Print the first ten rows of the tibble\n", "lm_results %>% \n", " slice_head(n = 10)" ], "outputs": [], "metadata": { "id": "UFZzTG0gwTs9" } }, { "cell_type": "markdown", "source": [ "Ja, du har precis tränat en modell och använt den för att göra förutsägelser! 🔮 Är den bra? Låt oss utvärdera modellens prestanda!\n", "\n", "I Tidymodels gör vi detta med `yardstick::metrics()`! För linjär regression fokuserar vi på följande mått:\n", "\n", "- `Root Mean Square Error (RMSE)`: Kvadratroten av [MSE](https://en.wikipedia.org/wiki/Mean_squared_error). Detta ger ett absolut mått i samma enhet som etiketten (i detta fall priset på en pumpa). Ju mindre värde, desto bättre modell (förenklat sett representerar det det genomsnittliga priset med vilket förutsägelserna är fel!)\n", "\n", "- `Coefficient of Determination (vanligtvis känt som R-squared eller R2)`: Ett relativt mått där ett högre värde innebär en bättre passform för modellen. I grund och botten representerar detta mått hur mycket av variansen mellan förutsagda och faktiska etikettvärden modellen kan förklara.\n" ], "metadata": { "id": "0A5MjzM7wW9M" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Evaluate performance of linear regression\n", "metrics(data = lm_results,\n", " truth = price,\n", " estimate = .pred)" ], "outputs": [], "metadata": { "id": "reJ0UIhQwcEH" } }, { "cell_type": "markdown", "source": [ "Där går modellens prestanda. Låt oss se om vi kan få en bättre indikation genom att visualisera ett spridningsdiagram av paketet och priset, och sedan använda de gjorda förutsägelserna för att lägga till en linje som bäst passar.\n", "\n", "Detta innebär att vi måste förbereda och bearbeta testuppsättningen för att koda paketkolumnen och sedan binda detta till de förutsägelser som vår modell har gjort.\n" ], "metadata": { "id": "fdgjzjkBwfWt" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Encode package column\n", "package_encode <- lm_pumpkins_recipe %>% \n", " prep() %>% \n", " bake(new_data = pumpkins_test) %>% \n", " select(package)\n", "\n", "\n", "# Bind encoded package column to the results\n", "lm_results <- lm_results %>% \n", " bind_cols(package_encode %>% \n", " rename(package_integer = package)) %>% \n", " relocate(package_integer, .after = package)\n", "\n", "\n", "# Print new results data frame\n", "lm_results %>% \n", " slice_head(n = 5)\n", "\n", "\n", "# Make a scatter plot\n", "lm_results %>% \n", " ggplot(mapping = aes(x = package_integer, y = price)) +\n", " geom_point(size = 1.6) +\n", " # Overlay a line of best fit\n", " geom_line(aes(y = .pred), color = \"orange\", size = 1.2) +\n", " xlab(\"package\")\n", " \n" ], "outputs": [], "metadata": { "id": "R0nw719lwkHE" } }, { "cell_type": "markdown", "source": [ "Bra! Som du kan se, generaliserar inte linjär regressionsmodellen särskilt väl relationen mellan ett paket och dess motsvarande pris.\n", "\n", "🎃 Grattis, du har precis skapat en modell som kan hjälpa till att förutsäga priset på några olika sorters pumpor. Din pumpaplantage inför högtiden kommer att bli fantastisk. Men du kan förmodligen skapa en ännu bättre modell!\n", "\n", "## 5. Bygg en polynomregressionsmodell\n", "\n", "

\n", " \n", "

Infografik av Dasani Madipalli
\n", "\n", "\n", "\n" ], "metadata": { "id": "HOCqJXLTwtWI" } }, { "cell_type": "markdown", "source": [ "Ibland kanske våra data inte har en linjär relation, men vi vill ändå förutsäga ett resultat. Polynomregression kan hjälpa oss att göra förutsägelser för mer komplexa icke-linjära samband.\n", "\n", "Ta till exempel sambandet mellan förpackning och pris i vår dataset med pumpor. Även om det ibland finns en linjär relation mellan variabler - ju större pumpan är i volym, desto högre pris - kan dessa samband ibland inte plottas som ett plan eller en rak linje.\n", "\n", "> ✅ Här är [några fler exempel](https://online.stat.psu.edu/stat501/lesson/9/9.8) på data som kan använda polynomregression\n", ">\n", "> Titta en gång till på sambandet mellan Sort och Pris i det tidigare diagrammet. Verkar det som att detta spridningsdiagram nödvändigtvis bör analyseras med en rak linje? Kanske inte. I detta fall kan du prova polynomregression.\n", ">\n", "> ✅ Polynom är matematiska uttryck som kan bestå av en eller flera variabler och koefficienter\n", "\n", "#### Träna en polynomregressionsmodell med hjälp av träningsdata\n", "\n", "Polynomregression skapar en *kurvad linje* för att bättre passa icke-linjär data.\n", "\n", "Låt oss se om en polynommodell presterar bättre när det gäller att göra förutsägelser. Vi kommer att följa en liknande procedur som vi gjorde tidigare:\n", "\n", "- Skapa ett recept som specificerar de förbehandlingssteg som ska utföras på våra data för att göra dem redo för modellering, dvs: kodning av prediktorer och beräkning av polynom av grad *n*\n", "\n", "- Bygga en modellspecifikation\n", "\n", "- Paketera receptet och modellspecifikationen i ett arbetsflöde\n", "\n", "- Skapa en modell genom att passa arbetsflödet\n", "\n", "- Utvärdera hur väl modellen presterar på testdata\n", "\n", "Nu kör vi igång!\n" ], "metadata": { "id": "VcEIpRV9wzYr" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Specify a recipe\r\n", "poly_pumpkins_recipe <-\r\n", " recipe(price ~ package, data = pumpkins_train) %>%\r\n", " step_integer(all_predictors(), zero_based = TRUE) %>% \r\n", " step_poly(all_predictors(), degree = 4)\r\n", "\r\n", "\r\n", "# Create a model specification\r\n", "poly_spec <- linear_reg() %>% \r\n", " set_engine(\"lm\") %>% \r\n", " set_mode(\"regression\")\r\n", "\r\n", "\r\n", "# Bundle recipe and model spec into a workflow\r\n", "poly_wf <- workflow() %>% \r\n", " add_recipe(poly_pumpkins_recipe) %>% \r\n", " add_model(poly_spec)\r\n", "\r\n", "\r\n", "# Create a model\r\n", "poly_wf_fit <- poly_wf %>% \r\n", " fit(data = pumpkins_train)\r\n", "\r\n", "\r\n", "# Print learned model coefficients\r\n", "poly_wf_fit\r\n", "\r\n", " " ], "outputs": [], "metadata": { "id": "63n_YyRXw3CC" } }, { "cell_type": "markdown", "source": [ "#### Utvärdera modellens prestanda\n", "\n", "👏👏Du har skapat en polynommodell, låt oss göra förutsägelser på testuppsättningen!\n" ], "metadata": { "id": "-LHZtztSxDP0" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Make price predictions on test data\r\n", "poly_results <- poly_wf_fit %>% predict(new_data = pumpkins_test) %>% \r\n", " bind_cols(pumpkins_test %>% select(c(package, price))) %>% \r\n", " relocate(.pred, .after = last_col())\r\n", "\r\n", "\r\n", "# Print the results\r\n", "poly_results %>% \r\n", " slice_head(n = 10)" ], "outputs": [], "metadata": { "id": "YUFpQ_dKxJGx" } }, { "cell_type": "markdown", "source": [ "Woo-hoo, låt oss utvärdera hur modellen presterade på test_set med hjälp av `yardstick::metrics()`.\n" ], "metadata": { "id": "qxdyj86bxNGZ" } }, { "cell_type": "code", "execution_count": null, "source": [ "metrics(data = poly_results, truth = price, estimate = .pred)" ], "outputs": [], "metadata": { "id": "8AW5ltkBxXDm" } }, { "cell_type": "markdown", "source": [ "🤩🤩 Mycket bättre prestanda.\n", "\n", "`rmse` minskade från cirka 7 till cirka 3, vilket indikerar en minskad felmarginal mellan det faktiska priset och det förutspådda priset. Du kan *ungefärligt* tolka detta som att felaktiga förutsägelser i genomsnitt är fel med cirka 3 dollar. `rsq` ökade från cirka 0,4 till 0,8.\n", "\n", "Alla dessa mätvärden visar att den polynomiska modellen presterar mycket bättre än den linjära modellen. Bra jobbat!\n", "\n", "Låt oss se om vi kan visualisera detta!\n" ], "metadata": { "id": "6gLHNZDwxYaS" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Bind encoded package column to the results\r\n", "poly_results <- poly_results %>% \r\n", " bind_cols(package_encode %>% \r\n", " rename(package_integer = package)) %>% \r\n", " relocate(package_integer, .after = package)\r\n", "\r\n", "\r\n", "# Print new results data frame\r\n", "poly_results %>% \r\n", " slice_head(n = 5)\r\n", "\r\n", "\r\n", "# Make a scatter plot\r\n", "poly_results %>% \r\n", " ggplot(mapping = aes(x = package_integer, y = price)) +\r\n", " geom_point(size = 1.6) +\r\n", " # Overlay a line of best fit\r\n", " geom_line(aes(y = .pred), color = \"midnightblue\", size = 1.2) +\r\n", " xlab(\"package\")\r\n" ], "outputs": [], "metadata": { "id": "A83U16frxdF1" } }, { "cell_type": "markdown", "source": [ "Du kan se en kurva som passar dina data bättre! 🤩\n", "\n", "Du kan göra detta ännu mjukare genom att skicka en polynomformel till `geom_smooth` så här:\n" ], "metadata": { "id": "4U-7aHOVxlGU" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Make a scatter plot\r\n", "poly_results %>% \r\n", " ggplot(mapping = aes(x = package_integer, y = price)) +\r\n", " geom_point(size = 1.6) +\r\n", " # Overlay a line of best fit\r\n", " geom_smooth(method = lm, formula = y ~ poly(x, degree = 4), color = \"midnightblue\", size = 1.2, se = FALSE) +\r\n", " xlab(\"package\")" ], "outputs": [], "metadata": { "id": "5vzNT0Uexm-w" } }, { "cell_type": "markdown", "source": [ "Mycket som en jämn kurva!🤩\n", "\n", "Så här gör du en ny förutsägelse:\n" ], "metadata": { "id": "v9u-wwyLxq4G" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Make a hypothetical data frame\r\n", "hypo_tibble <- tibble(package = \"bushel baskets\")\r\n", "\r\n", "# Make predictions using linear model\r\n", "lm_pred <- lm_wf_fit %>% predict(new_data = hypo_tibble)\r\n", "\r\n", "# Make predictions using polynomial model\r\n", "poly_pred <- poly_wf_fit %>% predict(new_data = hypo_tibble)\r\n", "\r\n", "# Return predictions in a list\r\n", "list(\"linear model prediction\" = lm_pred, \r\n", " \"polynomial model prediction\" = poly_pred)\r\n" ], "outputs": [], "metadata": { "id": "jRPSyfQGxuQv" } }, { "cell_type": "markdown", "source": [ "Prediktionen med `polynomial model` är rimlig, med tanke på spridningsdiagrammen för `price` och `package`! Och om detta är en bättre modell än den tidigare, baserat på samma data, behöver du planera för dessa dyrare pumpor!\n", "\n", "🏆 Bra jobbat! Du skapade två regressionsmodeller under en lektion. I den sista delen om regression kommer du att lära dig om logistisk regression för att bestämma kategorier.\n", "\n", "## **🚀Utmaning**\n", "\n", "Testa flera olika variabler i denna notebook för att se hur korrelationen påverkar modellens noggrannhet.\n", "\n", "## [**Quiz efter föreläsningen**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/14/)\n", "\n", "## **Granskning & Självstudier**\n", "\n", "I denna lektion lärde vi oss om linjär regression. Det finns andra viktiga typer av regression. Läs om Stepwise, Ridge, Lasso och Elasticnet-tekniker. En bra kurs att studera för att lära dig mer är [Stanford Statistical Learning course](https://online.stanford.edu/courses/sohs-ystatslearning-statistical-learning).\n", "\n", "Om du vill lära dig mer om hur du använder det fantastiska Tidymodels-ramverket, kolla in följande resurser:\n", "\n", "- Tidymodels webbplats: [Kom igång med Tidymodels](https://www.tidymodels.org/start/)\n", "\n", "- Max Kuhn och Julia Silge, [*Tidy Modeling with R*](https://www.tmwr.org/)*.*\n", "\n", "###### **TACK TILL:**\n", "\n", "[Allison Horst](https://twitter.com/allison_horst?lang=en) för att ha skapat de fantastiska illustrationerna som gör R mer välkomnande och engagerande. Hitta fler illustrationer i hennes [galleri](https://www.google.com/url?q=https://github.com/allisonhorst/stats-illustrations&sa=D&source=editors&ust=1626380772530000&usg=AOvVaw3zcfyCizFQZpkSLzxiiQEM).\n" ], "metadata": { "id": "8zOLOWqMxzk5" } }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n---\n\n**Ansvarsfriskrivning**: \nDetta dokument har översatts med hjälp av AI-översättningstjänsten [Co-op Translator](https://github.com/Azure/co-op-translator). Även om vi strävar efter noggrannhet, vänligen notera att automatiska översättningar kan innehålla fel eller felaktigheter. Det ursprungliga dokumentet på dess originalspråk bör betraktas som den auktoritativa källan. För kritisk information rekommenderas professionell mänsklig översättning. Vi ansvarar inte för eventuella missförstånd eller feltolkningar som uppstår vid användning av denna översättning.\n" ] } ] }