- sklearn.metrics.confusion_matrix(y_true, y_pred, *, labels=None, sample_weight=None, normalize=None)[source]¶
-
Compute confusion matrix to evaluate the accuracy of a classification.
By definition a confusion matrix (C) is such that (C_{i, j})
is equal to the number of observations known to be in group (i) and
predicted to be in group (j).Thus in binary classification, the count of true negatives is
(C_{0,0}), false negatives is (C_{1,0}), true positives is
(C_{1,1}) and false positives is (C_{0,1}).Read more in the User Guide.
- Parameters:
-
- y_truearray-like of shape (n_samples,)
-
Ground truth (correct) target values.
- y_predarray-like of shape (n_samples,)
-
Estimated targets as returned by a classifier.
- labelsarray-like of shape (n_classes), default=None
-
List of labels to index the matrix. This may be used to reorder
or select a subset of labels.
IfNoneis given, those that appear at least once
iny_trueory_predare used in sorted order. - sample_weightarray-like of shape (n_samples,), default=None
-
Sample weights.
New in version 0.18.
- normalize{‘true’, ‘pred’, ‘all’}, default=None
-
Normalizes confusion matrix over the true (rows), predicted (columns)
conditions or all the population. If None, confusion matrix will not be
normalized.
- Returns:
-
- Cndarray of shape (n_classes, n_classes)
-
Confusion matrix whose i-th row and j-th
column entry indicates the number of
samples with true label being i-th class
and predicted label being j-th class.
References
Examples
>>> from sklearn.metrics import confusion_matrix >>> y_true = [2, 0, 2, 2, 0, 1] >>> y_pred = [0, 0, 2, 2, 0, 2] >>> confusion_matrix(y_true, y_pred) array([[2, 0, 0], [0, 0, 1], [1, 0, 2]])
>>> y_true = ["cat", "ant", "cat", "cat", "ant", "bird"] >>> y_pred = ["ant", "ant", "cat", "cat", "ant", "cat"] >>> confusion_matrix(y_true, y_pred, labels=["ant", "bird", "cat"]) array([[2, 0, 0], [0, 0, 1], [1, 0, 2]])
In the binary case, we can extract true positives, etc as follows:
>>> tn, fp, fn, tp = confusion_matrix([0, 1, 0, 1], [1, 1, 1, 0]).ravel() >>> (tn, fp, fn, tp) (0, 2, 1, 1)
Examples using sklearn.metrics.confusion_matrix¶
В компьютерном зрении обнаружение объекта — это проблема определения местоположения одного или нескольких объектов на изображении. Помимо традиционных методов обнаружения, продвинутые модели глубокого обучения, такие как R-CNN и YOLO, могут обеспечить впечатляющие результаты при различных типах объектов. Эти модели принимают изображение в качестве входных данных и возвращают координаты прямоугольника, ограничивающего пространство вокруг каждого найденного объекта.
В этом руководстве обсуждается матрица ошибок и то, как рассчитываются precision, recall и accuracy метрики.
Здесь мы рассмотрим:
- Матрицу ошибок для двоичной классификации.
- Матрицу ошибок для мультиклассовой классификации.
- Расчет матрицы ошибок с помощью Scikit-learn.
- Accuracy, Precision и Recall.
- Precision или Recall?
Матрица ошибок для бинарной классификации
В бинарной классификации каждая выборка относится к одному из двух классов. Обычно им присваиваются такие метки, как 1 и 0, или положительный и отрицательный (Positive и Negative). Также могут использоваться более конкретные обозначения для классов: злокачественный или доброкачественный (например, если проблема связана с классификацией рака), успех или неудача (если речь идет о классификации результатов тестов учащихся).
Предположим, что существует проблема бинарной классификации с классами positive и negative. Вот пример достоверных или эталонных меток для семи выборок, используемых для обучения модели.
positive, negative, negative, positive, positive, positive, negative
Такие наименования нужны в первую очередь для того, чтобы нам, людям, было проще различать классы. Для модели более важна числовая оценка. Обычно при передаче очередного набора данных на выходе вы получите не метку класса, а числовой результат. Например, когда эти семь семплов вводятся в модель, каждому классу будут назначены следующие значения:
0.6, 0.2, 0.55, 0.9, 0.4, 0.8, 0.5
На основании полученных оценок каждой выборке присваивается соответствующий класс. Такое преобразование числовых результатов в метки происходит с помощью порогового значения. Данное граничное условие является гиперпараметром модели и может быть определено пользователем. Например, если порог равен 0.5, тогда любая оценка, которая больше или равна 0.5, получает положительную метку. В противном случае — отрицательную. Вот предсказанные алгоритмом классы:
positive (0.6), negative (0.2), positive (0.55), positive (0.9), negative (0.4), positive (0.8), positive (0.5)
Сравните достоверные и полученные метки — мы имеем 4 верных и 3 неверных предсказания. Стоит добавить, что изменение граничного условия отражается на результатах. Например, установка порога, равного 0.6, оставляет только два неверных прогноза.
Реальность: positive, negative, negative, positive, positive, positive, negative
Предсказания: positive, negative, positive, positive, negative, positive, positive
Для получения дополнительной информации о характеристиках модели используется матрица ошибок (confusion matrix). Матрица ошибок помогает нам визуализировать, «ошиблась» ли модель при различении двух классов. Как видно на следующем рисунке, это матрица 2х2. Названия строк представляют собой эталонные метки, а названия столбцов — предсказанные.

Четыре элемента матрицы (клетки красного и зеленого цвета) представляют собой четыре метрики, которые подсчитывают количество правильных и неправильных прогнозов, сделанных моделью. Каждому элементу дается метка, состоящая из двух слов:
- True или False.
- Positive или Negative.
True, если получено верное предсказание, то есть эталонные и предсказанные метки классов совпадают, и False, когда они не совпадают. Positive или Negative — названия предсказанных меток.
Таким образом, всякий раз, когда прогноз неверен, первое слово в ячейке False, когда верен — True. Наша цель состоит в том, чтобы максимизировать показатели со словом «True» (True Positive и True Negative) и минимизировать два других (False Positive и False Negative). Четыре метрики в матрице ошибок представляют собой следующее:
- Верхний левый элемент (True Positive): сколько раз модель правильно классифицировала Positive как Positive?
- Верхний правый (False Negative): сколько раз модель неправильно классифицировала Positive как Negative?
- Нижний левый (False Positive): сколько раз модель неправильно классифицировала Negative как Positive?
- Нижний правый (True Negative): сколько раз модель правильно классифицировала Negative как Negative?
Мы можем рассчитать эти четыре показателя для семи предсказаний, использованных нами ранее. Полученная матрица ошибок представлена на следующем рисунке.

Вот так вычисляется матрица ошибок для задачи двоичной классификации. Теперь посмотрим, как решить данную проблему для большего числа классов.
Матрица ошибок для мультиклассовой классификации
Что, если у нас более двух классов? Как вычислить эти четыре метрики в матрице ошибок для задачи мультиклассовой классификации? Очень просто!
Предположим, имеется 9 семплов, каждый из которых относится к одному из трех классов: White, Black или Red. Вот достоверные метки для 9 выборок:
Red, Black, Red, White, White, Red, Black, Red, White
После загрузки данных модель делает следующее предсказание:
Red, White, Black, White, Red, Red, Black, White, Red
Для удобства сравнения здесь они расположены рядом.
Реальность: Red, Black, Red, White, White, Red, Black, Red, White Предсказания: Red, White, Black, White, Red, Red, Black, White, Red
Перед вычислением матрицы ошибок необходимо выбрать целевой класс. Давайте назначим на эту роль класс Red. Он будет отмечен как Positive, а все остальные отмечены как Negative.
Positive, Negative, Positive, Negative, Negative, Positive, Negative, Positive, Negative Positive, Negative, Negative, Negative, Positive, Positive, Negative, Negative, Positive
11111111111111111111111После замены остались только два класса (Positive и Negative), что позволяет нам рассчитать матрицу ошибок, как было показано в предыдущем разделе. Стоит заметить, что полученная матрица предназначена только для класса Red.

Далее для класса White заменим каждое его вхождение на Positive, а метки всех остальных классов на Negative. Мы получим такие достоверные и предсказанные метки:
Negative, Negative, Negative, Positive, Positive, Negative, Negative, Negative, Positive Negative, Positive, Negative, Positive, Negative, Negative, Negative, Positive, Negative
На следующей схеме показана матрица ошибок для класса White.

