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

Введение в ML: Классификация с KNN

Лабораторная работа №7: Введение в ML. Классификация с KNN

Цель: Построить свой первый полноценный пайплайн машинного обучения: от разделения данных до оценки качества модели. Мы решим задачу бинарной классификации, используя алгоритм k-ближайших соседей (KNN), и научимся выбирать правильные метрики, когда Accuracy врет.

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

  • sklearn.model_selection: для разделения данных.
  • sklearn.preprocessing: для масштабирования (StandardScaler).
  • sklearn.neighbors: сама модель KNN.
  • sklearn.metrics: инструменты оценки.

Данные: Мы будем работать с классическим датасетом Breast Cancer Wisconsin (Рак груди).

  • Признаки (X): Характеристики клеточного ядра (радиус, текстура, периметр и т.д.).
  • Целевая переменная (y): Диагноз (0 = Malignant/Злокачественная, 1 = Benign/Доброкачественная).
    • Примечание: В sklearn часто 0 - это Malignant, но всегда лучше проверять target_names.

Часть 1: Подготовка данных и Train/Test Split

Модели нельзя давать “подглядывать” в ответы теста.


Часть 2: Масштабирование (Scaling) — Критически важно для KNN

KNN измеряет расстояния. Если один признак изменяется в пределах [0, 0.1], а другой [0, 1000], второй будет полностью доминировать. Нужно привести их к одному масштабу.

Золотое правило масштабирования

Правило: StandardScaler обучается (fit) ТОЛЬКО на Train, и применяется (transform) к Train и Test. Иначе — утечка данных.

Задание 2.1: StandardScaler

  1. Создайте объект StandardScaler.
  2. Обучите его на X_train и трансформируйте X_train.
  3. Трансформируйте X_test (без обучения!).
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()

# TODO: Обучите scaler на train и преобразуйте train
# X_train_scaled = scaler.fit_transform(...)

# TODO: Только преобразуйте test (используйте transform)
# X_test_scaled = scaler.transform(...)

# Проверка: среднее должно быть ~0, стд ~1
# print("Train Mean (первые 5 признаков):", X_train_scaled[:, :5].mean(axis=0))

Часть 3: Обучение и Предсказание

Задание 3.1: KNN Classifier

  1. Импортируйте KNeighborsClassifier.
  2. Создайте модель с n_neighbors=5.
  3. Обучите (fit) на масштабированных данных.
  4. Сделайте предсказание (predict) для теста.
from sklearn.neighbors import KNeighborsClassifier

# TODO: Создайте и обучите модель
# knn = KNeighborsClassifier(n_neighbors=5)
# knn.fit(..., ...)

# TODO: Получите предсказания для теста
# y_pred = knn.predict(...)

Часть 4: Оценка качества (Evaluation)

Мы диагностируем рак.

Типы ошибок классификации

  • Ошибка I рода (False Positive): Сказали “Рак”, а человек здоров. Стресс, биопсия, но человек жив.
  • Ошибка II рода (False Negative): Сказали “Здоров”, а у человека рак. Человек может умереть.

В этой задаче Recall (способность найти всех больных) важнее Precision.

Примечание: В sklearn датасете 0 = Malignant (Злокачественная). Чтобы метрики считались корректно для “Болезни” (класса 0), можно либо инвертировать метки, либо смотреть внимательно на отчет. В classification_report мы увидим метрики для каждого класса.

Задание 4.1: Матрица ошибок и Метрики

  1. Постройте Confusion Matrix (тепловую карту).
  2. Выведите classification_report.
  3. Посчитайте accuracy_score.
from sklearn.metrics import confusion_matrix, classification_report, accuracy_score

# TODO: Постройте матрицу ошибок
# cm = confusion_matrix(y_test, y_pred)

# Визуализация
# plt.figure(figsize=(6, 5))
# sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=data.target_names, yticklabels=data.target_names)
# plt.ylabel('Истинный класс')
# plt.xlabel('Предсказанный класс')
# plt.title('Матрица ошибок')
# plt.show()

# TODO: Выведите текстовый отчет
# print(classification_report(y_test, y_pred, target_names=data.target_names))

# Вопрос: Каков Recall для класса 'malignant'? Много ли опасных случаев мы пропустили?

Часть 5 (Бонус): Поиск лучшего K

Как выбрать n_neighbors? Давайте переберем значения от 1 до 20 и посмотрим, как меняется ошибка.

Задание 5.1: Цикл обучения

  1. Запустите цикл k от 1 до 20.
  2. В каждой итерации обучайте KNN, делайте предсказание и сохраняйте accuracy (или F1) в список.
  3. Постройте график зависимости метрики от K.
scores = []
k_range = range(1, 21)

# TODO: Напишите цикл
# for k in k_range:
#     knn_temp = KNeighborsClassifier(n_neighbors=k)
#     knn_temp.fit(X_train_scaled, y_train)
#     scores.append(knn_temp.score(X_test_scaled, y_test))

# plt.figure(figsize=(10, 6))
# plt.plot(k_range, scores, marker='o')
# plt.xlabel('Value of K')
# plt.ylabel('Testing Accuracy')
# plt.grid()
# plt.show()

# Какое K выглядит оптимальным (где график выходит на плато или имеет пик)?

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

Почему StandardScaler обучается (метод .fit()) только на тренировочной выборке (X_train), а не на всем датасете сразу?

В задаче диагностики рака (где 0 — злокачественная опухоль, а 1 — доброкачественная) модель ошибочно классифицировала больного пациента как здорового. Как называется этот тип ошибки и какая метрика призвана её минимизировать?