Лаб. работа “Машинное обучение: классификация”
Введение в машинное обучение и классификацию
Классификация — это один из основных видов задач машинного обучения, где целью является предсказание категориального класса для новых объектов на основе обучающей выборки. В этой лабораторной работе рассматриваются различные алгоритмы классификации и методы оценки их качества.
Типы классификации:
- Бинарная классификация — два класса (положительный/отрицательный)
- Многоклассовая классификация — три и более классов
- Многометочная классификация — один объект может принадлежать нескольким классам
Алгоритмы классификации:
- Логистическая регрессия — линейный метод с сигмоидной функцией
- Деревья решений — нелинейный метод на основе правил
- Случайный лес — ансамбль деревьев решений
- SVM (Support Vector Machine) — метод опорных векторов
- k-NN (k-ближайших соседей) — метод на основе сходства
Теоретические основы классификации
Метрики качества классификации
Для бинарной классификации:
Матрица ошибок (Confusion Matrix):
| Предсказано положительное | Предсказано отрицательное | |
|---|---|---|
| Действительно положительное | TP (True Positive) | FN (False Negative) |
| Действительно отрицательное | FP (False Positive) | TN (True Negative) |
Основные метрики:
- Accuracy = (TP + TN) / (TP + TN + FP + FN) — доля правильных предсказаний
- Precision = TP / (TP + FP) — точность положительных предсказаний
- Recall = TP / (TP + FN) — полнота (чувствительность)
- F1-score = 2 × (Precision × Recall) / (Precision + Recall) — гармоническое среднее
Для многоклассовой классификации:
- Macro-average — среднее по всем классам
- Weighted-average — среднее с весами пропорционально частоте классов
Подготовка данных
Загрузка и предобработка данных
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
from sklearn.metrics import classification_report, confusion_matrix
import matplotlib.pyplot as plt
import seaborn as sns
# Загрузка датасета Iris (классический пример)
from sklearn.datasets import load_iris
# Загрузка данных
iris = load_iris()
X = iris.data
y = iris.target
# Информация о данных
print(f"Размер данных: {X.shape}")
print(f"Количество классов: {len(np.unique(y))}")
print(f"Названия классов: {iris.target_names}")
# Разделение на обучающую и тестовую выборки
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# Масштабирование признаков
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)Визуализация данных
# Создание DataFrame для удобства визуализации
df = pd.DataFrame(data=X, columns=iris.feature_names)
df['target'] = y
df['target_name'] = df['target'].map({0: 'setosa', 1: 'versicolor', 2: 'virginica'})
# Построение графика
plt.figure(figsize=(10, 6))
sns.scatterplot(data=df, x='sepal length (cm)', y='petal length (cm)', hue='target_name')
plt.title('Визуализация данных Iris')
plt.xlabel('Длина чашелистика')
plt.ylabel('Длина лепестка')
plt.legend(title='Вид ириса')
plt.grid(True, alpha=0.3)
plt.show()Реализация алгоритмов классификации
1. Логистическая регрессия
from sklearn.linear_model import LogisticRegression
# Создание и обучение модели
log_reg = LogisticRegression(random_state=42, max_iter=1000)
log_reg.fit(X_train_scaled, y_train)
# Предсказание
y_pred_log = log_reg.predict(X_test_scaled)
# Оценка качества
print("=== Логистическая регрессия ===")
print(f"Accuracy: {accuracy_score(y_test, y_pred_log):.3f}")
print(f"Precision (weighted): {precision_score(y_test, y_pred_log, average='weighted'):.3f}")
print(f"Recall (weighted): {recall_score(y_test, y_pred_log, average='weighted'):.3f}")
print(f"F1-score (weighted): {f1_score(y_test, y_pred_log, average='weighted'):.3f}")
# Подробный отчет
print("\nДетальный отчет:")
print(classification_report(y_test, y_pred_log, target_names=iris.target_names))2. Деревья решений
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import plot_tree
# Создание и обучение модели
tree = DecisionTreeClassifier(random_state=42, max_depth=3)
tree.fit(X_train, y_train)
# Предсказание
y_pred_tree = tree.predict(X_test)
# Оценка качества
print("=== Дерево решений ===")
print(f"Accuracy: {accuracy_score(y_test, y_pred_tree):.3f}")
print(f"Precision (weighted): {precision_score(y_test, y_pred_tree, average='weighted'):.3f}")
print(f"Recall (weighted): {recall_score(y_test, y_pred_tree, average='weighted'):.3f}")
print(f"F1-score (weighted): {f1_score(y_test, y_pred_tree, average='weighted'):.3f}")
# Визуализация дерева
plt.figure(figsize=(15, 10))
plot_tree(tree, feature_names=iris.feature_names,
class_names=iris.target_names, filled=True)
plt.title('Дерево решений для классификации ирисов')
plt.show()3. Случайный лес
from sklearn.ensemble import RandomForestClassifier
# Создание и обучение модели
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)
# Предсказание
y_pred_rf = rf.predict(X_test)
# Оценка качества
print("=== Случайный лес ===")
print(f"Accuracy: {accuracy_score(y_test, y_pred_rf):.3f}")
print(f"Precision (weighted): {precision_score(y_test, y_pred_rf, average='weighted'):.3f}")
print(f"Recall (weighted): {recall_score(y_test, y_pred_rf, average='weighted'):.3f}")
print(f"F1-score (weighted): {f1_score(y_test, y_pred_rf, average='weighted'):.3f}")
# Важность признаков
feature_importance = pd.DataFrame({
'feature': iris.feature_names,
'importance': rf.feature_importances_
}).sort_values('importance', ascending=False)
plt.figure(figsize=(10, 6))
plt.bar(feature_importance['feature'], feature_importance['importance'])
plt.title('Важность признаков в случайном лесу')
plt.xlabel('Признаки')
plt.ylabel('Важность')
plt.xticks(rotation=45)
plt.grid(True, alpha=0.3)
plt.show()4. SVM (Support Vector Machine)
from sklearn.svm import SVC
# Создание и обучение модели
svm = SVC(kernel='rbf', random_state=42)
svm.fit(X_train_scaled, y_train)
# Предсказание
y_pred_svm = svm.predict(X_test_scaled)
# Оценка качества
print("=== SVM ===")
print(f"Accuracy: {accuracy_score(y_test, y_pred_svm):.3f}")
print(f"Precision (weighted): {precision_score(y_test, y_pred_svm, average='weighted'):.3f}")
print(f"Recall (weighted): {recall_score(y_test, y_pred_svm, average='weighted'):.3f}")
print(f"F1-score (weighted): {f1_score(y_test, y_pred_svm, average='weighted'):.3f}")5. k-NN (k-ближайших соседей)
from sklearn.neighbors import KNeighborsClassifier
# Создание и обучение модели
knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(X_train_scaled, y_train)
# Предсказание
y_pred_knn = knn.predict(X_test_scaled)
# Оценка качества
print("=== k-NN ===")
print(f"Accuracy: {accuracy_score(y_test, y_pred_knn):.3f}")
print(f"Precision (weighted): {precision_score(y_test, y_pred_knn, average='weighted'):.3f}")
print(f"Recall (weighted): {recall_score(y_test, y_pred_knn, average='weighted'):.3f}")
print(f"F1-score (weighted): {f1_score(y_test, y_pred_knn, average='weighted'):.3f}")Сравнительный анализ алгоритмов
# Сбор результатов
results = {
'Algorithm': ['Logistic Regression', 'Decision Tree', 'Random Forest', 'SVM', 'k-NN'],
'Accuracy': [
accuracy_score(y_test, y_pred_log),
accuracy_score(y_test, y_pred_tree),
accuracy_score(y_test, y_pred_rf),
accuracy_score(y_test, y_pred_svm),
accuracy_score(y_test, y_pred_knn)
],
'Precision': [
precision_score(y_test, y_pred_log, average='weighted'),
precision_score(y_test, y_pred_tree, average='weighted'),
precision_score(y_test, y_pred_rf, average='weighted'),
precision_score(y_test, y_pred_svm, average='weighted'),
precision_score(y_test, y_pred_knn, average='weighted')
],
'Recall': [
recall_score(y_test, y_pred_log, average='weighted'),
recall_score(y_test, y_pred_tree, average='weighted'),
recall_score(y_test, y_pred_rf, average='weighted'),
recall_score(y_test, y_pred_svm, average='weighted'),
recall_score(y_test, y_pred_knn, average='weighted')
],
'F1-score': [
f1_score(y_test, y_pred_log, average='weighted'),
f1_score(y_test, y_pred_tree, average='weighted'),
f1_score(y_test, y_pred_rf, average='weighted'),
f1_score(y_test, y_pred_svm, average='weighted'),
f1_score(y_test, y_pred_knn, average='weighted')
]
}
# Создание DataFrame
results_df = pd.DataFrame(results)
# Визуализация результатов
fig, axes = plt.subplots(2, 2, figsize=(15, 10))
# Accuracy
axes[0, 0].bar(results_df['Algorithm'], results_df['Accuracy'])
axes[0, 0].set_title('Accuracy Comparison')
axes[0, 0].set_ylabel('Accuracy')
axes[0, 0].tick_params(axis='x', rotation=45)
# Precision
axes[0, 1].bar(results_df['Algorithm'], results_df['Precision'])
axes[0, 1].set_title('Precision Comparison')
axes[0, 1].set_ylabel('Precision')
axes[0, 1].tick_params(axis='x', rotation=45)
# Recall
axes[1, 0].bar(results_df['Algorithm'], results_df['Recall'])
axes[1, 0].set_title('Recall Comparison')
axes[1, 0].set_ylabel('Recall')
axes[1, 0].tick_params(axis='x', rotation=45)
# F1-score
axes[1, 1].bar(results_df['Algorithm'], results_df['F1-score'])
axes[1, 1].set_title('F1-score Comparison')
axes[1, 1].set_ylabel('F1-score')
axes[1, 1].tick_params(axis='x', rotation=45)
plt.tight_layout()
plt.show()
print("\n=== Сравнительная таблица ===")
print(results_df.round(3))Визуализация матриц ошибок
# Создание подграфиков для матриц ошибок
fig, axes = plt.subplots(2, 3, figsize=(18, 12))
algorithms = {
'Logistic Regression': y_pred_log,
'Decision Tree': y_pred_tree,
'Random Forest': y_pred_rf,
'SVM': y_pred_svm,
'k-NN': y_pred_knn
}
for idx, (name, predictions) in enumerate(algorithms.items()):
row = idx // 3
col = idx % 3
cm = confusion_matrix(y_test, predictions)
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=iris.target_names,
yticklabels=iris.target_names,
ax=axes[row, col])
axes[row, col].set_title(f'Confusion Matrix - {name}')
axes[row, col].set_xlabel('Предсказанный класс')
axes[row, col].set_ylabel('Истинный класс')
# Удаляем пустой subplot
axes[1, 2].remove()
plt.tight_layout()
plt.show()Самостоятельные задания
Задание 1: Исследование влияния гиперпараметров
Цель: Проанализировать влияние гиперпараметров на качество классификации.
Задачи:
- Для дерева решений исследуйте влияние параметров
max_depth(3, 5, 10, None) иmin_samples_split(2, 5, 10) - Для случайного леса исследуйте влияние
n_estimators(10, 50, 100, 200) иmax_depth(3, 5, 10) - Для k-NN исследуйте влияние
n_neighbors(1, 3, 5, 7, 10) иweights(‘uniform’, ‘distance’) - Постройте графики зависимости accuracy от параметров
- Сделайте выводы об оптимальных значениях параметров
Формат отчета:
- Таблицы с результатами для каждого параметра
- Графики зависимостей
- Выводы о влиянии параметров
- Рекомендации по выбору параметров
Задание 2: Работа с несбалансированными данными
Цель: Изучить методы работы с несбалансированными классами.
Задачи:
- Создайте искусственно несбалансированный датасет (удалите часть образцов одного класса)
- Сравните качество работы алгоритмов на несбалансированных данных
- Примените методы балансировки:
- Random oversampling
- Random undersampling
- SMOTE (Synthetic Minority Over-sampling Technique)
- Сравните результаты до и после балансировки
- Проанализируйте изменения в матрицах ошибок
Формат отчета:
- Описание создания несбалансированного датасета
- Сравнение метрик до и после балансировки
- Визуализация распределения классов
- Выводы о эффективности методов балансировки
Задание 3: Кросс-валидация и настройка моделей
Цель: Научиться использовать кросс-валидацию для надежной оценки качества.
Задачи:
- Реализуйте k-fold кросс-валидацию (k=5, 10) для всех алгоритмов
- Сравните результаты кросс-валидации с hold-out методом
- Используйте GridSearchCV для автоматического подбора гиперпараметров
- Сравните время выполнения различных методов
- Проанализируйте стандартное отклонение результатов
Формат отчета:
- Таблицы с результатами кросс-валидации
- Сравнение с hold-out методом
- Оптимальные параметры, найденные GridSearchCV
- Графики зависимости качества от параметров
Задание 4: Feature Engineering и отбор признаков
Цель: Изучить влияние признаков на качество классификации.
Задачи:
- Создайте новые признаки (например, отношения существующих признаков)
- Реализуйте методы отбора признаков:
- Univariate feature selection
- Recursive Feature Elimination (RFE)
- Feature importance из случайного леса
- Сравните качество классификации с разным числом признаков
- Проанализируйте важность признаков для разных алгоритмов
- Постройте графики зависимости качества от числа признаков
Формат отчета:
- Описание созданных признаков
- Результаты отбора признаков
- Графики важности признаков
- Выводы о значимости различных признаков
Задание 5: Ансамбли и комбинирование моделей
Цель: Изучить методы создания ансамблей классификаторов.
Задачи:
- Реализуйте простое голосование (Voting Classifier) из 3-5 разных алгоритмов
- Сравните hard voting и soft voting
- Реализуйте бэггинг (Bagging) для деревьев решений
- Сравните ансамбли с отдельными моделями
- Проанализируйте влияние числа моделей в ансамбле
Формат отчета:
- Сравнение различных методов голосования
- Графики зависимости качества от числа моделей
- Анализ разнообразия моделей в ансамбле
- Рекомендации по созданию ансамблей
Контрольные вопросы
- Какие существуют основные метрики качества классификации и когда каждая из них применима?
- В чем различие между precision и recall? Приведите примеры задач, где важнее precision, и где важнее recall.
- Какие преимущества и недостатки у каждого из рассмотренных алгоритмов классификации?
- Зачем необходимо масштабирование признаков и какие методы масштабирования существуют?
- Что такое переобучение и как его можно выявить и предотвратить?
- Какие методы борьбы с несбалансированными классами существуют?
- В чем преимущество кросс-валидации по сравнению с простым разделением на train/test?
- Какие существуют методы отбора признаков и когда их применять?
Рекомендации по выполнению работы
- Начните с базового примера и убедитесь, что все работает корректно
- Используйте одинаковые random_state для воспроизводимости результатов
- Документируйте эксперименты в виде комментариев к коду
- Сохраняйте результаты в отдельные переменные для последующего анализа
- Визуализируйте данные - графики помогают лучше понять результаты
- Сравнивайте результаты с теоретическими ожиданиями