Точно так же может быть получена матрица ошибок для Black.
Расчет матрицы ошибок с помощью Scikit-Learn
В популярной Python-библиотеке Scikit-learn есть модуль metrics, который можно использовать для вычисления метрик в матрице ошибок.
Для задач с двумя классами используется функция confusion_matrix(). Мы передадим в функцию следующие параметры:
y_true: эталонные метки.y_pred: предсказанные метки.
Следующий код вычисляет матрицу ошибок для примера двоичной классификации, который мы обсуждали ранее.
import sklearn.metrics
y_true = ["positive", "negative", "negative", "positive", "positive", "positive", "negative"]
y_pred = ["positive", "negative", "positive", "positive", "negative", "positive", "positive"]
r = sklearn.metrics.confusion_matrix(y_true, y_pred)
print(r)
array([[1, 2],
[1, 3]], dtype=int64)
Обратите внимание, что порядок метрик отличается от описанного выше. Например, показатель True Positive находится в правом нижнем углу, а True Negative — в верхнем левом углу. Чтобы исправить это, мы можем перевернуть матрицу.
import numpy
r = numpy.flip(r)
print(r)
array([[3, 1],
[2, 1]], dtype=int64)
Чтобы вычислить матрицу ошибок для задачи с большим числом классов, используется функция multilabel_confusion_matrix(), как показано ниже. В дополнение к параметрам y_true и y_pred третий параметр labels принимает список классовых меток.
import sklearn.metrics
import numpy
y_true = ["Red", "Black", "Red", "White", "White", "Red", "Black", "Red", "White"]
y_pred = ["Red", "White", "Black", "White", "Red", "Red", "Black", "White", "Red"]
r = sklearn.metrics.multilabel_confusion_matrix(y_true, y_pred, labels=["White", "Black", "Red"])
print(r)
array([
[[4 2]
[2 1]]
[[6 1]
[1 1]]
[[3 2]
[2 2]]], dtype=int64)
Функция вычисляет матрицу ошибок для каждого класса и возвращает все матрицы. Их порядок соответствует порядку меток в параметре labels. Чтобы изменить последовательность метрик в матрицах, мы будем снова использовать функцию numpy.flip().
print(numpy.flip(r[0])) # матрица ошибок для класса White
print(numpy.flip(r[1])) # матрица ошибок для класса Black
print(numpy.flip(r[2])) # матрица ошибок для класса Red
# матрица ошибок для класса White
[[1 2]
[2 4]]
# матрица ошибок для класса Black
[[1 1]
[1 6]]
# матрица ошибок для класса Red
[[2 2]
[2 3]]
В оставшейся части этого текста мы сосредоточимся только на двух классах. В следующем разделе обсуждаются три ключевых показателя, которые рассчитываются на основе матрицы ошибок.
Как мы уже видели, матрица ошибок предлагает четыре индивидуальных показателя. На их основе можно рассчитать другие метрики, которые предоставляют дополнительную информацию о поведении модели:
- Accuracy
- Precision
- Recall
В следующих подразделах обсуждается каждый из этих трех показателей.
Метрика Accuracy
Accuracy — это показатель, который описывает общую точность предсказания модели по всем классам. Это особенно полезно, когда каждый класс одинаково важен. Он рассчитывается как отношение количества правильных прогнозов к их общему количеству.
Рассчитаем accuracy с помощью Scikit-learn на основе ранее полученной матрицы ошибок. Переменная acc содержит результат деления суммы True Positive и True Negative метрик на сумму всех значений матрицы. Таким образом, accuracy, равная 0.5714, означает, что модель с точностью 57,14% делает верный прогноз.
import numpy
import sklearn.metrics
y_true = ["positive", "negative", "negative", "positive", "positive", "positive", "negative"]
y_pred = ["positive", "negative", "positive", "positive", "negative", "positive", "positive"]
r = sklearn.metrics.confusion_matrix(y_true, y_pred)
r = numpy.flip(r)
acc = (r[0][0] + r[-1][-1]) / numpy.sum(r)
print(acc)
# вывод будет 0.571
В модуле sklearn.metrics есть функция precision_score(), которая также может вычислять accuracy. Она принимает в качестве аргументов достоверные и предсказанные метки.
acc = sklearn.metrics.accuracy_score(y_true, y_pred)
Стоит учесть, что метрика accuracy может быть обманчивой. Один из таких случаев — это несбалансированные данные. Предположим, у нас есть всего 600 единиц данных, из которых 550 относятся к классу Positive и только 50 — к Negative. Поскольку большинство семплов принадлежит к одному классу, accuracy для этого класса будет выше, чем для другого.
Если модель сделала 530 правильных прогнозов из 550 для класса Positive, по сравнению с 5 из 50 для Negative, то общая accuracy равна (530 + 5) / 600 = 0.8917. Это означает, что точность модели составляет 89.17%. Полагаясь на это значение, вы можете подумать, что для любой выборки (независимо от ее класса) модель сделает правильный прогноз в 89.17% случаев. Это неверно, так как для класса Negative модель работает очень плохо.
Precision
Precision представляет собой отношение числа семплов, верно классифицированных как Positive, к общему числу выборок с меткой Positive (распознанных правильно и неправильно). Precision измеряет точность модели при определении класса Positive.
Когда модель делает много неверных Positive классификаций, это увеличивает знаменатель и снижает precision. С другой стороны, precision высока, когда:
- Модель делает много корректных предсказаний класса Positive (максимизирует True Positive метрику).
- Модель делает меньше неверных Positive классификаций (минимизирует False Positive).
Представьте себе человека, который пользуется всеобщим доверием; когда он что-то предсказывает, окружающие ему верят. Метрика precision похожа на такого персонажа. Если она высока, вы можете доверять решению модели по определению очередной выборки как Positive. Таким образом, precision помогает узнать, насколько точна модель, когда она говорит, что семпл имеет класс Positive.
Основываясь на предыдущем обсуждении, вот определение precision:
Precision отражает, насколько надежна модель при классификации Positive-меток.
На следующем изображении зеленая метка означает, что зеленый семпл классифицирован как Positive, а красный крест – как Negative. Модель корректно распознала две Positive выборки, но неверно классифицировала один Negative семпл как Positive. Из этого следует, что метрика True Positive равна 2, когда False Positive имеет значение 1, а precision составляет 2 / (2 + 1) = 0.667. Другими словами, процент доверия к решению модели, что выборка относится к классу Positive, составляет 66.7%.

Цель precision – классифицировать все Positive семплы как Positive, не допуская ложных определений Negative как Positive. Согласно следующему рисунку, если все три Positive выборки предсказаны правильно, но один Negative семпл классифицирован неверно, precision составляет 3 / (3 + 1) = 0.75. Таким образом, утверждения модели о том, что выборка относится к классу Positive, корректны с точностью 75%.

Единственный способ получить 100% precision — это классифицировать все Positive выборки как Positive без классификации Negative как Positive.
В Scikit-learn модуль sklearn.metrics имеет функцию precision_score(), которая получает в качестве аргументов эталонные и предсказанные метки и возвращает precision. Параметр pos_label принимает метку класса Positive (по умолчанию 1).
import sklearn.metrics
y_true = ["positive", "positive", "positive", "negative", "negative", "negative"]
y_pred = ["positive", "positive", "negative", "positive", "negative", "negative"]
precision = sklearn.metrics.precision_score(y_true, y_pred, pos_label="positive")
print(precision)
Вывод: 0.6666666666666666.
Recall
Recall рассчитывается как отношение числа Positive выборок, корректно классифицированных как Positive, к общему количеству Positive семплов. Recall измеряет способность модели обнаруживать выборки, относящиеся к классу Positive. Чем выше recall, тем больше Positive семплов было найдено.
Recall заботится только о том, как классифицируются Positive выборки. Эта метрика не зависит от того, как предсказываются Negative семплы, в отличие от precision. Когда модель верно классифицирует все Positive выборки, recall будет 100%, даже если все представители класса Negative были ошибочно определены как Positive. Давайте посмотрим на несколько примеров.
На следующем изображении представлены 4 разных случая (от A до D), и все они имеют одинаковый recall, равный 0.667. Представленные примеры отличаются только тем, как классифицируются Negative семплы. Например, в случае A все Negative выборки корректно определены, а в случае D – наоборот. Независимо от того, как модель предсказывает класс Negative, recall касается только семплов относящихся к Positive.

Из 4 случаев, показанных выше, только 2 Positive выборки определены верно. Таким образом, метрика True Positive равна 2. False Negative имеет значение 1, потому что только один Positive семпл классифицируется как Negative. В результате recall будет равен 2 / (2 + 1) = 2/3 = 0.667.
Поскольку не имеет значения, как предсказываются объекты класса Negative, лучше их просто игнорировать, как показано на следующей схеме. При расчете recall необходимо учитывать только Positive выборки.

Что означает, когда recall высокий или низкий? Если recall имеет большое значение, все Positive семплы классифицируются верно. Следовательно, модели можно доверять в ее способности обнаруживать представителей класса Positive.
На следующем изображении recall равен 1.0, потому что все Positive семплы были правильно классифицированы. Показатель True Positive равен 3, а False Negative – 0. Таким образом, recall вычисляется как 3 / (3 + 0) = 1. Это означает, что модель обнаружила все Positive выборки. Поскольку recall не учитывает, как предсказываются представители класса Negative, могут присутствовать множество неверно определенных Negative семплов (высокая False Positive метрика).

С другой стороны, recall равен 0.0, если не удается обнаружить ни одной Positive выборки. Это означает, что модель обнаружила 0% представителей класса Positive. Показатель True Positive равен 0, а False Negative имеет значение 3. Recall будет равен 0 / (0 + 3) = 0.
Когда recall имеет значение от 0.0 до 1.0, это число отражает процент Positive семплов, которые модель верно классифицировала. Например, если имеется 10 экземпляров Positive и recall равен 0.6, получается, что модель корректно определила 60% объектов класса Positive (т.е. 0.6 * 10 = 6).
Подобно precision_score(), функция repl_score() из модуля sklearn.metrics вычисляет recall. В следующем блоке кода показан пример ее использования.
import sklearn.metrics
y_true = ["positive", "positive", "positive", "negative", "negative", "negative"]
y_pred = ["positive", "positive", "negative", "positive", "negative", "negative"]
recall = sklearn.metrics.recall_score(y_true, y_pred, pos_label="positive")
print(recall)
Вывод: 0.6666666666666666.
После определения precision и recall давайте кратко подведем итоги:
- Precision измеряет надежность модели при классификации Positive семплов, а recall определяет, сколько Positive выборок было корректно предсказано моделью.
- Precision учитывает классификацию как Positive, так и Negative семплов. Recall же использует при расчете только представителей класса Positive. Другими словами, precision зависит как от Negative, так и от Positive-выборок, но recall — только от Positive.
- Precision принимает во внимание, когда семпл определяется как Positive, но не заботится о верной классификации всех объектов класса Positive. Recall в свою очередь учитывает корректность предсказания всех Positive выборок, но не заботится об ошибочной классификации представителей Negative как Positive.
- Когда модель имеет высокий уровень recall метрики, но низкую precision, такая модель правильно определяет большинство Positive семплов, но имеет много ложных срабатываний (классификаций Negative выборок как Positive). Если модель имеет большую precision, но низкий recall, то она делает высокоточные предсказания, определяя класс Positive, но производит всего несколько таких прогнозов.
Некоторые вопросы для проверки понимания:
- Если recall равен 1.0, а в датасете имеются 5 объектов класса Positive, сколько Positive семплов было правильно классифицировано моделью?
- Учитывая, что recall составляет 0.3, когда в наборе данных 30 Positive семплов, сколько представителей класса Positive будет предсказано верно?
- Если recall равен 0.0 и в датасете14 Positive-семплов, сколько корректных предсказаний класса Positive было сделано моделью?
Precision или Recall?
Решение о том, следует ли использовать precision или recall, зависит от типа вашей проблемы. Если цель состоит в том, чтобы обнаружить все positive выборки (не заботясь о том, будут ли negative семплы классифицированы как positive), используйте recall. Используйте precision, если ваша задача связана с комплексным предсказанием класса Positive, то есть учитывая Negative семплы, которые были ошибочно классифицированы как Positive.
Представьте, что вам дали изображение и попросили определить все автомобили внутри него. Какой показатель вы используете? Поскольку цель состоит в том, чтобы обнаружить все автомобили, используйте recall. Такой подход может ошибочно классифицировать некоторые объекты как целевые, но в конечном итоге сработает для предсказания всех автомобилей.
Теперь предположим, что вам дали снимок с результатами маммографии, и вас попросили определить наличие рака. Какой показатель вы используете? Поскольку он обязан быть чувствителен к неверной идентификации изображения как злокачественного, мы должны быть уверены, когда классифицируем снимок как Positive (то есть с раком). Таким образом, предпочтительным показателем в данном случае является precision.
Вывод
В этом руководстве обсуждалась матрица ошибок, вычисление ее 4 метрик (true/false positive/negative) для задач бинарной и мультиклассовой классификации. Используя модуль metrics библиотеки Scikit-learn, мы увидели, как получить матрицу ошибок в Python.
Основываясь на этих 4 показателях, мы перешли к обсуждению accuracy, precision и recall метрик. Каждая из них была определена и использована в нескольких примерах. Модуль sklearn.metrics применяется для расчета каждого вышеперечисленного показателя.
Метрики в задачах машинного обучения
Привет, Хабр!

