Logistic Regression Classification

Основи класифікації та логістична регресія

Що таке задача класифікації, чим відрізняється від регресії, основи логістичної регресії та сигмоїдна функція

Основи класифікації та логістична регресія

🎯 Мета підрозділу

  • Зрозуміти різницю між регресією та класифікацією
  • Опанувати поняття бінарної та багатокласової класифікації
  • Познайомитися з логістичною регресією та сигмоїдною функцією
  • Навчитися інтерпретувати ймовірнісні прогнози
  • Зрозуміти поняття порогу прийняття рішень

🔑 Ключові терміни

  • Класифікація (classification) — передбачення категорії або класу об'єкта
  • Бінарна класифікація (binary classification) — задача з двома класами
  • Логістична регресія (logistic regression) — алгоритм для класифікації
  • Сигмоїдна функція (sigmoid) — перетворює число у ймовірність від 0 до 1
  • Поріг рішення (decision threshold) — межа, за якою відбувається класифікація

Історія про лікаря, який діагностує хвороби

Доктор Петренко працює в клініці і щодня приймає пацієнтів з підозрою на серцево-судинні захворювання. Після аналізів (рівень холестерину, тиск, вік, вага) він має прийняти важливе рішення: чи є у пацієнта підвищений ризик хвороби серця?

На відміну від завдання передбачення точної ціни квартири (де результат — будь-яке число), тут результат може бути лише одним із двох варіантів:

  • Клас 0: здоровий пацієнт (низький ризик)
  • Клас 1: пацієнт з підвищеним ризиком (потрібне подальше обстеження)

Це класична задача бінарної класифікації (binary classification). Доктор не оцінює «наскільки хворий» пацієнт числом від 0 до 100 — він приймає дискретне рішення: направляти на додаткові обстеження чи ні.

Ключова відмінність від регресії: результат класифікації — це категорія (клас), а не неперервне число. Навіть якщо алгоритм внутрішньо обчислює ймовірність (наприклад, 0.73), фінальне рішення — дискретне: клас 0 або клас 1.

Що таке задача класифікації?

Класифікація (classification) — це тип завдання машинного навчання з учителем (supervised learning), де потрібно віднести об'єкт до одного з фіксованих дискретних класів на основі його ознак.

Приклади класифікаційних задач

Вхідні ознакиЦільова змінна (що передбачаємо)Кількість класів
Текст листа, відправник, заголовокСпам / не спам2 (бінарна)
Симптоми, результати аналізівЗдоровий / хворий2 (бінарна)
Фотографія руки з цифроюЦифра від 0 до 910 (багатокласова)
Характеристики квітки (довжина пелюсток)Вид квітки (Setosa / Versicolor / Virginica)3 (багатокласова)
Характеристики транзакції (сума, час, місце)Шахрайство / легальна операція2 (бінарна)
Зображення твариниКіт / собака / пташка3 (багатокласова)
Як розпізнати класифікацію: якщо вас просять передбачити назву або категорію (а не число), це класифікація. Класи завжди дискретні та взаємовиключні — об'єкт не може одночасно належати до кількох класів (у стандартній постановці).

Типи класифікації

У машинному навчанні розрізняють кілька фундаментальних типів класифікаційних задач залежно від кількості класів та їхньої структури.

1. Бінарна класифікація (Binary Classification)

Визначення: задача, де об'єкт належить до одного з двох класів.

Зазвичай класи позначають як:

  • 0 та 1 (у програмуванні та математиці)
  • негативний та позитивний клас (negative / positive)
  • False та True (у логічних задачах)

Приклади:

  • Медична діагностика: хворий (1) / здоровий (0)
  • Фінанси: дефолт (1) / виплата (0)
  • Email: спам (1) / не спам (0)
  • Кредитний скоринг: схвалити заявку (1) / відхилити (0)
# Датасет з двома класами
y_train = np.array([0, 1, 0, 0, 1, 1, 0, 1])

# Прогноз моделі
y_pred = model.predict(X_test)
# Результат: [1, 0, 0, 1, 1] — лише 0 або 1

2. Багатокласова класифікація (Multiclass Classification)

Визначення: задача, де об'єкт належить до одного з трьох або більше класів.

Кожен об'єкт має один і тільки один клас. Класи взаємовиключні.

Приклади:

  • Розпізнавання рукописних цифр: 0, 1, 2, ..., 9 (10 класів)
  • Класифікація квітів Iris: Setosa, Versicolor, Virginica (3 класи)
  • Розпізнавання емоцій на фото: радість, сум, гнів, подив, страх (5 класів)
  • Класифікація жанрів фільмів: драма, комедія, бойовик, фантастика
multiclass_example.ipynb
Python 3 (ipykernel)
Code
In [1]:
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression

# Завантаження датасету Iris (3 класи)
iris = load_iris()
X, y = iris.data, iris.target

print(f"Кількість класів: {len(np.unique(y))}")
print(f"Класи: {iris.target_names}")

import matplotlib.pyplot as plt

colors = ['#ef4444', '#3b82f6', '#10b981']

plt.figure(figsize=(9, 6))
for k, name in enumerate(iris.target_names):
    plt.scatter(X[y == k, 2], X[y == k, 3], c=colors[k], s=60,
                alpha=0.8, edgecolor='white', label=name)
plt.xlabel('Довжина пелюстки (см)', fontsize=12)
plt.ylabel('Ширина пелюстки (см)', fontsize=12)
plt.title('Iris: три класи у просторі ознак пелюстки', fontsize=14)
plt.legend(title='Клас')
plt.grid(alpha=0.3)
plt.show()
Out[1]:

Кількість класів: 3
Класи: ['setosa' 'versicolor' 'virginica']

3. Мультилейбл класифікація (Multilabel Classification)

Визначення: задача, де об'єкт може одночасно належати до кількох класів.

На відміну від багатокласової класифікації, тут класи не взаємовиключні — об'єкт може мати кілька міток одночасно.

Приклади:

  • Теги для статті: "Python", "Machine Learning", "Tutorial"
  • Класифікація фільму за жанрами: "Action", "Sci-Fi", "Thriller"
  • Медична діагностика з кількома хворобами одночасно
  • Розпізнавання об'єктів на фото: "людина", "автомобіль", "будинок"
# Один клас на об'єкт
y = [2, 0, 1, 2, 1]
# Об'єкт належить ТІЛЬКИ до класу 2 АБО 0 АБО 1
Фокус цього розділу: ми зосередимося на бінарній класифікації, оскільки логістична регресія спочатку була розроблена саме для цього випадку. Багатокласова класифікація розглядається як розширення через стратегії "один проти всіх" (one-vs-rest) або "один проти одного" (one-vs-one).

