Логистическая регрессия для классификации

Логистическая регрессия для классификации Scikit-learn

Привет! Ты уже знаком с линейной регрессией, которая предсказывает числа. Но что, если нужно не предсказать значение, а отнести объект к одному из классов? Например, «спам» или «не спам», «болен» или «здоров»? Для этого есть логистическая регрессия.

В этой статье мы разберём:

  • Что такое логистическая регрессия и чем она отличается от линейной
  • Сигмоидная функция: как она превращает числа в вероятности
  • Пошаговая реализация на Python с scikit-learn
  • Оценка качества модели (Accuracy)
  • Практический пример с датасетом рака молочной железы

Что нужно знать перед началом

Для этого урока тебе понадобится:

  • Установленный scikit-learn (pip install scikit-learn)
  • Базовое понимание машинного обучения
  • Знание линейной регрессии из предыдущей статьи

Совет: Несмотря на название, логистическая регрессия — это классификатор, а не регрессия. Она используется для задач классификации.

Основная часть

Что такое логистическая регрессия?

Логистическая регрессия — это алгоритм машинного обучения для бинарной классификации. Она предсказывает вероятность того, что объект принадлежит к определённому классу .

Главное отличие от линейной регрессии:

  • Линейная регрессия предсказывает число (может быть любым)
  • Логистическая регрессия предсказывает вероятность (от 0 до 1)

Совет: Логистическая регрессия — один из самых простых и широко используемых алгоритмов классификации. Она часто служит отправной точкой для более сложных моделей.

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

Как логистическая регрессия превращает любое число в вероятность от 0 до 1? С помощью сигмоидной функции (S-образной кривой).

Формула сигмоиды:f(x)=11+exf(x)=1+ex1​

Где:

  • e — число Эйлера (~2.71828)
  • x — входное значение (линейная комбинация признаков)

Свойства сигмоиды:

  • Всегда возвращает значение от 0 до 1
  • При x = 0 возвращает 0.5
  • При больших положительных x стремится к 1
  • При больших отрицательных x стремится к 0

Таблица значений:

Вход (x)Сигмоида (вероятность)
-70.001
-50.007
-30.047
-10.269
00.500
10.731
30.952
50.993
70.999

Как это работает на практике:

  1. Модель вычисляет линейную комбинацию признаков: z = w₁x₁ + w₂x₂ + ... + b
  2. Затем z подставляется в сигмоидную функцию: y' = 1 / (1 + e^(-z))
  3. Результат — вероятность того, что объект принадлежит к классу 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)
Accuracyfrom sklearn.metrics import accuracy_score
Масштабированиеfrom sklearn.preprocessing import StandardScaler

Заключение

Сегодня мы узнали:

  • Что такое логистическая регрессия — классификатор для бинарных задач
  • Как сигмоидная функция превращает числа в вероятности
  • Как реализовать логистическую регрессию в scikit-learn
  • Как оценивать качество классификации (Accuracy, precision, recall)
  • Важность масштабирования признаков

КВИЗ

Что дальше?

Оцените статью
IMI-DS - PYTHON LERNEN
Содержание
Оглавление ×