Оценка качества в задачах классификации и регрессии

Материал из Викиконспекты
Версия от 04:32, 23 марта 2020; MuratOK (обсуждение | вклад) (MAPE, Mean Absolute Percentage Error (средняя абсолютная процентная ошибка))
Перейти к: навигация, поиск

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

Оценки качества классификации

Матрица ошибок (англ. Сonfusion matrix)

Перед переходом к самим метрикам необходимо ввести важную концепцию для описания этих метрик в терминах ошибок классификации — confusion matrix (матрица ошибок). Допустим, что у нас есть два класса [math]y = \{ 0, 1 \}[/math] и алгоритм, предсказывающий принадлежность каждого объекта одному из классов. Рассмотрим пример. Пусть банк использует систему классификации заёмщиков на кредитоспособных и некредитоспособных. При этом первым кредит выдаётся, а вторые получат отказ. Таким образом, обнаружение некредитоспособного заёмщика ([math]y = 1 [/math]) можно рассматривать как "сигнал тревоги", сообщающий о возможных рисках.

Любой реальный классификатор совершает ошибки. В нашем случае таких ошибок может быть две:

  • Кредитоспособный заёмщик распознается моделью как некредитоспособный и ему отказывается в кредите. Данный случай можно трактовать как "ложную тревогу".
  • Некредитоспособный заёмщик распознаётся как кредитоспособный и ему ошибочно выдаётся кредит. Данный случай можно рассматривать как "пропуск цели".

Несложно увидеть, что эти ошибки неравноценны по связанным с ними проблемам. В случае "ложной тревоги" потери банка составят только проценты по невыданному кредиту (только упущенная выгода). В случае "пропуска цели" можно потерять всю сумму выданного кредита. Поэтому системе важнее не допустить "пропуск цели", чем "ложную тревогу".

Поскольку с точки зрения логики задачи нам важнее правильно распознать некредитоспособного заёмщика с меткой [math]y = 1 [/math], чем ошибиться в распознавании кредитоспособного, будем называть соответствующий исход классификации положительным (заёмщик некредитоспособен), а противоположный - отрицательным (заемщик кредитоспособен [math]y = 0 [/math]). Тогда возможны следующие исходы классификации:

  • Некредитоспособный заёмщик классифицирован как некредитоспособный, т.е. положительный класс распознан как положительный. Наблюдения, для которых это имеет место называются истинно-положительными (true positive - TP).
  • Кредитоспособный заёмщик классифицирован как кредитоспособный, т.е. отрицательный класс распознан как отрицательный. Наблюдения, которых это имеет место, называются истинно отрицательными (true negative - TN).
  • Кредитоспособный заёмщик классифицирован как некредитоспособный, т.е. имела место ошибка, в результате которой отрицательный класс был распознан как положительный. Наблюдения, для которых был получен такой исход классификации, называются ложно-положительными (false positive - FP), а ошибка классификации называется ошибкой I рода.
  • Некредитоспособный заёмщик распознан как кредитоспособный, т.е. имела место ошибка, в результате которой положительный класс был распознан как отрицательный. Наблюдения, для которых был получен такой исход классификации, называются ложно-отрицательными (false negative - FN), а ошибка классификации называется ошибкой II рода.

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

Confusion matrix.png

Здесь [math]a ( x )[/math] — это ответ алгоритма на объекте, а [math]y [/math] — истинная метка класса на этом объекте. Таким образом, ошибки классификации бывают двух видов: False Negative (FN) и False Positive (FP). Каждая строка в матрице ошибок представляет фактический класс, а каждый столбец - спрогнозированный класс.

 # код для матрицы ошибок
 from sklearn.metrics import confusion_matrix
 import pandas as pd
 n = confusion_matrix(y, a) # 1-й способ
 n = pd.crosstab(y, a) # 2-й способ
 # Вычисление TN, FP, FN, TP 
 TN, FP, FN, TP = confusion_matrix(y, a).ravel()

Аккуратность (англ. Accuracy)

Интуитивно понятной, очевидной и почти неиспользуемой метрикой является accuracy — доля правильных ответов алгоритма:

[math] accuracy = \dfrac{TP+TN}{TP+TN+FP+FN} [/math]

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

