🔴 Сложный ⏱️ 50 минут

Confusion matrix

📋 Содержание урока

Confusion matrix 🔥

В уроке 307 ты познакомился с матрицей ошибок для бинарной классификации — таблицей $2\times2$ с четырьмя ячейками $TP$, $TN$, $FP$, $FN$. Но подавляющее большинство реальных задач классификации устроены сложнее: распознавание рукописных цифр — это 10 классов, категоризация новостей — обычно 5–10 рубрик, диагностика подтипов заболевания — часто 3–6 вариантов, классификация товаров в интернет-магазине — десятки категорий. Как только классов становится больше двух, ошибка модели перестаёт быть однонаправленной («пропустила» или «ложная тревога») — она превращается в вопрос «какой конкретно класс модель перепутала с каким», а таких пар в задаче с $N$ классами может быть $N(N-1)$.

Именно эту многомерность и раскрывает confusion matrix (матрица ошибок) для многоклассовой классификации — таблица $N\times N$, где каждая ячейка отвечает на предельно конкретный вопрос: сколько объектов реального класса $i$ модель предсказала как класс $j$. Диагональ таблицы — это успехи модели, а вот всё, что вне диагонали, — это не одна усреднённая цифра ошибки, а целая карта того, как именно модель путается. Из этой карты сразу видно то, что не покажет ни одна усреднённая метрика: например, что модель почти идеально отличает один класс от всех остальных, но систематически путает два похожих между собой класса чаще, чем любую другую пару.

Именно поэтому тепловая карта матрицы ошибок — один из первых графиков, которые ML-инженер строит сразу после обучения классификатора, задолго до того, как разбираться в десятках цифр вроде precision и recall по каждому классу. Одного взгляда на эту картинку достаточно, чтобы понять не просто «насколько хороша модель», а гораздо более полезный вопрос — где именно она регулярно ошибается и что с этим конкретно делать: собрать больше данных для слабого класса, добавить признак, который лучше разделяет два похожих класса, или пересмотреть саму разметку.

В этом уроке ты разберёшь четыре тесно связанные темы. Во-первых, как читать полную матрицу ошибок для задачи с тремя и более классами — что означают строки, столбцы и диагональ, и как из этой таблицы вообще получить привычные $TP$, $FP$, $FN$ для каждого отдельного класса. Во-вторых, как правильно усреднять precision и recall по всем классам сразу — через macro-усреднение (усредняем метрики по классам поровну) или через micro-усреднение (считаем общие $TP$, $FP$, $FN$ по всем классам вместе, что фактически взвешивает по частоте класса), и почему выбор между ними — не техническая деталь, а решение, которое сильно меняет итоговую оценку модели при дисбалансе классов. В-третьих, как нормализованная матрица ошибок в долях, а не в абсолютных числах, помогает сравнивать классы разного размера. И наконец, как по тепловой карте матрицы ошибок быстро находить именно систематические ошибки модели — не случайный шум, а устойчивый паттерн, который стоит явно устранять.

История

Сам термин confusion matrix (матрица ошибок, дословно «матрица путаницы») пришёл не из машинного обучения, а из более ранней области — психологии восприятия и распознавания образов первой половины XX века. Исследователи, изучавшие, как люди распознают буквы, звуки речи или зрительные символы, столкнулись с закономерной проблемой: испытуемые ошибались не случайным образом, а систематически путали конкретные пары стимулов друг с другом — например, буквы «Е» и «Ф» на зашумлённом изображении, или похожие по звучанию согласные в устной речи. Чтобы зафиксировать эти закономерности, экспериментаторы строили именно такую таблицу — по строкам реальный стимул, по столбцам ответ испытуемого, — и внедиагональные ячейки с высокими значениями сразу выдавали, какие пары стимулов человеческое восприятие путает чаще прочих. Эта же логика, только применительно к модели, а не к человеку, лежит в основе современной матрицы ошибок.

Многоклассовая версия задачи возникла естественно, как только статистическая классификация начала иметь дело больше чем с двумя категориями. Показательный исторический пример — классическая работа Рональда Фишера 1936 года о цветках ириса, где нужно было различить три вида: Iris setosa, Iris versicolor и Iris virginica по четырём измерениям лепестков и чашелистиков. Это один из первых задокументированных примеров многоклассовой классификации в статистике, и он же — классический учебный датасет, который ты не раз ещё встретишь в машинном обучении; в этом уроке он тоже станет одним из сквозных примеров. Позже, с развитием оптического распознавания символов (OCR) в 1950–60-х годах, инженерам пришлось иметь дело уже с десятью классами цифр или несколькими десятками букв алфавита сразу — и матрица ошибок стала естественным инструментом диагностики: она сразу показывала, что, скажем, цифры «3» и «8» или буквы «О» и «0» путаются друг с другом заметно чаще, чем с любыми другими символами.

В современном машинном обучении матрица ошибок и её визуализация в виде тепловой карты стали особенно необходимы с ростом задач с большим числом классов — распознавание тысячи категорий объектов на изображениях (ImageNet), классификация десятков языков или диалектов, многоклассовая медицинская диагностика. При таком числе классов просто невозможно удержать в голове десятки отдельных значений precision и recall — нужен один визуальный снимок, по которому сразу видно, где сосредоточены проблемы. Параллельно с этим в статистике информационного поиска и машинного обучения закрепились два стандартных способа свести множество попарных метрик к одному числу — macro- и micro-усреднение, — и сегодня sklearn.metrics.confusion_matrix, ConfusionMatrixDisplay и classification_report с параметрами average="macro" и average="micro" — это часть стандартного рабочего процесса почти любого специалиста по data science, который обучает классификатор больше чем на два класса.

Многоклассовая матрица ошибок: как читать таблицу N×N

Интуиция

Бинарная матрица ошибок из урока 307 — это частный случай общей конструкции при $N=2$. Как только классов становится три и больше, у каждой строки и каждого столбца появляется собственный смысл, который стоит проговорить явно. Строка таблицы отвечает на вопрос «что происходило с объектами, которые реально принадлежат этому классу?» — сумма элементов строки равна общему числу таких объектов в выборке (в англоязычной литературе это число называют support). Столбец отвечает на другой вопрос — «что модель вообще предсказывала как этот класс?» — сумма элементов столбца равна числу объектов, которым модель присвоила эту метку, независимо от того, правильно или нет. А диагональ — это единственное место, где реальный класс и предсказанный класс совпадают, то есть единственный источник правильных ответов модели.

Определение

Матрица ошибок для многоклассовой классификации. Для задачи с $N$ классами матрица ошибок — это таблица $M$ размером $N\times N$, где элемент $M_{ij}$ — число объектов, реальный класс которых равен $i$, а предсказанный моделью класс равен $j$:

$$ > M = \begin{array}{c|ccc} > & \text{Предск. } 1 & \text{Предск. } 2 & \cdots \\ > \hline > \text{Реально } 1 & M_{11} & M_{12} & \cdots \\ > \text{Реально } 2 & M_{21} & M_{22} & \cdots \\ > \vdots & \vdots & \vdots & \ddots \\ > \end{array} > $$

Диагональные элементы $M_{ii}$ — верные предсказания класса $i$; сумма строки $i$, $\sum_j M_{ij}$, — общее число реальных объектов класса $i$ (support); сумма столбца $j$, $\sum_i M_{ij}$, — общее число объектов, предсказанных моделью как класс $j$.

Чтобы получить привычные $TP$, $FP$, $FN$, $TN$ для одного класса $c$, применяется метод «один против всех» (one-vs-rest): класс $c$ временно объявляется «положительным», а все остальные классы вместе — «отрицательным»:

$$TP_c = M_{cc}, \qquad FN_c = \sum_{j\neq c} M_{cj}, \qquad FP_c = \sum_{i\neq c} M_{ic}, \qquad TN_c = \sum_{i\neq c}\sum_{j\neq c} M_{ij}$$

Иными словами: $TP_c$ — диагональная ячейка; $FN_c$ — вся остальная строка $c$ (реально класс $c$, но предсказано что-то другое); $FP_c$ — весь остальной столбец $c$ (реально что-то другое, но предсказан класс $c$); $TN_c$ — все ячейки, не лежащие ни в строке $c$, ни в столбце $c$.

Пример 1: классификатор фруктов по фото

Модель компьютерного зрения различает яблоки, груши и апельсины на фотографиях, протестирована на 300 изображениях — по 100 каждого фрукта.

                Предск: Яблоко   Предск: Груша   Предск: Апельсин
Реально: Яблоко        92              5                3
Реально: Груша          4             88                8
Реально: Апельсин       2             10               88

Проверка согласованности: суммы строк — $92+5+3=100$, $4+88+8=100$, $2+10+88=100$ ✓ (каждый класс представлен ровно 100 объектами). Суммы столбцов — $92+4+2=98$ (яблоком названо 98 раз), $5+88+10=103$ (грушей — 103 раза), $3+8+88=99$ (апельсином — 99 раз); всего $98+103+99=300$ ✓.

Разбор по one-vs-rest для класса «Груша»: $TP_{\text{груша}}=88$ (диагональ), $FN_{\text{груша}}=4+8=12$ (остаток строки — реально груша, а предсказано что-то другое), $FP_{\text{груша}}=5+10=15$ (остаток столбца — реально что-то другое, а предсказана груша).

Уже на этом этапе, просто читая таблицу без единой формулы усреднения, видно системную закономерность: яблоко почти не путается ни с чем ($5+3=8$ ошибок в его строке, $4+2=6$ в его столбце), а вот груша и апельсин путаются друг с другом заметно чаще ($8$ раз груша принята за апельсин, $10$ раз апельсин принят за грушу) — это и есть тот самый паттерн систематической ошибки, который стоит искать в первую очередь.

Пример 2: классификатор рукописных цифр 3, 5, 8

Модель, обученная различать три визуально неоднозначные цифры — 3, 5 и 8, — протестирована на 150 изображениях, по 50 каждой цифры.

              Предск: 3   Предск: 5   Предск: 8
Реально: 3       46           1           3
Реально: 5        2          47           1
Реально: 8        5           1          44

Проверка: строки — $46+1+3=50$, $2+47+1=50$, $5+1+44=50$ ✓; столбцы — «3» предсказана $46+2+5=53$ раза, «5» — $1+47+1=49$ раз, «8» — $3+1+44=48$ раз, всего $53+49+48=150$ ✓.

Посчитаем суммарное число ошибок по каждой паре классов: между «3» и «5» — $1+2=3$ ошибки; между «5» и «8» — $1+1=2$ ошибки; между «3» и «8» — $3+5=8$ ошибок. Пара «3»–«8» ошибается вчетверо чаще, чем любая другая пара в этой матрице — и это не случайность: округлые начертания цифр 3 и 8 действительно визуально ближе друг к другу, чем к цифре 5 с её прямыми штрихами, и это один из хорошо задокументированных фактов в литературе по распознаванию рукописных цифр. Диагональная accuracy здесь $\frac{46+47+44}{150}=\frac{137}{150}\approx91{,}3\%$ — цифра сама по себе неплохая, но она ничего не говорит о том, что почти все реальные ошибки модели сосредоточены именно в одной паре классов.

Пример 3: классификатор новостных статей

Модель размечает статьи по трём рубрикам — «Спорт», «Политика», «Технологии», протестирована на 270 статьях, по 90 в каждой рубрике.

                    Предск: Спорт   Предск: Политика   Предск: Технологии
Реально: Спорт            88               1                    1
Реально: Политика          2              75                   13
Реально: Технологии        1              14                   75

Проверка: строки — $88+1+1=90$, $2+75+13=90$, $1+14+75=90$ ✓; столбцы — «Спорт» предсказан $88+2+1=91$ раз, «Политика» — $1+75+14=90$ раз, «Технологии» — $1+13+75=89$ раз, всего $91+90+89=270$ ✓.

Спорт почти идеально отделён от двух других рубрик — всего $1+1+2+1=5$ ошибок на все статьи о спорте вместе взятые. А вот пара «Политика»–«Технологии» путается массово: $13+14=27$ ошибок — почти каждая шестая статья этих двух рубрик классифицирована неверно. Смысловая причина здесь очевидна при чтении заголовков: статьи о регулировании технологических компаний государством, о законах об искусственном интеллекте или о технологической политике правительств тематически лежат ровно на стыке двух рубрик — и матрица ошибок делает эту содержательную проблему видимой за секунды, тогда как общая accuracy $\frac{88+75+75}{270}=\frac{238}{270}\approx88{,}1\%$ выглядела бы просто «хорошим, но не идеальным результатом», не подсказывая, что именно нужно исправлять.

Почему это важно

Полная $N\times N$ матрица ошибок — это не промежуточный шаг перед подсчётом одной итоговой метрики, а самостоятельный диагностический документ: она отвечает не только на вопрос «насколько модель ошибается», но и на гораздо более практичный вопрос «в какую конкретно сторону и между какими именно классами эта ошибка сосредоточена». Именно из значений $M_{ij}$ этой таблицы, как ты увидишь в следующем разделе, строятся per-class precision и recall для каждого отдельного класса, а из них — итоговые macro- и micro-усреднённые метрики всей модели.

