Машинное обучение: понимание матрицы ошибок
Узнайте, что такое матрица ошибок, как построить её в Python с scikit-learn, визуализировать с seaborn и вычислить precision, recall и F1-score.
Матрица ошибок — это таблица, которая обобщает результаты предсказаний классификационной модели, сравнивая фактические метки с предсказанными. Она является отправной точкой для вычисления precision, recall, F1-score и большинства других метрик классификации.
В этой главе рассматривается:
- Что означают четыре ячейки (TP, FP, TN, FN) и почему каждая из них важна
- Как вычислять стандартные метрики из этих ячеек
- Построение и визуализация матрицы ошибок в Python с помощью scikit-learn и seaborn
- Многоклассовые матрицы ошибок
- Типичные ошибки — особенно при работе с несбалансированными наборами данных
Что такое матрица ошибок?
Для бинарного классификатора (два возможных класса: положительный и отрицательный) матрица ошибок представляет собой таблицу 2×2:
| Предсказан положительный | Предсказан отрицательный | |
|---|---|---|
| Фактически положительный | True Positive (TP) | False Negative (FN) |
| Фактически отрицательный | False Positive (FP) | True Negative (TN) |
Каждая ячейка считает определённый тип результата:
| Термин | Аббревиатура | Значение |
|---|---|---|
| True Positive | TP | Модель предсказала положительный; реальность — положительный ✓ |
| True Negative | TN | Модель предсказала отрицательный; реальность — отрицательный ✓ |
| False Positive | FP | Модель предсказала положительный; реальность — отрицательный ✗ (ошибка I рода) |
| False Negative | FN | Модель предсказала отрицательный; реальность — положительный ✗ (ошибка II рода) |
Простой способ запомнить: первое слово (True / False) говорит о том, было ли предсказание верным; второе слово (Positive / Negative) — что именно предсказала модель.
Метрики, вычисляемые из матрицы
Четыре счётчика лежат в основе всех стандартных метрик классификации:
| Метрика | Формула | Что измеряет |
|---|---|---|
| Accuracy | (TP + TN) / (TP + TN + FP + FN) | Общая доля верных предсказаний |
| Precision | TP / (TP + FP) | Из всех положительных предсказаний, сколько оказались верными |
| Recall (Sensitivity) | TP / (TP + FN) | Из всех фактически положительных, сколько было найдено |
| Specificity | TN / (TN + FP) | Из всех фактически отрицательных, сколько было корректно исключено |
| F1-Score | 2 × Precision × Recall / (Precision + Recall) | Гармоническое среднее precision и recall |
Когда отдавать приоритет precision или recall
- Приоритет recall актуален, когда пропуск положительного случая обходится дорого — медицинский скрининг, обнаружение мошенничества, спам-фильтры, которые должны поймать каждое нежелательное письмо.
- Приоритет precision актуален, когда ложные срабатывания обходятся дорого — рекомендации к операции, маркировка юридических документов, системы push-уведомлений.
- F1-score балансирует оба показателя и является метрикой по умолчанию при несбалансированных данных.
Численный пример с расчётами
Предположим, модель проверяет 100 пациентов на наличие заболевания:
- TP = 50 (больные пациенты, выявленные верно)
- FP = 5 (здоровые пациенты, ошибочно отмеченные как больные)
- FN = 10 (больные пациенты, пропущенные моделью)
- TN = 35 (здоровые пациенты, верно признанные здоровыми)
Пошаговые вычисления:
Accuracy = (50 + 35) / 100 = 0.85 (85 %)
Precision = 50 / (50 + 5) ≈ 0.909 (90.9 %)
Recall = 50 / (50 + 10) ≈ 0.833 (83.3 %)
F1-Score = 2 × 0.909 × 0.833 / (0.909 + 0.833) ≈ 0.869 (86.9 %)Обратите внимание: accuracy (85 %) выглядит неплохо, однако recall составляет лишь 83 % — то есть 10 из 60 больных пациентов были пропущены. В медицинском контексте это несоответствие важнее, чем само значение accuracy.
Построение матрицы ошибок в Python
Использование scikit-learn
sklearn.metrics предоставляет confusion_matrix() и готовый текстовый отчёт через classification_report().
from sklearn.metrics import confusion_matrix, classification_report
# Ground-truth labels and model predictions
y_true = [1, 1, 0, 0, 1, 0, 1, 0, 1, 0]
y_pred = [1, 0, 0, 1, 1, 0, 1, 0, 1, 1]
cm = confusion_matrix(y_true, y_pred)
print("Confusion Matrix:")
print(cm)
print()
print(classification_report(y_true, y_pred, target_names=["Negative", "Positive"]))confusion_matrix() возвращает массив NumPy. По умолчанию строки — фактические классы, а столбцы — предсказанные (соответствует показанной выше таблице). Расположение элементов массива:
[[TN FP]
[FN TP]]Ручное вычисление метрик
Можно извлечь четыре ячейки и вычислить метрики самостоятельно для проверки:
from sklearn.metrics import confusion_matrix
y_true = [1, 1, 0, 0, 1, 0, 1, 0, 1, 0]
y_pred = [1, 0, 0, 1, 1, 0, 1, 0, 1, 1]
tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel()
accuracy = (tp + tn) / (tp + tn + fp + fn)
precision = tp / (tp + fp)
recall = tp / (tp + fn)
f1 = 2 * precision * recall / (precision + recall)
print(f"TP={tp}, FP={fp}, FN={fn}, TN={tn}")
print(f"Accuracy : {accuracy:.3f}")
print(f"Precision: {precision:.3f}")
print(f"Recall : {recall:.3f}")
print(f"F1-Score : {f1:.3f}")Ожидаемый вывод:
TP=4, FP=2, FN=1, TN=3
Accuracy : 0.700
Precision: 0.667
Recall : 0.800
F1-Score : 0.727Визуализация с помощью seaborn
Тепловая карта делает матрицу ошибок более наглядной, особенно при многоклассовых задачах:
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.metrics import confusion_matrix
y_true = [1, 1, 0, 0, 1, 0, 1, 0, 1, 0]
y_pred = [1, 0, 0, 1, 1, 0, 1, 0, 1, 1]
cm = confusion_matrix(y_true, y_pred)
sns.heatmap(
cm,
annot=True,
fmt="d",
cmap="Blues",
xticklabels=["Negative", "Positive"],
yticklabels=["Negative", "Positive"],
)
plt.xlabel("Predicted label")
plt.ylabel("True label")
plt.title("Confusion Matrix")
plt.tight_layout()
plt.savefig("confusion_matrix.png", dpi=150)
plt.show()annot=True печатает количество внутри каждой ячейки; fmt="d" форматирует их как целые числа.
Многоклассовые матрицы ошибок
При наличии более двух классов матрица ошибок расширяется до сетки N×N. Каждая строка по-прежнему представляет фактические классы; каждый столбец — предсказанные. Диагональные ячейки — верные предсказания; внедиагональные — ошибки.
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
import matplotlib.pyplot as plt
# Three classes: cat, dog, rabbit
y_true = ["cat", "dog", "rabbit", "cat", "dog", "rabbit",
"cat", "dog", "cat", "rabbit"]
y_pred = ["cat", "dog", "rabbit", "dog", "dog", "cat",
"cat", "rabbit", "cat", "rabbit"]
labels = ["cat", "dog", "rabbit"]
cm = confusion_matrix(y_true, y_pred, labels=labels)
print(cm)
disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=labels)
disp.plot(cmap="Blues")
plt.title("Multi-Class Confusion Matrix")
plt.tight_layout()
plt.savefig("cm_multiclass.png", dpi=150)
plt.show()ConfusionMatrixDisplay (добавлен в scikit-learn 0.24) — удобная однострочная альтернатива тепловой карте seaborn, не требующая зависимости от seaborn.
Для многоклассовых задач precision и recall вычисляются для каждого класса и затем усредняются. classification_report() предоставляет три стратегии усреднения:
macro— невзвешенное среднее по классам (все классы равнозначны).weighted— среднее, взвешенное по поддержке (количеству истинных экземпляров каждого класса).micro— агрегирование TP/FP/FN по всем классам перед делением (даёт общую accuracy для сбалансированных наборов).
Типичные ошибки
Accuracy вводит в заблуждение на несбалансированных данных
Рассмотрим набор данных, где 95 % образцов относятся к отрицательному классу. Модель, всегда предсказывающая отрицательный класс, достигает 95 % accuracy, но имеет нулевой recall — она никогда не обнаруживает положительные случаи. Матрица ошибок сразу это показывает: вся первая строка (фактически положительные) будет состоять исключительно из FN.
Всегда дополняйте accuracy метриками precision, recall или F1-score при несбалансированных данных. Смотрите главу Train/Test Split о том, как создать репрезентативную выборку, и главу AUC-ROC Curve о метрике оценки, независимой от порога.
Неправильный выбор стратегии усреднения
Использование усреднения macro при сильном дисбалансе классов завышает оценку редких классов. Используйте weighted для реалистичного представления общего качества модели на всём наборе данных.
Отсутствие нормализации
Абсолютные значения зависят от размера набора данных. При сравнении моделей, обученных на наборах разного размера, нормализуйте матрицу, разделив каждую строку на её сумму (передайте normalize='true' в confusion_matrix()):
cm_normalized = confusion_matrix(y_true, y_pred, normalize="true")
print(cm_normalized.round(2))Теперь каждая строка суммируется до 1.0 и показывает долю каждого фактического класса, предсказанного верно.
Матрица ошибок и другие инструменты оценки
| Инструмент | Лучше всего подходит для |
|---|---|
| Матрица ошибок | Понимания конкретных типов ошибок модели |
| AUC-ROC Curve | Сравнения классификаторов при всех порогах принятия решений |
| Cross-Validation | Оценки того, насколько хорошо матрица обобщается на новых данных |
| Grid Search | Настройки гиперпараметров с использованием выбранной метрики (например, F1-score) |
Ключевые выводы
- Матрица ошибок разбивает предсказания на TP, FP, TN и FN — четыре значения, раскрывающие какие ошибки допускает модель, а не просто сколько.
- Accuracy в одиночку недостаточна; всегда проверяйте precision, recall и F1-score, особенно при несбалансированных данных.
- Используйте
sklearn.metrics.confusion_matrix()для вычислений и seaborn илиConfusionMatrixDisplayдля визуализации. - Многоклассовые матрицы следуют тому же соглашению: строка = фактический класс, столбец = предсказанный, и масштабируются до N×N.
- Выбирайте стратегию усреднения (
macro,weighted,micro) в соответствии с распределением классов в вашем наборе данных.