В задачах машинного обучения для оценки качества моделей и сравнения различных алгоритмов используются метрики, а их выбор и анализ — непременная часть работы датасатаниста.
В этой статье мы рассмотрим некоторые критерии качества в задачах классификации, обсудим, что является важным при выборе метрики и что может пойти не так.
Метрики в задачах классификации
Для демонстрации полезных функций sklearn и наглядного представления метрик мы будем использовать датасет по оттоку клиентов телеком-оператора.
Загрузим необходимые библиотеки и посмотрим на данные
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.pylab import rc, plot
import seaborn as sns
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.metrics import precision_recall_curve, classification_report
from sklearn.model_selection import train_test_split
df = pd.read_csv('../../data/telecom_churn.csv')
df.head(5)

Предобработка данных
# Сделаем маппинг бинарных колонок
# и закодируем dummy-кодированием штат (для простоты, лучше не делать так для деревянных моделей)
d = {'Yes' : 1, 'No' : 0}
df['International plan'] = df['International plan'].map(d)
df['Voice mail plan'] = df['Voice mail plan'].map(d)
df['Churn'] = df['Churn'].astype('int64')
le = LabelEncoder()
df['State'] = le.fit_transform(df['State'])
ohe = OneHotEncoder(sparse=False)
encoded_state = ohe.fit_transform(df['State'].values.reshape(-1, 1))
tmp = pd.DataFrame(encoded_state,
columns=['state ' + str(i) for i in range(encoded_state.shape[1])])
df = pd.concat([df, tmp], axis=1)
Accuracy, precision и recall
Перед переходом к самим метрикам необходимо ввести важную концепцию для описания этих метрик в терминах ошибок классификации — confusion matrix (матрица ошибок).
Допустим, что у нас есть два класса и алгоритм, предсказывающий принадлежность каждого объекта одному из классов, тогда матрица ошибок классификации будет выглядеть следующим образом:
| True Positive (TP) | False Positive (FP) | |
| False Negative (FN) | True Negative (TN) |
Здесь — это ответ алгоритма на объекте, а
— истинная метка класса на этом объекте.
Таким образом, ошибки классификации бывают двух видов: False Negative (FN) и False Positive (FP).
Обучение алгоритма и построение матрицы ошибок
X = df.drop('Churn', axis=1)
y = df['Churn']
# Делим выборку на train и test, все метрики будем оценивать на тестовом датасете
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, test_size=0.33, random_state=42)
# Обучаем ставшую родной логистическую регрессию
lr = LogisticRegression(random_state=42)
lr.fit(X_train, y_train)
# Воспользуемся функцией построения матрицы ошибок из документации sklearn
def plot_confusion_matrix(cm, classes,
normalize=False,
title='Confusion matrix',
cmap=plt.cm.Blues):
"""
This function prints and plots the confusion matrix.
Normalization can be applied by setting `normalize=True`.
"""
plt.imshow(cm, interpolation='nearest', cmap=cmap)
plt.title(title)
plt.colorbar()
tick_marks = np.arange(len(classes))
plt.xticks(tick_marks, classes, rotation=45)
plt.yticks(tick_marks, classes)
if normalize:
cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
print("Normalized confusion matrix")
else:
print('Confusion matrix, without normalization')
print(cm)
thresh = cm.max() / 2.
for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
plt.text(j, i, cm[i, j],
horizontalalignment="center",
color="white" if cm[i, j] > thresh else "black")
plt.tight_layout()
plt.ylabel('True label')
plt.xlabel('Predicted label')
font = {'size' : 15}
plt.rc('font', **font)
cnf_matrix = confusion_matrix(y_test, lr.predict(X_test))
plt.figure(figsize=(10, 8))
plot_confusion_matrix(cnf_matrix, classes=['Non-churned', 'Churned'],
title='Confusion matrix')
plt.savefig("conf_matrix.png")
plt.show()

Accuracy
Интуитивно понятной, очевидной и почти неиспользуемой метрикой является accuracy — доля правильных ответов алгоритма:
Эта метрика бесполезна в задачах с неравными классами, и это легко показать на примере.
Допустим, мы хотим оценить работу спам-фильтра почты. У нас есть 100 не-спам писем, 90 из которых наш классификатор определил верно (True Negative = 90, False Positive = 10), и 10 спам-писем, 5 из которых классификатор также определил верно (True Positive = 5, False Negative = 5).
Тогда accuracy:
Однако если мы просто будем предсказывать все письма как не-спам, то получим более высокую accuracy:
При этом, наша модель совершенно не обладает никакой предсказательной силой, так как изначально мы хотели определять письма со спамом. Преодолеть это нам поможет переход с общей для всех классов метрики к отдельным показателям качества классов.
Precision, recall и F-мера
Для оценки качества работы алгоритма на каждом из классов по отдельности введем метрики precision (точность) и recall (полнота).
Precision можно интерпретировать как долю объектов, названных классификатором положительными и при этом действительно являющимися положительными, а recall показывает, какую долю объектов положительного класса из всех объектов положительного класса нашел алгоритм.

Именно введение precision не позволяет нам записывать все объекты в один класс, так как в этом случае мы получаем рост уровня False Positive. Recall демонстрирует способность алгоритма обнаруживать данный класс вообще, а precision — способность отличать этот класс от других классов.
Как мы отмечали ранее, ошибки классификации бывают двух видов: False Positive и False Negative. В статистике первый вид ошибок называют ошибкой I-го рода, а второй — ошибкой II-го рода. В нашей задаче по определению оттока абонентов, ошибкой первого рода будет принятие лояльного абонента за уходящего, так как наша нулевая гипотеза состоит в том, что никто из абонентов не уходит, а мы эту гипотезу отвергаем. Соответственно, ошибкой второго рода будет являться «пропуск» уходящего абонента и ошибочное принятие нулевой гипотезы.
Precision и recall не зависят, в отличие от accuracy, от соотношения классов и потому применимы в условиях несбалансированных выборок.
Часто в реальной практике стоит задача найти оптимальный (для заказчика) баланс между этими двумя метриками. Классическим примером является задача определения оттока клиентов.
Очевидно, что мы не можем находить всех уходящих в отток клиентов и только их. Но, определив стратегию и ресурс для удержания клиентов, мы можем подобрать нужные пороги по precision и recall. Например, можно сосредоточиться на удержании только высокодоходных клиентов или тех, кто уйдет с большей вероятностью, так как мы ограничены в ресурсах колл-центра.
Обычно при оптимизации гиперпараметров алгоритма (например, в случае перебора по сетке GridSearchCV ) используется одна метрика, улучшение которой мы и ожидаем увидеть на тестовой выборке.
Существует несколько различных способов объединить precision и recall в агрегированный критерий качества. F-мера (в общем случае ) — среднее гармоническое precision и recall :
в данном случае определяет вес точности в метрике, и при
это среднее гармоническое (с множителем 2, чтобы в случае precision = 1 и recall = 1 иметь
)
F-мера достигает максимума при полноте и точности, равными единице, и близка к нулю, если один из аргументов близок к нулю.
В sklearn есть удобная функция _metrics.classificationreport, возвращающая recall, precision и F-меру для каждого из классов, а также количество экземпляров каждого класса.
report = classification_report(y_test, lr.predict(X_test), target_names=['Non-churned', 'Churned'])
print(report)
| class | precision | recall | f1-score | support |
|---|---|---|---|---|
| Non-churned | 0.88 | 0.97 | 0.93 | 941 |
| Churned | 0.60 | 0.25 | 0.35 | 159 |
| avg / total | 0.84 | 0.87 | 0.84 | 1100 |
Здесь необходимо отметить, что в случае задач с несбалансированными классами, которые превалируют в реальной практике, часто приходится прибегать к техникам искусственной модификации датасета для выравнивания соотношения классов. Их существует много, и мы не будем их касаться, здесь можно посмотреть некоторые методы и выбрать подходящий для вашей задачи.
AUC-ROC и AUC-PR
При конвертации вещественного ответа алгоритма (как правило, вероятности принадлежности к классу, отдельно см. SVM) в бинарную метку, мы должны выбрать какой-либо порог, при котором 0 становится 1. Естественным и близким кажется порог, равный 0.5, но он не всегда оказывается оптимальным, например, при вышеупомянутом отсутствии баланса классов.
Одним из способов оценить модель в целом, не привязываясь к конкретному порогу, является AUC-ROC (или ROC AUC) — площадь (Area Under Curve) под кривой ошибок (Receiver Operating Characteristic curve ). Данная кривая представляет из себя линию от (0,0) до (1,1) в координатах True Positive Rate (TPR) и False Positive Rate (FPR):
TPR нам уже известна, это полнота, а FPR показывает, какую долю из объектов negative класса алгоритм предсказал неверно. В идеальном случае, когда классификатор не делает ошибок (FPR = 0, TPR = 1) мы получим площадь под кривой, равную единице; в противном случае, когда классификатор случайно выдает вероятности классов, AUC-ROC будет стремиться к 0.5, так как классификатор будет выдавать одинаковое количество TP и FP.
Каждая точка на графике соответствует выбору некоторого порога. Площадь под кривой в данном случае показывает качество алгоритма (больше — лучше), кроме этого, важной является крутизна самой кривой — мы хотим максимизировать TPR, минимизируя FPR, а значит, наша кривая в идеале должна стремиться к точке (0,1).
Код отрисовки ROC-кривой
sns.set(font_scale=1.5)
sns.set_color_codes("muted")
plt.figure(figsize=(10, 8))
fpr, tpr, thresholds = roc_curve(y_test, lr.predict_proba(X_test)[:,1], pos_label=1)
lw = 2
plt.plot(fpr, tpr, lw=lw, label='ROC curve ')
plt.plot([0, 1], [0, 1])
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC curve')
plt.savefig("ROC.png")
plt.show()