Регресія vs Класифікація: фундаментальні відмінності

Хоча обидва типи задач належать до навчання з учителем (supervised learning), між ними існують принципові відмінності у природі цільової змінної та способах оцінювання моделей.

Концептуальні відмінності

ХарактеристикаРегресіяКласифікація
Тип цільової змінноїНеперервна числова величинаДискретна категорія
Приклад виводуЗавантаження...Завантаження...
Діапазон значеньЗавантаження... або Завантаження...Фіксована скінченна множина класів
Функція активаціїЛінійна (відсутня)Сигмоїда, softmax, tanh
Функція втратMSE, MAE, HuberCross-Entropy, Hinge Loss
Метрики оцінкиЗавантаження..., RMSE, MAEAccuracy, Precision, Recall, F1-Score
Геометрична інтерпретаціяПряма/крива апроксимаціїРозділова межа між класами
Простий спосіб розрізнити:
  • Якщо на запитання "скільки?" потрібна відповідь числом — це регресія
  • Якщо на запитання "який?" потрібна відповідь категорією — це класифікація

Математична формалізація

Регресія:

Завантаження...

Модель апроксимує неперервну функцію Завантаження..., де Завантаження... може приймати будь-яке дійсне значення.

Класифікація:

Завантаження...

Модель обчислює розподіл ймовірностей по класах Завантаження... і обирає клас з найвищою ймовірністю.

Аналогія (Термометр vs Світлофор):
  • Регресія — це термометр: показує точне неперервне число на шкалі (Завантаження..., Завантаження...).
  • Класифікація — це світлофор: обирає один із фіксованих станів (🔴 червоний, 🟡 жовтий, 🟢 зелений).

Чому лінійна регресія не підходить для класифікації?

На перший погляд, можна спробувати використати звичайну лінійну регресію для класифікації: позначити класи числами (0 та 1), навчити модель Завантаження..., і застосувати поріг — якщо Завантаження..., клас 1, інакше 0.

Але цей підхід має критичні проблеми.

Проблема 1: Прогнози виходять за межі 0, 1

Лінійна функція не обмежена зверху і знизу. Для великих або малих значень Завантаження... прогноз може бути меншим за 0 або більшим за 1, що не має сенсу як ймовірність.

linear_regression_fails.ipynb
Python 3.11 (ipykernel)
Code
In [1]:
0.12s
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression

# Дані: вік студента та чи склав іспит (0 = ні, 1 = так)
X = np.array([15, 18, 20, 22, 25, 28, 30, 35, 40, 45]).reshape(-1, 1)
y = np.array([0, 0, 0, 1, 1, 1, 1, 1, 1, 1])

# Навчання лінійної регресії
model = LinearRegression()
model.fit(X, y)

# Прогноз для різних значень віку
X_test = np.linspace(10, 50, 100).reshape(-1, 1)
y_pred = model.predict(X_test)

print(f"Прогноз для віку 10: {model.predict([[10]])[0]:.3f}")
print(f"Прогноз для віку 50: {model.predict([[50]])[0]:.3f}")
Out[1]:

Прогноз для віку 10: -0.287
Прогноз для віку 50: 1.543
Проблема: прогноз Завантаження... означає «ймовірність -28.7%», а Завантаження... — «ймовірність 154.3%». Це математично некоректно! Ймовірність має бути в межах Завантаження....

Проблема 2: Чутливість до викидів (outliers)

Лінійна регресія намагається мінімізувати середньоквадратичну помилку (MSE), що робить її надзвичайно чутливою до викидів. Один екстремальний об'єкт може сильно змістити лінію та зіпсувати класифікацію для всіх інших точок.

Аналогія: уявіть, що ви вибудовуєте шеренгу учнів за зростом, щоб провести «лінію» між високими та низькими. Раптом приходить один учень зростом 2 метри. Лінійна регресія спробує наблизити всю пряму до цього гіганта, зіпсувавши розподіл для решти.

Проблема 3: Семантична невідповідність

Лінійна регресія припускає, що різниця між 0 і 0.5 та між 0.5 і 1.0 однакова та має сенс. Але для класифікації це не так: клас 0 та клас 1 — це просто мітки, а не числа на осі. Різниця «на 0.3» між класами безглузда.

Висновок: для класифікації потрібен спеціальний алгоритм, який:
  1. Обмежує прогнози діапазоном Завантаження...
  2. Інтерпретує вихід як ймовірність належності до класу
  3. Стійкий до викидів
  4. Використовує функцію втрат, що відповідає природі задачі
Такий алгоритм називається логістична регресія.

Що таке логістична регресія?

Логістична регресія (logistic regression) — це алгоритм машинного навчання для задач бінарної класифікації, який моделює ймовірність належності об'єкта до класу 1 за допомогою сигмоїдної функції (sigmoid function).

Важливе зауваження: незважаючи на назву "регресія", це алгоритм класифікації! Історично він отримав таку назву через використання регресійного підходу (лінійна комбінація ознак), але розв'язує класифікаційну задачу.

Ідея алгоритму

Логістична регресія складається з двох етапів:

  1. Лінійна комбінація ознак:
Завантаження...

Це звичайна лінійна функція, де Завантаження....

  1. Застосування сигмоїдної функції:
Завантаження...

Сигмоїда "стискає" будь-яке дійсне число Завантаження... у діапазон Завантаження..., що інтерпретується як ймовірність належності до класу 1.

# Ознаки: вік, холестерин
x = np.array([45, 220])  # вік = 45 років, холестерин = 220 мг/дл
w = np.array([0.05, 0.02])
b = -8.5

z = w @ x + b  # Скалярний добуток + зміщення
print(f"z = {z:.2f}")  # Може бути будь-яким числом

Сигмоїдна функція: перетворення числа у ймовірність

Сигмоїдна функція (sigmoid function), також відома як логістична функція, — це математична функція, що перетворює будь-яке дійсне число у значення від 0 до 1.

Математичне визначення

Завантаження...

Де:

  • Завантаження... — вхідне значення (лінійна комбінація ознак)
  • Завантаження... — основа натурального логарифма
  • Завантаження... — вихід у діапазоні ймовірностей

Властивості сигмоїди

