Не радиус важен, а плотность! Часть 1: Глубокий взгляд на precision и recall

Нет, нет, я совсем не про геометрию или физику, я про множество!

Квадрат Серпинского

Правда красота? Квадрат Серпинского — по истине восхитительная вещь, особенно с точки зрения теории множеств, ведь если взять ручку и попробовать на нем нарисовать овал не отрывая руки, то вы не сможете его нарисовать так, чтобы в него не вошли белые области — это и есть неформальное определение «везде неплотного множества».

Почему я упоминаю его? Ну, просто дело в том, что как будто бы современные неглубокие знания очень многих начинающих дата-сайнтистов автору представляются именно таким образом. Да, что уж греха таить, знания автора тоже не так уж и далеки от квадрата Серпинского. Воспринимайте аналогию следующим образом: пусть какой-нибудь нарисованный таким образом овал — это какая-нибудь тема в машинном обучении и вся печаль в том, что стоит чуть отойти от этой темы или уйти в ее глубь, то сразу появляются пробелы и непонимания.

Автор действительно убежден, что не так важно в каком количестве тем вы разбираетесь, как важно то, насколько хорошо вы разбираетесь в том, в чем считаете, что разбираетесь, ибо как говорил Брюс Ли: «Я не боюсь того, кто изучает десять тысяч тем машинного обучения. Я боюсь того, кто изучает одну тему десять тысяч раз».

Какая тут связь с машинным обучением, спросите вы? Автор начал изучать, что же такое машинное обучение еще в далеком 2019-ом году, как только окончил 2-ой курс университета, и автору как-то сразу интуиция подсказывала, что карьера в машинном обучении не заканчивается на fit/predict, что должно быть сильно больше понимания в том, что мы fit'им и что predict'им.

Так вот, а теперь к сути. Хотелось бы попробовать озвучить некоторый, как кажется, более глубокий взгляд на привычные уже нам в ML вещи, вероятно, написать даже целую серию статей и попробовать в них посмотреть на многие классические аспекты машинного обучения с сильным погружением в теорию вероятности, математический анализ и линейную алгебру, или обратить внимание на просто некоторые неочевидные вещи, ибо как говорил Станиславский «не надо помнить, надо понимать» :)

PS: он так не говорил, автор это выдумал.

Accuracy, Precision, Recall, F1-score

Так и тянется рука приписать слева `from sklearn.metrics import`, не правда ли? : D

В этой статье речь пойдет про эти четыре, всем нам уже привычные, метрики классификации.

Если вы хоть чуть-чуть знакомы с тем, что такое «метрика классификации», то вам, вероятно, знакомы эти слова или по крайней мере первое — Accuracy. Но что в них может быть такого особенного?! Кажется, что размышление над этим вопросом заканчиваются где-то на «использовать это не очь, использовать это круть» ну или хотя бы на «использовать это, если классы сбалансированы, а это если нет». Такие же мысли посещали и автора, но давайте попробуем немножечко посмотреть на это математически!

Столп 1-ый

Для начала сформулируем, во что же мы сейчас будем углубляться.


И так, пусть

n \in \{1,2,3,...\}  - количество\ объектов\ в \ рассматриваемой \ выборке,\\C \in \{2,3,4,...\} - количество \ классов,\\\bar{t} \in \{0, 1, 2, ..., C-1\}^n - вектор \ длины \ n \ с \ реальными \ метками \ классов,\\\bar{y} \in \{0, 1, 2, ..., C-1\}^n - вектор \ длины \ n \ со \ спрогнозированными \ метками \ классов.

На основе этих обозначений введем следующие функции для более простого формального изложения последующего материала:

  • Пусть количество объектов, являющихся представителями класса «c» и при этом помеченных нашим алгоритмом как «c», будем называть true positive rate'ом и будем считать его равным значению следующей функции:

tp(\bar{t}, \bar{y}, c) = \sum^{n-1}_{i=0}{I[\bar{t}_i = c, \bar{y}_i = c]}

  • Пусть количество объектов, НЕ являющихся представителями класса «c», но при этом помеченных нашим алгоритмом как «c», будем называть false positive rate'ом и будем считать его равным значению следующей функции:

fp(\bar{t}, \bar{y}, c) = \sum^{n-1}_{i=0}{I[\bar{t}_i \neq c, \bar{y}_i = c]}

  • Пусть количество объектов, являющихся представителями класса «c», но при этом помеченных нашим алгоритмом как НЕ «c» будем называть false negative rate'ом и будем считать его равным значению следующей функции:

fn(\bar{t}, \bar{y}, c) = \sum^{n-1}_{i=0}{I[\bar{t}_i = c, \bar{y}_i \neq c]}

Чтож-ж, чуткий читатель может заметить, что тут нет true negative rate'а… хмм… ну что же, а вот и первый столп — ОН И НЕ НУЖЕН!


Действительно, лучше это будет понятно дальше, но, вообще говоря, когда рассматривается задача в общем виде, в которой может быть как 2, так и больше классов, то оказывается, что лучше и не определять никакое «количество объектов, НЕ являющихся представителями класса «c», но при этом помеченных нашим алгоритмом как НЕ «c»», т.к. это может иметь смысл только в бинарном случае, ибо в нем, мы предполагаем, что если объект имеет метку класса не равную «c», то он точно имеет метку равную »1-c», а в общем случае, когда имеем необязательно ровно два класса, то, пробегая по всем классам, вводить это понятие и не нужно, т.к. такие примеры уже учтены.

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

\sum^{C-1}_{k=0}(tp(\bar{t}, \bar{y}, c) + fp(\bar{t}, \bar{y}, c) + fn(\bar{t}, \bar{y}, c))=\\=\sum^{C-1}_{k=0}\sum^{n}_{i=1}(1 - I[\bar{t_i}\neq c,\bar{y_i}\neq c])=\sum^{n}_{i=1}\sum^{C-1}_{k=0}(1 - I[\bar{t_i}\neq c,\bar{y_i}\neq c])=\\=\{\sum^{C-1}_{k=0}(1 - I[t\neq c,y\neq c]) = 1, т.к. объект \ не\ может\ не\ принадлежать\ ни\ одному\ классу\\ и\ не\ может\ принадлежать\ больше, чем\ одному\ классу\}=\\=\sum^n_{i=0}1=n

Столп 2-ой

Давайте теперь сделаем некоторый неожиданный поворот сюжета и определим precision и recall не так, как вы привыкли:

Пусть

precision_c:=pr(t,y,c)=p(t=c|y=c),\\recall_c:=rc(t,y,c)=p(y=c|t=c).

То есть как условные вероятности. Что же это все значит?! Давайте разбираться и попробуем перевести на человеческий язык то, что здесь написано.

А написано следующее:

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

Что же, а теперь попробуем определенным образом расписать эти вероятности.

Но давайте сначала внесем еще немного формализма и определим, что же вообще такое вероятность. Охх, тут бы наверное еще постов 10 написать, чтобы апеллировать к чему-то, ну совсе-е-ем строгому, но давайте опустим это и напишем консервативное и очень давнее определение, обоснование уместности которого мы опустим:

Пусть в природе нашей задачи существует ровно N объектов, тогда верно следующее:

p(y=c)=\sum^{N}_{k=1}\frac{I[y_k=c]}{N},

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

p(y=c)=\lim_{N\to+\infty}\sum^{N}_{k=1}\frac{I[y_k=c]}{N}. \ (*)

Сформулируем теперь определение условной вероятности (опять же консервативное):

Пусть\ A\ и\ B - некоторые\ события, тогда\\ p(A|B)=\frac{p(A,B)}{p(B)}.

Хорошо, а теперь давайте объединим эти две формулы и распишем, допустим, precision (оставим вывод для recall’а читателю, чтобы сократить и так уже некороткое изложение):