Macro vs micro усреднение метрик

Интуиция

Когда классов больше двух, у тебя на руках оказывается не одно число precision и не одно число recall, а по одному значению каждой метрики на каждый класс — при трёх классах это уже шесть чисел, при десяти — двадцать. Для итогового отчёта и для сравнения моделей друг с другом эти числа обычно нужно свести к одному-двум значениям, и здесь есть два принципиально разных способа усреднения, дающих разный ответ на разные вопросы.

Macro-усреднение отвечает на вопрос «насколько хорошо модель работает на классе среднего размера, если считать каждый класс одинаково важным независимо от того, сколько в нём объектов?» — precision и recall сначала считаются отдельно для каждого класса, а затем усредняются арифметически, с равным весом.

Micro-усреднение отвечает на другой вопрос — «насколько хорошо модель работает в среднем на каждом отдельном объекте выборки?» — для этого суммируются общие $TP$, $FP$ и $FN$ по всем классам вместе, и метрика считается уже по этим суммарным числам. Поскольку крупные классы вносят в эту сумму больше объектов, micro-усреднение фактически взвешивает вклад каждого класса пропорционально его частоте в выборке.

Определение

Macro-усреднение.

$$\text{Precision}_{\text{macro}} = \frac{1}{N}\sum_{c=1}^{N}\text{Precision}_c, \qquad \text{Recall}_{\text{macro}} = \frac{1}{N}\sum_{c=1}^{N}\text{Recall}_c$$

где $\text{Precision}_c = \dfrac{TP_c}{TP_c+FP_c}$ и $\text{Recall}_c = \dfrac{TP_c}{TP_c+FN_c}$ — метрики каждого класса, вычисленные методом one-vs-rest. Каждый класс входит в сумму с одинаковым весом $1/N$ независимо от своего размера.

Micro-усреднение.

$$\text{Precision}_{\text{micro}} = \text{Recall}_{\text{micro}} = \frac{\sum_{c} TP_c}{\sum_{c} TP_c + \sum_{c} FP_c} = \frac{\sum_{c} TP_c}{\sum_{c} TP_c + \sum_{c} FN_c}$$

Эти два выражения равны, потому что в задаче с одной меткой на объект (single-label) каждая ошибка модели одновременно является false positive для предсказанного класса и false negative для реального класса — суммарное число $FP$ по всем классам всегда в точности равно суммарному числу $FN$ по всем классам. Из этого же следует, что micro-precision, micro-recall и обычная accuracy в многоклассовой single-label классификации — это одна и та же величина.

Пример 1: три вида ирисов (сбалансированные классы)

Классификатор различает три вида ирисов из классической задачи Фишера — Iris setosa, Iris versicolor, Iris virginica — на выборке из 150 цветков, по 50 каждого вида.

                    Предск: setosa   Предск: versicolor   Предск: virginica
Реально: setosa            50                0                    0
Реально: versicolor         0               45                    5
Реально: virginica          0                6                   44

Проверка: строки — $50$, $50$, $50$ ✓; столбцы — $50$, $51$, $49$, сумма $150$ ✓.

По one-vs-rest:

  • setosa: $TP=50$, $FN=0$, $FP=0$ → $\text{Precision}=50/50=1{,}0$, $\text{Recall}=50/50=1{,}0$;

  • versicolor: $TP=45$, $FN=5$, $FP=51-45=6$ → $\text{Precision}=45/51\approx0{,}882$, $\text{Recall}=45/50=0{,}9$;

  • virginica: $TP=44$, $FN=6$, $FP=49-44=5$ → $\text{Precision}=44/49\approx0{,}898$, $\text{Recall}=44/50=0{,}88$.

$$\text{Precision}_{\text{macro}} = \frac{1{,}0+0{,}882+0{,}898}{3} \approx 0{,}927 = 92{,}7\%, \qquad \text{Recall}_{\text{macro}} = \frac{1{,}0+0{,}9+0{,}88}{3} \approx 0{,}927 = 92{,}7\%$$

Для micro: суммарный $TP=50+45+44=139$, суммарный $FP=0+6+5=11$, суммарный $FN=0+5+6=11$.

$$\text{Precision}_{\text{micro}} = \text{Recall}_{\text{micro}} = \frac{139}{139+11} = \frac{139}{150} \approx 0{,}927 = 92{,}7\%$$

Здесь классы идеально сбалансированы (по 50 каждого), поэтому macro и micro дают практически одно и то же число — 92.7% против 92.7%. Это не совпадение, а прямое следствие того, что при равных по размеру классах взвешивание по частоте (micro) и равное взвешивание (macro) — это одна и та же операция.

Пример 2: приоритеты тикетов техподдержки (сильный дисбаланс)

Модель классифицирует обращения в техподдержку по трём приоритетам — «Низкий», «Средний», «Высокий» — на выборке из 1000 тикетов с сильным естественным дисбалансом: низкий приоритет встречается в подавляющем большинстве обращений.

                     Предск: Низкий   Предск: Средний   Предск: Высокий
Реально: Низкий            820              25                5
Реально: Средний            40              70               10
Реально: Высокий             3               7               20

Проверка: строки — $850$, $120$, $30$, сумма $1000$ ✓; столбцы — $863$, $102$, $35$, сумма $1000$ ✓.

По one-vs-rest:

  • Низкий: $TP=820$, $FN=850-820=30$, $FP=863-820=43$ → $\text{Precision}=820/863\approx0{,}950$, $\text{Recall}=820/850\approx0{,}965$;

  • Средний: $TP=70$, $FN=120-70=50$, $FP=102-70=32$ → $\text{Precision}=70/102\approx0{,}686$, $\text{Recall}=70/120\approx0{,}583$;

  • Высокий: $TP=20$, $FN=30-20=10$, $FP=35-20=15$ → $\text{Precision}=20/35\approx0{,}571$, $\text{Recall}=20/30\approx0{,}667$.

$$\text{Precision}_{\text{macro}} = \frac{0{,}950+0{,}686+0{,}571}{3} \approx 0{,}736 = 73{,}6\%, \qquad \text{Recall}_{\text{macro}} = \frac{0{,}965+0{,}583+0{,}667}{3} \approx 0{,}738 = 73{,}8\%$$

Для micro: суммарный $TP=820+70+20=910$, суммарный $FP=43+32+15=90$, суммарный $FN=30+50+10=90$.

$$\text{Precision}_{\text{micro}} = \text{Recall}_{\text{micro}} = \frac{910}{910+90} = \frac{910}{1000} = 0{,}91 = 91\%$$