σ(0) = 0.5
У нульовій точці сигмоїда повертає рівно 0.5 — це точка невизначеності, де модель не може віддати перевагу жодному класу.
σ(z) → 1 при z → +∞
Для великих позитивних значень Завантаження... сигмоїда асимптотично наближається до 1 (висока впевненість у класі 1).
σ(z) → 0 при z → -∞
Для великих негативних значень Завантаження... сигмоїда наближається до 0 (висока впевненість у класі 0).
Симетричність відносно (0, 0.5)
Сигмоїда симетрична: Завантаження.... Якщо Завантаження..., то Завантаження....
Монотонне зростання
Функція завжди зростає, але ніколи не досягає 0 або 1 — лише наближається асимптотично.
S-подібна форма
Графік нагадує латинську букву S — звідси неформальна назва "S-крива".
sigmoid_visualization.ipynb
Python 3.11 (ipykernel)
Code
In [1]:
0.18s
import numpy as np
import matplotlib.pyplot as plt

def sigmoid(z):
    return 1 / (1 + np.exp(-z))

# Діапазон значень z від -10 до +10
z = np.linspace(-10, 10, 200)
y = sigmoid(z)

# Побудова графіка
plt.figure(figsize=(10, 6))
plt.plot(z, y, linewidth=2.5, color='#3b82f6', label='σ(z)')
plt.axhline(y=0.5, color='#ef4444', linestyle='--', alpha=0.7, label='Поріг 0.5')
plt.axvline(x=0, color='#10b981', linestyle='--', alpha=0.7, label='z = 0')
plt.grid(alpha=0.3)
plt.xlabel('z (лінійна комбінація)', fontsize=12)
plt.ylabel('σ(z) — ймовірність класу 1', fontsize=12)
plt.title('Сигмоїдна функція: перетворення z у ймовірність', fontsize=14)
plt.legend()
plt.show()

# Перевірка ключових точок
print(f"σ(-5) = {sigmoid(-5):.4f}")
print(f"σ(0)  = {sigmoid(0):.4f}")
print(f"σ(5)  = {sigmoid(5):.4f}")
Out[1]:

σ(-5) = 0.0067
σ(0)  = 0.5000
σ(5)  = 0.9933

Інтерпретація виходу логістичної регресії

Логістична регресія повертає ймовірність належності до класу 1: Завантаження....

Фінальне рішення про клас приймається через поріг (threshold), зазвичай 0.5:

Завантаження...
Аналогія (Адвокат у суді): сигмоїда обчислює "ступінь впевненості" у виді відсотка (40%, 75%, 92%). Адвокат не каже "підсудний хороший на 68%" — він приймає остаточне рішення "винний" або "невинний" на основі порогу (наприклад, "якщо впевненість >50%, визнаємо винним").

Приклад інтерпретації

logistic_interpretation.ipynb
Python 3 (ipykernel)
Code
In [1]:
# Пацієнт: вік = 52, холестерин = 240, тиск = 145
X = np.array([[52, 240, 145]])

# Передбачена ймовірність (приклад)
y_prob = model.predict_proba(X)[0, 1]
y_class = model.predict(X)[0]

print(f"Ймовірність хвороби серця: {y_prob:.1%}")
print(f"Прогноз: {'підвищений ризик ⚠️' if y_class == 1 else 'низький ризик ✅'}")

import matplotlib.pyplot as plt

plt.figure(figsize=(9, 2.8))
plt.barh(['P(y=1)'], [y_prob], color='#ef4444' if y_prob >= 0.5 else '#10b981', height=0.5)
plt.barh(['P(y=1)'], [1 - y_prob], left=[y_prob], color='#e5e7eb', height=0.5)
plt.axvline(0.5, color='#1f2937', linestyle='--', label='Поріг 0.5')
plt.text(y_prob / 2, 0, f'{y_prob:.1%}', ha='center', va='center',
         color='white', fontsize=14, fontweight='bold')
plt.xlim(0, 1)
plt.xlabel('Ймовірність хвороби серця')
plt.title('Ймовірність → клас через поріг', fontsize=13)
plt.legend(loc='upper right')
plt.show()
Out[1]:

Ймовірність хвороби серця: 73.2%
Прогноз: підвищений ризик ⚠️
Важливо: вихід логістичної регресії — це ймовірність, а не впевненість. Значення 0.6 означає, що з 100 подібних пацієнтів приблизно 60 мають хворобу, а 40 — ні. Це не означає "пацієнт хворий на 60%".

Коли використовувати логістичну регресію?

Логістична регресія — простий, інтерпретований та ефективний алгоритм, але має свої обмеження.

Переваги

✅ Простота інтерпретації

Коефіцієнти Завантаження... показують вплив кожної ознаки на ймовірність. Можна пояснити, чому модель прийняла рішення.

✅ Швидке навчання

Алгоритм дуже швидкий навіть на великих датасетах — використовує градієнтний спуск або аналітичне рішення.

✅ Ймовірнісні прогнози

Повертає ймовірність, що дозволяє оцінити впевненість моделі та налаштувати поріг під бізнес-вимоги.

✅ Не вимагає великих даних

