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.
ML-For-Beginners/translations/bg/2-Regression/3-Linear/solution/R/lesson_3-R.ipynb

1086 lines
57 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

{
"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-04T06:24:28+00:00",
"source_file": "2-Regression/3-Linear/solution/R/lesson_3-R.ipynb",
"language_code": "bg"
}
},
"cells": [
{
"cell_type": "markdown",
"source": [
"# Създайте регресионен модел: линейни и полиномиални регресионни модели\n"
],
"metadata": {
"id": "EgQw8osnsUV-"
}
},
{
"cell_type": "markdown",
"source": [
"## Линейна и полиномиална регресия за ценообразуване на тикви - Урок 3\n",
"<p >\n",
" <img src=\"../../images/linear-polynomial.png\"\n",
" width=\"800\"/>\n",
" <figcaption>Инфографика от Дасани Мадипали</figcaption>\n",
"\n",
"\n",
"#### Въведение\n",
"\n",
"Досега разгледахте какво представлява регресията с примерни данни, събрани от набора с данни за ценообразуване на тикви, който ще използваме през целия този урок. Също така го визуализирахте с помощта на `ggplot2`. 💪\n",
"\n",
"Сега сте готови да се задълбочите в регресията за машинно обучение. В този урок ще научите повече за два типа регресия: *основна линейна регресия* и *полиномиална регресия*, както и за част от математиката, която стои зад тези техники.\n",
"\n",
"> В рамките на тази учебна програма предполагаме минимални познания по математика и се стремим да я направим достъпна за студенти от други области, така че следете за бележки, 🧮 подсказки, диаграми и други учебни инструменти, които да помогнат за разбирането.\n",
"\n",
"#### Подготовка\n",
"\n",
"Като напомняне, зареждате тези данни, за да задавате въпроси към тях.\n",
"\n",
"- Кога е най-доброто време за купуване на тикви?\n",
"\n",
"- Каква цена мога да очаквам за кутия с миниатюрни тикви?\n",
"\n",
"- Трябва ли да ги купувам в кошници с половин бушел или в кутии с 1 1/9 бушел? Нека продължим да изследваме тези данни.\n",
"\n",
"В предишния урок създадохте `tibble` (съвременна преосмислена версия на рамка за данни) и го попълнихте с част от оригиналния набор от данни, стандартизирайки цените по бушел. С това обаче успяхте да съберете само около 400 точки данни и само за есенните месеци. Може би можем да получим малко повече подробности за естеството на данните, като ги почистим повече? Ще видим... 🕵️‍♀️\n",
"\n",
"За тази задача ще ни трябват следните пакети:\n",
"\n",
"- `tidyverse`: [tidyverse](https://www.tidyverse.org/) е [колекция от R пакети](https://www.tidyverse.org/packages), създадена да направи науката за данни по-бърза, лесна и забавна!\n",
"\n",
"- `tidymodels`: [tidymodels](https://www.tidymodels.org/) е рамка, представляваща [колекция от пакети](https://www.tidymodels.org/packages/) за моделиране и машинно обучение.\n",
"\n",
"- `janitor`: [janitor](https://github.com/sfirke/janitor) предоставя прости инструменти за изследване и почистване на \"мръсни\" данни.\n",
"\n",
"- `corrplot`: [corrplot](https://cran.r-project.org/web/packages/corrplot/vignettes/corrplot-intro.html) предлага визуален инструмент за изследване на матрици на корелация, който поддържа автоматично пренареждане на променливите, за да помогне за откриване на скрити модели между тях.\n",
"\n",
"Можете да ги инсталирате със следната команда:\n",
"\n",
"`install.packages(c(\"tidyverse\", \"tidymodels\", \"janitor\", \"corrplot\"))`\n",
"\n",
"Скриптът по-долу проверява дали имате необходимите пакети за завършване на този модул и ги инсталира, ако липсват.\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": [
"Ще заредим тези страхотни пакети и ще ги направим достъпни в текущата R сесия. (Това е само за илюстрация, `pacman::p_load()` вече го направи за вас)\n",
"\n",
"## 1. Линия на линейна регресия\n",
"\n",
"Както научихте в Урок 1, целта на упражнението по линейна регресия е да начертаете *линия* *на* *най-добро съответствие*, за да:\n",
"\n",
"- **Покажете връзките между променливите**. Демонстрирайте връзката между променливите.\n",
"\n",
"- **Направите прогнози**. Направете точни прогнози за това къде нова точка от данни би попаднала спрямо тази линия.\n",
"\n",
"За да начертаем този тип линия, използваме статистическа техника, наречена **Регресия на най-малките квадрати**. Терминът `най-малки квадрати` означава, че всички точки от данни около регресионната линия се повдигат на квадрат и след това се сумират. Идеално, тази крайна сума трябва да бъде възможно най-малка, защото искаме нисък брой грешки, или `най-малки квадрати`. Следователно, линията на най-добро съответствие е линията, която ни дава най-ниската стойност за сумата на квадратите на грешките - оттук и името *регресия на най-малките квадрати*.\n",
"\n",
"Правим това, защото искаме да моделираме линия, която има най-малко кумулативно разстояние от всички наши точки от данни. Освен това повдигаме на квадрат стойностите преди да ги сумираме, защото се интересуваме от тяхната величина, а не от посоката им.\n",
"\n",
"> **🧮 Покажете ми математиката**\n",
">\n",
"> Тази линия, наречена *линия на най-добро съответствие*, може да бъде изразена чрез [уравнение](https://en.wikipedia.org/wiki/Simple_linear_regression):\n",
">\n",
"> Y = a + bX\n",
">\n",
"> `X` е '`обяснителна променлива` или `предиктор`'. `Y` е '`зависима променлива` или `резултат`'. Наклонът на линията е `b`, а `a` е пресечната точка с оста Y, която се отнася до стойността на `Y`, когато `X = 0`.\n",
">\n",
"\n",
"> ![](../../../../../../2-Regression/3-Linear/solution/images/slope.png \"наклон = $y/x$\")\n",
" Инфографика от Jen Looper\n",
">\n",
"> Първо, изчислете наклона `b`.\n",
">\n",
"> С други думи, и като се позоваваме на оригиналния въпрос за данните за тиквите: \"предскажете цената на тиква на бушел по месеци\", `X` би се отнасял до цената, а `Y` би се отнасял до месеца на продажба.\n",
">\n",
"> ![](../../../../../../2-Regression/3-Linear/solution/images/calculation.png)\n",
" Инфографика от Jen Looper\n",
"> \n",
"> Изчислете стойността на Y. Ако плащате около \\$4, значи е април!\n",
">\n",
"> Математиката, която изчислява линията, трябва да демонстрира наклона на линията, който също зависи от пресечната точка, или къде се намира `Y`, когато `X = 0`.\n",
">\n",
"> Можете да наблюдавате метода за изчисление на тези стойности на уебсайта [Math is Fun](https://www.mathsisfun.com/data/least-squares-regression.html). Също така посетете [този калкулатор за най-малки квадрати](https://www.mathsisfun.com/data/least-squares-calculator.html), за да видите как стойностите на числата влияят на линията.\n",
"\n",
"Не е толкова страшно, нали? 🤓\n",
"\n",
"#### Корелация\n",
"\n",
"Още един термин, който трябва да разберете, е **Коефициентът на корелация** между дадените X и Y променливи. С помощта на диаграма с разпръснати точки можете бързо да визуализирате този коефициент. Диаграма с точки, разположени в подредена линия, има висока корелация, но диаграма с точки, разпръснати навсякъде между X и Y, има ниска корелация.\n",
"\n",
"Добър модел на линейна регресия ще бъде този, който има висок (по-близо до 1, отколкото до 0) коефициент на корелация, използвайки метода на регресия на най-малките квадрати с линия на регресия.\n"
],
"metadata": {
"id": "cdX5FRpvsoP5"
}
},
{
"cell_type": "markdown",
"source": [
"## **2. Танц с данните: създаване на датафрейм за моделиране**\n",
"\n",
"<p >\n",
" <img src=\"../../images/janitor.jpg\"\n",
" width=\"700\"/>\n",
" <figcaption>Илюстрация от @allison_horst</figcaption>\n",
"\n",
"\n",
"<!--![Илюстрация от \\@allison_horst](../../../../../../2-Regression/3-Linear/images/janitor.jpg){width=\"700\"}-->\n"
],
"metadata": {
"id": "WdUKXk7Bs8-V"
}
},
{
"cell_type": "markdown",
"source": [
"Заредете необходимите библиотеки и набора от данни. Преобразувайте данните в дата фрейм, съдържащ подмножество от данните:\n",
"\n",
"- Вземете само тикви, оценени на цена за бушел\n",
"\n",
"- Преобразувайте датата в месец\n",
"\n",
"- Изчислете цената като средна стойност между високата и ниската цена\n",
"\n",
"- Преобразувайте цената, за да отразява ценообразуването според количеството в бушел\n",
"\n",
"> Покрихме тези стъпки в [предишния урок](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": [
"В духа на чистото приключение, нека изследваме [`janitor package`](../../../../../../2-Regression/3-Linear/solution/R/github.com/sfirke/janitor), който предоставя прости функции за изследване и почистване на замърсени данни. Например, нека разгледаме имената на колоните за нашите данни:\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": [
"🤔 Можем да се справим по-добре. Нека направим тези имена на колони `friendR`, като ги преобразуваме към конвенцията [snake_case](https://en.wikipedia.org/wiki/Snake_case), използвайки `janitor::clean_names`. За да научите повече за тази функция: `?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": [
"Много tidyR 🧹! Сега, танц с данните, използвайки `dplyr`, както в предишния урок! 💃\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": [
"Добра работа!👌 Сега разполагате с чист и подреден набор от данни, върху който можете да изградите новия си регресионен модел!\n",
"\n",
"Какво ще кажете за диаграма на разсейване?\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": [
"Диаграмата с разпръснати точки ни напомня, че разполагаме с данни само за месеците от август до декември. Вероятно ще ни трябват повече данни, за да можем да правим изводи по линеен начин.\n",
"\n",
"Нека отново разгледаме нашите данни за моделиране:\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": [
"Какво би станало, ако искахме да предвидим `цената` на тиква въз основа на колоните `град` или `опаковка`, които са от тип символен? Или още по-просто, как бихме могли да намерим корелацията (която изисква и двата входа да бъдат числови) между, например, `опаковка` и `цена`? 🤷🤷\n",
"\n",
"Моделите за машинно обучение работят най-добре с числови характеристики, а не с текстови стойности, така че обикновено трябва да преобразувате категориалните характеристики в числови представяния.\n",
"\n",
"Това означава, че трябва да намерим начин да преформатираме нашите предиктори, за да ги направим по-лесни за използване от модела, процес, известен като `инженеринг на характеристики`.\n"
],
"metadata": {
"id": "7hsHoxsStyjJ"
}
},
{
"cell_type": "markdown",
"source": [
"## 3. Предварителна обработка на данни за моделиране с recipes 👩‍🍳👨‍🍳\n",
"\n",
"Дейностите, които преформатират стойностите на предикторите, за да ги направят по-лесни за ефективно използване от модела, се наричат `feature engineering` (инженеринг на характеристики).\n",
"\n",
"Различните модели имат различни изисквания за предварителна обработка. Например, методът на най-малките квадрати изисква `кодиране на категорийни променливи`, като месец, сорт и име на град. Това включва просто `превръщане` на колона с `категорийни стойности` в една или повече `числови колони`, които заместват оригиналната.\n",
"\n",
"Например, да предположим, че вашите данни включват следната категорийна характеристика:\n",
"\n",
"| град |\n",
"|:-------:|\n",
"| Денвър |\n",
"| Найроби |\n",
"| Токио |\n",
"\n",
"Можете да приложите *ординално кодиране*, за да замените всяка категория с уникална целочислена стойност, ето така:\n",
"\n",
"| град |\n",
"|:----:|\n",
"| 0 |\n",
"| 1 |\n",
"| 2 |\n",
"\n",
"И точно това ще направим с нашите данни!\n",
"\n",
"В тази секция ще разгледаме още един невероятен пакет от Tidymodels: [recipes](https://tidymodels.github.io/recipes/) - който е създаден, за да ви помогне да подготвите данните си **преди** обучението на модела. В основата си, рецептата е обект, който определя какви стъпки трябва да бъдат приложени към даден набор от данни, за да бъде готов за моделиране.\n",
"\n",
"Сега, нека създадем рецепта, която подготвя нашите данни за моделиране, като заменя всички наблюдения в колоните на предикторите с уникални цели числа:\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": [
"Страхотно! 👏 Току-що създадохме първата си рецепта, която определя резултат (цена) и съответните предиктори, като всички колони с предиктори трябва да бъдат кодирани като набор от цели числа 🙌! Нека бързо да я разгледаме:\n",
"\n",
"- Извикването на `recipe()` с формула указва на рецептата *ролите* на променливите, използвайки данните от `new_pumpkins` като референция. Например, колоната `price` е определена с роля `outcome`, докато останалите колони са определени с роля `predictor`.\n",
"\n",
"- `step_integer(all_predictors(), zero_based = TRUE)` указва, че всички предиктори трябва да бъдат преобразувани в набор от цели числа, като номерирането започва от 0.\n",
"\n",
"Сигурни сме, че може би си мислите: \"Това е толкова готино!! Но какво ако трябва да се уверя, че рецептите правят точно това, което очаквам? 🤔\"\n",
"\n",
"Това е страхотна мисъл! Виждате ли, след като рецептата е дефинирана, можете да изчислите параметрите, необходими за действителната предварителна обработка на данните, и след това да извлечете обработените данни. Обикновено не е необходимо да правите това, когато използвате Tidymodels (ще видим нормалната конвенция след малко -> `workflows`), но може да бъде полезно, когато искате да направите проверка за потвърждение, че рецептите правят това, което очаквате.\n",
"\n",
"За това ще ви трябват още два глагола: `prep()` и `bake()`, а както винаги, нашите малки приятели от R, създадени от [`Allison Horst`](https://github.com/allisonhorst/stats-illustrations), ще ви помогнат да разберете това по-добре!\n",
"\n",
"<p >\n",
" <img src=\"../../images/recipes.png\"\n",
" width=\"550\"/>\n",
" <figcaption>Илюстрация от @allison_horst</figcaption>\n"
],
"metadata": {
"id": "KEiO0v7kuC9O"
}
},
{
"cell_type": "markdown",
"source": [
"[`prep()`](https://recipes.tidymodels.org/reference/prep.html): изчислява необходимите параметри от тренировъчен набор, които по-късно могат да бъдат приложени към други набори от данни. Например, за дадена колона с предиктори, кое наблюдение ще бъде присвоено като цяло число 0, 1, 2 и т.н.\n",
"\n",
"[`bake()`](https://recipes.tidymodels.org/reference/bake.html): взема предварително обработена рецепта и прилага операциите към всеки набор от данни.\n",
"\n",
"С това казано, нека подготвим и приложим нашите рецепти, за да потвърдим, че под повърхността колоните с предиктори първо ще бъдат кодирани, преди моделът да бъде обучен.\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": [
"Ура! 🥳 Обработените данни `baked_pumpkins` имат всички свои предиктори кодирани, което потвърждава, че стъпките за предварителна обработка, дефинирани като наша рецепта, ще работят както се очаква. Това прави данните по-трудни за четене, но много по-разбираеми за Tidymodels! Отделете малко време, за да разберете коя наблюдавана стойност е била съответно преобразувана в цяло число.\n",
"\n",
"Също така си струва да се спомене, че `baked_pumpkins` е дата фрейм, върху който можем да извършваме изчисления.\n",
"\n",
"Например, нека се опитаме да намерим добра корелация между две точки от вашите данни, за да изградим потенциално добър предсказателен модел. Ще използваме функцията `cor()` за това. Напишете `?cor()`, за да научите повече за функцията.\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": [
"Оказва се, че има само слаба връзка между Град и Цена. Въпреки това, има малко по-добра връзка между Пакет и неговата Цена. Това има смисъл, нали? Обикновено, колкото по-голяма е кутията с продукти, толкова по-висока е цената.\n",
"\n",
"Докато сме на тази тема, нека също опитаме да визуализираме матрица на корелация за всички колони, използвайки пакета `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": [
"🤩🤩 Много по-добре.\n",
"\n",
"Един добър въпрос, който можем да зададем за тези данни, е: '`Каква цена мога да очаквам за даден пакет тикви?`' Нека започнем веднага!\n",
"\n",
"> Note: Когато **`bake()`** на предварително подготвената рецепта **`pumpkins_prep`** с **`new_data = NULL`**, извличате обработените (т.е. кодирани) тренировъчни данни. Ако имате друг набор от данни, например тестов набор, и искате да видите как рецептата би го обработила, просто изпечете **`pumpkins_prep`** с **`new_data = test_set`**\n",
"\n",
"## 4. Създаване на модел за линейна регресия\n",
"\n",
"<p >\n",
" <img src=\"../../images/linear-polynomial.png\"\n",
" width=\"800\"/>\n",
" <figcaption>Инфографика от Дасани Мадипали</figcaption>\n",
"\n",
"\n",
"<!--![Инфографика от Дасани Мадипали](../../../../../../2-Regression/3-Linear/images/linear-polynomial.png){width=\"800\"}-->\n"
],
"metadata": {
"id": "YqXjLuWavNxW"
}
},
{
"cell_type": "markdown",
"source": [
"Сега, след като създадохме рецепта и потвърдихме, че данните ще бъдат предварително обработени правилно, нека изградим регресионен модел, за да отговорим на въпроса: `Каква цена мога да очаквам за даден пакет тикви?`\n",
"\n",
"#### Обучение на линеен регресионен модел с помощта на тренировъчния набор\n",
"\n",
"Както вероятно вече сте се досетили, колоната *price* е променливата `резултат`, докато колоната *package* е променливата `предиктор`.\n",
"\n",
"За да направим това, първо ще разделим данните така, че 80% да отидат в тренировъчния набор, а 20% в тестовия набор. След това ще дефинираме рецепта, която ще кодира колоната предиктор в набор от цели числа, и ще създадем спецификация на модела. Няма да подготвяме и изпичаме рецептата, тъй като вече знаем, че тя ще обработи данните според очакванията.\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": [
"Добра работа! Сега, след като имаме рецепта и спецификация на модела, трябва да намерим начин да ги обединим в един обект, който първо ще обработи данните (prep+bake зад кулисите), ще обучи модела върху предварително обработените данни и също така ще позволи потенциални дейности по последваща обработка. Как ти звучи това за спокойствие на ума!🤩\n",
"\n",
"В Tidymodels този удобен обект се нарича [`workflow`](https://workflows.tidymodels.org/) и удобно съхранява твоите компоненти за моделиране! Това е, което бихме нарекли *потоци* в *Python*.\n",
"\n",
"Така че, нека обединим всичко в един 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": [
"👌 В допълнение, работният процес може да бъде настроен/обучен по почти същия начин, както един модел.\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": [
"От изхода на модела можем да видим коефициентите, научени по време на обучението. Те представляват коефициентите на линията на най-добро съответствие, която ни дава най-ниската обща грешка между действителната и предсказаната променлива.\n",
"\n",
"#### Оценка на представянето на модела с помощта на тестовия набор\n",
"\n",
"Време е да видим как се е справил моделът 📏! Как да направим това?\n",
"\n",
"Сега, когато сме обучили модела, можем да го използваме, за да направим прогнози за `test_set`, използвайки `parsnip::predict()`. След това можем да сравним тези прогнози с действителните стойности на етикетите, за да оценим колко добре (или не!) работи моделът.\n",
"\n",
"Нека започнем с правенето на прогнози за тестовия набор, след което да свържем колоните към тестовия набор.\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": [
"Да, току-що обучихте модел и го използвахте, за да направите прогнози! 🔮 Добър ли е? Нека оценим представянето на модела!\n",
"\n",
"В Tidymodels правим това с помощта на `yardstick::metrics()`! За линейна регресия нека се фокусираме върху следните метрики:\n",
"\n",
"- `Root Mean Square Error (RMSE)`: Квадратният корен на [MSE](https://en.wikipedia.org/wiki/Mean_squared_error). Това дава абсолютна метрика в същата единица като етикета (в този случай, цената на тиквата). Колкото по-малка е стойността, толкова по-добър е моделът (в опростен смисъл, тя представлява средната стойност, с която прогнозите грешат спрямо реалните цени!).\n",
"\n",
"- `Coefficient of Determination (обикновено известен като R-squared или R2)`: Относителна метрика, при която колкото по-висока е стойността, толкова по-добре моделът пасва на данните. По същество тази метрика показва колко от вариацията между прогнозираните и реалните стойности на етикетите моделът успява да обясни.\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": [
"Там отива представянето на модела. Нека видим дали можем да получим по-добра индикация, като визуализираме разпръснат график на пакета и цената, след което използваме направените прогнози, за да наложим линия на най-добро съответствие.\n",
"\n",
"Това означава, че ще трябва да подготвим и обработим тестовия набор, за да кодираме колоната за пакета, след което да я свържем с прогнозите, направени от нашия модел.\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": [
"Чудесно! Както виждате, линейният регресионен модел не успява добре да обобщи връзката между пакета и съответната му цена.\n",
"\n",
"🎃 Поздравления, току-що създадохте модел, който може да помогне за предсказване на цената на няколко разновидности на тикви. Вашата празнична тиквена градина ще бъде красива. Но вероятно можете да създадете по-добър модел!\n",
"\n",
"## 5. Създайте полиномиален регресионен модел\n",
"\n",
"<p >\n",
" <img src=\"../../images/linear-polynomial.png\"\n",
" width=\"800\"/>\n",
" <figcaption>Инфографика от Дасани Мадипали</figcaption>\n",
"\n",
"\n",
"<!--![Инфографика от Дасани Мадипали](../../../../../../2-Regression/3-Linear/images/linear-polynomial.png){width=\"800\"}-->\n"
],
"metadata": {
"id": "HOCqJXLTwtWI"
}
},
{
"cell_type": "markdown",
"source": [
"Понякога нашите данни може да нямат линейна връзка, но все пак искаме да прогнозираме резултат. Полиномиалната регресия може да ни помогне да правим прогнози за по-сложни нелинейни връзки.\n",
"\n",
"Вземете например връзката между опаковката и цената в нашия набор от данни за тикви. Докато понякога има линейна връзка между променливите - колкото по-голяма е тиквата по обем, толкова по-висока е цената - понякога тези връзки не могат да бъдат изобразени като равнина или права линия.\n",
"\n",
"> ✅ Ето [някои допълнителни примери](https://online.stat.psu.edu/stat501/lesson/9/9.8) за данни, които могат да използват полиномиална регресия\n",
">\n",
"> Погледнете отново връзката между сорта и цената в предишния график. Изглежда ли този разпръснат график като нещо, което задължително трябва да бъде анализирано с права линия? Може би не. В този случай можете да опитате полиномиална регресия.\n",
">\n",
"> ✅ Полиномите са математически изрази, които могат да се състоят от една или повече променливи и коефициенти\n",
"\n",
"#### Обучение на модел за полиномиална регресия с помощта на тренировъчния набор\n",
"\n",
"Полиномиалната регресия създава *извита линия*, за да пасне по-добре на нелинейните данни.\n",
"\n",
"Нека видим дали полиномиалният модел ще се представи по-добре при правене на прогнози. Ще следваме подобна процедура, както направихме преди:\n",
"\n",
"- Създайте рецепта, която определя стъпките за предварителна обработка, които трябва да бъдат изпълнени върху нашите данни, за да ги подготвим за моделиране, например: кодиране на предиктори и изчисляване на полиноми от степен *n*\n",
"\n",
"- Изградете спецификация на модела\n",
"\n",
"- Комбинирайте рецептата и спецификацията на модела в работен поток\n",
"\n",
"- Създайте модел чрез напасване на работния поток\n",
"\n",
"- Оценете колко добре се представя моделът върху тестовите данни\n",
"\n",
"Да започваме!\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": [
"#### Оценка на производителността на модела\n",
"\n",
"👏👏Създадохте полиномен модел, нека направим прогнози върху тестовия набор!\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": [
"Ура, нека оценим как моделът се представи на test_set, използвайки `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": [
"🤩🤩 Много по-добра производителност.\n",
"\n",
"`rmse` намаля от около 7 до около 3, което показва намалена грешка между реалната цена и предсказаната цена. Можете *грубо* да интерпретирате това като средно, че грешните предсказания се отклоняват с около 3 долара. `rsq` се увеличи от около 0.4 до 0.8.\n",
"\n",
"Всички тези метрики показват, че полиномният модел се представя много по-добре от линейния модел. Отлична работа!\n",
"\n",
"Нека видим дали можем да го визуализираме!\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": [
"Можете да видите извита линия, която по-добре пасва на вашите данни! 🤩\n",
"\n",
"Можете да направите това още по-гладко, като подадете полиномиална формула на `geom_smooth`, ето така:\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": [
"Много прилича на гладка крива!🤩\n",
"\n",
"Ето как можете да направите нова прогноза:\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": [
"Прогнозата на `полиномния модел` има смисъл, като се вземат предвид разпръснатите графики на `цена` и `пакет`! И ако това е по-добър модел от предишния, гледайки същите данни, трябва да планирате бюджет за тези по-скъпи тикви!\n",
"\n",
"🏆 Браво! Създадохте два регресионни модела в един урок. В последната секция за регресия ще научите за логистичната регресия, за да определяте категории.\n",
"\n",
"## **🚀Предизвикателство**\n",
"\n",
"Тествайте няколко различни променливи в този тетрадка, за да видите как корелацията съответства на точността на модела.\n",
"\n",
"## [**Тест след лекцията**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/14/)\n",
"\n",
"## **Преглед и Самостоятелно обучение**\n",
"\n",
"В този урок научихме за Линейна регресия. Съществуват и други важни видове регресия. Прочетете за техниките Stepwise, Ridge, Lasso и Elasticnet. Един добър курс за изучаване на повече е [Статистическо обучение на Станфорд](https://online.stanford.edu/courses/sohs-ystatslearning-statistical-learning).\n",
"\n",
"Ако искате да научите повече за използването на невероятната рамка Tidymodels, моля, разгледайте следните ресурси:\n",
"\n",
"- Уебсайт на Tidymodels: [Започнете с Tidymodels](https://www.tidymodels.org/start/)\n",
"\n",
"- Макс Кун и Джулия Силге, [*Tidy Modeling with R*](https://www.tmwr.org/)*.*\n",
"\n",
"###### **БЛАГОДАРНОСТИ КЪМ:**\n",
"\n",
"[Алисън Хорст](https://twitter.com/allison_horst?lang=en) за създаването на невероятните илюстрации, които правят R по-приветлив и ангажиращ. Намерете повече илюстрации в нейния [галерия](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**Отказ от отговорност**: \nТози документ е преведен с помощта на AI услуга за превод [Co-op Translator](https://github.com/Azure/co-op-translator). Въпреки че се стремим към точност, моля, имайте предвид, че автоматизираните преводи може да съдържат грешки или неточности. Оригиналният документ на неговия изходен език трябва да се счита за авторитетен източник. За критична информация се препоръчва професионален човешки превод. Ние не носим отговорност за каквито и да е недоразумения или погрешни интерпретации, произтичащи от използването на този превод.\n"
]
}
]
}