Разница разительная: micro-усреднение (а значит и accuracy) даёт 91% — впечатляющий результат для отчёта руководству. Но macro-усреднение честно показывает 73.6–73.8%, потому что модель откровенно слабо справляется с классом «Высокий» (precision 57.1%, recall 66.7%), а этот класс, будучи маленьким по размеру (всего 30 тикетов из 1000), почти не влияет на micro-метрику, зато вносит полноценную треть веса в macro-метрику. Для техподдержки именно приоритет «Высокий» — самый критичный (это, вероятно, аварийные обращения), и micro-метрика в 91% попросту маскирует то, что модель ошибается почти в каждом третьем таком тикете.

Пример 3: редкий подтип заболевания (экстремальный дисбаланс)

Диагностическая модель классифицирует результат обследования на три исхода — «Норма», «Форма 1» (нечастое отклонение), «Форма 2» (редкий и опасный подтип) — на выборке из 1000 пациентов: 990 здоровы, 8 имеют форму 1, всего 2 — крайне редкую форму 2.

                    Предск: Норма   Предск: Форма 1   Предск: Форма 2
Реально: Норма           980              8                 2
Реально: Форма 1           3              5                 0
Реально: Форма 2           2              0                 0

Проверка: строки — $990$, $8$, $2$, сумма $1000$ ✓; столбцы — $985$, $13$, $2$, сумма $1000$ ✓.

По one-vs-rest:

  • Норма: $TP=980$, $FN=10$, $FP=985-980=5$ → $\text{Precision}=980/985\approx0{,}995$, $\text{Recall}=980/990\approx0{,}990$;

  • Форма 1: $TP=5$, $FN=3$, $FP=13-5=8$ → $\text{Precision}=5/13\approx0{,}385$, $\text{Recall}=5/8=0{,}625$;

  • Форма 2: $TP=0$, $FN=2$, $FP=2-0=2$ → $\text{Precision}=0/2=0$, $\text{Recall}=0/2=0$.

$$\text{Precision}_{\text{macro}} = \frac{0{,}995+0{,}385+0}{3} \approx 0{,}460 = 46{,}0\%, \qquad \text{Recall}_{\text{macro}} = \frac{0{,}990+0{,}625+0}{3} \approx 0{,}538 = 53{,}8\%$$

Для micro: суммарный $TP=980+5+0=985$, суммарный $FP=5+8+2=15$, суммарный $FN=10+3+2=15$.

$$\text{Precision}_{\text{micro}} = \text{Recall}_{\text{micro}} = \frac{985}{985+15} = \frac{985}{1000} = 0{,}985 = 98{,}5\%$$

Разрыв здесь драматический: micro/accuracy показывает 98.5% — практически идеальный результат. Но модель ни разу не поймала ни одного из двух пациентов с редкой и опасной формой 2 ($TP=0$), и macro-recall безжалостно показывает это как обвал до 53.8%, а macro-precision — до 46.0%. Именно такие ситуации — модель, которая полностью провалила один редкий, но клинически критичный класс, оставаясь почти невидимой в общей статистике, — и есть главный практический аргумент в пользу того, чтобы всегда смотреть macro-усреднённые метрики рядом с micro/accuracy, а не вместо них, особенно в задачах, где редкий класс — это не статистический шум, а самое важное, что вообще нужно найти.

Почему это важно

Выбор между macro- и micro-усреднением — прямое продолжение урока об опасности accuracy при дисбалансе классов (урок 307), только теперь применённое не к двум классам, а к произвольному числу: micro-усреднение (совпадающее с accuracy) неизбежно доминируется крупными классами, а macro-усреднение отдаёт голос каждому классу поровну, вне зависимости от того, сколько в нём объектов. Ни одно из двух усреднений не является «более правильным» само по себе — правильный выбор зависит от того, одинаково ли важны для тебя все классы по существу задачи, или же важность класса пропорциональна тому, как часто он встречается. В медицине, безопасности и любой задаче с редкими, но критичными классами почти всегда стоит ориентироваться на macro-усреднение (или явно смотреть на метрики редкого класса отдельно), тогда как в задачах, где ошибка на любом объекте стоит примерно одинаково, а частота классов в проде совпадает с частотой в тестовой выборке, micro-усреднение и accuracy остаются вполне осмысленным ориентиром.

Нормализованная матрица ошибок

Интуиция

Сырые числа в матрице ошибок из первого раздела читаются легко, только пока классы примерно одинакового размера. Но стоит одному классу оказаться на порядок больше других — и абсолютные числа начинают вводить в заблуждение: например, «20 ошибок» может значить и катастрофу (если в классе всего 30 объектов), и почти идеальную работу (если в классе 10 000 объектов). Чтобы сравнивать качество работы модели на разных по размеру классах на равных, каждую ячейку матрицы ошибок делят не на общее число объектов, а на сумму соответствующей строки или столбца — получается матрица не в абсолютных числах, а в долях, которую и называют нормализованной.

Определение

Нормализованная матрица ошибок. Нормализация по строкам (в sklearn.metrics.confusion_matrix(..., normalize="true")) делит каждый элемент строки $i$ на сумму этой строки:

$$\hat M_{ij} = \frac{M_{ij}}{\sum_{k} M_{ik}}$$

После такой нормализации сумма элементов каждой строки равна 1, а диагональный элемент $\hat M_{cc}$ в точности равен recall класса $c$ — доле реальных объектов этого класса, которых модель нашла верно.

Нормализация по столбцам (normalize="pred") делит каждый элемент на сумму соответствующего столбца, и тогда диагональный элемент даёт precision класса $c$. Нормализация по всей матрице (normalize="all") делит каждый элемент на общее число объектов в выборке, показывая долю каждой комбинации «реальный класс — предсказанный класс» от всех предсказаний сразу.

Пример 1: нормализация по строкам матрицы тикетов техподдержки

Возьми сырую матрицу тикетов из предыдущего раздела и нормализуй каждую строку на её сумму (support класса):

Строка "Низкий" / 850:   [820/850, 25/850, 5/850]   = [0,965, 0,029, 0,006]
Строка "Средний" / 120:  [40/120, 70/120, 10/120]    = [0,333, 0,583, 0,083]
Строка "Высокий" / 30:   [3/30, 7/30, 20/30]          = [0,100, 0,233, 0,667]

В абсолютных числах разница между «5 ошибок» в строке «Низкий» и «10 ошибок» в строке «Высокий» выглядела бы почти незаметной на фоне тысячи тикетов. Но в нормализованном виде сразу видно: класс «Низкий» правильно распознаётся в 96.5% случаев (диагональ = recall), а класс «Высокий» — лишь в 66.7% случаев, то есть каждый третий по-настоящему важный тикет модель классифицирует неверно. Это ровно те числа recall, что были посчитаны в предыдущем разделе (66.7% для класса «Высокий»), но теперь они видны прямо в самой матрице, без отдельного вычисления.

Пример 2: нормализация по строкам матрицы редких подтипов заболевания

Проделай то же самое с матрицей диагностики из предыдущего раздела:

Строка "Норма" / 990:    [980/990, 8/990, 2/990]   = [0,990, 0,008, 0,002]
Строка "Форма 1" / 8:    [3/8, 5/8, 0/8]            = [0,375, 0,625, 0,000]
Строка "Форма 2" / 2:    [2/2, 0/2, 0/2]             = [1,000, 0,000, 0,000]

Строка «Форма 2» в нормализованном виде — это, пожалуй, самая тревожная строчка во всём уроке: диагональный элемент равен ровно 0. В сырых абсолютных числах эта информация тонула среди тысячи пациентов («2 из 1000 неверно классифицированы» звучит незначительно), но в нормализованном виде она читается мгновенно и однозначно — модель распознаёт эту редкую форму заболевания в 0% случаев, стопроцентно принимая каждого такого пациента за здорового.

Пример 3: нормализация по столбцам против нормализации по строкам

Возьми матрицу фруктов из первого раздела урока и нормализуй её по столбцам вместо строк, чтобы увидеть, какой именно вопрос отвечает столбцовая нормализация.

Столбец "Яблоко" / 98:      [92/98, 4/98, 2/98]     = [0,939, 0,041, 0,020]
Столбец "Груша" / 103:      [5/103, 88/103, 10/103]  = [0,049, 0,854, 0,097]
Столбец "Апельсин" / 99:    [3/99, 8/99, 88/99]       = [0,030, 0,081, 0,889]

Диагональ здесь — это уже не recall, а precision: 93.9% для яблока, 85.4% для груши, 88.9% для апельсина. Разница между двумя видами нормализации принципиальна: строковая нормализация отвечает на вопрос «из всех реальных объектов этого класса, какую долю модель нашла верно?» (recall), а столбцовая — на вопрос «из всех объектов, которые модель назвала этим классом, какая доля действительно им является?» (precision). Обе версии нормализованной матрицы полезны, но отвечают на принципиально разные вопросы, и путать их — значит делать неверные выводы о том, какая именно ошибка у модели преобладает.

Почему это важно

Нормализованная матрица ошибок — это способ уравнять в правах классы разного размера прямо внутри самой таблицы, без отдельного вычисления precision и recall для каждого класса вручную. Она особенно незаменима именно в задачах с дисбалансом классов — а таких задач, как ты уже видел в уроке 307 и в этом уроке, в индустрии абсолютное большинство: сырые числа в маленьком по размеру классе визуально теряются на фоне больших чисел в доминирующем классе, тогда как в нормализованном виде процентная разница видна мгновенно и одинаково отчётливо для класса любого размера.

Визуализация матрицы ошибок: тепловая карта и диагностика систематических ошибок

Интуиция

Даже нормализованную таблицу из девяти-десяти чисел приходится читать и сопоставлять вручную, а при 10 и более классах таблица превращается в сотню цифр, которые физически трудно охватить взглядом. Тепловая карта решает эту проблему, превращая числа в цвет: каждая ячейка матрицы закрашивается тем интенсивнее, чем больше её значение. Человеческий глаз устроен так, что яркое пятно на общем фоне замечается почти мгновенно, без сознательного сравнения чисел, — и именно поэтому тепловая карта матрицы ошибок обычно оказывается первым графиком, который ML-инженер строит сразу после обучения классификатора, ещё до того, как смотреть на таблицу с precision, recall и F1 по каждому классу.

Как это выглядит на практике

Тепловая карта матрицы ошибок. Это матрица ошибок (обычно нормализованная по строкам), где числовое значение каждой ячейки закодировано цветом по некоторой шкале (например, от светлого к тёмно-синему). У идеальной модели тепловая карта — это ярко выраженная диагональ на тёмном фоне и полностью светлые, почти невидимые недиагональные ячейки. Любая заметно окрашенная ячейка вне диагонали — это не случайный шум, а конкретная, воспроизводимая пара «реальный класс — класс, с которым его путает модель», которую стоит исследовать отдельно.

Стандартный код для построения такой карты в sklearn:

from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
import matplotlib.pyplot as plt

labels = ["setosa", "versicolor", "virginica"]
cm = confusion_matrix(y_true, y_pred, labels=labels, normalize="true")

disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=labels)
disp.plot(cmap="Blues", values_format=".2f")
plt.title("Нормализованная матрица ошибок")
plt.show()

Начиная с недавних версий sklearn тот же результат можно получить ещё короче, напрямую из предсказаний модели, без ручного вызова confusion_matrix:

ConfusionMatrixDisplay.from_predictions(y_true, y_pred, normalize="true", cmap="Blues")

Пример 1: тепловая карта классификатора цифр 3, 5, 8

Возьми нормализованную по строкам матрицу цифр из первого раздела урока и представь её как тепловую карту: диагональ («3»→«3», «5»→«5», «8»→«8») закрашена тёмно-синим цветом (значения около 0.9), а вот ячейка на пересечении строки «8» и столбца «3» заметно ярче фона соседних недиагональных ячеек (значение $5/50=0{,}10$ против $1/50=0{,}02$ у пары «3»–«5»). ML-инженер, увидев это единственное выделяющееся пятно, сразу понимает, куда смотреть дальше: не нужно перебирать все возможные пары классов — достаточно вытащить конкретные примеры, где модель предсказала «3» при реальной «8» (и наоборот), визуально их просмотреть и проверить гипотезу — возможно, дело в почерке конкретных людей в датасете, качестве скана или в том, что этим двум цифрам действительно не хватает различающих признаков в текущей архитектуре модели.

Пример 2: тепловая карта ирисов Фишера

На тепловой карте нормализованной матрицы ирисов из раздела про macro/micro сразу видно: строка setosa целиком тёмная только на диагонали — класс отделён от двух других идеально, ни одной светящейся недиагональной ячейки. А вот на пересечении versicolor и virginica — в обе стороны — заметны две симметрично окрашенные ячейки (0.10 и 0.12 соответственно). Это известный и часто повторяемый на практике факт про классический датасет ирисов: setosa линейно отделим от двух других видов практически идеально, тогда как versicolor и virginica пересекаются в пространстве признаков, и модели (особенно линейные) регулярно путают именно эту пару. Тепловая карта делает этот факт очевидным за секунду, тогда как таблица с precision и recall по каждому классу потребовала бы отдельного сопоставления шести чисел.