Може працювати навіть на невеликих вибірках (від кількох сотень об'єктів).

Обмеження

❌ Тільки лінійна розділова межа

Модель малює пряму лінію між класами. Якщо дані лінійно нероздільні, потрібні нелінійні алгоритми (дерева рішень, SVM з RBF ядром).

❌ Чутливість до мультиколінеарності

Якщо ознаки сильно корелюють між собою, коефіцієнти стають нестабільними. Потрібна регуляризація (Ridge, Lasso).

❌ Не працює зі складними залежностями

Для нелінійних паттернів (XOR-задача) потрібні поліноміальні ознаки або глибші моделі.
Золоте правило: почніть з логістичної регресії як базової моделі (baseline). Якщо вона дає результат >80% точності — чудово! Якщо ні — переходьте до складніших моделей (Random Forest, Gradient Boosting, нейронні мережі).

Резюме

📌 Класифікація

Задача передбачення дискретної категорії (класу) на основі ознак. Результат — одна з фіксованих міток.

📌 Бінарна vs Багатокласова

Бінарна: 2 класи (спам/не спам). Багатокласова: 3+ класів (кіт/собака/пташка).

📌 Логістична регресія

Алгоритм для класифікації, що моделює ймовірність через лінійну комбінацію + сигмоїду.

📌 Сигмоїдна функція

Завантаження... — перетворює будь-яке число у ймовірність від 0 до 1.

📌 Поріг рішення

Зазвичай 0.5: якщо Завантаження..., клас 1; інакше клас 0.

📌 Переваги

Швидка, інтерпретована, ймовірнісна, працює на малих даних.

Розділова межа (Decision Boundary)

Одна з найважливіших концепцій у класифікації — розділова межа (decision boundary). Це геометричне представлення того, як модель "розрізає" простір ознак на області, що відповідають різним класам.

Математичне визначення

Розділова межа — це множина точок у просторі ознак, де ймовірність належності до класу 1 дорівнює 0.5:

Завантаження...

Оскільки Завантаження..., розділова межа визначається рівнянням:

Завантаження...
Геометрична інтерпретація: для двох ознак (Завантаження...) це рівняння задає пряму лінію у площині. Для трьох ознак — площину у 3D просторі. Для Завантаження... ознак — гіперплощину у Завантаження...-вимірному просторі.

Приклад у двовимірному просторі

Розглянемо задачу класифікації студентів на основі двох іспитів:

decision_boundary_2d.ipynb
Python 3.11 (ipykernel)
Code
In [1]:
0.22s
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression

# Дані: оцінки з двох іспитів та результат (0 = не прийнято, 1 = прийнято)
X_train = np.array([
    [45, 85], [55, 70], [60, 90], [65, 75], [70, 88],
    [75, 92], [80, 85], [85, 95], [30, 50], [40, 60],
    [50, 65], [35, 55], [42, 68]
])
y_train = np.array([0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0])

# Навчання моделі
model = LogisticRegression()
model.fit(X_train, y_train)

# Отримання параметрів
w1, w2 = model.coef_[0]
b = model.intercept_[0]

print(f"Рівняння розділової межі:")
print(f"{w1:.3f} * x1 + {w2:.3f} * x2 + {b:.3f} = 0")
print(f"\nСпрощено (x2 через x1):")
x2_formula = f"x2 = {-w1/w2:.3f} * x1 + {-b/w2:.3f}"
print(x2_formula)
Out[1]:
Рівняння розділової межі:
0.057 * x1 + 0.089 * x2 + -6.421 = 0

Спрощено (x2 через x1):
x2 = -0.641 * x1 + 72.146
In [2]:
0.28s
# Побудова графіка з розділовою межею
plt.figure(figsize=(10, 7))

# Точки класу 0 (не прийнято)
plt.scatter(X_train[y_train == 0, 0], X_train[y_train == 0, 1],
            c='#ef4444', marker='x', s=100, linewidths=2,
            label='Клас 0 (не прийнято)', alpha=0.8)

# Точки класу 1 (прийнято)
plt.scatter(X_train[y_train == 1, 0], X_train[y_train == 1, 1],
            c='#10b981', marker='o', s=100, linewidths=2,
            label='Клас 1 (прийнято)', alpha=0.8)

# Розділова межа
x1_line = np.linspace(20, 90, 100)
x2_line = -(w1 * x1_line + b) / w2
plt.plot(x1_line, x2_line, 'b--', linewidth=2.5, label='Розділова межа')

# Регіони класів (фон)
xx, yy = np.meshgrid(np.linspace(20, 90, 200), np.linspace(40, 100, 200))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.1, levels=[-0.5, 0.5, 1.5],
             colors=['#ef4444', '#10b981'])

plt.xlabel('Іспит 1 (бали)', fontsize=12)
plt.ylabel('Іспит 2 (бали)', fontsize=12)
plt.title('Розділова межа логістичної регресії', fontsize=14)
plt.legend(fontsize=11)
plt.grid(alpha=0.3)
plt.show()
Out[2]:

Властивості розділової межі

Лінійність
Для логістичної регресії розділова межа завжди лінійна (пряма, площина, гіперплощина). Це обмеження алгоритму.
Нахил визначається вагами
Коефіцієнти Завантаження... визначають орієнтацію межі у просторі ознак.
Зміщення визначається bias
Вільний член Завантаження... визначає положення межі вздовж осей (паралельний зсув).
Перпендикулярність до вектора ваг
Вектор ваг Завантаження... завжди перпендикулярний до розділової межі. Він вказує напрямок, у якому ймовірність класу 1 зростає найшвидше.
Аналогія (Кордон між країнами): розділова межа — це як державний кордон на карті. З одного боку — територія класу 0 (наприклад, Польща), з іншого — класу 1 (Україна). Точки на самій межі — це "нейтральна зона", де модель не впевнена (ймовірність = 50%).

Вплив параметрів на розділову межу

Параметри моделі Завантаження... (ваги) та Завантаження... (зміщення) повністю визначають положення та орієнтацію розділової межі.

Вплив ваг (w)

Ваги визначають нахил (кут) розділової межі та важливість кожної ознаки.

weights_impact.ipynb
Python 3 (ipykernel)
Code
In [1]:
# Приклад 1: рівноважні ваги
w = np.array([1, 1])  # x1 та x2 однаково важливі
b = -100

# Рівняння: x1 + x2 = 100
# Це пряма під кутом 45° (нахил -1)

print("Приклад 1: w = [1, 1], b = -100")
print("Розділова межа: x2 = -x1 + 100 (діагональ)")

import matplotlib.pyplot as plt

x1 = np.linspace(0, 100, 100)
x2 = -(w[0] * x1 + b) / w[1]

plt.figure(figsize=(7, 6))
plt.plot(x1, x2, color='#3b82f6', linewidth=2.5, label='x1 + x2 = 100')
plt.fill_between(x1, x2, 100, color='#10b981', alpha=0.12, label='Клас 1')
plt.fill_between(x1, 0, x2, color='#ef4444', alpha=0.12, label='Клас 0')
plt.xlim(0, 100); plt.ylim(0, 100)
plt.xlabel('x1'); plt.ylabel('x2')
plt.title('w = [1, 1], b = -100: діагональна межа (45°)', fontsize=13)
plt.legend(); plt.grid(alpha=0.3)
plt.show()
Out[1]:

Приклад 1: w = [1, 1], b = -100
Розділова межа: x2 = -x1 + 100 (діагональ)
weights_impact_2.ipynb
Python 3 (ipykernel)
Code
In [2]:
# Приклад 2: x1 важливіший за x2
w = np.array([3, 1])
b = -100

# Рівняння: 3*x1 + x2 = 100
# x2 = -3*x1 + 100 (крутіший нахил)

print("\nПриклад 2: w = [3, 1], b = -100")
print("Розділова межа: x2 = -3*x1 + 100 (більше залежить від x1)")
print("Інтерпретація: x1 в 3 рази важливіша за x2")

import matplotlib.pyplot as plt

x1 = np.linspace(0, 100, 200)

plt.figure(figsize=(7, 6))
plt.plot(x1, -(1 * x1 - 100) / 1, color='#3b82f6', linewidth=2.5, label='w = [1, 1]: x2 = -x1 + 100')
plt.plot(x1, -(3 * x1 - 100) / 1, color='#ef4444', linewidth=2.5, label='w = [3, 1]: x2 = -3·x1 + 100')
plt.xlim(0, 100); plt.ylim(0, 100)
plt.xlabel('x1'); plt.ylabel('x2')
plt.title('Більша вага x1 робить межу крутішою', fontsize=13)
plt.legend(); plt.grid(alpha=0.3)
plt.show()
Out[2]:

Приклад 2: w = [3, 1], b = -100
Розділова межа: x2 = -3*x1 + 100 (більше залежить від x1)
Інтерпретація: x1 в 3 рази важливіша за x2
Правило: чим більший абсолютний коефіцієнт Завантаження..., тим більше ця ознака впливає на рішення моделі. Від'ємна вага означає зворотний зв'язок: зростання ознаки знижує ймовірність класу 1.

Вплив зміщення (bias)

Bias Завантаження... зміщує розділову межу паралельно сама собі, не змінюючи її нахилу.

bias_impact.ipynb
Python 3 (ipykernel)
Code
In [1]:
# Фіксуємо ваги, змінюємо bias
w = np.array([1, 1])

# Три різні bias
biases = [-80, -100, -120]

for b in biases:
    # x1 + x2 + b = 0  =>  x2 = -x1 - b
    print(f"b = {b:4d}  =>  x2 = -x1 + {-b} (пряма проходить через точку (0, {-b}))")

import matplotlib.pyplot as plt

x1 = np.linspace(0, 130, 200)
colors = ['#10b981', '#3b82f6', '#ef4444']

plt.figure(figsize=(7, 6))
for b, c in zip(biases, colors):
    plt.plot(x1, -x1 - b, color=c, linewidth=2.5, label=f'b = {b}')
plt.xlim(0, 130); plt.ylim(0, 130)
plt.xlabel('x1'); plt.ylabel('x2')
plt.title('Зміна bias зсуває межу паралельно', fontsize=13)
plt.legend(); plt.grid(alpha=0.3)
plt.show()
Out[1]:

b =  -80  =>  x2 = -x1 + 80 (пряма проходить через точку (0, 80))
b = -100  =>  x2 = -x1 + 100 (пряма проходить через точку (0, 100))
b = -120  =>  x2 = -x1 + 120 (пряма проходить через точку (0, 120))
Візуальний образ: уявіть, що ви тримаєте лінійку під фіксованим кутом. Зміна Завантаження... — це як пересунути лінійку вгору чи вниз, не обертаючи її.


Нелінійні розділові межі: обмеження логістичної регресії

Базова логістична регресія може будувати лише лінійні розділові межі. Для складних паттернів, де класи розділені кривою, колом чи іншою нелінійною формою, потрібні розширення.

Приклад: XOR-задача

Розглянемо класичну задачу XOR (виключне АБО):

xor_problem.ipynb
Python 3 (ipykernel)
Code
In [1]:
# Дані XOR: клас 1 у протилежних кутах квадрата
X_xor = np.array([
    [0, 0],  # клас 0
    [0, 1],  # клас 1
    [1, 0],  # клас 1
    [1, 1]   # клас 0
])
y_xor = np.array([0, 1, 1, 0])

# Спроба навчити звичайну логістичну регресію
model_linear = LogisticRegression()
model_linear.fit(X_xor, y_xor)

accuracy = model_linear.score(X_xor, y_xor)
print(f"Точність лінійної моделі на XOR: {accuracy:.0%}")
print("Проблема: жодна пряма лінія не може розділити ці точки!")

import matplotlib.pyplot as plt

xx, yy = np.meshgrid(np.linspace(-0.5, 1.5, 300), np.linspace(-0.5, 1.5, 300))
Z = model_linear.predict_proba(np.c_[xx.ravel(), yy.ravel()])[:, 1].reshape(xx.shape)

plt.figure(figsize=(7, 6))
plt.contourf(xx, yy, Z, levels=20, cmap='RdYlGn', alpha=0.35)
plt.contour(xx, yy, Z, levels=[0.5], colors='#1f2937', linewidths=2.5, linestyles='--')
plt.scatter(X_xor[y_xor == 0, 0], X_xor[y_xor == 0, 1], c='#ef4444', marker='x', s=200, linewidths=3, label='Клас 0')
plt.scatter(X_xor[y_xor == 1, 0], X_xor[y_xor == 1, 1], c='#10b981', marker='o', s=200, edgecolor='white', label='Клас 1')
plt.xlabel('x1'); plt.ylabel('x2')
plt.title(f'XOR: лінійна модель, точність {accuracy:.0%}', fontsize=13)
plt.legend(); plt.grid(alpha=0.3)
plt.show()
Out[1]:

Точність лінійної моделі на XOR: 50%
Проблема: жодна пряма лінія не може розділити ці точки!

Рішення: поліноміальні ознаки

Щоб розв'язати нелінійні задачі, можна штучно створити нелінійні ознаки — квадрати, добутки, степені вихідних змінних.

polynomial_features.ipynb
Python 3 (ipykernel)
Code
In [1]:
from sklearn.preprocessing import PolynomialFeatures

# Створюємо поліноміальні ознаки (квадрати та добутки)
poly = PolynomialFeatures(degree=2, include_bias=False)
X_poly = poly.fit_transform(X_xor)

print("Вихідні ознаки:")
print(X_xor)
print("\nПісля перетворення (x1, x2, x1², x1*x2, x2²):")
print(X_poly)
Out[1]:
Вихідні ознаки:
[[0 0]
 [0 1]
 [1 0]
 [1 1]]

Після перетворення (x1, x2, x1², x1*x2, x2²):
[[0. 0. 0. 0. 0.]
 [0. 1. 0. 0. 1.]
 [1. 0. 1. 0. 0.]
 [1. 1. 1. 1. 1.]]
polynomial_logistic.ipynb
Python 3 (ipykernel)
Code
In [2]:
# Навчання моделі на поліноміальних ознаках
# C=100 — слабка регуляризація, бо даних лише 4 точки
model_poly = LogisticRegression(C=100)
model_poly.fit(X_poly, y_xor)

accuracy_poly = model_poly.score(X_poly, y_xor)
print(f"Точність моделі з поліноміальними ознаками: {accuracy_poly:.0%}")
print("Успіх! Тепер розділова межа — це крива, а не пряма.")

import matplotlib.pyplot as plt

xx, yy = np.meshgrid(np.linspace(-0.5, 1.5, 300), np.linspace(-0.5, 1.5, 300))
grid_poly = poly.transform(np.c_[xx.ravel(), yy.ravel()])
Z = model_poly.predict_proba(grid_poly)[:, 1].reshape(xx.shape)

