{ "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-03T19:23:07+00:00", "source_file": "2-Regression/3-Linear/solution/R/lesson_3-R.ipynb", "language_code": "pl" } }, "cells": [ { "cell_type": "markdown", "source": [], "metadata": { "id": "EgQw8osnsUV-" } }, { "cell_type": "markdown", "source": [ "## Regresja liniowa i wielomianowa w wycenie dyni - Lekcja 3\n", "

\n", " \n", "

Infografika autorstwa Dasani Madipalli
\n", "\n", "\n", "\n", "\n", "#### Wprowadzenie\n", "\n", "Do tej pory zapoznałeś się z pojęciem regresji, korzystając z przykładowych danych z zestawu dotyczącego wyceny dyni, który będziemy używać w tej lekcji. Zobrazowałeś je również za pomocą `ggplot2`. 💪\n", "\n", "Teraz jesteś gotowy, aby zagłębić się w temat regresji w kontekście uczenia maszynowego. W tej lekcji dowiesz się więcej o dwóch typach regresji: *podstawowej regresji liniowej* oraz *regresji wielomianowej*, a także o matematyce stojącej za tymi technikami.\n", "\n", "> W całym tym kursie zakładamy minimalną znajomość matematyki i staramy się uczynić ją przystępną dla studentów z innych dziedzin, dlatego zwracaj uwagę na notatki, 🧮 wskazówki, diagramy i inne narzędzia edukacyjne, które pomogą w zrozumieniu materiału.\n", "\n", "#### Przygotowanie\n", "\n", "Przypominając, wczytujesz te dane, aby móc zadawać im pytania.\n", "\n", "- Kiedy jest najlepszy czas na zakup dyni?\n", "\n", "- Jakiej ceny mogę się spodziewać za skrzynkę miniaturowych dyń?\n", "\n", "- Czy powinienem kupować je w koszach o pojemności pół buszla czy w pudełkach o pojemności 1 1/9 buszla? Zobaczmy, co jeszcze możemy odkryć w tych danych.\n", "\n", "W poprzedniej lekcji stworzyłeś `tibble` (nowoczesne podejście do ramek danych) i wypełniłeś go częścią oryginalnego zestawu danych, standaryzując ceny według buszla. Jednakże, w ten sposób udało Ci się zebrać jedynie około 400 punktów danych i tylko dla jesiennych miesięcy. Może uda nam się uzyskać więcej szczegółów na temat charakteru danych, jeśli je bardziej oczyścimy? Zobaczymy... 🕵️‍♀️\n", "\n", "Do tego zadania będziemy potrzebować następujących pakietów:\n", "\n", "- `tidyverse`: [tidyverse](https://www.tidyverse.org/) to [zbiór pakietów R](https://www.tidyverse.org/packages) zaprojektowany, aby uczynić analizę danych szybszą, łatwiejszą i bardziej przyjemną!\n", "\n", "- `tidymodels`: [tidymodels](https://www.tidymodels.org/) to [framework](https://www.tidymodels.org/packages/) składający się z pakietów do modelowania i uczenia maszynowego.\n", "\n", "- `janitor`: [pakiet janitor](https://github.com/sfirke/janitor) oferuje proste narzędzia do badania i czyszczenia \"brudnych\" danych.\n", "\n", "- `corrplot`: [pakiet corrplot](https://cran.r-project.org/web/packages/corrplot/vignettes/corrplot-intro.html) zapewnia wizualne narzędzie eksploracyjne dla macierzy korelacji, wspierające automatyczne porządkowanie zmiennych w celu wykrycia ukrytych wzorców między zmiennymi.\n", "\n", "Możesz je zainstalować za pomocą:\n", "\n", "`install.packages(c(\"tidyverse\", \"tidymodels\", \"janitor\", \"corrplot\"))`\n", "\n", "Poniższy skrypt sprawdza, czy masz zainstalowane wymagane pakiety do ukończenia tego modułu i instaluje je w razie ich braku.\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": [ "Załadujemy później te świetne pakiety i udostępnimy je w naszej bieżącej sesji R. (To tylko ilustracja, `pacman::p_load()` już to dla Ciebie zrobił)\n", "\n", "## 1. Linia regresji liniowej\n", "\n", "Jak nauczyłeś się w Lekcji 1, celem ćwiczenia regresji liniowej jest możliwość narysowania *linii* *najlepszego dopasowania*, aby:\n", "\n", "- **Pokazać zależności między zmiennymi**. Zobrazować relacje między zmiennymi.\n", "\n", "- **Dokonywać prognoz**. Dokonywać dokładnych prognoz, gdzie nowy punkt danych znajdzie się w odniesieniu do tej linii.\n", "\n", "Aby narysować tego typu linię, używamy techniki statystycznej zwanej **Regresją Metodą Najmniejszych Kwadratów**. Termin `najmniejsze kwadraty` oznacza, że wszystkie punkty danych otaczające linię regresji są podnoszone do kwadratu, a następnie sumowane. Idealnie, ta końcowa suma powinna być jak najmniejsza, ponieważ chcemy mieć jak najmniej błędów, czyli `najmniejsze kwadraty`. W związku z tym linia najlepszego dopasowania to linia, która daje nam najniższą wartość sumy kwadratów błędów - stąd nazwa *regresja metodą najmniejszych kwadratów*.\n", "\n", "Robimy to, ponieważ chcemy modelować linię, która ma najmniejszą skumulowaną odległość od wszystkich naszych punktów danych. Podnosimy wartości do kwadratu przed ich dodaniem, ponieważ interesuje nas ich wielkość, a nie kierunek.\n", "\n", "> **🧮 Pokaż mi matematykę**\n", ">\n", "> Ta linia, zwana *linią najlepszego dopasowania*, może być wyrażona za pomocą [równania](https://en.wikipedia.org/wiki/Simple_linear_regression):\n", ">\n", "> Y = a + bX\n", ">\n", "> `X` to '`zmienna objaśniająca` lub `predyktor`'. `Y` to '`zmienna zależna` lub `wynik`'. Nachylenie linii to `b`, a `a` to punkt przecięcia z osią Y, który odnosi się do wartości `Y`, gdy `X = 0`.\n", ">\n", "\n", "> ![](../../../../../../2-Regression/3-Linear/solution/images/slope.png \"nachylenie = $y/x$\")\n", " Infografika autorstwa Jen Looper\n", ">\n", "> Najpierw oblicz nachylenie `b`.\n", ">\n", "> Innymi słowy, odnosząc się do pierwotnego pytania dotyczącego danych o dyniach: \"przewidzieć cenę dyni za buszel w zależności od miesiąca\", `X` odnosiłoby się do ceny, a `Y` do miesiąca sprzedaży.\n", ">\n", "> ![](../../../../../../translated_images/calculation.989aa7822020d9d0ba9fc781f1ab5192f3421be86ebb88026528aef33c37b0d8.pl.png)\n", " Infografika autorstwa Jen Looper\n", "> \n", "> Oblicz wartość Y. Jeśli płacisz około 4$, to musi być kwiecień!\n", ">\n", "> Matematyka, która oblicza linię, musi uwzględniać nachylenie linii, które również zależy od punktu przecięcia, czyli miejsca, gdzie `Y` znajduje się, gdy `X = 0`.\n", ">\n", "> Możesz zobaczyć metodę obliczania tych wartości na stronie [Math is Fun](https://www.mathsisfun.com/data/least-squares-regression.html). Odwiedź również [ten kalkulator regresji metodą najmniejszych kwadratów](https://www.mathsisfun.com/data/least-squares-calculator.html), aby zobaczyć, jak wartości liczb wpływają na linię.\n", "\n", "Nie takie straszne, prawda? 🤓\n", "\n", "#### Korelacja\n", "\n", "Jeszcze jedno pojęcie do zrozumienia to **Współczynnik Korelacji** między danymi zmiennymi X i Y. Korzystając z wykresu punktowego, możesz szybko zobrazować ten współczynnik. Wykres z punktami danych ułożonymi w schludną linię ma wysoką korelację, ale wykres z punktami danych rozrzuconymi wszędzie między X i Y ma niską korelację.\n", "\n", "Dobry model regresji liniowej to taki, który ma wysoki (bliższy 1 niż 0) Współczynnik Korelacji, korzystając z metody regresji metodą najmniejszych kwadratów z linią regresji.\n" ], "metadata": { "id": "cdX5FRpvsoP5" } }, { "cell_type": "markdown", "source": [ "## **2. Taniec z danymi: tworzenie ramki danych do modelowania**\n", "\n", "

\n", " \n", "

Grafika autorstwa @allison_horst
\n", "\n", "\n", "\n" ], "metadata": { "id": "WdUKXk7Bs8-V" } }, { "cell_type": "markdown", "source": [ "Załaduj wymagane biblioteki i zestaw danych. Przekształć dane w ramkę danych zawierającą podzbiór danych:\n", "\n", "- Uwzględnij tylko dynie wyceniane na podstawie buszla\n", "\n", "- Przekształć datę na miesiąc\n", "\n", "- Oblicz cenę jako średnią cen wysokich i niskich\n", "\n", "- Przekształć cenę, aby odzwierciedlała wycenę według ilości buszli\n", "\n", "> Omówiliśmy te kroki w [poprzedniej lekcji](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": [ "W duchu czystej przygody, przyjrzyjmy się [`pakietowi janitor`](../../../../../../2-Regression/3-Linear/solution/R/github.com/sfirke/janitor), który oferuje proste funkcje do badania i czyszczenia brudnych danych. Na przykład, spójrzmy na nazwy kolumn w naszych danych:\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": [ "🤔 Możemy zrobić to lepiej. Zmieńmy nazwy tych kolumn na `friendR`, konwertując je na konwencję [snake_case](https://en.wikipedia.org/wiki/Snake_case) za pomocą `janitor::clean_names`. Aby dowiedzieć się więcej o tej funkcji: `?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": [ "Dużo porządku 🧹! Teraz taniec z danymi przy użyciu `dplyr`, tak jak w poprzedniej lekcji! 💃\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": [ "Dobra robota!👌 Masz teraz czysty, uporządkowany zestaw danych, na którym możesz oprzeć swój nowy model regresji!\n", "\n", "Co powiesz na wykres punktowy?\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": [ "Wykres punktowy przypomina nam, że posiadamy dane miesięczne tylko od sierpnia do grudnia. Prawdopodobnie potrzebujemy więcej danych, aby móc wyciągać wnioski w sposób liniowy.\n", "\n", "Spójrzmy ponownie na nasze dane modelowe:\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": [ "Co jeśli chcielibyśmy przewidzieć `cenę` dyni na podstawie kolumn `miasto` lub `opakowanie`, które są typu znakowego? A nawet bardziej podstawowo, jak moglibyśmy znaleźć korelację (która wymaga, aby oba jej wejścia były numeryczne) między, na przykład, `opakowaniem` a `ceną`? 🤷🤷\n", "\n", "Modele uczenia maszynowego najlepiej działają z cechami numerycznymi, a nie wartościami tekstowymi, więc zazwyczaj trzeba przekształcić cechy kategoryczne w reprezentacje numeryczne.\n", "\n", "Oznacza to, że musimy znaleźć sposób na przekształcenie naszych predyktorów, aby były bardziej użyteczne dla modelu, proces ten nazywany jest `inżynierią cech`.\n" ], "metadata": { "id": "7hsHoxsStyjJ" } }, { "cell_type": "markdown", "source": [ "## 3. Przygotowanie danych do modelowania za pomocą recipes 👩‍🍳👨‍🍳\n", "\n", "Działania, które przekształcają wartości predyktorów, aby model mógł je skuteczniej wykorzystać, nazywane są `inżynierią cech`.\n", "\n", "Różne modele mają różne wymagania dotyczące przetwarzania danych. Na przykład metoda najmniejszych kwadratów wymaga `kodowania zmiennych kategorycznych`, takich jak miesiąc, odmiana czy city_name. Polega to na `przekształceniu` kolumny z `wartościami kategorycznymi` w jedną lub więcej `kolumn numerycznych`, które zastępują oryginalną kolumnę.\n", "\n", "Na przykład, jeśli Twoje dane zawierają następującą cechę kategoryczną:\n", "\n", "| miasto |\n", "|:---------:|\n", "| Denver |\n", "| Nairobi |\n", "| Tokio |\n", "\n", "Możesz zastosować *kodowanie porządkowe*, aby zastąpić każdą kategorię unikalną wartością całkowitą, tak jak tutaj:\n", "\n", "| miasto |\n", "|:------:|\n", "| 0 |\n", "| 1 |\n", "| 2 |\n", "\n", "I właśnie to zrobimy z naszymi danymi!\n", "\n", "W tej sekcji przyjrzymy się kolejnemu niesamowitemu pakietowi Tidymodels: [recipes](https://tidymodels.github.io/recipes/) - który został zaprojektowany, aby pomóc w przetwarzaniu danych **przed** trenowaniem modelu. W swojej istocie, recipe to obiekt, który definiuje, jakie kroki należy zastosować do zestawu danych, aby przygotować go do modelowania.\n", "\n", "Teraz stwórzmy recipe, która przygotuje nasze dane do modelowania, zastępując unikalną wartością całkowitą wszystkie obserwacje w kolumnach predyktorów:\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": [ "Super! 👏 Właśnie stworzyliśmy nasz pierwszy przepis, który określa wynik (cena) oraz odpowiadające mu predyktory, a także to, że wszystkie kolumny predyktorów powinny być zakodowane jako zestaw liczb całkowitych 🙌! Szybko to rozłóżmy na części:\n", "\n", "- Wywołanie `recipe()` z formułą informuje przepis o *rolach* zmiennych, używając danych `new_pumpkins` jako odniesienia. Na przykład kolumna `price` została przypisana do roli `outcome`, podczas gdy pozostałe kolumny zostały przypisane do roli `predictor`.\n", "\n", "- `step_integer(all_predictors(), zero_based = TRUE)` określa, że wszystkie predyktory powinny zostać przekształcone w zestaw liczb całkowitych, zaczynając od numeracji 0.\n", "\n", "Jesteśmy pewni, że możesz mieć takie myśli jak: \"To jest takie świetne!! Ale co jeśli chciałbym upewnić się, że przepisy robią dokładnie to, czego od nich oczekuję? 🤔\"\n", "\n", "To świetna myśl! Widzisz, gdy Twój przepis jest zdefiniowany, możesz oszacować parametry potrzebne do faktycznego przetworzenia danych, a następnie wyodrębnić przetworzone dane. Zazwyczaj nie musisz tego robić, gdy używasz Tidymodels (zaraz zobaczymy normalną konwencję -\\> `workflows`), ale może się to przydać, gdy chcesz przeprowadzić pewnego rodzaju kontrolę poprawności, aby upewnić się, że przepisy działają zgodnie z oczekiwaniami.\n", "\n", "Do tego potrzebujesz dwóch dodatkowych czasowników: `prep()` i `bake()`, a jak zawsze, nasi mali przyjaciele z R od [`Allison Horst`](https://github.com/allisonhorst/stats-illustrations) pomogą Ci lepiej to zrozumieć!\n", "\n", "

\n", " \n", "

Ilustracja autorstwa @allison_horst
\n" ], "metadata": { "id": "KEiO0v7kuC9O" } }, { "cell_type": "markdown", "source": [ "[`prep()`](https://recipes.tidymodels.org/reference/prep.html): szacuje wymagane parametry na podstawie zestawu treningowego, które później mogą być zastosowane do innych zestawów danych. Na przykład, dla danej kolumny predyktora, które obserwacje zostaną przypisane jako liczba całkowita 0, 1, 2 itd.\n", "\n", "[`bake()`](https://recipes.tidymodels.org/reference/bake.html): bierze przygotowany przepis i stosuje operacje do dowolnego zestawu danych.\n", "\n", "Mając to na uwadze, przygotujmy i zastosujmy nasze przepisy, aby naprawdę potwierdzić, że w tle kolumny predyktorów zostaną najpierw zakodowane, zanim model zostanie dopasowany.\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": [ "Hurra! 🥳 Przetworzone dane `baked_pumpkins` mają wszystkie predyktory zakodowane, co potwierdza, że kroki przetwarzania wstępnego zdefiniowane w naszym przepisie działają zgodnie z oczekiwaniami. Może to być trudniejsze do odczytania dla Ciebie, ale za to znacznie bardziej zrozumiałe dla Tidymodels! Poświęć chwilę, aby sprawdzić, która obserwacja została przypisana do odpowiedniej liczby całkowitej.\n", "\n", "Warto również wspomnieć, że `baked_pumpkins` to ramka danych, na której możemy wykonywać obliczenia.\n", "\n", "Na przykład spróbujmy znaleźć dobrą korelację między dwoma punktami w Twoich danych, aby potencjalnie zbudować dobry model predykcyjny. Użyjemy do tego funkcji `cor()`. Wpisz `?cor()`, aby dowiedzieć się więcej o tej funkcji.\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": [ "Jak się okazuje, istnieje tylko słaba korelacja między Miastem a Ceną. Jednakże, korelacja między Opakowaniem a jego Ceną jest nieco lepsza. To ma sens, prawda? Zazwyczaj, im większe pudełko z produktami, tym wyższa cena.\n", "\n", "Skoro już o tym mowa, spróbujmy również zwizualizować macierz korelacji wszystkich kolumn za pomocą pakietu `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": [ "🤩🤩 O wiele lepiej.\n", "\n", "Dobre pytanie, które teraz można zadać na podstawie tych danych, to: '`Jakiej ceny mogę się spodziewać za dany pakiet dyni?`' Przejdźmy od razu do rzeczy!\n", "\n", "> Uwaga: Kiedy **`bake()`** wykonujesz na przygotowanym przepisie **`pumpkins_prep`** z **`new_data = NULL`**, uzyskujesz przetworzone (tj. zakodowane) dane treningowe. Jeśli miałbyś inny zbiór danych, na przykład zbiór testowy, i chciałbyś zobaczyć, jak przepis go przetworzy, wystarczyłoby wykonać **`bake()`** na **`pumpkins_prep`** z **`new_data = test_set`**.\n", "\n", "## 4. Zbuduj model regresji liniowej\n", "\n", "

\n", " \n", "

Infografika autorstwa Dasani Madipalli
\n", "\n", "\n", "\n" ], "metadata": { "id": "YqXjLuWavNxW" } }, { "cell_type": "markdown", "source": [ "Teraz, gdy stworzyliśmy przepis i faktycznie potwierdziliśmy, że dane będą odpowiednio przetwarzane wstępnie, zbudujmy model regresji, aby odpowiedzieć na pytanie: `Jakiej ceny mogę się spodziewać dla danego opakowania dyni?`\n", "\n", "#### Wytrenuj model regresji liniowej na zbiorze treningowym\n", "\n", "Jak zapewne już zauważyłeś, kolumna *price* jest zmienną `wynikową`, podczas gdy kolumna *package* jest zmienną `predyktorem`.\n", "\n", "Aby to zrobić, najpierw podzielimy dane tak, aby 80% trafiło do zbioru treningowego, a 20% do zbioru testowego. Następnie zdefiniujemy przepis, który zakoduje kolumnę predyktora jako zestaw liczb całkowitych, a potem stworzymy specyfikację modelu. Nie będziemy przygotowywać i piec naszego przepisu, ponieważ już wiemy, że odpowiednio przetworzy dane.\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": [ "Świetna robota! Teraz, gdy mamy przepis i specyfikację modelu, musimy znaleźć sposób na połączenie ich w jeden obiekt, który najpierw wstępnie przetworzy dane (prep+bake za kulisami), dopasuje model do wstępnie przetworzonych danych, a także umożliwi ewentualne działania post-processingowe. Jak to brzmi dla Twojego spokoju ducha!🤩\n", "\n", "W Tidymodels ten wygodny obiekt nazywa się [`workflow`](https://workflows.tidymodels.org/) i przechowuje wszystkie komponenty modelowania w jednym miejscu! To jest to, co w *Pythonie* nazywamy *pipelines*.\n", "\n", "Więc połączmy wszystko w 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": [ "Na dodatek, przepływ pracy można dopasować/szkolić w bardzo podobny sposób, jak model.\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": [ "Z wyników modelu możemy zobaczyć współczynniki wyuczone podczas treningu. Reprezentują one współczynniki linii najlepszego dopasowania, która daje nam najniższy ogólny błąd między rzeczywistą a przewidywaną zmienną.\n", "\n", "\n", "#### Ocena wydajności modelu za pomocą zestawu testowego\n", "\n", "Czas sprawdzić, jak model sobie poradził 📏! Jak to zrobić?\n", "\n", "Teraz, gdy wytrenowaliśmy model, możemy go użyć do przewidywania dla test_set za pomocą `parsnip::predict()`. Następnie możemy porównać te przewidywania z rzeczywistymi wartościami etykiet, aby ocenić, jak dobrze (lub nie!) działa model.\n", "\n", "Zacznijmy od przewidywania dla zestawu testowego, a następnie połączmy kolumny z zestawem testowym.\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": [ "Tak, właśnie wytrenowałeś model i użyłeś go do przewidywań! 🔮 Czy jest dobry? Sprawdźmy, jak działa nasz model!\n", "\n", "W Tidymodels robimy to za pomocą `yardstick::metrics()`! W przypadku regresji liniowej skupmy się na następujących metrykach:\n", "\n", "- `Root Mean Square Error (RMSE)`: Pierwiastek kwadratowy z [MSE](https://en.wikipedia.org/wiki/Mean_squared_error). Daje to absolutną miarę w tej samej jednostce co etykieta (w tym przypadku cena dyni). Im mniejsza wartość, tym lepszy model (w uproszczeniu, reprezentuje średnią wartość, o którą przewidywania są błędne!).\n", "\n", "- `Coefficient of Determination (często nazywany R-kwadrat lub R2)`: Względna miara, w której wyższa wartość oznacza lepsze dopasowanie modelu. W istocie ta metryka pokazuje, jak dużą część zmienności między przewidywanymi a rzeczywistymi wartościami etykiety model jest w stanie wyjaśnić.\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": [ "Tam idzie wydajność modelu. Zobaczmy, czy możemy uzyskać lepszy obraz, wizualizując wykres punktowy przedstawiający pakiet i cenę, a następnie używając przewidywań do nałożenia linii najlepszego dopasowania.\n", "\n", "Oznacza to, że będziemy musieli przygotować i przetworzyć zestaw testowy, aby zakodować kolumnę pakietu, a następnie połączyć to z przewidywaniami naszego modelu.\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": [ "Świetnie! Jak widać, model regresji liniowej niezbyt dobrze uogólnia zależność między opakowaniem a jego odpowiadającą ceną.\n", "\n", "🎃 Gratulacje, właśnie stworzyłeś model, który może pomóc przewidzieć cenę kilku odmian dyń. Twoja świąteczna dyniowa grządka będzie piękna. Ale prawdopodobnie możesz stworzyć lepszy model!\n", "\n", "## 5. Zbuduj model regresji wielomianowej\n", "\n", "

\n", " \n", "

Infografika autorstwa Dasani Madipalli
\n", "\n", "\n", "\n" ], "metadata": { "id": "HOCqJXLTwtWI" } }, { "cell_type": "markdown", "source": [ "Czasami nasze dane mogą nie mieć liniowej zależności, ale mimo to chcemy przewidzieć wynik. Regresja wielomianowa może pomóc nam w przewidywaniu bardziej złożonych, nieliniowych zależności.\n", "\n", "Weźmy na przykład zależność między opakowaniem a ceną w naszym zestawie danych o dyniach. Chociaż czasami istnieje liniowa zależność między zmiennymi - im większa dynia pod względem objętości, tym wyższa cena - czasami tych zależności nie da się przedstawić jako płaszczyznę lub prostą linię.\n", "\n", "> ✅ Oto [kilka innych przykładów](https://online.stat.psu.edu/stat501/lesson/9/9.8) danych, które mogą korzystać z regresji wielomianowej\n", ">\n", "> Spójrz jeszcze raz na zależność między odmianą a ceną na wcześniejszym wykresie. Czy ten wykres punktowy wydaje się być koniecznie analizowany za pomocą prostej linii? Być może nie. W takim przypadku możesz spróbować regresji wielomianowej.\n", ">\n", "> ✅ Wielomiany to wyrażenia matematyczne, które mogą składać się z jednej lub więcej zmiennych i współczynników\n", "\n", "#### Wytrenuj model regresji wielomianowej na zbiorze treningowym\n", "\n", "Regresja wielomianowa tworzy *zakrzywioną linię*, aby lepiej dopasować dane nieliniowe.\n", "\n", "Sprawdźmy, czy model wielomianowy będzie lepiej przewidywał wyniki. Postępujemy według podobnej procedury jak wcześniej:\n", "\n", "- Utwórz przepis, który określa kroki wstępnego przetwarzania danych, aby przygotować je do modelowania, np. kodowanie predyktorów i obliczanie wielomianów stopnia *n*\n", "\n", "- Zbuduj specyfikację modelu\n", "\n", "- Połącz przepis i specyfikację modelu w jeden przepływ pracy\n", "\n", "- Utwórz model, dopasowując przepływ pracy\n", "\n", "- Oceń, jak dobrze model działa na danych testowych\n", "\n", "Zaczynajmy!\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": [ "#### Ocena wydajności modelu\n", "\n", "👏👏Stworzyłeś model wielomianowy, teraz czas na przewidywania na zestawie testowym!\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": [ "Hurra, oceńmy, jak model wypadł na testowym zestawie danych, używając `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": [ "🤩🤩 Znacznie lepsza wydajność.\n", "\n", "`rmse` zmniejszyło się z około 7 do około 3, co wskazuje na mniejszy błąd między rzeczywistą ceną a przewidywaną ceną. Można to *luźno* interpretować jako średni błąd prognoz wynoszący około 3 USD. `rsq` wzrosło z około 0.4 do 0.8.\n", "\n", "Wszystkie te wskaźniki pokazują, że model wielomianowy działa znacznie lepiej niż model liniowy. Świetna robota!\n", "\n", "Zobaczmy, czy możemy to zwizualizować!\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": [ "Widać krzywą, która lepiej dopasowuje się do Twoich danych! 🤩\n", "\n", "Możesz ją wygładzić, przekazując formułę wielomianową do `geom_smooth`, na przykład tak:\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": [ "Podobnie jak gładka krzywa!🤩\n", "\n", "Oto jak możesz dokonać nowej prognozy:\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": [ "Predykcja za pomocą `modelu wielomianowego` ma sens, biorąc pod uwagę wykresy rozrzutu dla `price` i `package`! A jeśli ten model jest lepszy od poprzedniego, patrząc na te same dane, musisz uwzględnić budżet na te droższe dynie!\n", "\n", "🏆 Brawo! Stworzyłeś dwa modele regresji w jednej lekcji. W ostatniej części dotyczącej regresji nauczysz się o regresji logistycznej, aby określać kategorie.\n", "\n", "## **🚀Wyzwanie**\n", "\n", "Przetestuj kilka różnych zmiennych w tym notebooku, aby zobaczyć, jak korelacja wpływa na dokładność modelu.\n", "\n", "## [**Quiz po wykładzie**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/14/)\n", "\n", "## **Przegląd i samodzielna nauka**\n", "\n", "W tej lekcji nauczyliśmy się o regresji liniowej. Istnieją inne ważne rodzaje regresji. Przeczytaj o technikach Stepwise, Ridge, Lasso i Elasticnet. Dobrym kursem do nauki w celu zgłębienia tematu jest [Stanford Statistical Learning course](https://online.stanford.edu/courses/sohs-ystatslearning-statistical-learning).\n", "\n", "Jeśli chcesz dowiedzieć się więcej o korzystaniu z niesamowitego frameworka Tidymodels, sprawdź poniższe zasoby:\n", "\n", "- Strona Tidymodels: [Rozpocznij pracę z Tidymodels](https://www.tidymodels.org/start/)\n", "\n", "- Max Kuhn i Julia Silge, [*Tidy Modeling with R*](https://www.tmwr.org/)*.*\n", "\n", "###### **PODZIĘKOWANIA DLA:**\n", "\n", "[Allison Horst](https://twitter.com/allison_horst?lang=en) za stworzenie niesamowitych ilustracji, które sprawiają, że R jest bardziej przyjazne i angażujące. Znajdź więcej ilustracji w jej [galerii](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**Zastrzeżenie**: \nTen dokument został przetłumaczony za pomocą usługi tłumaczenia AI [Co-op Translator](https://github.com/Azure/co-op-translator). Chociaż dokładamy wszelkich starań, aby tłumaczenie było precyzyjne, prosimy pamiętać, że automatyczne tłumaczenia mogą zawierać błędy lub nieścisłości. Oryginalny dokument w jego rodzimym języku powinien być uznawany za źródło autorytatywne. W przypadku informacji o kluczowym znaczeniu zaleca się skorzystanie z profesjonalnego tłumaczenia przez człowieka. Nie ponosimy odpowiedzialności za jakiekolwiek nieporozumienia lub błędne interpretacje wynikające z użycia tego tłumaczenia.\n" ] } ] }