Критерий AUC-ROC устойчив к несбалансированным классам (спойлер: увы, не всё так однозначно) и может быть интерпретирован как вероятность того, что случайно выбранный positive объект будет проранжирован классификатором выше (будет иметь более высокую вероятность быть positive), чем случайно выбранный negative объект.
Рассмотрим следующую задачу: нам необходимо выбрать 100 релевантных документов из 1 миллиона документов. Мы намашинлернили два алгоритма:
- Алгоритм 1 возвращает 100 документов, 90 из которых релевантны. Таким образом,
- Алгоритм 2 возвращает 2000 документов, 90 из которых релевантны. Таким образом,
Скорее всего, мы бы выбрали первый алгоритм, который выдает очень мало False Positive на фоне своего конкурента. Но разница в False Positive Rate между этими двумя алгоритмами крайне мала — всего 0.0019. Это является следствием того, что AUC-ROC измеряет долю False Positive относительно True Negative и в задачах, где нам не так важен второй (больший) класс, может давать не совсем адекватную картину при сравнении алгоритмов.
Для того чтобы поправить положение, вернемся к полноте и точности :
- Алгоритм 1
- Алгоритм 2
Здесь уже заметна существенная разница между двумя алгоритмами — 0.855 в точности!
Precision и recall также используют для построения кривой и, аналогично AUC-ROC, находят площадь под ней.

Здесь можно отметить, что на маленьких датасетах площадь под PR-кривой может быть чересчур оптимистична, потому как вычисляется по методу трапеций, но обычно в таких задачах данных достаточно. За подробностями о взаимоотношениях AUC-ROC и AUC-PR можно обратиться сюда.
Logistic Loss
Особняком стоит логистическая функция потерь, определяемая как:
здесь — это ответ алгоритма на
-ом объекте,
— истинная метка класса на
-ом объекте, а
размер выборки.
Подробно про математическую интерпретацию логистической функции потерь уже написано в рамках поста про линейные модели.
Данная метрика нечасто выступает в бизнес-требованиях, но часто — в задачах на kaggle.
Интуитивно можно представить минимизацию logloss как задачу максимизации accuracy путем штрафа за неверные предсказания. Однако необходимо отметить, что logloss крайне сильно штрафует за уверенность классификатора в неверном ответе.
Рассмотрим пример:
def logloss_crutch(y_true, y_pred, eps=1e-15):
return - (y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred))
print('Logloss при неуверенной классификации %f' % logloss_crutch(1, 0.5))
>> Logloss при неуверенной классификации 0.693147
print('Logloss при уверенной классификации и верном ответе %f' % logloss_crutch(1, 0.9))
>> Logloss при уверенной классификации и верном ответе 0.105361
print('Logloss при уверенной классификации и НЕверном ответе %f' % logloss_crutch(1, 0.1))
>> Logloss при уверенной классификации и НЕверном ответе 2.302585
Отметим, как драматически выросла logloss при неверном ответе и уверенной классификации!
Следовательно, ошибка на одном объекте может дать существенное ухудшение общей ошибки на выборке. Такие объекты часто бывают выбросами, которые нужно не забывать фильтровать или рассматривать отдельно.
Всё становится на свои места, если нарисовать график logloss:

Видно, что чем ближе к нулю ответ алгоритма при ground truth = 1, тем выше значение ошибки и круче растёт кривая.
Подытожим:
- В случае многоклассовой классификации нужно внимательно следить за метриками каждого из классов и следовать логике решения задачи, а не оптимизации метрики
- В случае неравных классов нужно подбирать баланс классов для обучения и метрику, которая будет корректно отражать качество классификации
- Выбор метрики нужно делать с фокусом на предметную область, предварительно обрабатывая данные и, возможно, сегментируя (как в случае с делением на богатых и бедных клиентов)
Полезные ссылки
- Курс Евгения Соколова: Семинар по выбору моделей (там есть информация по метрикам задач регрессии)
- Задачки на AUC-ROC от А.Г. Дьяконова
- Дополнительно о других метриках можно почитать на kaggle. К описанию каждой метрики добавлена ссылка на соревнования, где она использовалась
- Презентация Богдана Мельника aka ld86 про обучение на несбалансированных выборках
Благодарности
Спасибо mephistopheies и madrugado за помощь в подготовке статьи.
Матрица ошибок – это метрика производительности классифицирующей модели Машинного обучения (ML).
Когда мы получаем данные, то после очистки и предварительной обработки, первым делом передаем их в модель и, конечно же, получаем результат в виде вероятностей. Но как мы можем измерить эффективность нашей модели? Именно здесь матрица ошибок и оказывается в центре внимания.
Матрица ошибок – это показатель успешности классификации, где классов два или более. Это таблица с 4 различными комбинациями сочетаний прогнозируемых и фактических значений.

Давайте рассмотрим значения ячеек (истинно позитивные, ошибочно позитивные, ошибочно негативные, истинно негативные) с помощью «беременной» аналогии.

Истинно позитивное предсказание (True Positive, сокр. TP)
Вы предсказали положительный результат, и женщина действительно беременна.
Истинно отрицательное предсказание (True Negative, TN)
Вы предсказали отрицательный результат, и мужчина действительно не беременен.
Ошибочно положительное предсказание (ошибка типа I, False Positive, FN)
Вы предсказали положительный результат (мужчина беременен), но на самом деле это не так.
Ошибочно отрицательное предсказание (ошибка типа II, False Negative, FN)
Вы предсказали, что женщина не беременна, но на самом деле она беременна.
Давайте разберемся в матрице ошибок с помощью арифметики.
Пример. Мы располагаем датасетом пациентов, у которых диагностируют рак. Зная верный диагноз (столбец целевой переменной «Y на самом деле»), хотим усовершенствовать диагностику с помощью модели Машинного обучения. Модель получила тренировочные данные, и на тестовой части, состоящей из 7 записей (в реальных задачах, конечно, больше) и изображенной ниже, мы оцениваем, насколько хорошо прошло обучение.

