machine-learningЛабораторная работаMachine Learning

Введение в ML: Логистическая регрессия и ROC-AUC

👀 Загрузка...

Цель: Решить задачу бинарной классификации (предсказание оттока клиентов). Мы разберем работу Логистической регрессии, увидим на практике разницу между L1 и L2 регуляризацией (как L1 обнуляет веса ненужных признаков) и научимся оценивать качество модели с помощью кривой ROC-AUC.

Инструменты:

  • sklearn.linear_model: LogisticRegression.
  • sklearn.preprocessing: StandardScaler (обязателен!), OneHotEncoder.
  • sklearn.metrics: roc_auc_score, roc_curve.

Данные: Telecom Churn Dataset. Данные оператора связи о клиентах: сколько говорят, какие тарифы подключены и ушел ли клиент (Churn).


Часть 1: Подготовка данных (Preprocessing)

Логистическая регрессия — это математическая модель (уравнение плоскости). Она требует:

  1. Чисел: Все категории ("Yes"/"No", "Kansas") должны быть закодированы.
  2. Масштаба: Признаки должны быть в одном диапазоне (StandardScaler), иначе регуляризация будет работать неправильно.

Задание 1.1:

  1. Загрузите датасет.
  2. Превратите бинарные признаки (International plan, Voice mail plan) в числа (0 и 1).
    • Подсказка: Можно использовать .map({'Yes': 1, 'No': 0}) или astype(int) если там булевы значения.
  3. Удалите "мусорные" признаки, которые не влияют на физику процесса: State, Area code, Phone number.
  4. Целевая переменная: Churn.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
 
# Загрузка датасета
url = "[https://raw.githubusercontent.com/yorko/mlcourse.ai/master/data/telecom_churn.csv](https://raw.githubusercontent.com/yorko/mlcourse.ai/master/data/telecom_churn.csv)"
df = pd.read_csv(url)
 
# TODO: Преобразуйте 'International plan' и 'Voice mail plan' в числа (0 и 1)
# df['International plan'] = ...
# df['Voice mail plan'] = ...
 
# TODO: Целевая переменная 'Churn' в этом датасете - bool (True/False). Преобразуйте в int (1/0).
# df['Churn'] = ...
 
# TODO: Удалите колонки ['State', 'Area code', 'Phone number']? так как они сложны для OHE и малоинформативны
# df = df.drop(..., axis=1)
 
# print(df.info())
# print(df.head())

Часть 2: Логистическая Регрессия и L1/L2 Регуляризация

В sklearn параметр penalty отвечает за тип регуляризации, а C — за её силу (обратная величина: чем меньше C, тем сильнее штраф).

Задание 2.1: L2 Регуляризация — Стандарт Обучите модель с penalty='l2'. Это стандартное поведение.

from sklearn.linear_model import LogisticRegression
 
# TODO: Обучите модель (используйте solver='liblinear' для универсальности)
# logit_l2 = LogisticRegression(penalty='l2', C=1.0, solver='liblinear', random_state=17)
# logit_l2.fit(...)
 
# Выведите accuracy на тесте
# print("Accuracy L2:", logit_l2.score(X_test_scaled, y_test))

Задание 2.3: Визуализация весов (Инсайт)

Сравним веса двух моделей. Посмотрите, сколько весов занулила L1 модель.

# Создаем DataFrame с весами
coef_df = pd.DataFrame({
    'Feature': X.columns,
    'L2_Weights': logit_l2.coef_[0],
    'L1_Weights': logit_l1.coef_[0]
})
 
# Сортируем по L2
coef_df = coef_df.sort_values(by='L2_Weights', key=abs, ascending=False)
 
# Визуализация
plt.figure(figsize=(12, 6))
 
# Рисуем L2
plt.subplot(1, 2, 1)
sns.barplot(x='L2_Weights', y='Feature', data=coef_df)
plt.title("L2 (Ridge) Weights")
plt.grid(True)
 
# Рисуем L1
plt.subplot(1, 2, 2)
sns.barplot(x='L1_Weights', y='Feature', data=coef_df)
plt.title("L1 (Lasso) Weights")
plt.grid(True)
 
plt.tight_layout()
plt.show()
 
# Вопрос: Какие признаки L1 модель посчитала "мусором" (вес = 0)?
# Напишите 1-2 примера в комментарии.

Часть 3: ROC-AUC и Вероятности

Логистическая регрессия предсказывает не просто класс, а вероятность (predict_proba).

Задание 3.1: ROC-кривая

Постройте график ROC-кривой для L2-модели.

  1. Получите вероятности положительного класса (колонка с индексом 1).
  2. Используйте roc_curve.
  3. Посчитайте площадь roc_auc_score.
from sklearn.metrics import roc_curve, roc_auc_score
 
# TODO: Получите вероятности для класса 1 (Churn)
# y_probs = logit_l2.predict_proba(X_test_scaled)[:, 1]
 
# TODO: Вычислите FPR, TPR и пороги
# fpr, tpr, thresholds = roc_curve(y_test, y_probs)
 
# TODO: Вычислите AUC
# auc_val = roc_auc_score(y_test, y_probs)
 
# График
# plt.figure(figsize=(8, 6))
# plt.plot(fpr, tpr, label=f'Logistic Regression (AUC = {auc_val:.3f})')
# plt.plot([0, 1], [0, 1], 'k--') # Случайная модель
# plt.xlabel('False Positive Rate')
# plt.ylabel('True Positive Rate')
# plt.title('ROC Curve')
# plt.legend()
# plt.show()

Задание 3.2: Интерпретация

Если AUC = 0.82, это хорошо или плохо? В задаче оттока мы хотим найти всех, кто уйдет. Какой порог вероятности выбрать?

Бизнес-логика

Представьте, что мы удерживаем клиентов скидкой.

  • Скидка стоит денег -> нельзя давать всем подряд (нужен низкий False Positive).
  • Ушедший клиент — это потеря денег -> нужно найти всех (высокий True Positive).

Посмотрите на вероятности первых 10 клиентов из теста.

# results = pd.DataFrame({
#     'True_Class': y_test[:10].values,
#     'Predicted_Prob': y_probs[:10]
# })
# print(results)

🧠 Проверка знаний

В чем главное отличие действия L1-регуляризации (Lasso) от L2-регуляризации (Ridge) при обучении логистической регрессии?

Почему перед применением регуляризации в логистической регрессии критически важно провести масштабирование признаков (например, через StandardScaler)?