Пример 3: диагностический процесс после просмотра тепловой карты тикетов

Возьми тепловую карту нормализованной по строкам матрицы тикетов техподдержки. Самая яркая недиагональная ячейка — на пересечении строки «Средний» и столбца «Низкий» (значение $40/120\approx0{,}333$): треть тикетов среднего приоритета модель по ошибке относит к низкому. Дальнейший процесс диагностики обычно выглядит так:

  • вытащить конкретные тикеты, где реальный приоритет «Средний», а предсказан «Низкий», и вручную просмотреть 20–30 из них — часто оказывается, что формулировки в этих тикетах действительно неоднозначны даже для человека-разметчика, а не только для модели;

  • проверить, не размечены ли эти два класса непоследовательно в обучающей выборке — возможно, граница между «низким» и «средним» приоритетом определялась разными людьми по-разному в разное время;

  • если граница объективно размыта, попробовать добавить признаки, которые её проясняют (например, наличие определённых ключевых слов, срочность в истории клиента), либо явно взвесить обучающую выборку, чтобы модель уделяла классу «Средний» больше внимания;

  • пересчитать тепловую карту после каждого изменения и убедиться, что именно эта ячейка светлеет, а не просто общая accuracy выросла за счёт другого, уже и так хорошо работающего класса.

Почему это важно

Тепловая карта — не просто более красивый способ показать те же числа, что и в текстовой таблице: она меняет саму скорость и способ диагностики. Вместо того чтобы вручную пробегать взглядом по десяткам или сотням чисел в поисках отклонений, ML-инженер сразу видит, где именно сосредоточена систематическая ошибка модели — а систематическая ошибка, в отличие от случайного шума, воспроизводится стабильно и почти всегда поддаётся конкретному исправлению: через данные, признаки или архитектуру модели. Именно поэтому построение тепловой карты матрицы ошибок — практически первый шаг после обучения любого классификатора на практике, ещё до того, как сравнивать модели по единому числу вроде macro-F1 или accuracy.

Практика: 30 заданий

Базовые задания (1–10)

Задание 1: Модель определяет тональность отзыва (Позитив / Нейтрал / Негатив), протестирована на 120 отзывах:

                    Предск: Позитив   Предск: Нейтрал   Предск: Негатив
Реально: Позитив          35                4                  1
Реально: Нейтрал           3               30                  7
Реально: Негатив           2                9                 29

Найти support (сумму строк) для каждого класса и общее число объектов $N$.


Задание 2: Для матрицы из задания 1 вычислить accuracy.


Задание 3: Для матрицы из задания 1 методом one-vs-rest найти $TP$, $FN$, $FP$ для класса «Нейтрал».


Задание 4: Используя данные задания 3, вычислить precision и recall класса «Нейтрал».


Задание 5: Объяснить своими словами разницу между тем, что показывает сумма строки, и тем, что показывает сумма столбца в многоклассовой матрице ошибок.


Задание 6: Precision трёх классов равны 87.5%, 69.8%, 78.4%. Вычислить macro-precision.


Задание 7: Для трёх классов известны $TP$ и $FP$: класс А ($TP=35$, $FP=5$), класс Б ($TP=30$, $FP=13$), класс В ($TP=29$, $FP=8$). Вычислить micro-precision.


Задание 8: Объяснить, почему micro-precision в многоклассовой single-label классификации всегда совпадает с accuracy.


Задание 9: Для строки «Негатив» матрицы из задания 1 ($2$, $9$, $29$, сумма строки $=40$) вычислить нормализованную по строке версию (в долях).


Задание 10: Фрагмент вывода sklearn.metrics.classification_report для трёх классов:

              precision    recall  f1-score   support

           0       0.95      0.96      0.96       850
           1       0.69      0.58      0.63       120
           2       0.57      0.67      0.62        30

   micro avg       0.91      0.91      0.91      1000
   macro avg       0.74      0.74      0.74      1000

Объяснить, почему строка micro avg совпадает с accuracy модели, а строка macro avg — нет.


Средние задания (11–20)

Задание 11: Дана матрица ошибок классификатора тикетов техподдержки на 1000 объектах:

                     Предск: Низкий   Предск: Средний   Предск: Высокий
Реально: Низкий            820              25                5
Реально: Средний            40              70               10
Реально: Высокий             3               7               20

Вычислить $TP$, $FN$, $FP$ методом one-vs-rest для всех трёх классов.


Задание 12: Используя данные задания 11, вычислить precision и recall каждого класса и macro-precision, macro-recall.


Задание 13: Используя данные задания 11, вычислить micro-precision и проверить, что она совпадает с accuracy.


Задание 14: Нормализовать матрицу из задания 11 по строкам и назвать класс с наименьшим recall.


Задание 15: Нормализовать ту же матрицу по столбцам и назвать класс с наименьшим precision.


Задание 16: Дана нормализованная по строкам матрица (только доли, без исходных чисел) и support каждого класса: строка «А»: $[0{,}9,\ 0{,}1,\ 0{,}0]$, support $=200$; строка «Б»: $[0{,}2,\ 0{,}7,\ 0{,}1]$, support $=50$. Восстановить абсолютные числа для этих двух строк.


Задание 17: Модель А имеет macro-F1 выше, чем модель Б, на одном и том же трёхклассовом тестовом наборе, а модель Б имеет более высокую accuracy (и, соответственно, micro-F1), чем модель А. Что это говорит о том, где именно у каждой модели сосредоточены ошибки?


Задание 18: Код confusion_matrix(y_true, y_pred, normalize="true") для трёхклассовой задачи вернул массив [[0.96, 0.03, 0.01], [0.33, 0.58, 0.08], [0.10, 0.23, 0.67]]. Объяснить, что означает число 0.58 в этой матрице.


Задание 19: В отчёте classification_report помимо macro avg часто встречается строка weighted avg. Объяснить, чем weighted avg (взвешенное по support среднее каждого показателя по классам) отличается и от macro, и от micro-усреднения.


Задание 20: На тепловой карте нормализованной по строкам матрицы ошибок пятиклассового классификатора одна недиагональная ячейка (строка класса C, столбец класса D) заметно ярче всех остальных недиагональных ячеек, со значением 0.28. Какие конкретные шаги стоит предпринять дальше?


Продвинутые задания (21–30)

Задание 21: По списку из 15 пар (реальный класс, предсказанный класс) для трёх классов A, B, C построить матрицу ошибок:

(A,A) (A,A) (A,B) (A,A) (A,A)
(B,B) (B,B) (B,A) (B,C) (B,B)
(C,C) (C,C) (C,C) (C,B) (C,A)

Задание 22: По матрице из задания 21 вычислить macro-precision, macro-recall и micro-precision.


Задание 23: Объяснить, почему в многоклассовой single-label классификации суммарное число $FP$ по всем классам всегда равно суммарному числу $FN$ по всем классам.


Задание 24: Опираясь на факт из задания 23, формально показать, что micro-recall равен micro-precision в многоклассовой single-label классификации.


Задание 25: Модель показывает macro-F1 заметно ниже micro-F1 на пятиклассовой задаче из-за одного класса, где модель совсем не работает (recall 0%), хотя объектов этого класса всего 0.3% выборки. Стоит ли компании всё равно ориентироваться на macro-F1 при принятии решения о запуске модели в продакшен?


Задание 26: В матрице тикетов техподдержки (задание 11) модель 40 раз предсказывает «Низкий» при реальном «Среднем», но лишь 25 раз предсказывает «Средний» при реальном «Низком» — асимметрия в сторону «Низкого». Что это говорит о поведении модели и какая может быть причина?


Задание 27: Как формулы macro-усреднения, micro-усреднения и построение матрицы ошибок изменятся при переходе от 3 классов к, скажем, 7 классам?


Задание 28: Соревнование по машинному обучению оценивает участников по метрике на 8-классовой задаче с сильным дисбалансом (один класс — 70% выборки, остальные семь — по 4-5% каждый). Какую метрику — macro-F1 или micro-F1 — стоит выбрать организаторам в качестве основной, и почему?


Задание 29: Для матрицы тикетов техподдержки (precision: 95.0%, 68.6%, 57.1% для классов «Низкий» (850), «Средний» (120), «Высокий» (30) соответственно) вычислить weighted-average precision (среднее, взвешенное по support) и сравнить с micro-precision (91%) из задания 13.


Задание 30: Спроектируй процесс диагностики для начинающего ML-инженера, который только что обучил классификатор на 6 классов: какой график смотреть первым, какую метрику выбрать как основную (с учётом того, известно, что часть классов редкие, но важные), и что делать при обнаружении яркой недиагональной ячейки на тепловой карте.


Частые ошибки

Ошибка 1. Считают, что матрица ошибок для многоклассовой задачи читается так же, как для бинарной, — путают, что стоит по строкам, а что по столбцам.

Как выглядит: «в матрице 20 объектов класса B, значит модель предсказала класс B 20 раз» — смешение суммы строки (реальное число объектов класса) и суммы столбца (число предсказаний этого класса).

Почему возникает: в бинарной матрице из урока 307 строки и столбцы визуально симметричны по размеру (обычно оба класса представлены достаточно), и разница между ними реже бросается в глаза.

Как правильно: всегда явно проверять, какая ось — строки или столбцы — соответствует реальному классу, а какая — предсказанному (в sklearn.metrics.confusion_matrix по умолчанию строки — реальный класс, столбцы — предсказанный), и считать support именно по сумме строки.

Ошибка 2. Используют micro-усреднение (или просто accuracy) как единственную метрику в задаче с редкими, но важными классами.

Как выглядит: «модель показывает accuracy 98.5% на трёх диагнозах — отличный результат, запускаем в продакшен», при том что модель ни разу не распознала самый редкий и самый опасный диагноз.

Почему возникает: accuracy и micro-усреднение — самые интуитивно понятные и привычные метрики, и их высокое значение создаёт ложное ощущение полной готовности модели.

Как правильно: всегда смотреть macro-усреднённые метрики (или per-class метрики) рядом с micro/accuracy, особенно если хотя бы один класс в задаче — редкий, но клинически или бизнес-критичный.

Ошибка 3. Путают нормализацию по строкам и по столбцам, принимая диагональ строково-нормализованной матрицы за precision.

Как выглядит: «диагональный элемент 0.95 в нормализованной матрице — значит precision класса 95%», хотя матрица была нормализована по строкам (normalize="true"), и это значение на самом деле recall.

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

Как правильно: всегда явно указывать и запоминать, какая нормализация использована — normalize="true" (по строкам, диагональ = recall) или normalize="pred" (по столбцам, диагональ = precision) — и подписывать это на самом графике.

Ошибка 4. Сравнивают macro-F1 двух моделей, обученных и протестированных на выборках с разным числом классов или с разным набором классов.

Как выглядит: «модель А (macro-F1 = 0.80 на 5 классах) лучше модели Б (macro-F1 = 0.75 на 8 классах)».

Почему возникает: забывают, что macro-усреднение зависит от числа классов $N$ — чем больше редких и объективно более сложных классов в задаче, тем ниже обычно оказывается macro-метрика при прочих равных, независимо от реального качества модели.

Как правильно: сравнивать macro-метрики только на одном и том же наборе классов и одном и том же тестовом наборе данных, как и в случае с AUC в уроке 308.

Ошибка 5. Считают, что яркая ячейка на тепловой карте матрицы ошибок сама по себе объясняет причину ошибки, и сразу переходят к исправлению, не посмотрев на конкретные примеры.

Как выглядит: «модель путает классы C и D — значит, нужно добавить ещё один слой в нейросеть», без единого просмотра реальных неверно классифицированных объектов.

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

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

Ошибка 6. Игнорируют предупреждение о делении на ноль, когда в тестовой выборке нет объектов какого-то класса (support = 0), и не глядя доверяют итоговому macro-среднему.

Как выглядит: модель тестируется на небольшой выборке, где случайно не оказалось ни одного объекта редкого класса, precision или recall для этого класса не определены (деление на ноль), а инструмент молча подставляет 0 или пропускает класс при усреднении, искажая итоговое macro-значение.

Почему возникает: при работе с автоматизированными пайплайнами легко не заметить предупреждение (UndefinedMetricWarning в sklearn) в потоке логов.

Как правильно: перед вычислением macro-усреднённых метрик проверять, что каждый класс из ожидаемого набора действительно присутствует в тестовой выборке с ненулевым support, и явно решать, как обрабатывать классы с нулевым числом объектов (исключать из усреднения или явно помечать как неопределённые), а не полагаться на поведение по умолчанию.