p(y=c|t=c)=\frac{p(y=c,t=c)}{p(y=c)}=\{применяем\ (*)\}=\\=\frac{\lim_{N\to+\infty}\sum^{N}_{k=1}\frac{I[y_k=c,t_k=c]}{N}}{\lim_{N\to+\infty}\sum^{N}_{k=1}\frac{I[y_k=c]}{N}}=...

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

...= \{пусть\ \bar{y}\ и\ \bar{t} -\ соответствующие\ выборки\}=p(y=c|t=c)=\frac{p(y=c,t=c)}{p(y=c)}\approx\\\approx\frac{\sum^{N}_{k=1}\frac{I[y_k=c,t_k=c]}{N}}{\sum^{N}_{k=1}\frac{I[y_k=c]}{N}}=\frac{\sum^{N}_{k=1}I[y_k=c,t_k=c]}{\sum^{N}_{k=1}I[y_k=c]}=\\=\frac{\sum^{N}_{k=1}I[y_k=c,t_k=c]}{\sum^{N}_{k=1}I[(t_k=c\ или\ t_k\neq c),y_k=c]}=\\=\frac{\sum^{N}_{k=1}I[y_k=c,t_k=c]}{\sum^{N}_{k=1}(I[t_k=c,y_k=c] + I[t_k\neq c,y_k=c])}=\\=\frac{\sum^{N}_{k=1}I[y_k=c,t_k=c]}{\sum^{N}_{k=1}I[t_k=c,y_k=c] + \sum^{N}_{k=1}I[t_k\neq c,y_k=c]}=\\=\frac{tp(\bar{t},\bar{y},c)}{tp(\bar{t},\bar{y},c) + fp(\bar{t},\bar{y},c)}.

Получаем уже всем известные равенства, которые обычно вводятся сразу как определения:

pr(\bar{t},\bar{y},c)=\frac{tp(\bar{t},\bar{y},c)}{tp(\bar{t},\bar{y},c) + fp(\bar{t},\bar{y},c)};\ \ rc(\bar{t},\bar{y},c)=\frac{tp(\bar{t},\bar{y},c)}{tp(\bar{t},\bar{y},c) + fn(\bar{t},\bar{y},c)};\\f1(\bar{t},\bar{y},c)=\frac{2*pr(\bar{t},\bar{y},c)*rc(\bar{t},\bar{y},c)}{pr(\bar{t},\bar{y},c) + rc(\bar{t},\bar{y},c)}.

Таким образом, если наши рассматриваемые объекты получены из генеральной совокупности максимально случайным образом (точнее говоря «равновероятно»), то чем больше выборка, тем точнее посчитанные нами precision и recall приближают значения (точнее говоря «аппроксимируют») упомянутые выше условные вероятности.

Столп 3-ий

Так, а теперь мы уже совсем близко к финальному определению метрик для некоторой общей задачи с «c» классами, осталось только напомнить, что метрики многоклассовой классификации разделяются на micro, macro и weighted.

Сформулируем их определения:

accuracy := acc(\bar{t},\bar{y},C)=\frac{\sum^{C-1}_{c=0}tp(\bar{t},\bar{y},c)}{n}=\{или, если\ без\ C\} = \frac{\sum^{n}_{i=1}I[\bar{t_i}=\bar{y_i}]}{n};\\precision_{micro}:=PR_{micro}(\bar{t},\bar{y},C)=\frac{\sum^{C-1}_{c=0}tp(\bar{t},\bar{y},c)}{\sum^{C-1}_{c=0}tp(\bar{t},\bar{y},c) + \sum^{C-1}_{c=0}fp(\bar{t},\bar{y},c)};\\recall_{micro}:=RC_{micro}(\bar{t},\bar{y},C)=\frac{\sum^{C-1}_{c=0}tp(\bar{t},\bar{y},c)}{\sum^{C-1}_{c=0}tp(\bar{t},\bar{y},c) + \sum^{C-1}_{c=0}fn(\bar{t},\bar{y},c)};\\F1_{micro}:=F1_{micro}(\bar{t},\bar{y},C)=\frac{2*PR_{micro}(\bar{t},\bar{y},C)*RC_{micro}(\bar{t},\bar{y},C)}{PR_{micro}(\bar{t},\bar{y},C) + RC_{micro}(\bar{t},\bar{y},C)};\\precision_{macro}:=PR_{macro}(\bar{t},\bar{y},C)=\frac{\sum^{C-1}_{c=0}pr(\bar{t},\bar{y},c)}{C};\\recall_{macro}:=RC_{macro}(\bar{t},\bar{y},C)=\frac{\sum^{C-1}_{c=0}rc(\bar{t},\bar{y},c)}{C};\\F1_{macro}:=F1_{macro}(\bar{t},\bar{y},C)=\frac{\sum^{C-1}_{c=0}f1(\bar{t},\bar{y},c)}{C};\\precision_{weighted}:=PR_{weighted}(\bar{t},\bar{y},C)=\frac{\sum^{C-1}_{c=0}(pr(\bar{t},\bar{y},c) * (\frac{\sum^n_{i=1}I[\bar{t_i}=c]}{n}))}{C};\\recall_{weighted}:=RC_{weighted}(\bar{t},\bar{y},C)=\frac{\sum^{C-1}_{c=0}(rc(\bar{t},\bar{y},c) * (\frac{\sum^n_{i=1}I[\bar{t_i}=c]}{n}))}{C};\\F1_{weighted}:=F1_{weighted}(\bar{t},\bar{y},C)=\frac{\sum^{C-1}_{c=0}(f1(\bar{t},\bar{y},c) * (\frac{\sum^n_{i=1}I[\bar{t_i}=c]}{n}))}{C}.

Что же, а что же тут еще у нас осталось интересного? А на самом деле осталось. На этот раз не будем томить и просто выпишем последние утверждения и докажем их:

1.\ acc(\bar{t},\bar{y},C)=PR_{micro}(\bar{t},\bar{y},C)=RC_{micro}(\bar{t},\bar{y},C)=F1_{micro}(\bar{t},\bar{y},C);2.\ Если\ \forall c\in\{0,1,C-1\}\ верно\  \frac{\sum^n_{i=1}I[\bar{y_i}=c]}{n}=const,\ то\\ acc(\bar{t},\bar{y},C)=PR_{macro}(\bar{t},\bar{y},C)=RC_{macro}(\bar{t},\bar{y},C);3.\ pr(\bar{t},\bar{y},c)=rc(\bar{y},\bar{t},c),\ f1(\bar{t},\bar{y},c)=f1(\bar{t},\bar{y},c).

В целях незагромождения повествования доказательства можно найти ниже:

b88a01897b69dedc9746e87194766664.png

Действительно, precision и recall имеют своеобразную обратную зависимость по аргументам, а micro метрики представляют собой просто новый взгляд на число полученное подсчетом accuracy.

Итог

Таким образом, в этой статье нам удалось посмотреть на уже привычные метрики совершенно непривычным взглядом, более того, теперь, когда вы будете отрисовывать графики обучения своих нейронных сетей через matplotlib или tensorboard, вы будете совершенно по-иному смотреть на их динамику, вы будете знать заранее, что фактически, если у вас классы на валидации сбалансированы, то достаточно рисовать только accuracy, macro precision и macro f1, больше вы не будете представлять никакие круги и квадраты, никакие подбитые/неподбитые самолеты, какие-нибудь отсеивающие сетки и т.п., вы можете их вспоминать, чтобы вспомнить формулу, но у вас теперь будет понимание того, как численное значение precision'а и recall'а характеризует прогноз вашей модели с точки зрения вероятности.

Что же, это дебютная статья автора, он будет очень благодарен любой конструктивной критике и фидбеку в комментариях, так же дайте знать, если вам импонирует подобные «уплотнения множеств», то автор в свою очередь будет рад написать еще серию подобных статей наподобие «интерпретации ROC-AUC'а», «почему не оптимизируют MSE при классификации», «теория за скользящим экспоненциальным средним» или «почему человеческий мозг тоже оптимизирует logloss».

До новых встреч :)

© Habrahabr.ru