Precision score – это одна из метрик, оценивающих качество решения задачи бинарной классификации в машинном обучении. Она давно себя зарекомендовала: это одно интерпретируемое и легко вычисляемое число, оценивающее качество алгоритма. Словесное описание precision score: “Среди примеров с предсказанным положительным классом, какая их доля действительно имеет положительный класс?” Например, если precision score у некого теста на болезнь равен 0.95, то 95% людей с положительным результатом действительно больны, а 5% – на самом деле здоровы.

Теперь к сути этой статьи. В последнем предложении предыдущего абзаца я опустил критически важную информацию для понимания точности теста: я ничего не сказал про данные, на которых было рассчитано значение precision score. Дело в том, что precision score не является внутренним свойством алгоритма – скор измеряется на наборе данных и может меняться вместе с этим набором, поэтому формулировка “precision score у теста на болезнь равен 0.95” без уточнения характеристик данных, на которых он рассчитан, на мой взгляд, не до конца позволяет оценить свойство классификатора, которое мы на самом деле хотим оценить, а иногда и вовсе может привести к неправильным выводам. Как? Что я предлагаю? Попробую объяснить. 

Спойлер: во всём виновата несбалансированность классов. Баланс классов может легко менять метрику в ту или иную сторону, не изменяя сам классификатор. А решить проблему можно либо с помощью отказа от precision score в пользу confusion matrix, что не всегда подходит по причине многословности (четыре числа вместо одного, к каждому из которых нужно делать пояснения), либо с помощью расчета сбалансированного precision score, о котором и пойдет речь.

О precision score и балансе классов

Precision score зависит от таких метрик, как True Positive (TP) и False Positive (FP). Вот формула:

PrecisionScore=\frac{TP}{TP+FP}

Обычно метрики располагают в confusion matrix, как в таблице ниже.

Predicted Positive

Predicted Negative

Actual Positive

True Positive (TP)

False Negative (FN)

Actual Negative

False Positive (FP)

True Negative (TN)

Когда увеличивается FP – precision score снижается, и наоборот. Ясно, что абсолютное значение FP зависит от баланса классов: больше негативного класса – неизбежно выше и FP при том же классификаторе. И изменяя баланс классов, можно сделать precision score равным как 0 (сделав TP равным 0, т.е. убрав все позитивные примеры), так и 1 (сделав FP равным 0, т.е. убрав все негативные примеры).

Когда вы оцениваете точность алгоритма на данных из настоящего распределения, которое вы ожидаете видеть в жизни, и для целей задачи вам важно знать именно реальную долю False Positives в продакшене, то обычный precision score сработает прекрасно. Однако некоторые сценарии могут привести вас к неприятным ошибкам. Вот примеры:

  1. Precision score увеличился при обучении на данных с upsampling-ом позитивного класса или downsampling-ом негативного. Значит, при обучении финальной модели стоит делать так же?
    Не обязательно. Вы могли искусственно увеличить метрику путем увеличения числа True Positive, а предсказывающая способность алгоритма осталось той же. Посмотрите на формулу precision score.

  2. При обучении использовался downsampling или upsampling любого из классов. После обучения модели ключевые метрики (включая precision score) оказались достойными. Модель можно пробовать в продакшене?
    Аналогично предыдущему пункту. В реальном распределении количество негативных примеров может быть критически выше, что неизбежно повлияет на число FP и на precision score.

  3. “Низкий precision score – это плохое качество классификации”.
    Не всегда. Реальный False Positive Rate (False Positives / Actual Negative) может быть очень низким. Однако из-за большого числа негативных примеров из-за несбалансированности классов высокое значние FP снижает precision score (взгляните на формулу метрики ещё раз). Возможно, вам удасться снизить число входящих негативных примеров во время инференса.  И тогда тот же алгоритм уже окажется хорош.

Сбалансированный precision score

Если вы будете использовать confusion matrix, то шанс допустить ошибку станет значительно ниже. Confusion matrix более выразительна, чем precision score сам по себе, поэтому заметить важные особенности работы классификатора будет проще.

Однако если confusion matrix не для вас, и вам нужно быстро сравнивать precision score моделей, обученных для одной задачи на данных с разным распределением классов, то взять значения метрик и сравнить их “в лоб” не получится по описанным выше причинам – разные балансы классов. Вместо этого можно для каждого случая рассчитать precision score на данных с одинаковым распределеним классов. Например, на идеально сбалансированном наборе данных – получится сбалансированный precision score.

Такой подход нивелирует различия между количеством False Positives и True Positives, придавая им одинаковый вес при расчете precision score. Очевидно, новая метрика не оценивает точность алгоритма на данных из реальной жизни. Однако она позволяет сравнивать модели между собой, сохраняя инвариантность к распределению классов, а также позволяет иначе посмотреть на качество классификации (вспомните пример о низком precision score при низком False Positive Rate, но большом дисбалансе классов в сторону негативного).

Чтобы рассчитать сбалансированный precision score, можно выровнять распределение классов с помощью up-/downsampling, и посчитать обычный precision score на новых данных. Можно, но не нужно. Вместо этого можно использовать следующую формулу:

PrecisionScore=\frac{k_1TP}{k_1TP+k_2FP}k_1=\frac{0.5}{TP+FN}=\frac{0.5}{ActualPositive}k_2=\frac{0.5}{TN+FP}=\frac{0.5}{ActualNegative}

Если вы пользуетесь Python-библиотекой sklearn, то в ней уже реализована функция precision_score, в которой можно использовать параметр sample_weight:

import numpy as np
from sklearn.metrics import precision_score

# y_true, y_pred, ...

# the probabilities of classes:
# np.array([0.9092, 0.0908])

sample_coeff = 0.5 / true_class_dist

weights = np.zeros(len(y_true))
weights[y_true == 1] = sample_coeff[1]
weights[y_true == 0] = sample_coeff[0]

precision_score(y_true, y_pred, sample_weight=weights) # balanced precision score

Если вы не пользуетесь этой библиотекой, то сбалансированный precision score несложно посчитать по вышеупомянутой формуле.

Пример

Возьмем один и тот же классификатор и два набора данных, отличающихся только балансом классов, и проверим значения обычного precision score и сбалансированного precision score.

Две confusion matrix, соответствующие хуже и лучше сбалансированным данным соответстсвенно:

Predicted Positive

Predicted Negative

Total

Actual Positive

90 (TP)

10 (FN)

100

Actual Negative

50 (FP)

850 (TN)

900

Predicted Positive

Predicted Negative

Total

Actual Positive

90 (TP)

10 (FN)

100

Actual Negative

10 (FP)

170 (TN)

180

Посчитав precision score по обычной формуле, мы получим 0.64 для первого набора и 0.9 для второго. Если же мы посчитаем сбалансированный precision score, то оба раза он окажется равен 0.94.


Надеюсь, вы найдете применение этому методу, ровно как и его недостатки. А также с интересом отвечу на ваши комментарии!

Комментарии (2)


  1. imageman
    15.08.2024 10:01

    в чем отличие по сравнению с F1 score? В каких случаях лучше применять?


    1. AntonSoroka Автор
      15.08.2024 10:01

      Сбалансированный precision score - просто версия precision score, равная скору на идеально сбалансированных данных. Она не учитывает баланс классов, когда это необходимо.

      А F1 score "усредняет" precision и recall. Я думаю, у метрик разное предназначение. Однако было бы любопытно проверить, как влияет дисбаланс классов на F1 score.