Главное запомнить

  • Матрица ошибок для $N$ классов — таблица $N\times N$: строка $i$ — реальный класс (сумма строки = support), столбец $j$ — предсказанный класс, диагональ — верные предсказания.

  • Для каждого отдельного класса $TP$, $FN$, $FP$, $TN$ получаются методом «один против всех» (one-vs-rest): $TP$ — диагональная ячейка, $FN$ — остаток строки, $FP$ — остаток столбца, $TN$ — всё остальное.

  • Macro-усреднение считает метрику отдельно для каждого класса и усредняет их с равным весом — все классы одинаково важны независимо от размера.

  • Micro-усреднение суммирует $TP$, $FP$, $FN$ по всем классам вместе и лишь потом делит — крупные классы фактически получают больший вес, и в многоклассовой single-label классификации micro-precision = micro-recall = accuracy.

  • При сильном дисбалансе классов macro- и micro-усреднение могут расходиться очень сильно: micro/accuracy маскирует провал на редком классе, macro честно его показывает — прямое продолжение проблемы accuracy при дисбалансе из урока 307.

  • Нормализованная матрица ошибок делит каждую ячейку на сумму строки (normalize="true", диагональ = recall) или столбца (normalize="pred", диагональ = precision) — удобна для сравнения классов разного размера в долях, а не в абсолютных числах.

  • Тепловая карта — это визуализация (нормализованной) матрицы ошибок цветом; яркая недиагональная ячейка — сигнал систематической, воспроизводимой ошибки, а не случайного шума.

  • sklearn.metrics.confusion_matrix, ConfusionMatrixDisplay и classification_reportaverage="macro" / "micro" / "weighted") — стандартные инструменты для построения и анализа многоклассовой матрицы ошибок на практике.

  • Обнаружив яркую ячейку систематической ошибки, следующий шаг — не сразу менять модель, а вручную просмотреть конкретные неверно классифицированные объекты этой пары классов и понять содержательную причину путаницы.

Связь с темами курса

Этот урок — прямое продолжение и углубление урока 307, где ты впервые встретил матрицу ошибок, но только для бинарного случая — таблицы $2\times2$ с четырьмя ячейками. Всё, что ты изучил там про $TP$, $FP$, $FN$, precision и recall, остаётся справедливым и здесь — просто теперь эти понятия определяются для каждого класса отдельно методом one-vs-rest, а не для единственной пары «положительный/отрицательный». Проблема, которую урок 307 поднял для бинарной accuracy при дисбалансе двух классов, в этом уроке масштабируется на произвольное число классов через противопоставление macro- и micro-усреднения — и вывод остаётся тем же самым: чем сильнее дисбаланс, тем важнее не ограничиваться одной усреднённой цифрой, а смотреть на качество модели по каждому классу в отдельности.

Урок также перекликается с уроком 308 про ROC-кривую и AUC: там ты видел, что precision резко чувствителен к дисбалансу классов, тогда как TPR и FPR — нет, потому что считаются внутри каждого класса отдельно. Ровно та же логика объясняет разницу между macro- и micro-усреднением здесь: macro-усреднение, как и TPR/FPR по отдельности, трактует каждый класс независимо от его размера, тогда как micro-усреднение и accuracy, как и precision в уроке 308, напрямую зависят от того, сколько объектов в каждом классе.

Интересные факты

  • Классический датасет ирисов Фишера 1936 года, использованный в этом уроке для примера macro/micro усреднения, остаётся одним из самых часто используемых учебных наборов данных в машинном обучении почти сто лет спустя — и известное свойство «setosa отделяется идеально, versicolor и virginica немного путаются» воспроизводится практически на любой модели, от простейшей линейной до сложных ансамблей.

  • В распознавании рукописных цифр цифры 3 и 8 — один из самых часто цитируемых примеров систематической путаницы моделей: оба символа состоят преимущественно из округлых петель, и на этом сходстве спотыкаются даже современные свёрточные нейросети при недостаточно качественном или зашумлённом изображении.

  • Термин confusion matrix (буквально «матрица путаницы») действительно происходит от английского слова confusion в психологическом смысле — «спутывание» одного стимула с другим человеческим восприятием, а не от «путаницы» в разговорном смысле «беспорядок».

  • Micro-усреднение precision и recall совпадает с accuracy только в задачах с одной меткой на объект (single-label). В задачах, где один объект может одновременно принадлежать нескольким классам (multi-label classification, например, теги статьи), это равенство перестаёт быть верным, и micro-precision с micro-recall становятся самостоятельными, различающимися метриками — важная тонкость, с которой стоит быть аккуратным при переходе от однометочной к многометочной классификации.

Лайфхаки

  • Строй тепловую карту матрицы ошибок сразу после обучения любого классификатора с числом классов от трёх — до того, как смотреть на итоговый macro- или micro-F1: один взгляд на картинку часто экономит часы разбора текстовых таблиц с метриками.

  • Если в задаче есть хотя бы один класс, который важен независимо от его частоты (редкое, но опасное состояние; редкий, но дорогой тип дефекта), всегда сообщай в отчёте macro-метрики рядом с micro/accuracy — одно число без другого может ввести читателя отчёта в заблуждение в любую сторону.

  • Для нормализованной матрицы ошибок явно подписывай тип нормализации на самом графике (normalize="true" — recall по диагонали, normalize="pred" — precision по диагонали) — без подписи через месяц даже ты сам можешь забыть, какую версию строил.

  • При обнаружении систематической путаницы между двумя конкретными классами попробуй сначала посмотреть на это с точки зрения человека: смогла бы группа людей-разметчиков надёжно отличить эти два класса друг от друга на тех же примерах? Если нет — проблема, скорее всего, не в модели, а в объективной размытости границы между классами или в качестве разметки.

  • Перед тем как публиковать macro-F1 как итоговую метрику модели в отчёте, проверь через classification_report, что ни у одного класса нет предупреждения о неопределённой метрике из-за нулевого support в тестовой выборке — иначе итоговое среднее может оказаться посчитано не по тому числу классов, которое ты предполагаешь.

Ты прошёл путь от единственной ячейки бинарной матрицы ошибок в уроке 307 до полной диагностики многоклассового классификатора — таблицы, из которой одним взглядом на тепловую карту можно выцепить конкретную пару классов, которую модель путает систематически, а не случайно. Вместе с macro- и micro-усреднением, нормализацией и умением находить систематические ошибки эта диагностика завершает блок уроков про метрики качества классификации — с этого момента ты умеешь не просто получить одно число «насколько хороша модель», а понять, где именно она слаба и что с этим делать. В следующем уроке ты сделаешь качественный шаг вперёд: от того, как оценивать готовую модель, к тому, как такую модель вообще построить — начнёшь с линейной регрессии, первого и самого фундаментального алгоритма машинного обучения, на примере которого разберёшь, как модель в принципе учится на данных.

Понял тему? Закрепи в боте! 🚀

Попрактикуйся на задачах и получи персональные рекомендации от AI

💪 Начать тренировку
💬 Есть вопрос? Спроси бота!