{ "nbformat": 4, "nbformat_minor": 2, "metadata": { "colab": { "name": "lesson_2-R.ipynb", "provenance": [], "collapsed_sections": [], "toc_visible": true }, "kernelspec": { "name": "ir", "display_name": "R" }, "language_info": { "name": "R" }, "coopTranslator": { "original_hash": "f3c335f9940cfd76528b3ef918b9b342", "translation_date": "2025-09-04T07:13:06+00:00", "source_file": "2-Regression/2-Data/solution/R/lesson_2-R.ipynb", "language_code": "bg" } }, "cells": [ { "cell_type": "markdown", "source": [ "# Създаване на регресионен модел: подготовка и визуализация на данни\n", "\n", "## **Линейна регресия за тикви - Урок 2**\n", "#### Въведение\n", "\n", "Сега, когато разполагате с инструментите, необходими за изграждане на модели за машинно обучение с Tidymodels и Tidyverse, сте готови да започнете да задавате въпроси към вашите данни. Докато работите с данни и прилагате решения за машинно обучение, е изключително важно да разберете как да зададете правилния въпрос, за да отключите потенциала на вашия набор от данни.\n", "\n", "В този урок ще научите:\n", "\n", "- Как да подготвите данните си за изграждане на модел.\n", "\n", "- Как да използвате `ggplot2` за визуализация на данни.\n", "\n", "Въпросът, на който искате да получите отговор, ще определи какъв тип алгоритми за машинно обучение ще използвате. А качеството на отговора, който ще получите, ще зависи в голяма степен от естеството на вашите данни.\n", "\n", "Нека видим това чрез практическо упражнение.\n", "\n", "
\n",
" \n",
"
\n",
"\n",
"> Припомняне: Операторът за тръбопровод (`%>%`) изпълнява операции в логическа последователност, като предава обект напред към функция или израз. Можете да мислите за оператора за тръбопровод като за \"и след това\" във вашия код.\n"
],
"metadata": {
"id": "REWcIv9yX29v"
}
},
{
"cell_type": "markdown",
"source": [
"## 2. Проверка за липсващи данни\n",
"\n",
"Един от най-често срещаните проблеми, с които се сблъскват специалистите по данни, е непълните или липсващи данни. В R липсващите или неизвестни стойности се представят със специална стойност: `NA` (Not Available).\n",
"\n",
"Как можем да разберем дали дадена таблица с данни съдържа липсващи стойности? \n",
"
\n",
"- Един директен начин е да използваме базовата R функция `anyNA`, която връща логическите стойности `TRUE` или `FALSE`.\n"
],
"metadata": {
"id": "Zxfb3AM5YbUe"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"pumpkins %>% \n",
" anyNA()"
],
"outputs": [],
"metadata": {
"id": "G--DQutAYltj"
}
},
{
"cell_type": "markdown",
"source": [
"Чудесно, изглежда, че липсват някои данни! Това е добро място за начало.\n",
"\n",
"- Друг начин би бил да използвате функцията `is.na()`, която показва кои отделни елементи в колоните липсват с логическа стойност `TRUE`.\n"
],
"metadata": {
"id": "mU-7-SB6YokF"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"pumpkins %>% \n",
" is.na() %>% \n",
" head(n = 7)"
],
"outputs": [],
"metadata": {
"id": "W-DxDOR4YxSW"
}
},
{
"cell_type": "markdown",
"source": [
"Добре, свършихме работата, но с толкова голяма таблица като тази би било неефективно и практически невъзможно да се прегледат всички редове и колони индивидуално😴.\n",
"\n",
"- По-интуитивен начин би бил да се изчисли сумата на липсващите стойности за всяка колона:\n"
],
"metadata": {
"id": "xUWxipKYY0o7"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"pumpkins %>% \n",
" is.na() %>% \n",
" colSums()"
],
"outputs": [],
"metadata": {
"id": "ZRBWV6P9ZArL"
}
},
{
"cell_type": "markdown",
"source": [
"Много по-добре! Липсват данни, но може би това няма да е от значение за задачата. Нека видим какво ще покаже по-нататъшният анализ.\n",
"\n",
"> Освен страхотните пакети и функции, R разполага с много добра документация. Например, използвайте `help(colSums)` или `?colSums`, за да научите повече за функцията.\n"
],
"metadata": {
"id": "9gv-crB6ZD1Y"
}
},
{
"cell_type": "markdown",
"source": [
"## 3. Dplyr: Граматика на манипулиране на данни\n",
"\n",
"
\n",
" \n",
"
\n"
],
"metadata": {
"id": "i5o33MQBZWWw"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::select()\n",
"\n",
"`select()` е функция в пакета `dplyr`, която ви помага да изберете колони, които да запазите или изключите.\n",
"\n",
"За да направите вашата таблица с данни по-лесна за работа, премахнете няколко от нейните колони, използвайки `select()`, като запазите само колоните, които са ви необходими.\n",
"\n",
"Например, в това упражнение нашият анализ ще включва колоните `Package`, `Low Price`, `High Price` и `Date`. Нека изберем тези колони.\n"
],
"metadata": {
"id": "x3VGMAGBZiUr"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Select desired columns\n",
"pumpkins <- pumpkins %>% \n",
" select(Package, `Low Price`, `High Price`, Date)\n",
"\n",
"\n",
"# Print data set\n",
"pumpkins %>% \n",
" slice_head(n = 5)"
],
"outputs": [],
"metadata": {
"id": "F_FgxQnVZnM0"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::mutate()\n",
"\n",
"`mutate()` е функция в пакета `dplyr`, която ви помага да създавате или модифицирате колони, като запазвате съществуващите колони.\n",
"\n",
"Общата структура на `mutate` е:\n",
"\n",
"`data %>% mutate(new_column_name = what_it_contains)`\n",
"\n",
"Нека използваме `mutate` върху колоната `Date`, като извършим следните операции:\n",
"\n",
"1. Конвертирайте датите (в момента от тип символ) във формат за месец (това са американски дати, така че форматът е `MM/DD/YYYY`).\n",
"\n",
"2. Извлечете месеца от датите в нова колона.\n",
"\n",
"В R, пакетът [lubridate](https://lubridate.tidyverse.org/) улеснява работата с данни от тип дата и час. Затова нека използваме `dplyr::mutate()`, `lubridate::mdy()`, `lubridate::month()` и да видим как да постигнем горните цели. Можем да премахнем колоната `Date`, тъй като няма да ни е необходима за следващите операции.\n"
],
"metadata": {
"id": "2KKo0Ed9Z1VB"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Load lubridate\n",
"library(lubridate)\n",
"\n",
"pumpkins <- pumpkins %>% \n",
" # Convert the Date column to a date object\n",
" mutate(Date = mdy(Date)) %>% \n",
" # Extract month from Date\n",
" mutate(Month = month(Date)) %>% \n",
" # Drop Date column\n",
" select(-Date)\n",
"\n",
"# View the first few rows\n",
"pumpkins %>% \n",
" slice_head(n = 7)"
],
"outputs": [],
"metadata": {
"id": "5joszIVSZ6xe"
}
},
{
"cell_type": "markdown",
"source": [
"Ура! 🤩\n",
"\n",
"Следващата стъпка е да създадем нова колона `Price`, която представлява средната цена на тиква. Сега, нека изчислим средната стойност на колоните `Low Price` и `High Price`, за да попълним новата колона Price.\n",
"
\n"
],
"metadata": {
"id": "nIgLjNMCZ-6Y"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Create a new column Price\n",
"pumpkins <- pumpkins %>% \n",
" mutate(Price = (`Low Price` + `High Price`)/2)\n",
"\n",
"# View the first few rows of the data\n",
"pumpkins %>% \n",
" slice_head(n = 5)"
],
"outputs": [],
"metadata": {
"id": "Zo0BsqqtaJw2"
}
},
{
"cell_type": "markdown",
"source": [
"Дааа!💪\n",
"\n",
"„Но чакай малко!“, ще кажете, след като прегледате целия набор от данни с `View(pumpkins)`, „Тук има нещо странно!“🤔\n",
"\n",
"Ако погледнете колоната `Package`, тиквите се продават в много различни конфигурации. Някои се продават в мерки от `1 1/9 bushel`, други в мерки от `1/2 bushel`, някои на тиква, някои на килограм, а някои в големи кутии с различни ширини.\n",
"\n",
"Нека проверим това:\n"
],
"metadata": {
"id": "p77WZr-9aQAR"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Verify the distinct observations in Package column\n",
"pumpkins %>% \n",
" distinct(Package)"
],
"outputs": [],
"metadata": {
"id": "XISGfh0IaUy6"
}
},
{
"cell_type": "markdown",
"source": [
"Невероятно!👏\n",
"\n",
"Тиквите изглежда са много трудни за претегляне по последователен начин, затова нека ги филтрираме, като изберем само тиквите със стринга *bushel* в колоната `Package` и поставим това в новия датафрейм `new_pumpkins`.\n"
],
"metadata": {
"id": "7sMjiVujaZxY"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::filter() и stringr::str_detect()\n",
"\n",
"[`dplyr::filter()`](https://dplyr.tidyverse.org/reference/filter.html): създава подмножество от данни, съдържащо само **редове**, които отговарят на вашите условия, в този случай тикви със стринга *bushel* в колоната `Package`.\n",
"\n",
"[stringr::str_detect()](https://stringr.tidyverse.org/reference/str_detect.html): открива наличието или отсъствието на даден шаблон в стринг.\n",
"\n",
"Пакетът [`stringr`](https://github.com/tidyverse/stringr) предоставя лесни функции за често срещани операции със стрингове.\n"
],
"metadata": {
"id": "L8Qfcs92ageF"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Retain only pumpkins with \"bushel\"\n",
"new_pumpkins <- pumpkins %>% \n",
" filter(str_detect(Package, \"bushel\"))\n",
"\n",
"# Get the dimensions of the new data\n",
"dim(new_pumpkins)\n",
"\n",
"# View a few rows of the new data\n",
"new_pumpkins %>% \n",
" slice_head(n = 5)"
],
"outputs": [],
"metadata": {
"id": "hy_SGYREampd"
}
},
{
"cell_type": "markdown",
"source": [
"Можете да видите, че сме стеснили избора до около 415 реда данни, съдържащи тикви на едро.🤩 \n",
"
\n"
],
"metadata": {
"id": "VrDwF031avlR"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::case_when()\n",
"\n",
"**Но чакайте! Има още нещо, което трябва да направите**\n",
"\n",
"Забелязахте ли, че количеството в бушел варира за всеки ред? Трябва да нормализирате цените, така че да показвате цената на бушел, а не на 1 1/9 или 1/2 бушел. Време е за малко математика, за да я стандартизирате.\n",
"\n",
"Ще използваме функцията [`case_when()`](https://dplyr.tidyverse.org/reference/case_when.html), за да *променим* колоната Price в зависимост от някои условия. `case_when` ви позволява да векторизирате множество изрази `if_else()`.\n"
],
"metadata": {
"id": "mLpw2jH4a0tx"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Convert the price if the Package contains fractional bushel values\n",
"new_pumpkins <- new_pumpkins %>% \n",
" mutate(Price = case_when(\n",
" str_detect(Package, \"1 1/9\") ~ Price/(1 + 1/9),\n",
" str_detect(Package, \"1/2\") ~ Price/(1/2),\n",
" TRUE ~ Price))\n",
"\n",
"# View the first few rows of the data\n",
"new_pumpkins %>% \n",
" slice_head(n = 30)"
],
"outputs": [],
"metadata": {
"id": "P68kLVQmbM6I"
}
},
{
"cell_type": "markdown",
"source": [
"Сега можем да анализираме цената на единица въз основа на измерването им в бушели. Цялото това изследване на бушели с тикви обаче показва колко `важно` е да `разберем естеството на данните си`!\n",
"\n",
"> ✅ Според [The Spruce Eats](https://www.thespruceeats.com/how-much-is-a-bushel-1389308), теглото на един бушел зависи от вида на продукцията, тъй като това е измерване на обем. \"Един бушел домати, например, трябва да тежи 56 паунда... Листата и зелените заемат повече пространство с по-малко тегло, така че един бушел спанак е само 20 паунда.\" Всичко това е доста сложно! Нека не се занимаваме с преобразуване от бушели в паунди, а вместо това да определим цената на бушел. Цялото това изследване на бушели с тикви обаче показва колко важно е да разберем естеството на данните си!\n",
">\n",
"> ✅ Забелязахте ли, че тиквите, продавани на половин бушел, са много скъпи? Можете ли да разберете защо? Подсказка: малките тикви са много по-скъпи от големите, вероятно защото има много повече от тях в един бушел, като се има предвид неизползваното пространство, което заема една голяма куха тиква за пай.\n"
],
"metadata": {
"id": "pS2GNPagbSdb"
}
},
{
"cell_type": "markdown",
"source": [
"Сега, накрая, заради чистото удоволствие от приключението 💁♀️, нека също преместим колоната Month на първа позиция, т.е. `преди` колоната `Package`.\n",
"\n",
"`dplyr::relocate()` се използва за промяна на позициите на колоните.\n"
],
"metadata": {
"id": "qql1SowfbdnP"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Create a new data frame new_pumpkins\n",
"new_pumpkins <- new_pumpkins %>% \n",
" relocate(Month, .before = Package)\n",
"\n",
"new_pumpkins %>% \n",
" slice_head(n = 7)"
],
"outputs": [],
"metadata": {
"id": "JJ1x6kw8bixF"
}
},
{
"cell_type": "markdown",
"source": [
"Браво!👌 Сега разполагате с чист и подреден набор от данни, върху който можете да изградите новия си регресионен модел! \n",
"
\n"
],
"metadata": {
"id": "y8TJ0Za_bn5Y"
}
},
{
"cell_type": "markdown",
"source": [
"## 4. Визуализация на данни с ggplot2\n",
"\n",
"
\n",
" \n",
"
\n"
],
"metadata": {
"id": "Ml7SDCLQcPvE"
}
},
{
"cell_type": "markdown",
"source": [
"### **Как да го направим полезно?**\n",
"\n",
"За да покажем полезни данни в диаграмите, обикновено трябва да групираме данните по някакъв начин. Например, в нашия случай, намирането на средната цена на тиквите за всеки месец би предоставило повече информация за основните модели в нашите данни. Това ни води до още един бърз поглед към **dplyr**:\n",
"\n",
"#### `dplyr::group_by() %>% summarize()`\n",
"\n",
"Групирана агрегация в R може лесно да се изчисли с помощта на\n",
"\n",
"`dplyr::group_by() %>% summarize()`\n",
"\n",
"- `dplyr::group_by()` променя единицата на анализ от целия набор от данни към отделни групи, например по месеци.\n",
"\n",
"- `dplyr::summarize()` създава нова таблица с една колона за всяка променлива на групиране и една колона за всяка от статистиките, които сте посочили.\n",
"\n",
"Например, можем да използваме `dplyr::group_by() %>% summarize()`, за да групираме тиквите в групи въз основа на колоната **Month** и след това да намерим **средната цена** за всеки месец.\n"
],
"metadata": {
"id": "jMakvJZIcVkh"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Find the average price of pumpkins per month\r\n",
"new_pumpkins %>%\r\n",
" group_by(Month) %>% \r\n",
" summarise(mean_price = mean(Price))"
],
"outputs": [],
"metadata": {
"id": "6kVSUa2Bcilf"
}
},
{
"cell_type": "markdown",
"source": [
"Кратко!✨\n",
"\n",
"Категориални характеристики, като например месеци, се представят по-добре с помощта на стълбовидна диаграма 📊. Слоевете, отговорни за стълбовидните диаграми, са `geom_bar()` и `geom_col()`. Консултирайте се с `?geom_bar`, за да научите повече.\n",
"\n",
"Да създадем една!\n"
],
"metadata": {
"id": "Kds48GUBcj3W"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Find the average price of pumpkins per month then plot a bar chart\r\n",
"new_pumpkins %>%\r\n",
" group_by(Month) %>% \r\n",
" summarise(mean_price = mean(Price)) %>% \r\n",
" ggplot(aes(x = Month, y = mean_price)) +\r\n",
" geom_col(fill = \"midnightblue\", alpha = 0.7) +\r\n",
" ylab(\"Pumpkin Price\")"
],
"outputs": [],
"metadata": {
"id": "VNbU1S3BcrxO"
}
},
{
"cell_type": "markdown",
"source": [
"🤩🤩Това е по-полезна визуализация на данни! Изглежда, че най-високата цена за тикви се наблюдава през септември и октомври. Това отговаря ли на вашите очаквания? Защо или защо не?\n",
"\n",
"Поздравления за завършването на втория урок 👏! Подготвихте данните си за изграждане на модел, след което открихте повече прозрения чрез визуализации!\n"
],
"metadata": {
"id": "zDm0VOzzcuzR"
}
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Отказ от отговорност**: \nТози документ е преведен с помощта на AI услуга за превод [Co-op Translator](https://github.com/Azure/co-op-translator). Въпреки че се стремим към точност, моля, имайте предвид, че автоматичните преводи може да съдържат грешки или неточности. Оригиналният документ на неговия изходен език трябва да се счита за авторитетен източник. За критична информация се препоръчва професионален превод от човек. Ние не носим отговорност за каквито и да е недоразумения или погрешни интерпретации, произтичащи от използването на този превод.\n"
]
}
]
}