Допустим, мы хотим оценить работу спам-фильтра почты. У нас есть 100 не-спам писем, 90 из которых наш классификатор определил верно (True Negative = 90, False Positive = 10), и 10 спам-писем, 5 из которых классификатор также определил верно (True Positive = 5, False Negative = 5). Тогда accuracy:

[math] accuracy = \dfrac{5+90}{5+90+10+5} = 86,4 [/math]

Однако если мы просто будем предсказывать все письма как не-спам, то получим более высокую accuracy:

[math] accuracy = \dfrac{0+100}{0+100+0+10} = 90,9 [/math]

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

Точность (англ. Precision)

Precision (точностью) называется доля правильных ответов модели в пределах класса – это доля объектов действительно принадлежащих данному классу относительно всех объектов которые система отнесла к этому классу.

[math] Precision = \dfrac{TP}{TP+FP} [/math]

Именно введение precision не позволяет нам записывать все объекты в один класс, так как в этом случае мы получаем рост уровня False Positive.

Полнота (англ. Recall)

Recall (Полнота системы) – это доля найденных классфикатором объектов принадлежащих классу относительно всех документов этого класса в тестовой выборке.

[math] Recall = \dfrac{TP}{TP+FN} [/math]

Recall демонстрирует способность алгоритма обнаруживать данный класс вообще.

Имея матрицу ошибок, очень просто можно вычислить точность и полноту для каждого класса. Precision (точность) равняется отношению соответствующего диагонального элемента матрицы и суммы всей строки класса. Recall (полнота) – отношению диагонального элемента матрицы и суммы всего столбца класса. Формально:

[math] Precision_c = \dfrac{A_{c,c}}{\sum \limits_{i=1}^{n} A_{c,i}} [/math]
[math] Recall_c = \dfrac{A_{c,c}}{\sum \limits_{i=1}^{n} A_{i,c}} [/math]

Результирующая точность классификатора рассчитывается как арифметическое среднее его точности по всем классам. То же самое с полнотой. Технически этот подход называется macro-averaging.

 # код для для подсчета точности и полноты:
 from sklearn.metrics import precision_score, recall_score
 precision_score(y_train, y_train_pred)
 recall_score(y_train, y_train_pred)

F-mera

Рис.1 Сбалансированная F-мера, [math]β=1[/math]
Рис.2 F-мера c приоритетом точности, [math]β^2=\dfrac{ 1 }{ 4 }[/math]
Рис.3 F-мера c приоритетом полноты, [math]β^2=2[/math]

Precision и recall не зависят, в отличие от accuracy, от соотношения классов и потому применимы в условиях несбалансированных выборок. Часто в реальной практике стоит задача найти оптимальный (для заказчика) баланс между этими двумя метриками. Понятно что чем выше точность и полнота, тем лучше. Но в реальной жизни максимальная точность и полнота не достижимы одновременно и приходится искать некий баланс. Поэтому, хотелось бы иметь некую метрику которая объединяла бы в себе информацию о точности и полноте нашего алгоритма. В этом случае нам будет проще принимать решение о том какую реализацию запускать в производство (у кого больше тот и круче). Именно такой метрикой является F-мера.

F-мера представляет собой гармоническое среднее между точностью и полнотой. Она стремится к нулю, если точность или полнота стремится к нулю.

[math] F = \dfrac{ 2 \times precision \times recall }{ precision + recall }[/math]

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

[math] F_β = \dfrac{(1+β^2) \times precision \times recall }{ (β^2 \times precision) + recall } [/math]

где [math]β[/math] принимает значения в диапазоне [math]0\lt β\lt 1[/math] если вы хотите отдать приоритет точности, а при [math]β\gt 1[/math] приоритет отдается полноте. При [math]β=1[/math] формула сводится к предыдущей и вы получаете сбалансированную F-меру (также ее называют [math]F_1[/math]):

F-мера достигает максимума при максимальной полноте и точности, и близка к нулю, если один из аргументов близок к нулю.

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

 # код для подсчета метрики F-mera:
 from sklearn.metrics import f1_score
 f1_score(y_train, y_train_pred)

ROC-кривая

Receiver Operating Characteristics curve (кривая рабочих характеристик). Используется для анализа поведения классификаторов при различных пороговых значениях. Позволяет рассмотреть все пороговые значения для данного классификатора. Показывает долю ложно положительных примеров ( FPR, false positive rate ) в сравнении с долей истинно положительных примеров ( TPR, true positive rate).