plt.figure(figsize=(7, 6))
plt.contourf(xx, yy, Z, levels=20, cmap='RdYlGn', alpha=0.35)
plt.contour(xx, yy, Z, levels=[0.5], colors='#1f2937', linewidths=2.5, linestyles='--')
plt.scatter(X_xor[y_xor == 0, 0], X_xor[y_xor == 0, 1], c='#ef4444', marker='x', s=200, linewidths=3, label='Клас 0')
plt.scatter(X_xor[y_xor == 1, 0], X_xor[y_xor == 1, 1], c='#10b981', marker='o', s=200, edgecolor='white', label='Клас 1')
plt.xlabel('x1'); plt.ylabel('x2')
plt.title(f'XOR: поліноміальні ознаки, точність {accuracy_poly:.0%}', fontsize=13)
plt.legend(); plt.grid(alpha=0.3)
plt.show()
Out[2]:

Точність моделі з поліноміальними ознаками: 100%
Успіх! Тепер розділова межа — це крива, а не пряма.
Стратегія: якщо лінійна логістична регресія дає низьку точність (<70%), спробуйте:
  1. Додати поліноміальні ознаки (степені 2 або 3)
  2. Використати ядрові методи (SVM з RBF ядром)
  3. Перейти до нелінійних моделей (дерева рішень, нейронні мережі)

Поріг прийняття рішень (Decision Threshold)

За замовчуванням, логістична регресія використовує поріг 0.5: якщо Завантаження..., прогнозується клас 1. Але цей поріг можна налаштувати під специфіку задачі.

Чому важливий вибір порогу?

У різних задачах помилки класифікації мають різну ціну:

🏥 Медична діагностика

False Negative (пропустили хвороби) — дуже небезпечно! Пацієнт не отримає лікування.

False Positive (хибна тривога) — менш критично, додаткові обстеження.

Рішення: знизити поріг до 0.3, щоб виявити більше потенційних хворих.

🛡️ Детекція спаму

False Positive (важливий лист у спам) — дуже погано! Користувач пропустить важливу інформацію.

False Negative (спам у вхідних) — менш критично, трохи дратує.

Рішення: підвищити поріг до 0.7, щоб бути впевненим перед блокуванням листа.

Зміна порогу у коді

custom_threshold.ipynb
Python 3.11 (ipykernel)
Code
In [1]:
0.08s
from sklearn.linear_model import LogisticRegression
import numpy as np

# Припустимо, модель вже навчена
# model = LogisticRegression()
# model.fit(X_train, y_train)

# Отримуємо ймовірності для тестової вибірки
X_test = np.array([[50, 75], [70, 90], [40, 60]])
y_probs = model.predict_proba(X_test)[:, 1]  # Ймовірність класу 1

print("Ймовірності класу 1:")
print(y_probs)

import matplotlib.pyplot as plt

labels = [f'Об\'єкт {i + 1}' for i in range(len(y_probs))]

plt.figure(figsize=(9, 5))
plt.bar(labels, y_probs, color='#3b82f6', alpha=0.85, width=0.5)
for t, c in zip([0.3, 0.5, 0.7], ['#10b981', '#1f2937', '#ef4444']):
    plt.axhline(t, color=c, linestyle='--', linewidth=2, label=f'Поріг {t}')
for i, p in enumerate(y_probs):
    plt.text(i, p + 0.02, f'{p:.2f}', ha='center', fontsize=12)
plt.ylim(0, 1)
plt.ylabel('P(y = 1)')
plt.title('Той самий об\'єкт — різні рішення при різних порогах', fontsize=13)
plt.legend()
plt.show()
Out[1]:

Ймовірності класу 1:
[0.35 0.82 0.18]
In [2]:
0.03s
# Застосування різних порогів
thresholds = [0.3, 0.5, 0.7]

for threshold in thresholds:
    y_pred = (y_probs >= threshold).astype(int)
    print(f"\nПоріг {threshold}: прогнози = {y_pred}")
Out[2]:
Поріг 0.3: прогнози = [1 1 0]
Поріг 0.5: прогнози = [0 1 0]
Поріг 0.7: прогнози = [0 1 0]
Практичне правило:
  • Низький поріг (0.3) → модель стає більш "обережною", частіше прогнозує клас 1 (висока повнота, recall)
  • Високий поріг (0.7) → модель стає більш "консервативною", рідше прогнозує клас 1 (висока точність, precision)

Багатокласова логістична регресія (Multiclass)

Базова логістична регресія призначена для бінарної класифікації (2 класи). Для задач з 3+ класами використовують розширення.

Стратегія "Один проти всіх" (One-vs-Rest)

Ідея: навчити Завантаження... окремих бінарних класифікаторів (де Завантаження... — кількість класів). Кожен класифікатор відповідає на питання: "Чи належить об'єкт до класу Завантаження...?"

multiclass_ovr.ipynb
Python 3.11 (ipykernel)
Code
In [1]:
0.11s
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split

# Завантаження датасету Iris
iris = load_iris()
X, y = iris.data, iris.target

# Розбиття на навчальну та тестову вибірки
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42
)

# Навчання моделі з multi_class='ovr'
model_ovr = LogisticRegression(multi_class='ovr', max_iter=200)
model_ovr.fit(X_train, y_train)

accuracy = model_ovr.score(X_test, y_test)
print(f"Точність на тестовій вибірці: {accuracy:.1%}")
print(f"\nМодель навчила {len(model_ovr.coef_)} бінарних класифікаторів")
print(f"Форма матриці ваг: {model_ovr.coef_.shape}")
Out[1]:
Точність на тестовій вибірці: 97.8%

Модель навчила 3 бінарних класифікаторів
Форма матриці ваг: (3, 4)
In [2]:
0.05s
# Прогноз для одного об'єкта
sample = X_test[0:1]
probs = model_ovr.predict_proba(sample)[0]

print("Ймовірності для кожного класу:")
for i, (class_name, prob) in enumerate(zip(iris.target_names, probs)):
    print(f"  Клас {i} ({class_name:10s}): {prob:.1%}")

predicted_class = model_ovr.predict(sample)[0]
print(f"\nПрогноз: клас {predicted_class} ({iris.target_names[predicted_class]})")

import matplotlib.pyplot as plt

colors = ['#ef4444', '#3b82f6', '#10b981']

plt.figure(figsize=(8, 5))
bars = plt.bar(iris.target_names, probs, color=colors, alpha=0.85)
for bar, p in zip(bars, probs):
    plt.text(bar.get_x() + bar.get_width() / 2, p + 0.02, f'{p:.1%}', ha='center', fontsize=12)
plt.ylim(0, 1.1)
plt.ylabel('Ймовірність')
plt.title(f'Прогноз: {iris.target_names[predicted_class]}', fontsize=13)
plt.show()
Out[2]:

Ймовірності для кожного класу:
  Клас 0 (setosa    ): 0.1%
  Клас 1 (versicolor): 95.3%
  Клас 2 (virginica ): 4.6%

Прогноз: клас 1 (versicolor)

Стратегія "Мультиноміальна" (Softmax)

Ідея: навчити одну модель, яка одразу обчислює ймовірності для всіх класів через softmax-функцію.

Завантаження...

Де Завантаження... — лінійна комбінація для класу Завантаження....

multiclass_softmax.ipynb
Python 3 (ipykernel)
Code
In [1]:
# Навчання моделі з multi_class='multinomial'
model_softmax = LogisticRegression(multi_class='multinomial', max_iter=200)
model_softmax.fit(X_train, y_train)

accuracy_softmax = model_softmax.score(X_test, y_test)
print(f"Точність (softmax): {accuracy_softmax:.1%}")

import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap

# Для 2D-візуалізації навчаємо softmax лише на ознаках пелюстки
model_2d = LogisticRegression(max_iter=200)
model_2d.fit(X_train[:, 2:], y_train)

xx, yy = np.meshgrid(np.linspace(0.5, 7.5, 300), np.linspace(-0.2, 2.8, 300))
Z = model_2d.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)
colors = ['#ef4444', '#3b82f6', '#10b981']

plt.figure(figsize=(9, 6))
plt.contourf(xx, yy, Z, alpha=0.2, cmap=ListedColormap(colors))
for k, name in enumerate(iris.target_names):
    plt.scatter(X_train[y_train == k, 2], X_train[y_train == k, 3], c=colors[k],
                s=50, edgecolor='white', label=name)
plt.xlabel('Довжина пелюстки (см)', fontsize=12)
plt.ylabel('Ширина пелюстки (см)', fontsize=12)
plt.title('Softmax: три лінійні області рішень', fontsize=14)
plt.legend()
plt.show()
Out[1]:

Точність (softmax): 100.0%
Яку стратегію обрати?
  • One-vs-Rest: простіша, швидша для великої кількості класів (>10)
  • Multinomial (Softmax): часто точніша, природніша для багатокласових задач, краще калібровані ймовірності

Резюме другої частини

📌 Розділова межа

Геометричне представлення рішень моделі. Для логістичної регресії — лінійна (пряма, площина, гіперплощина).

📌 Вплив параметрів

Ваги Завантаження... визначають нахил межі та важливість ознак. Bias Завантаження... зміщує межу паралельно.

📌 Нелінійні задачі

Лінійна логістична регресія не підходить для XOR-подібних паттернів. Рішення: поліноміальні ознаки або нелінійні моделі.

📌 Поріг рішення

За замовчуванням 0.5, але можна налаштувати під бізнес-вимоги (балансувати точність і повноту).

📌 Багатокласова класифікація

One-vs-Rest: Завантаження... бінарних моделей. Softmax: одна модель з розподілом ймовірностей.

Практичний приклад: передбачення ризику серцевих захворювань

Розглянемо реальну медичну задачу: на основі характеристик пацієнта передбачити, чи є у нього підвищений ризик хвороби серця.

Опис датасету

Припустимо, у нас є дані про 300 пацієнтів з такими ознаками:

ОзнакаОписОдиниці
ageВік пацієнтароки
cholesterolРівень холестеринумг/дл
blood_pressureАртеріальний тиск (систолічний)мм рт.ст.
bmiІндекс маси тілакг/м²
smokingЧи палить (1 = так, 0 = ні)бінарна
diseaseЧи є хвороба серця (0 = ні, 1 = так)цільова змінна
heart_disease_classification.ipynb
Python 3.11 (ipykernel)
Code
In [1]:
0.09s
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report

# Генерація синтетичних даних (імітація реального датасету)
rng = np.random.default_rng(seed=42)

n_samples = 300
age = rng.integers(30, 80, size=n_samples)
cholesterol = rng.integers(150, 300, size=n_samples)
blood_pressure = rng.integers(90, 180, size=n_samples)
bmi = rng.uniform(18, 40, size=n_samples)
smoking = rng.choice([0, 1], size=n_samples, p=[0.7, 0.3])

# Цільова змінна: ймовірність хвороби зростає з віком, холестерином, тиском
risk_score = (
    0.05 * age +
    0.01 * cholesterol +
    0.02 * blood_pressure +
    0.3 * bmi +
    5 * smoking - 12
)
disease = (risk_score + rng.normal(0, 5, n_samples) > 0).astype(int)

# Створення DataFrame
df = pd.DataFrame({
    'age': age,
    'cholesterol': cholesterol,
    'blood_pressure': blood_pressure,
    'bmi': bmi,
    'smoking': smoking,
    'disease': disease
})

print(df.head(10))
print(f"\nРозподіл класів:")
print(df['disease'].value_counts())
Out[1]:
agecholesterolblood_pressurebmismokingdisease
06023314828.9501
14519812224.1211
27226516531.7801
33818710522.4500
45522113827.3311

Розподіл класів: disease 0 151 1 149

In [2]:
0.06s
# Розділення на ознаки (X) та цільову змінну (y)
X = df.drop('disease', axis=1)
y = df['disease']

# Розбиття на навчальну та тестову вибірки (70% / 30%)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42, stratify=y
)

print(f"Розмір навчальної вибірки: {X_train.shape}")
print(f"Розмір тестової вибірки: {X_test.shape}")
print(f"\nРозподіл у навчальній вибірці:")
print(y_train.value_counts())
Out[2]:
Розмір навчальної вибірки: (210, 5)
Розмір тестової вибірки: (90, 5)

Розподіл у навчальній вибірці:
disease
0    106
1    104
In [3]:
0.04s
# Стандартизація ознак (важливо для логістичної регресії!)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

print("Середні значення до масштабування:")
print(X_train.mean())
print("\nСередні значення після масштабування:")
print(pd.DataFrame(X_train_scaled, columns=X_train.columns).mean())
Out[3]:
Середні значення до масштабування:
age                54.419048
cholesterol       224.152381
blood_pressure    134.442857
bmi                29.156190
smoking             0.304762

Середні значення після масштабування:
age               -0.000000
cholesterol        0.000000
blood_pressure    -0.000000
bmi                0.000000
smoking           -0.000000
Чому потрібне масштабування? Логістична регресія використовує градієнтний спуск, який чутливий до масштабу ознак. Якщо одна ознака має значення від 0 до 1, а інша — від 0 до 1000, алгоритм навчання буде нестабільним. Стандартизація приводить усі ознаки до однакового масштабу (середнє = 0, стандартне відхилення = 1).