Модель сделала свои предсказания для каждого пациента и записала вероятности от 0 до 1 в столбец «Предсказанный Y». Мы округляем эти числа, приводя их к нулю или единице, с помощью порога, равного 0,6 (ниже этого значения – ноль, пациент здоров). Результаты округления попадают в столбец «Предсказанная вероятность»: например, для первой записи модель указала 0,5, что соответствует нулю. В последнем столбце мы анализируем, угадала ли модель.
Теперь, используя простейшие формулы, мы рассчитаем Отзыв (Recall), точность результата измерений (Precision), точность измерений (Accuracy), и наконец поймем разницу между этими метриками.
Отзыв
Из всех положительных значений, которые мы предсказали правильно, сколько на самом деле положительных? Подсчитаем, сколько единиц в столбце «Y на самом деле» (4), это и есть сумма TP + FN. Теперь определим с помощью «Предсказанной вероятности», сколько из них диагностировано верно (2), это и будет TP.
$$Отзыв = frac{TP}{TP + FN} = frac{2}{2 + 2} = frac{1}{2}$$
Точность результата измерений (Precision)
В этом уравнении из неизвестных только FP. Ошибочно диагностированных как больных здесь только одна запись.
$$Точностьspaceрезультатаspaceизмерений = frac{TP}{TP + FP} = frac{2}{2 + 1} = frac{2}{3}$$
Точность измерений (Accuracy)
Последнее значение, которое предстоит экстраполировать из таблицы – TN. Правильно диагностированных моделью здоровых людей здесь 2.
$$Точностьspaceизмерений = frac{TP + TN}{Всегоspaceзначений} = frac{2 + 2}{7} = frac{4}{7}$$
F-мера точности теста
Эти метрики полезны, когда помогают вычислить F-меру – конечный показатель эффективности модели.
$$F-мера = frac{2 * Отзыв * Точностьspaceизмерений}{Отзыв + Точностьspaceизмерений} = frac{2 * frac{1}{2} * frac{2}{3}}{frac{1}{2} + frac{2}{3}} = 0,56$$
Наша скромная модель угадывает лишь 56% процентов диагнозов, и такой результат, как правило, считают промежуточным и работают над улучшением точности модели.
SkLearn
С помощью замечательной библиотеки Scikit-learn мы можем мгновенно определить множество метрик, и матрица ошибок – не исключение.
from sklearn.metrics import confusion_matrix
y_true = [2, 0, 2, 2, 0, 1]
y_pred = [0, 0, 2, 2, 0, 2]
confusion_matrix(y_true, y_pred)
Выводом будет ряд, состоящий из трех списков:
array([[2, 0, 0],
[0, 0, 1],
[1, 0, 2]])
Значения диагонали сверху вниз слева направо [2, 0, 2] – это число верно предсказанных значений.
Фото: @opeleye
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import classification_report
def Confusion_matrix(y_test, y_pred, target_names=None):
if target_names == None:
m = len(set(y_test))
else:
m = len(target_names)
size = len(y_test)
matrix = dict()
for class_name in range(m):
matrix[class_name] = [0 for k in range(m)]
for i in range(size):
actual_class = y_test[i]
pred_class = y_pred[i]
matrix[actual_class][pred_class] += 1
if target_names == None:
print("Confusion Matrix of given model is :")
if m == 3:
print("Count=%-14d %-15s %-15s %-15s" % (size,
'0', '1',
'2'))
for key, value in matrix.items():
print("Actual %-13s %-15d %-15d %-15d" %
(key, value[0], value[1], value[2]))
elif m == 2:
print("Count=%-14d %-15s %-15s" % (size, '0', '1'))
for key, value in matrix.items():
print("Actual %-13s %-15d %-15d" % (key, value[0],
value[1]))
else:
matrix = dict(zip(target_names, list(matrix.values())))
print("Confusion Matrix of given model is :")
print("Count=%-14d %-15s %-15s %-15s" %
(size, target_names[0], target_names[1], target_names[2]))
for key, value in matrix.items():
print("Actual %-13s %-15d %-15d %-15d" %
(key, value[0], value[1], value[2]))
return matrix
def performance_report(cm):
col = len(cm)
arr = []
for key, value in cm.items():
arr.append(value)
cr = dict()
support_sum = 0
macro = [0]*3
weighted = [0]*3
for i in range(col):
vertical_sum= sum([arr[j][i] for j in range(col)])
horizontal_sum= sum(arr[i])
p = arr[i][i] / vertical_sum
r = arr[i][i] / horizontal_sum
f = (2 * p * r) / (p + r)
s = horizontal_sum
row=[p,r,f,s]
support_sum+=s
for j in range(3):
macro[j]+=row[j]
weighted[j]+=row[j]*s
cr[i]=row
truepos=0
total=0
for i in range(col):
truepos+=arr[i][i]
total+=sum(arr[i])
cr['Accuracy']=["", "", truepos/total, support_sum]
macro_avg=[Sum/col for Sum in macro]
macro_avg.append(support_sum)
cr['Macro_avg']=macro_avg
weighted_avg=[Sum/support_sum for Sum in weighted]
weighted_avg.append(support_sum)
cr['Weighted_avg']=weighted_avg
print("Performance report of the model is :")
space,p,r,f,s=" ","Precision","Recall","F1-Score","Support"
print("%13s %9s %9s %9s %9sn"%(space,p,r,f,s))
stop=0
for key,value in cr.items():
if stop<col:
stop+=1
print("%13s %9.2f %9.2f %9.2f %9d"%(key,value[0],
value[1],
value[2],
value[3]))
elif stop==col:
stop+=1
print("n%13s %9s %9s %9.2f %9d"%(key,value[0],
value[1],
value[2],
value[3]))
else:
print("%13s %9.2f %9.2f %9.2f %9d"%(key,
value[0],
value[1],
value[2],
value[3]))
def main():
dataset=load_iris()
X,y,classes=dataset['data'],dataset['target'],
dataset['target_names']
X_train,X_test,y_train,y_test=train_test_split(
X,y,shuffle=True,random_state=5,test_size=0.3)
model=GaussianNB().fit(X_train,y_train)
y_pred=model.predict(X_test)
classes=list(classes)
cm=Confusion_matrix(y_test, y_pred, classes)
cr=performance_report(cm)
print("nCR by library method=n",
classification_report(y_test, y_pred))
if __name__ == '__main__':
main()
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import classification_report
def Confusion_matrix(y_test, y_pred, target_names=None):
if target_names == None:
m = len(set(y_test))
else:
m = len(target_names)
size = len(y_test)
matrix = dict()
for class_name in range(m):
matrix[class_name] = [0 for k in range(m)]
for i in range(size):
actual_class = y_test[i]
pred_class = y_pred[i]
matrix[actual_class][pred_class] += 1
if target_names == None:
print("Confusion Matrix of given model is :")
if m == 3:
print("Count=%-14d %-15s %-15s %-15s" % (size,
'0', '1',
'2'))
for key, value in matrix.items():
print("Actual %-13s %-15d %-15d %-15d" %
(key, value[0], value[1], value[2]))
elif m == 2:
print("Count=%-14d %-15s %-15s" % (size, '0', '1'))
for key, value in matrix.items():
print("Actual %-13s %-15d %-15d" % (key, value[0],
value[1]))
else:
matrix = dict(zip(target_names, list(matrix.values())))
print("Confusion Matrix of given model is :")
print("Count=%-14d %-15s %-15s %-15s" %
(size, target_names[0], target_names[1], target_names[2]))
for key, value in matrix.items():
print("Actual %-13s %-15d %-15d %-15d" %
(key, value[0], value[1], value[2]))
return matrix
def performance_report(cm):
col = len(cm)
arr = []
for key, value in cm.items():
arr.append(value)
cr = dict()
support_sum = 0
macro = [0]*3
weighted = [0]*3
for i in range(col):
vertical_sum= sum([arr[j][i] for j in range(col)])
horizontal_sum= sum(arr[i])
p = arr[i][i] / vertical_sum
r = arr[i][i] / horizontal_sum
f = (2 * p * r) / (p + r)
s = horizontal_sum
row=[p,r,f,s]
support_sum+=s
for j in range(3):
macro[j]+=row[j]
weighted[j]+=row[j]*s
cr[i]=row
truepos=0
total=0
for i in range(col):
truepos+=arr[i][i]
total+=sum(arr[i])
cr['Accuracy']=["", "", truepos/total, support_sum]
macro_avg=[Sum/col for Sum in macro]
macro_avg.append(support_sum)
cr['Macro_avg']=macro_avg
weighted_avg=[Sum/support_sum for Sum in weighted]
weighted_avg.append(support_sum)
cr['Weighted_avg']=weighted_avg
print("Performance report of the model is :")
space,p,r,f,s=" ","Precision","Recall","F1-Score","Support"
print("%13s %9s %9s %9s %9sn"%(space,p,r,f,s))
stop=0
for key,value in cr.items():
if stop<col:
stop+=1
print("%13s %9.2f %9.2f %9.2f %9d"%(key,value[0],
value[1],
value[2],
value[3]))
elif stop==col:
stop+=1
print("n%13s %9s %9s %9.2f %9d"%(key,value[0],
value[1],
value[2],
value[3]))
else:
print("%13s %9.2f %9.2f %9.2f %9d"%(key,
value[0],
value[1],
value[2],
value[3]))
def main():
dataset=load_iris()
X,y,classes=dataset['data'],dataset['target'],
dataset['target_names']
X_train,X_test,y_train,y_test=train_test_split(
X,y,shuffle=True,random_state=5,test_size=0.3)
model=GaussianNB().fit(X_train,y_train)
y_pred=model.predict(X_test)
classes=list(classes)
cm=Confusion_matrix(y_test, y_pred, classes)
cr=performance_report(cm)
print("nCR by library method=n",
classification_report(y_test, y_pred))
if __name__ == '__main__':
main()

Confusion Matrix Guide
How many times your read about confusion matrix, and after a while forgot about the ture positive, false negative … etc, Even you implemented confusion matrix with sklearn or tensorflow, Still we get confusion about the each componets of the matrix.
But after reading this article, you will never forget confusion matrix any more.
So forgot everything you learned so far, and start fresh now.
The machine learning model building journey end goal is not about building the model. The real journey will begin when we start measuring the performance of the model we built.
We are having numerous ways to quantify the performance of the model. The confusion matrix is one such case, This model performance metrics is popularly used for quantifying the performance of the classification models which fall under the supervised learning algorithms.
Before we drive further let me explain what you are about to learn in this article.
Why we need a confusion matrix
Before we learn about the confusion matrix, Let’s understand what is the need of using the confusion matrix as performance metrics for the classification models.
Accuracy is the popular model evaluation method used for the majority of the classification models in supervised learning algorithms. This makes us to think about the below question.
When we are having accuracy as a measure for knowing the performance of the classification models then why we need another measure to quantify the performance of the model?
Let’s understand this with an example.
Suppose if we are building a binary classification model for imbalanced target class data.
Let me give you an example of an imbalanced dataset. In the target class imbalance dataset, the target classes are not properly balanced.
What is target class imbalance
Let’s say we are having two expected classes for the target variable.
Which are
- Positive
- Negative

95% percentage we are getting a positive class and only 5% percentage we’re getting the negative class. Here positive class is dominating the negative class, this kind of in balance of the target class within the target classes is called imbalance.
Examples of the imbalanced dataset
Below are some of the examples with the imbalance dataset.
- Credit card fraud detections datasets.
- Default customers prediction datasets
In the above examples the target classes distribution, will not be in equally distributed. In general target class imbalance means the target classes are not equally distributed, one class will be dominating the other classes.
Let’s go back to our question of what is the need for confusion matrix when we have the accuracy to calculate the performance of the classification model?
In the above example, we have seen the positive class is coming 95% percent cases whereas the negative class is coming only 5% of the time.
Without building any machine learning model if we predict all the target classes as positive. What do you think our model accuracy could be?
Yes, you are correct our model accuracy is 95%
But do you think this is the correct way of quantifying the performance of the model?
A big No!
So when we are dealing with target class imbalance datasets, accuracy is not the best performance measure technique.
In such cases, we will use the confusion matrix to measure the efficiency of the classification model.
In the next section of this article, we will learn more about the confusion matrix representation.
What is confusion matrix?
To understand the confusion matrix in the much deeper level we are considering the below example dataset.
|
S no. |
Actual Target |
Predicted Target |
|---|---|---|
|
1 |
Positive |
Positive |
|
2 |
Positive |
Negative |
|
3 |
Positive |
Positive |
|
4 |
Positive |
Negative |
|
5 |
Positive |
Positive |
|
6 |
Negative |
Negative |
|
7 |
Negative |
Positive |
|
8 |
Positive |
Positive |
|
9 |
Positive |
Positive |
|
10 |
Positive |
Positive |
The above table contains the actual target class and the predicted class information.
If we calcualte the accuracy of this data it will 70%, as the predicted target column’s values are matching 7 times in an overall 10 cases in actual targets.
Accuracy is not able to explain the below question.
- How many actual positive targets are predicted as positive?
- How many actual positive targets are predicted as negative?
- How many actual negative targets are predicted as positive?
- How many actual negative targets are predicted as negative?
We can answer all these questions with a confusion matrix, below is the pictorial representation of answer all the above questions.

A confusion matrix is a matrix representation of showing how well the trained model predicting each target class with respect to the counts. Confusion Matrix mainly used for the classification algorithms which fall under supervised learning.
Below are the descriptions for the terms used in the confusion matrix
- Ture positive: Target is positive and the model predicted it as positive
- False negative: Target is positive and the model predicted it as negative
- False positive: Target is negative and the model predicted it as positive
- True negative: Target is negative and the model predicted it as negative
Using the above positive and negative targets information table, we will populate the matrix which gives a much more clear understanding of how the confusion matrix constructed.
Confusion matrix representation for a binary classification problem

The above image is representing the confusion matrix for the binary classification problem, each cell values of the matrixs, are calculated for the example dataset we showed before.
- TP: Out of 8 actual positive cases, in 6 cases the model predicted positive.
- FN: (8 — 6), the remaining 2 cases will fall into the true negative cases.
- FP: We are having 2 negative cases and 1 we predicted as positive.
- TN: Out of 2 negative cases, the model predicted 1 negative case correctly.
So these cell values of the confusion matrix are addressed the above questions we have.
By seeing the matrix representation, we can understand where the model is much more accurate and we can clearly know where the model not able to predict properly. This helps in tuning the right model parameters to reduce the false positive and false negative.
By now we are having clear understanding about each component of the confusion but still TP, TN, FP, FN is hard to remember, we know the concepts but these terms are really a bit confusing.
So Let’s understand how we can remember these terms forever.

In the above image we spilt the each term into two characters, the second
character represents what the model predicting, in our case, is the model predicting postive class or negative class. The first character represents, is the model prediction is correct or not.
Let’s undersand with an example.
Suppose TN means, the second character is N means model predicted negative class, the first character T means model predicted correctly.
Hope this gives clear picture about these individual components about the matrix.
What is the ideal model?
The ideal machine learning model which will always predict the correct target values. If we are using accuracy as a measure to quantify the performance of the model. The ideal model should get 100% accuracy.
In the same way, to say a model is ideal with confusion matrix performance metrics, it should have zero cases in false positive and false negative, which are called as type 1 and type 2 errors.
What are Type 1 and Type 2 errors?
Below are the two error types we can represent with confusion matrix.
- Type 01 (False positive)
- Type 02 (False negative)


The above image clearly explaining the difference between Type 1 and type 2 errors. Below are the key difference between type 1 and type 2 errors.
Difference between Type 1 and Type 2 errors
Type 1 Error
- False positive from confusion matrix.
- Predicting negative as positive.
Type 2 Error
- False negative from confusion matrix.
- Predicting positive as negative.
By now we clearly understood how the confusion matrix can build and aware of the components of the confusion matrix.
Now we will learn how to implement the confusion matrix in different ways. Before that below is the full representation of the learnings we got in one picture.

Implementing confusion matrix in python
We are going to implement confusion matrix in two different ways.
- Confusion matrix with Sklearn
- Confusion matrix with Tensorflow
Confusion matrix implementation with sklearn


The scikit learn confusion matrix representation will be a bit different, as scikit learn considers the actual target classes as columns and the predicted classes as rows, because of this scikit learn confusion matrix output look different.
Confusion matrix implementation with Tensorflow

How to plot the confusion matrix
Using the below code, we can easily plot the confusion matrix, we are using seaborn heat map to visuvalize the confusion matrix in more representive way.

If we run the above code we will get the below kind of graph, the below graph is the confusion matrix created for the email spam classification model.

Confusion matrix
By now we know the different components of the confusion matrix, using these components we can derive multiple model performance metrics to quantify the performance of the trained model. We will cover that in another article.
Below are the different measures we can calculate using the confusion matrix.
- Accuracy
- Misclassification rate
- True positive rate or Recall or Sensitivity
- False positive rate
- True negative rate or Specificity
- Precision
- F 1 score
We will learn about these measures in the upcoming article.
Complete Code
Below is the code for implementing confusion matrix in sklearn and tensorflow along with visuvalization code.
You can also clone this code in our Github.
Conclusion
In this article we learned what is the need for confusion matrix, different components of the confusion matrix, how to implement them with sklearn and TensorFlow and we also have seen the code to visualize it.
Recommended Courses

Machine Learning A to Z Course

AWS Machine Learning Full Guide

Data Science Full Specialization
Были ли вы в ситуации, когда вы ожидали, что ваша модель машинного обучения должна работать очень хорошо, но у нее была низкая точность? Вы проделали всю тяжелую работу — так где же модель классификации сработала не так? Как это исправить?
Существует множество способов оценить эффективность вашей модели классификации, но ни один из них не выдержал испытания временем, кроме матрицы ошибок. Она помогает нам оценить, как наша модель работала, где она пошла не туда, и предлагает нам рекомендации по исправлению нашего пути.
В этой статье мы рассмотрим, как матрица ошибок дает целостное представление об эффективности вашей модели. И, в отличие от названия, вы поймете, что матрица ошибок — довольно простая, но мощная концепция. Итак, давайте раскроем тайну матрицы ошибок!
Что такое матрица ошибок?
Вопрос на миллион долларов — что такое, в конце концов, матрица ошибок?
Матрица ошибок — это матрица размером N x N, используемая для оценки эффективности модели классификации, где N — количество целевых классов. Матрица сравнивает фактические целевые значения с предсказанными моделью машинного обучения. Это дает нам целостное представление о том, насколько хорошо работает наша классификационная модель и какие ошибки она допускает.
Для задачи двоичной классификации у нас будет матрица 2 x 2, как показано ниже, с 4 значениями:

Расшифруем матрицу:
- Целевая переменная имеет два значения: положительное или отрицательное.
- Столбцы представляют фактические значения целевой переменной.
- Строки представляют собой прогнозируемые значения целевой переменной.
Но подождите — что здесь TP, FP, FN и TN? Это важнейшая часть матрицы ошибок. Давайте разберемся с каждым термином ниже.
Понимание True Positive, True Negative, False Positive и False Negative в матрице ошибок
True Positive (TP)
- Прогнозируемое значение соответствует фактическому значению.
- Фактическое значение было положительным, и модель предсказала положительное значение.
True Negative (TN)
- Прогнозируемое значение соответствует фактическому значению.
- Фактическое значение было отрицательным, и модель предсказала отрицательное значение.
False Positive (FP) — ошибка 1-го типа
- Прогнозируемое значение было предсказано неверно.
- Фактическое значение было отрицательным, но модель предсказала положительное значение.
- Также известна как ошибка 1-го типа.
False Negative (FN) — ошибка 2-го типа
- Прогнозируемое значение было предсказано неверно.
- Фактическое значение было положительным, но модель предсказала отрицательное значение.
- Также известна как ошибка 2-го типа.
Позвольте мне привести пример, чтобы лучше это понять. Предположим, у нас есть набор данных классификации с 1000 точками данных. Мы подгоняем на нем классификатор и получаем следующую матрицу ошибок:

Различные значения матрицы ошибок будут следующими:
- True Positive (TP) = 560; это означает, что 560 положительных точек данных были правильно классифицированы моделью.
- True Negative (TN) = 330; это означает, что 330 отрицательных точек данных были правильно классифицированы моделью.
- False Positive (FP) = 60; это означает, что 60 отрицательных точек данных были неправильно классифицированы моделью как положительные.
- False Negative (FN) = 50; это означает, что 50 положительных точек данных были неправильно классифицированы моделью как отрицательные.
Это оказался довольно приличный классификатор для нашего набора данных, учитывая относительно большее количество истинно положительных и истинно отрицательных значений.
Помните об ошибках 1-го и 2-го типа. Интервьюеры любят спрашивать, в чем разница между ними!
Зачем нам нужна матрица ошибок?
Прежде чем ответить на этот вопрос, давайте подумаем о проблеме гипотетической классификации.
Допустим, вы хотите предсказать, сколько людей инфицировано заразным вирусом, до того, как у них проявятся симптомы, и изолировать их от здорового населения. Двумя значениями для нашей целевой переменной будут: Sick и Not Sick.
Теперь вы, должно быть, задаетесь вопросом — зачем нам матрица ошибок, когда у нас есть наш вечный друг — Точность? Что ж, посмотрим, где точность не работает.
Наш набор данных является примером несбалансированного набора данных. Имеется 947 точек данных для отрицательного класса и 3 точки данных для положительного класса. Вот как мы рассчитаем точность:

Посмотрим, как работает наша модель:

Общие значения результатов:
TP = 30, TN = 930, FP = 30, FN = 10
Итак, точность для нашей модели:

96%! Неплохо!
Но это дает неверное представление о результате. Подумайте об этом.
Наша модель гласит: «Я могу предсказать заболевание в 96% случаев». Однако она делает наоборот. Это предсказание людей, которые не заболеют с точностью 96%, пока больные распространяют вирус!
Как вы думаете, это правильный показатель для нашей модели, учитывая серьезность проблемы? Разве мы не должны измерять, сколько положительных случаев мы можем правильно предсказать, чтобы остановить распространение заразного вируса? Или, из правильно спрогнозированных случаев сколько положительных случаев для проверки надежности нашей модели?
Здесь мы сталкиваемся с двойным понятием «точность (Precision) и полнота (Recall)».
Precision vs. Recall
Точность говорит нам, сколько из правильно предсказанных случаев действительно оказались положительными.
Вот как рассчитать точность:

