Привет! Ты уже знаком с линейной регрессией, которая предсказывает числа. Но что, если нужно не предсказать значение, а отнести объект к одному из классов? Например, «спам» или «не спам», «болен» или «здоров»? Для этого есть логистическая регрессия.
В этой статье мы разберём:
- Что такое логистическая регрессия и чем она отличается от линейной
- Сигмоидная функция: как она превращает числа в вероятности
- Пошаговая реализация на Python с scikit-learn
- Оценка качества модели (Accuracy)
- Практический пример с датасетом рака молочной железы
- Что нужно знать перед началом
- Основная часть
- Что такое логистическая регрессия?
- Сигмоидная функция
- Бинарная классификация
- Реализация на Python
- Подготовка данных
- Масштабирование признаков
- Обучение модели
- Предсказание и оценка
- Визуализация границ решения
- Задачи для закрепления
- Нюансы и подводные камни
- Регуляризация
- Многоклассовая классификация
- Частые ошибки и как их избежать
- Ошибка 1: Не разделил данные перед масштабированием
- Ошибка 2: Интерпретация вероятностей
- Ошибка 3: Слишком много признаков
- Шпаргалка
- Заключение
- КВИЗ
- Что дальше?
Что нужно знать перед началом
Для этого урока тебе понадобится:
- Установленный scikit-learn (
pip install scikit-learn) - Базовое понимание машинного обучения
- Знание линейной регрессии из предыдущей статьи
Совет: Несмотря на название, логистическая регрессия — это классификатор, а не регрессия. Она используется для задач классификации.
Основная часть
Что такое логистическая регрессия?
Логистическая регрессия — это алгоритм машинного обучения для бинарной классификации. Она предсказывает вероятность того, что объект принадлежит к определённому классу .
Главное отличие от линейной регрессии:
- Линейная регрессия предсказывает число (может быть любым)
- Логистическая регрессия предсказывает вероятность (от 0 до 1)
Совет: Логистическая регрессия — один из самых простых и широко используемых алгоритмов классификации. Она часто служит отправной точкой для более сложных моделей.
Сигмоидная функция
Как логистическая регрессия превращает любое число в вероятность от 0 до 1? С помощью сигмоидной функции (S-образной кривой).
Формула сигмоиды:f(x)=1+e−x1
Где:
e— число Эйлера (~2.71828)x— входное значение (линейная комбинация признаков)
Свойства сигмоиды:
- Всегда возвращает значение от 0 до 1
- При
x = 0возвращает0.5 - При больших положительных
xстремится к1 - При больших отрицательных
xстремится к0
Таблица значений:
| Вход (x) | Сигмоида (вероятность) |
|---|---|
| -7 | 0.001 |
| -5 | 0.007 |
| -3 | 0.047 |
| -1 | 0.269 |
| 0 | 0.500 |
| 1 | 0.731 |
| 3 | 0.952 |
| 5 | 0.993 |
| 7 | 0.999 |
Как это работает на практике:
- Модель вычисляет линейную комбинацию признаков:
z = w₁x₁ + w₂x₂ + ... + b - Затем
zподставляется в сигмоидную функцию:y' = 1 / (1 + e^(-z)) - Результат — вероятность того, что объект принадлежит к классу 1
Совет: Сигмоидная функция гарантирует, что модель всегда возвращает корректную вероятность.
Бинарная классификация
В бинарной классификации у нас два класса. Обычно их обозначают как:
- 0 — отрицательный класс (например, «не спам»)
- 1 — положительный класс (например, «спам»)
Правило классификации:
- Если вероятность
>= 0.5→ предсказываем класс1 - Если вероятность
< 0.5→ предсказываем класс0
Совет: Порог можно менять. Например, в медицине часто используют более низкий порог, чтобы не пропустить болезнь.
Реализация на Python
Для практики будем использовать датасет рака молочной железы из scikit-learn. Это классическая задача бинарной классификации: определить, является ли опухоль злокачественной (malignant) или доброкачественной (benign).
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_breast_cancer
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, classification_report, confusion_matrix
# Загружаем датасет
cancer = load_breast_cancer(as_frame=True)
df = cancer.frame
print("=== Датасет рака молочной железы ===")
print(f"Размер: {df.shape}")
print(f"Целевые классы: {cancer.target_names}")
print(f"Колонки: {df.columns[:5].tolist()}...")Результат:
=== Датасет рака молочной железы ===
Размер: (569, 31)
Целевые классы: ['malignant' 'benign']
Колонки: ['mean radius', 'mean texture', 'mean perimeter', 'mean area', 'mean smoothness']...Совет: При загрузке с
as_frame=Trueдатасет возвращается как DataFrame, что удобно для работы.
Подготовка данных
# Разделяем признаки и целевую переменную
X = df.drop('target', axis=1)
y = df['target']
# Разделяем на train/test
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
print(f"Обучающая выборка: {X_train.shape[0]} объектов")
print(f"Тестовая выборка: {X_test.shape[0]} объектов")
# Проверяем баланс классов
print(f"\nРаспределение в train: {sum(y_train == 0)} злокачественных, {sum(y_train == 1)} доброкачественных")
print(f"Распределение в test: {sum(y_test == 0)} злокачественных, {sum(y_test == 1)} доброкачественных")Масштабирование признаков
Логистическая регрессия чувствительна к масштабу признаков. Рекомендуется масштабировать данные перед обучением:
# Масштабируем признаки
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
print("Признаки масштабированы: среднее ≈ 0, дисперсия ≈ 1")Совет: Масштабирование особенно важно, когда признаки имеют разные единицы измерения.
Обучение модели
# Создаём и обучаем модель
model = LogisticRegression(random_state=42, max_iter=1000)
model.fit(X_train_scaled, y_train)
# Выводим информацию о модели
print(f"Коэффициенты (веса): {model.coef_.shape}")
print(f"Смещение (intercept): {model.intercept_[0]:.4f}")Результат:
Коэффициенты (веса): (1, 30)
Смещение (intercept): 0.1234Предсказание и оценка
# Предсказываем на тестовых данных
y_pred = model.predict(X_test_scaled)
# Получаем вероятности
y_proba = model.predict_proba(X_test_scaled)
# Оценка качества
accuracy = accuracy_score(y_test, y_pred)
print(f"Точность модели (Accuracy): {accuracy:.2%}")
print("\n=== Подробный отчёт ===")
print(classification_report(y_test, y_pred, target_names=cancer.target_names))
print("\n=== Матрица ошибок ===")
print(confusion_matrix(y_test, y_pred))Результат (примерный):
Точность модели (Accuracy): 97.37%
=== Подробный отчёт ===
precision recall f1-score support
malignant 0.98 0.95 0.96 42
benign 0.97 0.99 0.98 72
accuracy 0.97 114
macro avg 0.97 0.97 0.97 114
weighted avg 0.97 0.97 0.97 114
=== Матрица ошибок ===
[[40 2]
[ 1 71]]Совет:
Accuracyпоказывает долю правильных предсказаний. Для несбалансированных данных лучше смотреть наprecisionиrecall.
Визуализация границ решения
Для двумерного случая можно визуализировать границу решения:
from sklearn.datasets import load_iris
# Берём только два признака для визуализации
iris = load_iris()
X = iris.data[:, :2] # Длина и ширина чашелистика
y = iris.target
# Оставляем только два класса (для бинарной классификации)
X = X[y != 2]
y = y[y != 2]
# Масштабируем
X_scaled = StandardScaler().fit_transform(X)
# Обучаем модель
model = LogisticRegression(random_state=42)
model.fit(X_scaled, y)
# Создаём сетку для визуализации
h = 0.02
x_min, x_max = X_scaled[:, 0].min() - 1, X_scaled[:, 0].max() + 1
y_min, y_max = X_scaled[:, 1].min() - 1, X_scaled[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
# Рисуем
plt.figure(figsize=(8, 6))
plt.contourf(xx, yy, Z, cmap=plt.cm.RdYlBu, alpha=0.3)
plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=y, cmap=plt.cm.RdYlBu, edgecolors='k', s=50)
plt.xlabel('Длина чашелистика (масштабировано)')
plt.ylabel('Ширина чашелистика (масштабировано)')
plt.title('Границы решения логистической регрессии')
plt.show()Задачи для закрепления
Задача 1. Загрузи датасет load_breast_cancer() и выведи названия классов.
Задача 2. Раздели данные на train/test с test_size=0.3.
Задача 3. Обучи модель LogisticRegression с random_state=42.
Задача 4. Вычисли Accuracy на тестовой выборке.
Задача 5. Получи вероятности классов через predict_proba().
Ответы:
Задача 1.
from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer()
print(cancer.target_names) # ['malignant' 'benign']Задача 2.
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)Задача 3.
from sklearn.linear_model import LogisticRegression
model = LogisticRegression(random_state=42)
model.fit(X_train_scaled, y_train)Задача 4.
from sklearn.metrics import accuracy_score
y_pred = model.predict(X_test_scaled)
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.2%}")Задача 5.
y_proba = model.predict_proba(X_test_scaled)
print(y_proba[:5]) # Первые 5 вероятностейНюансы и подводные камни
Регуляризация
Логистическая регрессия в scikit-learn по умолчанию использует регуляризацию L2. Параметр C контролирует силу регуляризации:
C=1.0— стандартная силаCменьше — более сильная регуляризацияCбольше — более слабая регуляризация (может привести к переобучению)
Многоклассовая классификация
Логистическую регрессию можно использовать и для задач с более чем двумя классами. В scikit-learn есть параметр multi_class:
'ovr'(one-vs-rest) — для каждого класса строится бинарный классификатор'multinomial'— прямое обобщение на несколько классов
Частые ошибки и как их избежать
Ошибка 1: Не разделил данные перед масштабированием
# Неправильно — утечка данных
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
X_train, X_test = train_test_split(X_scaled, y)
# Правильно — сначала разделяем, потом масштабируем
X_train, X_test, y_train, y_test = train_test_split(X, y)
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)Ошибка 2: Интерпретация вероятностей
Сигмоида возвращает вероятность класса 1. Для получения метки класса нужно применить порог (обычно 0.5).
Ошибка 3: Слишком много признаков
При большом количестве признаков (больше, чем объектов) используй регуляризацию.
Шпаргалка
| Что нужно | Как пишется |
|---|---|
| Импорт модели | from sklearn.linear_model import LogisticRegression |
| Создание модели | model = LogisticRegression(random_state=42) |
| Обучение | model.fit(X_train, y_train) |
| Предсказание классов | y_pred = model.predict(X_test) |
| Предсказание вероятностей | y_proba = model.predict_proba(X_test) |
| Accuracy | from sklearn.metrics import accuracy_score |
| Масштабирование | from sklearn.preprocessing import StandardScaler |
Заключение
Сегодня мы узнали:
- Что такое логистическая регрессия — классификатор для бинарных задач
- Как сигмоидная функция превращает числа в вероятности
- Как реализовать логистическую регрессию в scikit-learn
- Как оценивать качество классификации (Accuracy, precision, recall)
- Важность масштабирования признаков




