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/uk/2-Regression/4-Logistic/solution/R/lesson_4-R.ipynb

685 lines
42 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.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Побудова моделі логістичної регресії - Урок 4\n",
"\n",
"![Інфографіка: логістична vs. лінійна регресія](../../../../../../2-Regression/4-Logistic/images/linear-vs-logistic.png)\n",
"\n",
"#### **[Тест перед лекцією](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/15/)**\n",
"\n",
"#### Вступ\n",
"\n",
"У цьому останньому уроці про регресію, одну з базових *класичних* технік машинного навчання, ми розглянемо логістичну регресію. Цю техніку використовують для виявлення закономірностей з метою прогнозування бінарних категорій. Це цукерка з шоколадом чи ні? Це захворювання заразне чи ні? Чи обере цей клієнт продукт чи ні?\n",
"\n",
"У цьому уроці ви дізнаєтесь:\n",
"\n",
"- Техніки логістичної регресії\n",
"\n",
"✅ Поглибте своє розуміння роботи з цим типом регресії у цьому [модулі навчання](https://learn.microsoft.com/training/modules/introduction-classification-models/?WT.mc_id=academic-77952-leestott)\n",
"\n",
"## Передумови\n",
"\n",
"Працюючи з даними про гарбузи, ми вже достатньо знайомі з ними, щоб зрозуміти, що є одна бінарна категорія, з якою ми можемо працювати: `Color`.\n",
"\n",
"Давайте побудуємо модель логістичної регресії, щоб передбачити, враховуючи деякі змінні, *який колір, ймовірно, матиме даний гарбуз* (помаранчевий 🎃 чи білий 👻).\n",
"\n",
"> Чому ми говоримо про бінарну класифікацію в уроці, присвяченому регресії? Лише для мовного зручності, оскільки логістична регресія [насправді є методом класифікації](https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression), хоча й базується на лінійних принципах. Дізнайтеся про інші способи класифікації даних у наступній групі уроків.\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",
"- `ggbeeswarm`: [Пакет ggbeeswarm](https://github.com/eclarke/ggbeeswarm) пропонує методи для створення графіків у стилі \"бджолиного рою\" за допомогою ggplot2.\n",
"\n",
"Ви можете встановити їх за допомогою:\n",
"\n",
"`install.packages(c(\"tidyverse\", \"tidymodels\", \"janitor\", \"ggbeeswarm\"))`\n",
"\n",
"Або ж скрипт нижче перевірить, чи є у вас необхідні пакети для виконання цього модуля, і встановить їх, якщо вони відсутні.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"suppressWarnings(if (!require(\"pacman\"))install.packages(\"pacman\"))\n",
"\n",
"pacman::p_load(tidyverse, tidymodels, janitor, ggbeeswarm)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **Визначення питання**\n",
"\n",
"Для наших цілей ми будемо виражати це як бінарне: 'Білий' або 'Не білий'. У нашому наборі даних також є категорія 'смугастий', але випадків її використання дуже мало, тому ми не будемо її враховувати. Вона зникає, як тільки ми видаляємо null-значення з набору даних.\n",
"\n",
"> 🎃 Цікавий факт: ми іноді називаємо білі гарбузи 'гарбузами-привидами'. Їх не дуже легко вирізати, тому вони не такі популярні, як помаранчеві, але виглядають круто! Тож ми також могли б переформулювати наше питання як: 'Привид' або 'Не привид'. 👻\n",
"\n",
"## **Про логістичну регресію**\n",
"\n",
"Логістична регресія відрізняється від лінійної регресії, про яку ви дізналися раніше, кількома важливими аспектами.\n",
"\n",
"#### **Бінарна класифікація**\n",
"\n",
"Логістична регресія не пропонує ті ж функції, що й лінійна регресія. Перша дає прогноз щодо `бінарної категорії` (\"помаранчевий чи не помаранчевий\"), тоді як друга здатна прогнозувати `безперервні значення`, наприклад, враховуючи походження гарбуза та час збору врожаю, *наскільки зросте його ціна*.\n",
"\n",
"![Інфографіка від Dasani Madipalli](../../../../../../2-Regression/4-Logistic/images/pumpkin-classifier.png)\n",
"\n",
"### Інші класифікації\n",
"\n",
"Існують інші типи логістичної регресії, включаючи мультиноміальну та порядкову:\n",
"\n",
"- **Мультиноміальна**, яка передбачає наявність більше ніж однієї категорії - \"Помаранчевий, Білий і Смугастий\".\n",
"\n",
"- **Порядкова**, яка передбачає впорядковані категорії, корисна, якщо ми хочемо впорядкувати наші результати логічно, наприклад, наші гарбузи, які впорядковані за обмеженою кількістю розмірів (mini, sm, med, lg, xl, xxl).\n",
"\n",
"![Мультиноміальна vs порядкова регресія](../../../../../../2-Regression/4-Logistic/images/multinomial-vs-ordinal.png)\n",
"\n",
"#### **Змінні НЕ повинні корелювати**\n",
"\n",
"Пам'ятаєте, як лінійна регресія працювала краще з більш корельованими змінними? Логістична регресія — це протилежність: змінні не обов'язково мають бути узгодженими. Це підходить для цього набору даних, у якому кореляції досить слабкі.\n",
"\n",
"#### **Потрібно багато чистих даних**\n",
"\n",
"Логістична регресія дасть більш точні результати, якщо використовувати більше даних; наш невеликий набір даних не є оптимальним для цього завдання, тому майте це на увазі.\n",
"\n",
"✅ Подумайте про типи даних, які добре підходять для логістичної регресії.\n",
"\n",
"## Вправа - впорядкування даних\n",
"\n",
"Спочатку трохи очистіть дані, видаливши null-значення та вибравши лише деякі з колонок:\n",
"\n",
"1. Додайте наступний код:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Load the core tidyverse packages\n",
"library(tidyverse)\n",
"\n",
"# Import the data and clean column names\n",
"pumpkins <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/2-Regression/data/US-pumpkins.csv\") %>% \n",
" clean_names()\n",
"\n",
"# Select desired columns\n",
"pumpkins_select <- pumpkins %>% \n",
" select(c(city_name, package, variety, origin, item_size, color)) \n",
"\n",
"# Drop rows containing missing values and encode color as factor (category)\n",
"pumpkins_select <- pumpkins_select %>% \n",
" drop_na() %>% \n",
" mutate(color = factor(color))\n",
"\n",
"# View the first few rows\n",
"pumpkins_select %>% \n",
" slice_head(n = 5)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ви завжди можете переглянути ваш новий датафрейм, використовуючи функцію [*glimpse()*](https://pillar.r-lib.org/reference/glimpse.html), як показано нижче:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"pumpkins_select %>% \n",
" glimpse()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Давайте підтвердимо, що ми дійсно будемо вирішувати задачу бінарної класифікації:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Subset distinct observations in outcome column\n",
"pumpkins_select %>% \n",
" distinct(color)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Візуалізація - категоріальний графік\n",
"На даний момент ви знову завантажили дані про гарбузи та очистили їх, щоб зберегти набір даних, який містить кілька змінних, включаючи Color. Давайте візуалізуємо цей датафрейм у блокноті за допомогою бібліотеки ggplot.\n",
"\n",
"Бібліотека ggplot пропонує зручні способи візуалізації ваших даних. Наприклад, ви можете порівняти розподіли даних для кожного Variety і Color у категоріальному графіку.\n",
"\n",
"1. Створіть такий графік, використовуючи функцію geombar, наші дані про гарбузи, і задайте кольорове відображення для кожної категорії гарбузів (помаранчевий або білий):\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "python"
}
},
"outputs": [],
"source": [
"# Specify colors for each value of the hue variable\n",
"palette <- c(ORANGE = \"orange\", WHITE = \"wheat\")\n",
"\n",
"# Create the bar plot\n",
"ggplot(pumpkins_select, aes(y = variety, fill = color)) +\n",
" geom_bar(position = \"dodge\") +\n",
" scale_fill_manual(values = palette) +\n",
" labs(y = \"Variety\", fill = \"Color\") +\n",
" theme_minimal()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Спостерігаючи за даними, можна побачити, як дані про Колір пов'язані з Різновидом.\n",
"\n",
"✅ Враховуючи цей категоріальний графік, які цікаві дослідження ви можете уявити?\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Попередня обробка даних: кодування ознак\n",
"\n",
"Наш набір даних про гарбузи містить текстові значення у всіх своїх стовпцях. Робота з категоріальними даними є інтуїтивно зрозумілою для людей, але не для машин. Алгоритми машинного навчання добре працюють із числовими даними. Саме тому кодування є дуже важливим етапом у фазі попередньої обробки даних, оскільки воно дозволяє перетворити категоріальні дані на числові, не втрачаючи жодної інформації. Якісне кодування сприяє створенню якісної моделі.\n",
"\n",
"Для кодування ознак існує два основних типи кодерів:\n",
"\n",
"1. Ординальний кодер: добре підходить для ординальних змінних, які є категоріальними змінними, де їхні дані мають логічний порядок, як, наприклад, стовпець `item_size` у нашому наборі даних. Він створює відображення, де кожна категорія представлена числом, яке відповідає порядку категорії у стовпці.\n",
"\n",
"2. Категоріальний кодер: добре підходить для номінальних змінних, які є категоріальними змінними, де їхні дані не мають логічного порядку, як усі ознаки, окрім `item_size`, у нашому наборі даних. Це кодування \"один із багатьох\" (one-hot encoding), що означає, що кожна категорія представлена окремим бінарним стовпцем: закодована змінна дорівнює 1, якщо гарбуз належить до цієї категорії, і 0 — в іншому випадку.\n",
"\n",
"Tidymodels пропонує ще один зручний пакет: [recipes](https://recipes.tidymodels.org/) — пакет для попередньої обробки даних. Ми визначимо `recipe`, який вказує, що всі стовпці предикторів мають бути закодовані у набір цілих чисел, `prep` для оцінки необхідних кількостей і статистичних даних, потрібних для будь-яких операцій, і, нарешті, `bake`, щоб застосувати обчислення до нових даних.\n",
"\n",
"> Зазвичай recipes використовується як попередній процесор для моделювання, де він визначає, які кроки слід застосувати до набору даних, щоб підготувати його до моделювання. У цьому випадку **дуже рекомендується** використовувати `workflow()` замість ручного оцінювання рецепту за допомогою prep і bake. Ми розглянемо це трохи згодом.\n",
">\n",
"> Однак наразі ми використовуємо recipes + prep + bake, щоб визначити, які кроки слід застосувати до набору даних, щоб підготувати його до аналізу даних, а потім витягнути попередньо оброблені дані з застосованими кроками.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Preprocess and extract data to allow some data analysis\n",
"baked_pumpkins <- recipe(color ~ ., data = pumpkins_select) %>%\n",
" # Define ordering for item_size column\n",
" step_mutate(item_size = ordered(item_size, levels = c('sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo'))) %>%\n",
" # Convert factors to numbers using the order defined above (Ordinal encoding)\n",
" step_integer(item_size, zero_based = F) %>%\n",
" # Encode all other predictors using one hot encoding\n",
" step_dummy(all_nominal(), -all_outcomes(), one_hot = TRUE) %>%\n",
" prep(data = pumpkin_select) %>%\n",
" bake(new_data = NULL)\n",
"\n",
"# Display the first few rows of preprocessed data\n",
"baked_pumpkins %>% \n",
" slice_head(n = 5)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"✅ Які переваги використання порядкового кодувальника для стовпця Item Size?\n",
"\n",
"### Аналіз взаємозв'язків між змінними\n",
"\n",
"Тепер, коли ми попередньо обробили наші дані, можемо проаналізувати взаємозв'язки між ознаками та міткою, щоб зрозуміти, наскільки добре модель зможе передбачати мітку на основі ознак. Найкращий спосіб виконати такий аналіз — це візуалізація даних. \n",
"Ми знову будемо використовувати функцію ggplot geom_boxplot_, щоб візуалізувати взаємозв'язки між Item Size, Variety і Color у категоріальному графіку. Для кращої візуалізації даних ми будемо використовувати закодований стовпець Item Size і некодований стовпець Variety.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Define the color palette\n",
"palette <- c(ORANGE = \"orange\", WHITE = \"wheat\")\n",
"\n",
"# We need the encoded Item Size column to use it as the x-axis values in the plot\n",
"pumpkins_select_plot<-pumpkins_select\n",
"pumpkins_select_plot$item_size <- baked_pumpkins$item_size\n",
"\n",
"# Create the grouped box plot\n",
"ggplot(pumpkins_select_plot, aes(x = `item_size`, y = color, fill = color)) +\n",
" geom_boxplot() +\n",
" facet_grid(variety ~ ., scales = \"free_x\") +\n",
" scale_fill_manual(values = palette) +\n",
" labs(x = \"Item Size\", y = \"\") +\n",
" theme_minimal() +\n",
" theme(strip.text = element_text(size = 12)) +\n",
" theme(axis.text.x = element_text(size = 10)) +\n",
" theme(axis.title.x = element_text(size = 12)) +\n",
" theme(axis.title.y = element_blank()) +\n",
" theme(legend.position = \"bottom\") +\n",
" guides(fill = guide_legend(title = \"Color\")) +\n",
" theme(panel.spacing = unit(0.5, \"lines\"))+\n",
" theme(strip.text.y = element_text(size = 4, hjust = 0)) \n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Використання swarm plot\n",
"\n",
"Оскільки Color є бінарною категорією (Білий або Ні), для її візуалізації потрібен '[спеціалізований підхід](https://github.com/rstudio/cheatsheets/blob/main/data-visualization.pdf)'.\n",
"\n",
"Спробуйте `swarm plot`, щоб показати розподіл кольору відносно item_size.\n",
"\n",
"Ми використаємо [пакет ggbeeswarm](https://github.com/eclarke/ggbeeswarm), який надає методи для створення графіків у стилі beeswarm за допомогою ggplot2. Beeswarm-графіки дозволяють розташовувати точки, які зазвичай накладаються одна на одну, так, щоб вони розміщувалися поруч.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Create beeswarm plots of color and item_size\n",
"baked_pumpkins %>% \n",
" mutate(color = factor(color)) %>% \n",
" ggplot(mapping = aes(x = color, y = item_size, color = color)) +\n",
" geom_quasirandom() +\n",
" scale_color_brewer(palette = \"Dark2\", direction = -1) +\n",
" theme(legend.position = \"none\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Тепер, коли ми маємо уявлення про зв'язок між бінарними категоріями кольору та більшою групою розмірів, давайте розглянемо логістичну регресію, щоб визначити ймовірний колір гарбуза.\n",
"\n",
"## Створіть свою модель\n",
"\n",
"Виберіть змінні, які ви хочете використовувати у своїй класифікаційній моделі, і розділіть дані на навчальний та тестовий набори. [rsample](https://rsample.tidymodels.org/), пакет у Tidymodels, забезпечує інфраструктуру для ефективного розподілу даних та повторного вибіркового аналізу:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Split data into 80% for training and 20% for testing\n",
"set.seed(2056)\n",
"pumpkins_split <- pumpkins_select %>% \n",
" initial_split(prop = 0.8)\n",
"\n",
"# Extract the data in each split\n",
"pumpkins_train <- training(pumpkins_split)\n",
"pumpkins_test <- testing(pumpkins_split)\n",
"\n",
"# Print out the first 5 rows of the training set\n",
"pumpkins_train %>% \n",
" slice_head(n = 5)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"🙌 Ми готові навчати модель, підбираючи навчальні ознаки до навчальної мітки (колір).\n",
"\n",
"Почнемо з створення рецепту, який визначає кроки попередньої обробки даних, щоб підготувати їх до моделювання, тобто: кодування категоріальних змінних у набір цілих чисел. Так само, як `baked_pumpkins`, ми створюємо `pumpkins_recipe`, але не використовуємо `prep` і `bake`, оскільки це буде включено в робочий процес, який ви побачите через кілька кроків.\n",
"\n",
"Існує досить багато способів визначити модель логістичної регресії в Tidymodels. Дивіться `?logistic_reg()`. На даний момент ми визначимо модель логістичної регресії через стандартний двигун `stats::glm()`.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Create a recipe that specifies preprocessing steps for modelling\n",
"pumpkins_recipe <- recipe(color ~ ., data = pumpkins_train) %>% \n",
" step_mutate(item_size = ordered(item_size, levels = c('sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo'))) %>%\n",
" step_integer(item_size, zero_based = F) %>% \n",
" step_dummy(all_nominal(), -all_outcomes(), one_hot = TRUE)\n",
"\n",
"# Create a logistic model specification\n",
"log_reg <- logistic_reg() %>% \n",
" set_engine(\"glm\") %>% \n",
" set_mode(\"classification\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Тепер, коли у нас є рецепт і специфікація моделі, потрібно знайти спосіб об'єднати їх в один об'єкт, який спочатку буде попередньо обробляти дані (підготовка + обробка за лаштунками), навчати модель на попередньо оброблених даних, а також дозволить виконувати потенційні дії з постобробки.\n",
"\n",
"У Tidymodels цей зручний об'єкт називається [`workflow`](https://workflows.tidymodels.org/) і зручно зберігає ваші компоненти моделювання.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Bundle modelling components in a workflow\n",
"log_reg_wf <- workflow() %>% \n",
" add_recipe(pumpkins_recipe) %>% \n",
" add_model(log_reg)\n",
"\n",
"# Print out the workflow\n",
"log_reg_wf\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Після того, як робочий процес *визначено*, модель можна `навчити` за допомогою функції [`fit()`](https://tidymodels.github.io/parsnip/reference/fit.html). Робочий процес оцінить рецепт і попередньо обробить дані перед навчанням, тому нам не доведеться робити це вручну за допомогою prep і bake.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Train the model\n",
"wf_fit <- log_reg_wf %>% \n",
" fit(data = pumpkins_train)\n",
"\n",
"# Print the trained workflow\n",
"wf_fit\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Модель виводить коефіцієнти, отримані під час навчання.\n",
"\n",
"Тепер, коли ми навчили модель на навчальних даних, можемо робити прогнози на тестових даних, використовуючи [parsnip::predict()](https://parsnip.tidymodels.org/reference/predict.model_fit.html). Давайте почнемо з використання моделі для прогнозування міток для нашого тестового набору та ймовірностей для кожної мітки. Якщо ймовірність перевищує 0.5, передбачений клас — `WHITE`, інакше — `ORANGE`.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Make predictions for color and corresponding probabilities\n",
"results <- pumpkins_test %>% select(color) %>% \n",
" bind_cols(wf_fit %>% \n",
" predict(new_data = pumpkins_test)) %>%\n",
" bind_cols(wf_fit %>%\n",
" predict(new_data = pumpkins_test, type = \"prob\"))\n",
"\n",
"# Compare predictions\n",
"results %>% \n",
" slice_head(n = 10)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Дуже добре! Це дає більше розуміння того, як працює логістична регресія.\n",
"\n",
"### Краще розуміння через матрицю плутанини\n",
"\n",
"Порівнювати кожне передбачення з відповідним \"еталонним\" фактичним значенням — не дуже ефективний спосіб визначити, наскільки добре модель робить прогнози. На щастя, Tidymodels має ще кілька хитрощів у своєму арсеналі: [`yardstick`](https://yardstick.tidymodels.org/) — пакет, який використовується для оцінки ефективності моделей за допомогою метрик продуктивності.\n",
"\n",
"Однією з метрик продуктивності, пов’язаних із задачами класифікації, є [`матриця плутанини`](https://wikipedia.org/wiki/Confusion_matrix). Матриця плутанини описує, наскільки добре працює модель класифікації. Вона показує, скільки прикладів у кожному класі були правильно класифіковані моделлю. У нашому випадку вона покаже, скільки помаранчевих гарбузів були класифіковані як помаранчеві, а скільки білих гарбузів — як білі; матриця плутанини також покаже, скільки з них були класифіковані у **неправильні** категорії.\n",
"\n",
"Функція [**`conf_mat()`**](https://tidymodels.github.io/yardstick/reference/conf_mat.html) з пакету yardstick обчислює цю крос-табуляцію спостережуваних і передбачених класів.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Confusion matrix for prediction results\n",
"conf_mat(data = results, truth = color, estimate = .pred_class)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Давайте розглянемо матрицю плутанини. Нашу модель просять класифікувати гарбузи між двома бінарними категоріями: категорія `білий` і категорія `не-білий`.\n",
"\n",
"- Якщо ваша модель прогнозує гарбуз як білий, і він насправді належить до категорії \"білий\", ми називаємо це `істинно позитивним`, що показано у верхньому лівому куті.\n",
"\n",
"- Якщо ваша модель прогнозує гарбуз як не білий, і він насправді належить до категорії \"білий\", ми називаємо це `хибно негативним`, що показано у нижньому лівому куті.\n",
"\n",
"- Якщо ваша модель прогнозує гарбуз як білий, і він насправді належить до категорії \"не-білий\", ми називаємо це `хибно позитивним`, що показано у верхньому правому куті.\n",
"\n",
"- Якщо ваша модель прогнозує гарбуз як не білий, і він насправді належить до категорії \"не-білий\", ми називаємо це `істинно негативним`, що показано у нижньому правому куті.\n",
"\n",
"| Реальність |\n",
"|:----------:|\n",
"\n",
"| | | |\n",
"|---------------|--------|-------|\n",
"| **Прогноз** | БІЛИЙ | ПОМАРАНЧЕВИЙ |\n",
"| БІЛИЙ | TP | FP |\n",
"| ПОМАРАНЧЕВИЙ | FN | TN |\n",
"\n",
"Як ви могли здогадатися, бажано мати більше істинно позитивних і істинно негативних результатів, а також менше хибно позитивних і хибно негативних результатів, що свідчить про кращу роботу моделі.\n",
"\n",
"Матриця плутанини є корисною, оскільки вона дозволяє обчислювати інші метрики, які допомагають краще оцінити продуктивність моделі класифікації. Давайте розглянемо деякі з них:\n",
"\n",
"🎓 Точність (Precision): `TP/(TP + FP)` визначається як частка передбачених позитивних результатів, які насправді є позитивними. Також називається [позитивною прогностичною цінністю](https://en.wikipedia.org/wiki/Positive_predictive_value \"Positive predictive value\").\n",
"\n",
"🎓 Повнота (Recall): `TP/(TP + FN)` визначається як частка позитивних результатів серед кількості зразків, які насправді є позитивними. Також відома як `чутливість`.\n",
"\n",
"🎓 Специфічність (Specificity): `TN/(TN + FP)` визначається як частка негативних результатів серед кількості зразків, які насправді є негативними.\n",
"\n",
"🎓 Точність класифікації (Accuracy): `TP + TN/(TP + TN + FP + FN)` Відсоток міток, які були правильно передбачені для зразка.\n",
"\n",
"🎓 F-міра (F Measure): Зважене середнє між точністю та повнотою, де найкраще значення — 1, а найгірше — 0.\n",
"\n",
"Давайте обчислимо ці метрики!\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Combine metric functions and calculate them all at once\n",
"eval_metrics <- metric_set(ppv, recall, spec, f_meas, accuracy)\n",
"eval_metrics(data = results, truth = color, estimate = .pred_class)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Візуалізація ROC-кривої цієї моделі\n",
"\n",
"Давайте зробимо ще одну візуалізацію, щоб побачити так звану [`ROC-криву`](https://en.wikipedia.org/wiki/Receiver_operating_characteristic):\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Make a roc_curve\n",
"results %>% \n",
" roc_curve(color, .pred_ORANGE) %>% \n",
" autoplot()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Криві ROC часто використовуються для оцінки роботи класифікатора в термінах його істинно позитивних та хибно позитивних результатів. Криві ROC зазвичай мають `True Positive Rate`/Чутливість на осі Y та `False Positive Rate`/1-Специфічність на осі X. Таким чином, важливими є крутизна кривої та простір між діагоналлю і самою кривою: бажано, щоб крива швидко піднімалася вгору і відходила від діагоналі. У нашому випадку спочатку є хибно позитивні результати, а потім крива правильно піднімається вгору.\n",
"\n",
"Нарешті, давайте використаємо `yardstick::roc_auc()`, щоб обчислити фактичну площу під кривою (AUC). Один зі способів інтерпретації AUC — це ймовірність того, що модель оцінить випадковий позитивний приклад вище, ніж випадковий негативний приклад.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Calculate area under curve\n",
"results %>% \n",
" roc_auc(color, .pred_ORANGE)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Результат становить приблизно `0.975`. Оскільки AUC варіюється від 0 до 1, вам потрібен високий показник, адже модель, яка на 100% правильна у своїх прогнозах, матиме AUC, рівний 1; у цьому випадку модель є *доволі хорошою*.\n",
"\n",
"У майбутніх уроках про класифікацію ви дізнаєтеся, як покращити показники вашої моделі (наприклад, як працювати з незбалансованими даними у цьому випадку).\n",
"\n",
"## 🚀Виклик\n",
"\n",
"Є багато аспектів, які варто дослідити щодо логістичної регресії! Але найкращий спосіб навчитися — це експериментувати. Знайдіть набір даних, який підходить для такого типу аналізу, і побудуйте модель на його основі. Що ви дізналися? підказка: спробуйте [Kaggle](https://www.kaggle.com/search?q=logistic+regression+datasets) для цікавих наборів даних.\n",
"\n",
"## Огляд та самостійне навчання\n",
"\n",
"Прочитайте перші кілька сторінок [цієї статті зі Стенфорда](https://web.stanford.edu/~jurafsky/slp3/5.pdf) про практичне використання логістичної регресії. Поміркуйте над завданнями, які краще підходять для одного чи іншого типу регресії, які ми вивчали до цього моменту. Що працюватиме найкраще?\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Відмова від відповідальності**: \nЦей документ був перекладений за допомогою сервісу автоматичного перекладу [Co-op Translator](https://github.com/Azure/co-op-translator). Хоча ми прагнемо до точності, будь ласка, майте на увазі, що автоматичні переклади можуть містити помилки або неточності. Оригінальний документ на його рідній мові слід вважати авторитетним джерелом. Для критичної інформації рекомендується професійний людський переклад. Ми не несемо відповідальності за будь-які непорозуміння або неправильні тлумачення, що виникають у результаті використання цього перекладу.\n"
]
}
],
"metadata": {
"anaconda-cloud": "",
"kernelspec": {
"display_name": "R",
"langauge": "R",
"name": "ir"
},
"language_info": {
"codemirror_mode": "r",
"file_extension": ".r",
"mimetype": "text/x-r-source",
"name": "R",
"pygments_lexer": "r",
"version": "3.4.1"
},
"coopTranslator": {
"original_hash": "feaf125f481a89c468fa115bf2aed580",
"translation_date": "2025-09-04T06:59:39+00:00",
"source_file": "2-Regression/4-Logistic/solution/R/lesson_4-R.ipynb",
"language_code": "uk"
}
},
"nbformat": 4,
"nbformat_minor": 1
}