Навчання моделі

heart_disease_training.ipynb
Python 3.11 (ipykernel)
Code
In [4]:
0.08s
# Створення та навчання моделі
model = LogisticRegression(random_state=42, max_iter=1000)
model.fit(X_train_scaled, y_train)

# Прогнози на тестовій вибірці
y_pred = model.predict(X_test_scaled)
y_probs = model.predict_proba(X_test_scaled)[:, 1]

# Оцінка точності
accuracy = accuracy_score(y_test, y_pred)
print(f"Точність на тестовій вибірці: {accuracy:.1%}")
Out[4]:
Точність на тестовій вибірці: 85.6%
In [5]:
0.03s
# Отримання коефіцієнтів (ваг)
coef_df = pd.DataFrame({
    'Ознака': X.columns,
    'Коефіцієнт': model.coef_[0],
    'Абсолютне значення': np.abs(model.coef_[0])
}).sort_values('Абсолютне значення', ascending=False)

print("Важливість ознак (за абсолютним коефіцієнтом):")
print(coef_df)
print(f"\nВільний член (bias): {model.intercept_[0]:.4f}")

import matplotlib.pyplot as plt

plt.figure(figsize=(9, 5))
plt.barh(coef_df['Ознака'][::-1], coef_df['Коефіцієнт'][::-1], color='#3b82f6')
plt.axvline(0, color='#1f2937', linewidth=1)
plt.xlabel('Коефіцієнт (ознаки стандартизовані)')
plt.title('Вплив ознак на ризик хвороби серця', fontsize=13)
plt.grid(axis='x', alpha=0.3)
plt.show()
Out[5]:

Важливість ознак (за абсолютним коефіцієнтом):
          Ознака  Коефіцієнт  Абсолютне значення
2  blood_pressure      0.8234              0.8234
1     cholesterol      0.7856              0.7856
3             bmi      0.6421              0.6421
0             age      0.5123              0.5123
4         smoking      0.4567              0.4567

Вільний член (bias): 0.0234
Інтерпретація коефіцієнтів:
  • Позитивний коефіцієнт (+0.82 для тиску) → зростання ознаки збільшує ймовірність хвороби
  • Від'ємний коефіцієнт → зростання ознаки зменшує ймовірність хвороби
  • Чим більше абсолютне значення → тим сильніший вплив ознаки на результат

Інтерпретація прогнозів

prediction_interpretation.ipynb
Python 3 (ipykernel)
Code
In [1]:
# Приклад: аналіз одного пацієнта
sample_index = 5
sample_patient = X_test.iloc[sample_index:sample_index+1]
sample_patient_scaled = X_test_scaled[sample_index:sample_index+1]

# Характеристики пацієнта
print("Характеристики пацієнта:")
print(sample_patient.to_string(index=False))

# Прогноз моделі
prob = model.predict_proba(sample_patient_scaled)[0, 1]
pred_class = model.predict(sample_patient_scaled)[0]
true_class = y_test.iloc[sample_index]

print(f"\nЙмовірність хвороби серця: {prob:.1%}")
print(f"Прогноз моделі: {'Підвищений ризик ⚠️' if pred_class == 1 else 'Низький ризик ✅'}")
print(f"Справжній діагноз: {'Хворий' if true_class == 1 else 'Здоровий'}")
Out[1]:
Характеристики пацієнта:
age  cholesterol  blood_pressure   bmi  smoking
 62          245             158  32.1        1

Ймовірність хвороби серця: 82.3%
Прогноз моделі: Підвищений ризик ⚠️
Справжній діагноз: Хворий
Аналогія (Консультація лікаря): модель — це як досвідчений лікар, який побачив тисячі пацієнтів. Він не каже "у вас точно є хвороба", а каже "у 82% схожих пацієнтів діагностували хворобу, тому рекомендую додаткові обстеження".

Порівняння з іншими алгоритмами класифікації

Логістична регресія — не єдиний алгоритм для класифікації. Розглянемо, коли вона краща, а коли варто використати інші методи.

Порівняльна таблиця

АлгоритмПеревагиНедолікиКоли використовувати
Логістична регресіяШвидка, інтерпретована, ймовірніснаТільки лінійна межаЛінійно роздільні дані, потрібна інтерпретація
Дерева рішеньНелінійні, інтерпретованіСхильні до перенавчанняКатегоріальні ознаки, нелінійні залежності
Random ForestВисока точність, стійкіВажко інтерпретуватиСкладні задачі, великі датасети
SVMЕфективні з ядрами (RBF)Повільні на великих данихМалі/середні датасети з нелінійними межами
Naive BayesДуже швидкийПрипущення незалежностіТекстова класифікація, великі датасети
k-NNПростий, без навчанняДуже повільний прогнозМалі датасети, прототипування
Нейронні мережіНадзвичайно потужніБагато даних, важко налаштуватиЗображення, текст, складні паттерни
Стратегія вибору алгоритму:
  1. Почніть з логістичної регресії — швидка baseline-модель
  2. Якщо точність <75%, спробуйте Random Forest або Gradient Boosting
  3. Для зображень та текстів — нейронні мережі
  4. Якщо потрібна інтерпретація — логістична регресія або дерева рішень

Типові помилки при роботі з логістичною регресією


Інтерактивні запитання для самоперевірки


Практичні завдання


Підсумкове резюме статті

✅ Класифікація vs Регресія

Класифікація передбачає категорію, регресія — число. Основна відмінність у типі цільової змінної.

✅ Типи класифікації

Бінарна (2 класи), багатокласова (3+), мультилейбл (кілька міток одночасно).

✅ Логістична регресія

Алгоритм для класифікації: лінійна комбінація + сигмоїда = ймовірність класу 1.

✅ Сигмоїдна функція

Завантаження... — перетворює Завантаження... у Завантаження....

✅ Розділова межа

Лінія/площина, де Завантаження.... Визначається рівнянням Завантаження....

✅ Поріг рішення

За замовчуванням 0.5, але налаштовується під бізнес-вимоги (баланс точності та повноти).

✅ Обмеження

Тільки лінійні межі. Для нелінійних задач — поліноміальні ознаки або інші алгоритми.

✅ Практичне застосування

Медична діагностика, детекція спаму, кредитний скоринг, передбачення відтоку клієнтів.

Наступна стаття: У наступному розділі ми глибоко зануримося в метрики якості класифікації — accuracy, precision, recall, F1-score, ROC-AUC, confusion matrix. Ви дізнаєтесь, як правильно оцінювати моделі класифікації та уникати типових помилок інтерпретації результатів.
Copyright © 2026