Это определило бы надежность нашей модели.
Полнота сообщает нам, сколько реальных положительных случаев мы смогли правильно предсказать с помощью нашей модели.
А вот как мы можем рассчитать полноту:


Мы можем легко рассчитать точность и полноту для нашей модели, подставив значения в приведенные выше уравнения:

50% процентов правильно предсказанных случаев оказались положительными. В то время как 75% положительных результатов были успешно предсказаны нашей моделью. Потрясающие!
Точность — полезный показатель в тех случаях, когда ложноположительный результат важнее, чем ложноотрицательный.
Точность важна в системах рекомендаций по музыке или видео, на веб-сайтах электронной коммерции и т. д. Неправильные результаты могут привести к оттоку клиентов и нанести вред бизнесу.
Полнота — полезный показатель в случаях, когда ложноотрицательный результат важнее ложноположительного.
Полнота важна в медицинских случаях, когда не имеет значения, что возникает ложная тревога, но реальные положительные случаи не должны оставаться незамеченными!
В нашем примере полнота была бы лучшим показателем, потому что мы не хотим, чтобы случайно выписали инфицированного человека и позволили ему смешаться со здоровым населением, тем самым распространяя заразный вирус. Теперь вы можете понять, почему точность была плохим показателем для нашей модели.
Но будут случаи, когда нет четкой разницы между тем, что важнее: точность или полнота. Что нам делать в таких случаях? Мы их совмещаем!
F1-Score
На практике, когда мы пытаемся повысить точность нашей модели, полнота снижается, и наоборот. F1-Score отражает обе тенденции в одном значении:

F1-Score представляет собой гармоничное среднее значение точности и полноты, поэтому дает общее представление об этих двух показателях. Оно максимально, когда точность равно полноте.
Но здесь есть одна загвоздка. Интерпретируемость оценки F1 оставляет желать лучшего. Это означает, что мы не знаем, чего добивается наш классификатор — точности или полноты? Итак, мы используем его в сочетании с другими оценочными метриками, что дает нам полную картину результата.
Матрица ошибок с использованием scikit-learn в Python
Вы знаете теорию — теперь давайте применим ее на практике. Давайте запрограммируем матрицу ошибок с помощью библиотеки Scikit-learn (sklearn) на Python.
# confusion matrix in sklearn
from sklearn.metrics import confusion_matrix
3 from sklearn.metrics import classification_report
# actual values
actual = [1,0,0,1,0,0,1,0,0,1]
# predicted values
predicted = [1,0,0,1,0,0,0,1,0,0]
# confusion matrix
matrix = confusion_matrix(actual,predicted, labels=[1,0])
print(‘Confusion matrix : n’,matrix)
# outcome values order in sklearn
tp, fn, fp, tn = confusion_matrix(actual,predicted,labels=[1,0]).reshape(-1)
print(‘Outcome values : n’, tp, fn, fp, tn)
# classification report for precision, recall f1-score and accuracy
matrix = classification_report(actual,predicted,labels=[1,0])
print(‘Classification report : n’,matrix)

Sklearn имеет две отличные функции: confusion_matrix() и classification_report().
возвращает значения матрицы ошибок. Однако результат немного отличается от того, что мы изучили до сих пор. Она принимает строки как фактические значения, а столбцы как прогнозные значения. В остальном концепция осталась прежней.
выводит точность, полноту и f1-score для каждого целевого класса. В дополнение к этому, она также имеет некоторые дополнительные значения: micro avg, macro avg и weighted avg.
Mirco average — это оценка точности/полноты/f1, рассчитанная для всех классов.

Macro average — это среднее значение точности/полноты/f1-score.

Weighted average — это просто средневзвешенное значение точности/полноты/f1-score.
Матрица ошибок для мультиклассовой классификации
Как матрица ошибок будет работать для задачи классификации нескольких классов? Мы рассмотрим и этот случай.
Давайте нарисуем матрицу ошибок для мультиклассовой задачи, в которой мы должны предсказать, любит ли человек Facebook, Instagram или Snapchat. Матрица ошибок будет иметь вид 3 x 3:

true positive, true negative, false positive и false negative для каждого класса будут вычисляться путем сложения значений ячеек следующим образом:

Вот и все! Вы готовы расшифровать любую матрицу ошибок размером N x N!
Заключение
И вдруг матрица ошибок перестает быть такой запутанной! Эта статья должна дать вам прочную основу для интерпретации и использования матрицы ошибок для алгоритмов классификации в машинном обучении.
Вскоре мы выпустим статью о кривой AUC-ROC и продолжим наше обсуждение там. До этого не теряйте надежды на свою модель классификации, возможно, вы просто используете неправильную метрику оценки!
| title | date | categories | tags | |||||
|---|---|---|---|---|---|---|---|---|
|
How to create a confusion matrix with Scikit-learn? |
2020-05-05 |
frameworks |
|
After training a supervised machine learning model such as a classifier, you would like to know how well it works.
This is often done by setting apart a small piece of your data called the test set, which is used as data that the model has never seen before.
If it performs well on this dataset, it is likely that the model performs well on other data too — if it is sampled from the same distribution as your test set, of course.
Now, when you test your model, you feed it the data — and compare the predictions with the ground truth, measuring the number of true positives, true negatives, false positives and false negatives. These can subsequently be visualized in a visually appealing confusion matrix.
In today’s blog post, we’ll show you how to create such a confusion matrix with Scikit-learn, one of the most widely used frameworks for machine learning in today’s ML community. By means of an example created with Python, we’ll show you step-by-step how to generate a matrix with which you can visually determine the performance of your model easily.
All right, let’s go! 🙂
[toc]
A confusion matrix in more detail
Training your machine learning model involves its evaluation. In many cases, you have set apart a test set for this.
The test set is a dataset that the trained model has never seen before. Using it allows you to test whether the model has overfit, or adapted to the training data too well, or whether it still generalizes to new data.
This allows you to ensure that your model does not perform very poorly on new data while it still performs really good on the training set. That wouldn’t really work in practice, would it 🙂
Evaluation with a test set often happens by feeding all the samples to the model, generating a prediction. Subsequently, the predictions are compared with the ground truth — or the true targets corresponding to the test set. These can subsequently be used for computing various metrics.
But they can also be used to demonstrate model performance in a visual way.
Here is an example of a confusion matrix:

To be more precise, it is a normalized confusion matrix. Its axes describe two measures:
- The true labels, which are the ground truth represented by your test set.
- The predicted labels, which are the predictions generated by the machine learning model for the features corresponding to the true labels.
It allows you to easily compare how well your model performs. For example, in the model above, for all true labels 1, the predicted label is 1. This means that all samples from class 1 were classified correctly. Great!
For the other classes, performance is also good, but a little bit worse. As you can see, for class 2, some samples were predicted as being part of classes 0 and 1.
In short, it answers the question «For my true labels / ground truth, how well does the model predict?».
It’s also possible to start from a prediction point of view. In this case, the question would change to «For my predicted label, how many predictions are actually part of the predicted class?». It’s the opposite point of view, but could be a valid question in many machine learning cases.
Most preferably, the entire set of true labels is equal to the set of predicted labels. In those cases, you would see zeros everywhere except for the line from the top left to the bottom right. In practice, however, this does not happen often. Likely, the plot is much more scattered, like this SVM classifier where many supporrt vectors are necessary to draw a decision boundary that does not work perfectly, but adequately enough:
Creating a confusion matrix with Python and Scikit-learn
Let’s now see if we can create a confusion matrix ourselves. Today, we will be using Python and Scikit-learn, one of the most widely used frameworks for machine learning today.
Creating a confusion matrix involves various steps:
- Generating an example dataset. This one makes sense: we need data to train our model on. We’ll therefore be generating data first, so that we can make an adequate choice for a ML model class next.
- Picking a machine learning model class. Obviously, if we want to evaluate a model, we need to train a model. We’ll choose a particular type of model first that fits the characteristics of our data.
- Constructing and training the ML model. The consequence of the first two steps is that we end up with a trained model.
- Generating the confusion matrix. Finally, based on the trained model, we can create our confusion matrix.
Software dependencies you need to install
Very briefly, but importantly: if you wish to run this code, you must make sure that you have certain software dependencies installed. Here they are:
- You need to install Python, which is the platform that our code runs on, version 3.6+.
- You need to install Scikit-learn, the machine learning framework that we will be using today:
pip install -U scikit-learn. - You need to install Numpy for numbers processing:
pip install numpy. - You need to install Matplotlib for visualizing the plots:
pip install matplotlib. - Finally, if you wish to generate a plot of decision boundaries (not required), you also need to install Mlxtend:
pip install mlxtend.
[affiliatebox]
Generating an example dataset
The first step is generating an example dataset. We will be using Scikit-learn for this purpose too. First, create a file called confusion-matrix.py, and open it in a code editor. The first thing we do is add the imports:
# Imports
from sklearn.datasets import make_blobs
from sklearn.model_selection import train_test_split
import numpy as np
import matplotlib.pyplot as plt
The make_blobs function from Scikit-learn allows us to generate ‘blobs’, or clusters, of samples. Those blobs are centered around some point and are the samples are scattered around this point based on some standard deviation. This gives you flexibility about both the position and the structure of your generated dataset, in turn allowing you to experiment with a variety of ML models without having to worry about the data.
As we will evaluate the model, we need to ensure that the dataset is split between training and testing data. Scikit-learn also allows us to do this, with train_test_split. We therefore import that one too.
Configuration options
Next, we can define a number of configuration options:
# Configuration options
blobs_random_seed = 42
centers = [(0,0), (5,5), (0,5), (2,3)]
cluster_std = 1.3
frac_test_split = 0.33
num_features_for_samples = 4
num_samples_total = 5000
The random seed describes the initialization of the pseudo-random number generator used for generating the blobs of data. As you may know, no random number generator is truly random. What’s more, they are also initialized differently. Configuring a fixed seed ensures that every time you run the script, the random number generator initializes in the same way. If weird behavior occurs, you know that it’s likely not the random number generator.
The centers describe the centers in two-dimensional space of our blobs of data. As you can see, we have 4 blobs today.
The cluster standard deviation describes the standard deviation with which a sample is drawn from the sampling distribution used by the random point generator. We set it to 1.3; a lower number produces clusters that are better separable, and vice-versa.
The fraction of the train/test split determines how much data is split off for testing purposes. In our case, that’s 33% of the data.
The number of features for our samples is 4, and indeed describes how many targets we have: 4, as we have 4 blobs of data.
Finally, the number of samples generated is pretty self-explanatory. We set it to 5000 samples. That’s not too much data, but more than sufficient for the educational purposes of today’s blog post.
Generating the data
Next up is the call to make_blobs and to train_test_split for actually generating and splitting the data:
# Generate data
inputs, targets = make_blobs(n_samples = num_samples_total, centers = centers, n_features = num_features_for_samples, cluster_std = cluster_std)
X_train, X_test, y_train, y_test = train_test_split(inputs, targets, test_size=frac_test_split, random_state=blobs_random_seed)
Saving the data (optional)
Once the data is generated, you may choose to save it to file. This is an optional step — and I include it because I want to re-use the same dataset every time I run the script (e.g. because I am tweaking a visualization). If you use the code below, you can run it once — then, it’s saved in the .npy file. When you subsequently uncomment the np.save call, and possibly also the generate data calls, you’ll always have the same data load from file.
Then, you can tweak away your visualization easily without having to deal with new data all the time 🙂
# Save and load temporarily
np.save('./data_cf.npy', (X_train, X_test, y_train, y_test))
X_train, X_test, y_train, y_test = np.load('./data_cf.npy', allow_pickle=True)
Should you wish to visualize the data, this is of course possible:
# Generate scatter plot for training data
plt.scatter(X_train[:,0], X_train[:,1])
plt.title('Linearly separable data')
plt.xlabel('X1')
plt.ylabel('X2')
plt.show()
Picking a machine learning model class
Now that we have our code for generating the dataset, we can take a look at the output to determine what kind of model we could use:

I can derive a few characteristics from this dataset (which, obviously, I also built-in up front 😉 ).
First of all, the number of features is low: only two — as our data is two-dimensional. This is good, because then we likely don’t face the curse of dimensionality, and a wider range of ML models is applicable.
Next, when inspecting the data from a closer point of view, I can see a gap between what seem to be blobs of data (it is also slightly visible in the diagram above):

This suggests that the data may be separable, and possibly even linearly so (yes, of course, I know this is the case 😉 ).
Third, and finally, the number of samples is relatively low: only 5.000 samples are present. Neural networks with their relatively large amount of trainable parameters would likely start overfitting relatively quickly, so they wouldn’t be my preferable choice.
However, traditional machine learning techniques to the rescue. A Support Vector Machine, which attempts to construct a decision boundary between separable blobs of data, can be a good candidate here. Let’s give it a try: we’re going to construct and train an SVM and see how well it performs through its confusion matrix.
Constructing and training the ML model
As we have seen in the post linked above, we can also use Scikit-learn to construct and train a SVM classifier. Let’s do so next.
Model imports
First, we’ll have to add a few extra imports to the top of our script:
from sklearn import svm
from sklearn.metrics import plot_confusion_matrix
from mlxtend.plotting import plot_decision_regions
(The Mlxtend one is optional, as we discussed at ‘what you need to install’, but could be useful if you wish to visualize the decision boundary later.)
Training the classifier
First, we initialize the SVM classifier. I’m using a linear kernel because I suspect (actually, I’m confident, as we constructed the data ourselves) that the data is linearly separable:
# Initialize SVM classifier
clf = svm.SVC(kernel='linear')
Then, we fit the training data — starting the training process:
# Fit data
clf = clf.fit(X_train, y_train)
That’s it for training the machine learning model! The classifier variable, or clf, now contains a reference to the trained classifier. By calling clf.predict, you can now generate predictions for new data.
Generating the confusion matrix
But let’s take a look at generating that confusion matrix now. As we discussed, it’s part of the evaluation step, and we use it to visualize its predictive and generalization power on the test set.
Recall that we compare the predictions generated during evaluation with the ground truth available for those inputs.
The plot_confusion_matrix call takes care of this for us, and we simply have to provide it the classifier (clf), the test set (X_test and y_test), a color map and whether to normalize the data.
# Generate confusion matrix
matrix = plot_confusion_matrix(clf, X_test, y_test,
cmap=plt.cm.Blues,
normalize='true')
plt.title('Confusion matrix for our classifier')
plt.show(matrix)
plt.show()

Normalization, here, involves converting back the data into the [0, 1] format above. If you leave out normalization, you get the number of samples that are part of that prediction:

Here are some other visualizations that help us explain the confusion matrix (for the boundary plot, you need to install Mlxtend with pip install mlxtend):
# Get support vectors
support_vectors = clf.support_vectors_
# Visualize support vectors
plt.scatter(X_train[:,0], X_train[:,1])
plt.scatter(support_vectors[:,0], support_vectors[:,1], color='red')
plt.title('Linearly separable data with support vectors')
plt.xlabel('X1')
plt.ylabel('X2')
plt.show()
# Plot decision boundary
plot_decision_regions(X_test, y_test, clf=clf, legend=2)
plt.show()
It’s clear that we need many support vectors (the red samples) to generate the decision boundary. Given the relative unclarity of the separability between the data points, this is not unexpected. I’m actually quite satisfied with the performance of the model, as demonstrated by the confusion matrix (relatively blue diagonal line).
The only class that underperforms is class 3, with a score of 0.68. It’s still acceptable, but is lower than preferred. This can be explained by looking at the class in the decision boundary plot. Here, it’s clear that it’s the middle class — the reds. As those samples are surrounded by the other ones, it’s clear that the model has had significant difficulty generating the decision boundary. We might for example counter this by using a different kernel function which takes this into account, ensuring better separability. However, that’s not the core of today’s post.
Full model code
Should you wish to obtain the full model code, that’s of course possible. Here you go 🙂
# Imports
from sklearn.datasets import make_blobs
from sklearn.model_selection import train_test_split
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm
from sklearn.metrics import plot_confusion_matrix
from mlxtend.plotting import plot_decision_regions
# Configuration options
blobs_random_seed = 42
centers = [(0,0), (5,5), (0,5), (2,3)]
cluster_std = 1.3
frac_test_split = 0.33
num_features_for_samples = 4
num_samples_total = 5000
# Generate data
inputs, targets = make_blobs(n_samples = num_samples_total, centers = centers, n_features = num_features_for_samples, cluster_std = cluster_std)
X_train, X_test, y_train, y_test = train_test_split(inputs, targets, test_size=frac_test_split, random_state=blobs_random_seed)
# Save and load temporarily
np.save('./data_cf.npy', (X_train, X_test, y_train, y_test))
X_train, X_test, y_train, y_test = np.load('./data_cf.npy', allow_pickle=True)
# Generate scatter plot for training data
plt.scatter(X_train[:,0], X_train[:,1])
plt.title('Linearly separable data')
plt.xlabel('X1')
plt.ylabel('X2')
plt.show()
# Initialize SVM classifier
clf = svm.SVC(kernel='linear')
# Fit data
clf = clf.fit(X_train, y_train)
# Generate confusion matrix
matrix = plot_confusion_matrix(clf, X_test, y_test,
cmap=plt.cm.Blues)
plt.title('Confusion matrix for our classifier')
plt.show(matrix)
plt.show()
# Get support vectors
support_vectors = clf.support_vectors_
# Visualize support vectors
plt.scatter(X_train[:,0], X_train[:,1])
plt.scatter(support_vectors[:,0], support_vectors[:,1], color='red')
plt.title('Linearly separable data with support vectors')
plt.xlabel('X1')
plt.ylabel('X2')
plt.show()
# Plot decision boundary
plot_decision_regions(X_test, y_test, clf=clf, legend=2)
plt.show()
[affiliatebox]
Summary
That’s it for today! In this blog post, we created a confusion matrix with Python and Scikit-learn. After studying what a confusion matrix is, and how it displays true positives, true negatives, false positives and false negatives, we gave a step-by-step example for creating one yourself.
The example included generating a dataset, picking a suitable machine learning model for the dataset, constructing, configuring and training it, and finally interpreting the results i.e. the confusion matrix. This way, you should be able to understand what is happening and why I made certain choices.
I hope you’ve learnt something from today’s blog post! 🙂 If you did, I would really appreciate it if you left a comment in the comments section 💬 Please do the same if you have questions or remarks. I’ll happily answer and improve my blog post where necessary.
Thank you for reading MachineCurve today and happy engineering! 😎
[scikitbox]
References
Raschka, S. (n.d.). Home — mlxtend. Site not found · GitHub Pages. https://rasbt.github.io/mlxtend/
Scikit-learn. (n.d.). scikit-learn: machine learning in Python — scikit-learn 0.16.1 documentation. Retrieved May 3, 2020, from https://scikit-learn.org/stable/index.html
Scikit-learn. (n.d.). 1.4. Support vector machines — scikit-learn 0.22.2 documentation. scikit-learn: machine learning in Python — scikit-learn 0.16.1 documentation. Retrieved May 3, 2020, from https://scikit-learn.org/stable/modules/svm.html#classification
Scikit-learn. (n.d.). Confusion matrix — scikit-learn 0.22.2 documentation. scikit-learn: machine learning in Python — scikit-learn 0.16.1 documentation. Retrieved May 5, 2020, from https://scikit-learn.org/stable/auto_examples/model_selection/plot_confusion_matrix.html
Scikit-learn. (n.d.). Sklearn.metrics.plot_confusion_matrix — scikit-learn 0.22.2 documentation. scikit-learn: machine learning in Python — scikit-learn 0.16.1 documentation. Retrieved May 5, 2020, from https://scikit-learn.org/stable/modules/generated/sklearn.metrics.plot_confusion_matrix.html#sklearn.metrics.plot_confusion_matrix