Roccurves.png

[math] TPR = \dfrac{TP}{TP+FN} [/math]
[math] FPR = \dfrac{FP}{FP+TN} [/math]
 # Код отрисовки 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()

Precison-recall кривая

Чувствительность к соотношению классов. Рассмотрим задачу выделения математических статей из множества научных статей. Допустим, что всего имеется 1.000.100 статей, из которых лишь 100 относятся к математике. Если нам удастся построить алгоритм a(x), идеально решающий задачу, то его TPR будет равен единице, а FPR — нулю. Рассмотрим теперь плохой алгоритм, дающий положительный ответ на 95 математических и 50.000 нематематических статьях. Такой алгоритм совершенно бесполезен, но при этом имеет TPR = 0.95 и FPR = 0.05, что крайне близко к показателям идеального алгоритма. Таким образом, если положительный класс существенно меньше по размеру, то AUC-ROC может давать неадекватную оценку качества работы алгоритма, поскольку измеряет долю неверно принятых объектов относительно общего числа отрицательных. Так, алгоритм b(x), помещающий 100 релевантных документов на позиции с 50.001-й по 50.101-ю, будет иметь AUC-ROC 0.95.

Precison-recall кривая. Избавиться от указанной проблемы с несбалансированными классами можно, перейдя от ROC-кривой к Precision-Recall кривой. Она определяется аналогично ROC-кривой, только по осям откладываются не FPR и TPR, а полнота (по оси абсцисс) и точность (по оси ординат). Критерием качества семейства алгоритмов выступает площадь под PR-кривой (AUC-PR)

Pr-rec.png

Оценки качества регрессии

Наиболее типичными мерами качества в задачах регрессии являются

MSE, Mean Squared Error (средняя квадратичная ошибка)

[math] MSE = \dfrac{1}{l}\sum \limits_{i=1}^{l}(a(x_i) - y_i)^2 [/math] и

MAE, Mean Absolute Error (средняя абсолютная ошибка)

[math] MAE = \dfrac{1}{l}\sum \limits_{i=1}^{l}|a(x_i) - y_i| [/math]

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

Среднеквадратичная ошибка подходит для сравнения двух моделей или для контроля качества во время обучения, но не позволяет сделать выводов о том, на сколько хорошо данная модель решает задачу. Например, MSE = 10 является очень плохим показателем, если целевая переменная принимает значения от 0 до 1, и очень хорошим, если целевая переменная лежит в интервале (10000, 100000). В таких ситуациях вместо среднеквадратичной ошибки полезно использовать коэффициент детерминации, или коэффициент [math]R^2[/math]

Коэффициент детерминации

[math] R^2 = 1 - \dfrac{\sum \limits_{i=1}^{l}(a(x_i) - y_i)^2}{\sum \limits_{i=1}^{l}(y_i - \overline{y})^2} [/math]

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

MAPE, Mean Absolute Percentage Error (средняя абсолютная процентная ошибка)

Mape1.png

[math] MAPE = 100\% \times \dfrac{1}{l}\sum \limits_{i=1}^{l} \dfrac{|y_i - a_i|}{|y_i|} [/math]


Это коэффициент, не имеющий размерности, с очень простой интерпретацией. Его можно измерять в долях или процентах. Если у вас получилось, например, что MAPE=11.4%, то это говорит о том, что ошибка составила 11,4% от фактических значений. Основная проблема данной ошибки — нестабильность.

RMSE, Root Mean Squared Error (корень из средней квадратичной ошибки)

Rmse.jpeg

Примерно такая же проблема, как и в MAPE: так как каждое отклонение возводится в квадрат, любое небольшое отклонение может значительно повлиять на показатель ошибки. Стоит отметить, что существует также ошибка MSE, из которой RMSE как раз и получается путем извлечения корня. Но так как MSE дает расчетные единицы измерения в квадрате, то использовать данную ошибку будет немного неправильно.

SMAPE, Symmetric MAPE (симметричная MAPE)

Smape1.png

MASE, Mean absolute scaled error (cредняя абсолютная масштабированная ошибка)

Mase.png

MASE является очень хорошим вариантом для расчета точности, так как сама ошибка не зависит от масштабов данных и является симметричной: то есть положительные и отрицательные отклонения от факта рассматриваются в равной степени. Обратите внимание, что в мы имеем дело с двумя суммами: та, что в числителе, соответствует тестовой выборке, та, что в знаменателе - обучающей. Вторая фактически представляет собой среднюю абсолютную ошибку прогноза по методу Naive. Она же соответствует среднему абсолютному отклонению ряда в первых разностях. Эта величина, по сути, показывает, насколько обучающая выборка предсказуема. Она может быть равна нулю только в том случае, когда все значения в обучающей выборке равны друг другу, что соответствует отсутствию каких-либо изменений в ряде данных, ситуации на практике почти невозможной. Кроме того, если ряд имеет тендецию к росту либо снижению, его первые разности будут колебаться около некоторого фиксированного уровня. В результате этого по разным рядам с разной структурой, знаменатели будут более-менее сопоставимыми. Всё это, конечно же, является очевидными плюсами MASE, так как позволяет складывать разные значения по разным рядам и получать несмещённые оценки.

Но, конечно же, без минусов нельзя. Проблема MASE в том, что её тяжело интерпретировать. Например, MASE=1.21 ни о чём, по сути, не говорит. Это просто означает, что ошибка прогноза оказалась в 1.21 раза выше среднего абсолютного отклонения ряда в первых разностях, и ничего более.

k-fold кросс-валидация

  1. Обучающая выборка разбивается на [math] k [/math] непересекающихся одинаковых по объему частей;
  2. Производится [math] k [/math] итераций. На каждой итерации происходит следующее:
    1. Модель обучается на [math] k - 1 [/math] части обучающей выборки;
    2. Модель тестируется на части обучающей выборки, которая не участвовала в обучении.

Каждая из [math]k[/math] частей единожды используется для тестирования. Как правило, [math]k = 10[/math] (5 в случае малого размера выборки).

K-fold-validation.png

[math]T^l = F_1 \cup \dots \cup F_k, |F_i| \approx \frac{l}{k}, \\ CV_k = \frac{1}{k} \sum_{i=1}^{k} Q(\mu(T^l \setminus F_i),F_i) \to min [/math].

 # Пример кода для k-fold кросс-валидация:
 
 import numpy as np
 from sklearn.model_selection import StratifiedKFold
 from sklearn.datasets import fetch_openml
 from sklearn.base import clone
 from sklearn.linear_model import SGDClassifier
 
 mnist = fetch_openml('mnist_784', version=1)
 X, y = mnist["data"], mnist["target"]
 some_digit = X[0] # признаки цифры пять
 some_digit_image = some_digit.reshape(28, 28)
 y = y.astype(np.uint8)
 X_train, X_test, y_train, y_test = X[:60000], X[60000:], y[:60000], y[60000:]
 y_train_5 = (y_train == 5) # True для всех пятерок, False для в сех остальных цифр
 y_test_5 = (y_test == 5)
 sgd_clf = SGDClassifier(random_state=42)
 sgd_clf.fit(X_train, y_train_5)
 sgd_clf.predict([some_digit])
 skfolds = StratifiedKFold(n_splits=3, random_state=42)
 for train_index, test_index in skfolds.split(X_train, y_train_5):
 
    clone_clf = clone(sgd_clf)
    X_train_folds = X_train[train_index]
    y_train_folds = y_train_5[train_index]
    X_test_fold = X_train[test_index]
    y_test_fold = y_train_5[test_index]
    clone_clf.fit(X_train_folds, y_train_folds)
    y_pred = clone_clf.predict(X_test_fold)
    n_correct = sum(y_pred == y_test_fold)
    print(n_correct / len(y_pred))
 # print 0.95035, 0.96035, 0.9604

Источники информации

  1. Соколов Е. Семинар по выбору моделей
  2. [1] - Дьяконов А. Функции ошибки / функционалы качества
  3. [2] - Оценка качества прогнозных моделей
  4. [3] - HeinzBr Ошибка прогнозирования: виды, формулы, примеры
  5. [4] - egor_labintcev Метрики в задачах машинного обучения
  6. [5] - grossu Методы оценки качества прогноза
  7. [6] - К.В.Воронцов, Классификация