Обзор

  • Точность и полнота — две важные, но неправильно понимаемые темы в машинном обучении.
  • Мы обсудим, что такое точность и полнота, как они работают и их роль в оценке модели машинного обучения.
  • Мы также получим представление о терминах площади под кривой (AUC) и точности.

Введение

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

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

Итак, давайте установим рекорд прямо в этой статье.

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

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

Но как это сделать? В этой статье мы рассмотрим метрики оценки классификации, сосредоточив внимание на точности и полноте. Мы также узнаем, как рассчитать эти показатели в Python, взяв набор данных и простой алгоритм классификации. Итак, приступим!

Подробнее о показателях оценки можно узнать здесь — Показатели оценки для моделей машинного обучения.

Оглавление

  1. Понимание постановки задачи
  2. Что такое точность?
  3. Что такое вспомнить?
  4. Самый простой показатель оценки — точность
  5. Роль F1-Score
  6. Знаменитый компромисс между точностью и отзывом
  7. Понимание площади под кривой (AUC)

Понимание постановки задачи

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

Давайте возьмем популярный набор данных о сердечных заболеваниях, доступный в репозитории UCI. Здесь мы должны предсказать, страдает ли пациент сердечным заболеванием или не использует данный набор функций. Вы можете скачать чистый набор данных здесь.

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

Как всегда, начнем с импорта необходимых библиотек и пакетов:

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report
from sklearn.metrics import roc_curve
from sklearn.metrics import roc_auc_score
from sklearn.metrics import precision_recall_curve
from sklearn.metrics import auc
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

Затем давайте посмотрим на данные и целевые переменные, с которыми мы имеем дело:

data_file_path = '../input/heart-disease-uci/heart.csv'
data_df = pd.read_csv(data_file_path)

#To get information on the number of entries and the datatypes of the features
data_df.head()

Давайте проверим, есть ли у нас пропущенные значения:

data_df.isnull().sum()

Пропущенных значений нет. Теперь мы можем посмотреть, сколько пациентов действительно страдают сердечными заболеваниями (1), а сколько нет (0):

#2. distribution of target variable.
sns.countplot(data_df['target'])

# Add labels
plt.title('Countplot of Target')
plt.xlabel('target')
plt.ylabel('Patients')
plt.show()

Это график подсчета ниже:

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

y = data_df["target"].values
x = data_df.drop(["target"], axis = 1)

#Scaling - mandatory for knn
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
x = ss.fit_transform(x)

#Splitting into train and test
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size = 0.3) # 70% training and 30% test

Интуиция, стоящая за выбором наилучшего значения k, выходит за рамки этой статьи, но мы должны знать, что можем определить оптимальное значение k, когда получим наивысший результат теста для этого значения. Для этого мы можем оценить результаты обучения и тестирования до 20 ближайших соседей:

train_score = []
test_score = []
k_vals = []

for k in range(1, 21):
    k_vals.append(k)
    knn = KNeighborsClassifier(n_neighbors = k)
    knn.fit(X_train, y_train)
    
    tr_score = knn.score(X_train, y_train)
    train_score.append(tr_score)
    
    te_score = knn.score(X_test, y_test)
    test_score.append(te_score)

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

## score that comes from the testing set only
max_test_score = max(test_score)
test_scores_ind = [i for i, v in enumerate(test_score) if v == max_test_score]
print('Max test score {} and k = {}'.format(max_test_score * 100, list(map(lambda x: x + 1, test_scores_ind))))

Таким образом, мы получили оптимальное значение k равное 3, 11 или 20 с оценкой 83,5. Мы завершим одно из этих значений и соответствующим образом подгоним модель:

#Setup a knn classifier with k neighbors
knn = KNeighborsClassifier(3)

knn.fit(X_train, y_train)
knn.score(X_test, y_test)

Теперь, как мы оцениваем, является ли эта модель хорошей моделью или нет? Для этого мы используем так называемую матрицу путаницы:

y_pred = knn.predict(X_test)
confusion_matrix(y_test,y_pred)
pd.crosstab(y_test, y_pred, rownames = ['Actual'], colnames =['Predicted'], margins = True)

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

Из наших обучающих и тестовых данных мы уже знаем, что наши тестовые данные состоят из 91 точки данных. Это значение 3-й строки и 3-го столбца в конце. Мы также замечаем, что есть некоторые фактические и прогнозируемые значения. Фактические значения — это количество точек данных, которые изначально были отнесены к категории 0 или 1. Прогнозируемые значения — это количество точек данных, которые наша модель KNN предсказала как 0 или 1.

Фактические значения:

  • Пациенты, у которых на самом деле нет болезни сердца = 41
  • Пациенты, у которых действительно есть болезнь сердца = 50

Прогнозируемые значения:

  • Количество пациентов, у которых прогнозировалось отсутствие болезни сердца = 40.
  • Количество пациентов с прогнозируемым заболеванием сердца = 51.

Все значения, которые мы получили выше, имеют терм. Давайте рассмотрим их один за другим:

  1. Случаи, в которых у пациентов на самом деле не было болезней сердца, и наша модель также предсказывала их отсутствие, называются Истинно отрицательными результатами. Для нашей матрицы истинно отрицательные случаи = 33.
  2. Случаи, в которых у пациентов действительно есть заболевание сердца, и наша модель также предсказала его наличие, называются Истинно положительные результаты. Для нашей матрицы истинно положительные результаты = 43.
  3. Однако бывают случаи, когда у пациента на самом деле нет болезни сердца, но наша модель предсказала, что она есть. Этот тип ошибки является ошибкой типа I, и мы называем значения как Ложные срабатывания. Для нашей матрицы ложные срабатывания = 8
  4. Точно так же бывают случаи, когда у пациента действительно есть заболевание сердца, но наша модель предсказала, что у него его нет. Этот тип ошибки является ошибкой типа II, и мы называем значения как Ложноотрицательные. Для нашей матрицы Ложноотрицательные = 7

Что такое точность?

Итак, теперь мы подходим к сути этой статьи. Что такое Точность? И при чем здесь все вышеперечисленное?

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

Какова точность нашей модели? Да, это 0,843 или, когда он предсказывает наличие у пациента болезни сердца, он верен примерно в 84% случаев.

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

Что такое вспомнить?

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

Для нашей модели Recall = 0,86. Отзыв также дает меру того, насколько точно наша модель способна идентифицировать соответствующие данные. Мы называем это чувствительностью или истинной положительной скоростью. Что, если у пациента есть заболевание сердца, но ему/ей не назначено лечение, потому что так предсказывала наша модель? Это ситуация, которую мы хотели бы избежать!

Самый простой для понимания показатель — точность

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

Для нашей модели Точность будет = 0,835.

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

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

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

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

Роль F1-Score

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

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

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

В таких случаях мы используем то, что называется F1-score. F1-оценка представляет собой гармоническое среднее точности и полноты:

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

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

print(classification_report(y_test, y_pred))

ROC-кривая

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

  1. Коэффициент ложных срабатываний (FPR): это отношение ложных срабатываний к фактическому количеству отрицательных результатов. В контексте нашей модели это мера того, сколько случаев модель предсказывает, что у пациента есть заболевание сердца, из всех пациентов, у которых на самом деле не было заболевания сердца. Для наших данных FPR = 0,195.
  2. Доля истинно отрицательных результатов (TNR) или специфичность: это соотношение истинно отрицательных результатов и фактического количества отрицательных результатов. Для нашей модели это мера того, сколько случаев модель правильно предсказала, что у пациента нет болезни сердца, из всех пациентов, у которых на самом деле не было болезни сердца. TNR для приведенных выше данных = 0,804. Из этих 2-х определений мы также можем сделать вывод, что Специфичность или TNR = 1 — FPR

Мы также можем визуализировать точность и полноту, используя кривые ROC и кривые PRC.

1. Кривые ROC (кривая рабочих характеристик приемника)

Это график между TPR (ось Y) и FPR (ось X). Поскольку наша модель классифицирует пациента как страдающего сердечным заболеванием или нет на основе вероятностей, сгенерированных для каждого класса, мы также можем определить порог вероятностей.

Например, мы хотим установить пороговое значение 0,4. Это означает, что модель будет классифицировать точку данных/пациента как страдающего сердечным заболеванием, если вероятность наличия у пациента сердечного заболевания больше 0,4. Это, очевидно, даст высокое значение отзыва и уменьшит количество ложных срабатываний. Точно так же мы можем визуализировать, как наша модель работает для разных пороговых значений, используя кривую ROC.

Давайте создадим кривую ROC для нашей модели с k = 3.

y_pred_proba = knn.predict_proba(X_test)[:,1]
fpr, tpr, thresholds = roc_curve(y_test, y_pred_proba)

Интерпретация AUC-

  • В самой нижней точке, т.е. в (0, 0) - порог устанавливается равным 1,0. Это означает, что наша модель классифицирует всех пациентов как не имеющих заболевания сердца.
  • В самой высокой точке, то есть в (1, 1), порог устанавливается на 0,0. Это означает, что наша модель классифицирует всех пациентов как страдающих сердечными заболеваниями.
  • Остальная часть кривой представляет собой значения FPR и TPR для пороговых значений от 0 до 1. При некотором пороговом значении мы наблюдаем, что для FPR, близкого к 0, мы достигаем TPR, близкого к 1. Это когда модель будет почти идеально предсказывать пациентов, страдающих сердечными заболеваниями.
  • Область с кривой и осями в качестве границ называется площадью под кривой (AUC). Именно эта площадь считается показателем хорошей модели. С этим показателем в диапазоне от 0 до 1 мы должны стремиться к высокому значению AUC. Модели с высокой AUC называются моделями с хорошим навыком. Давайте вычислим показатель AUC нашей модели и приведенного выше графика:
roc_auc_score(y_test, y_pred_proba)

  • Мы получаем значение 0,868 в качестве AUC, что является довольно хорошим показателем! Проще говоря, это означает, что модель сможет различать пациентов с сердечными заболеваниями и тех, у кого их нет, в 87% случаев. Мы можем улучшить этот показатель, и я призываю вас попробовать разные значения гиперпараметров.
  • Диагональная линия — это случайная модель с AUC 0,5, модель без навыков, которая точно так же делает случайный прогноз. Можете ли вы догадаться, почему?

2. Кривая точности-отзыва (PRC)

Как следует из названия, эта кривая является прямым представлением точности (ось Y) и полноты (ось X). Если вы обратите внимание на наши определения и формулы для точности и полноты, приведенные выше, вы заметите, что мы ни в коем случае не используем истинные отрицания (фактическое количество людей, у которых нет сердечных заболеваний).

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

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

precision, recall, thresholds = precision_recall_curve(y_test, y_pred_proba)

plt.figure(figsize = (10,8))
plt.plot([0, 1], [0.5, 0.5],'k--')
plt.plot(recall, precision, label = 'Knn')
plt.xlabel('recall')
plt.ylabel('precision')
plt.title('Knn(n_neighbors = 8) PRC curve')
plt.show()

Интерпретация КНР:

  • В самой нижней точке, т.е. в (0, 0) - порог устанавливается равным 1,0. Это означает, что наша модель не делает различий между пациентами с заболеваниями сердца и пациентами без них.
  • В самой высокой точке, то есть в (1, 1), порог устанавливается на 0,0. Это означает, что и наша точность, и отзыв высоки, и модель прекрасно различает.
  • Остальная часть кривой — это значения Precision и Recall для пороговых значений от 0 до 1. Наша цель — сделать кривую как можно ближе к (1, 1), что означает хорошую точность и полноту.
  • Подобно ROC, область с кривой и осями в качестве границ является площадью под кривой (AUC). Рассматривайте эту площадь как показатель хорошей модели. AUC колеблется от 0 до 1. Поэтому мы должны стремиться к высокому значению AUC. Давайте вычислим AUC для нашей модели и приведенного выше графика:
# calculate precision-recall AUC
auc_prc = auc(recall, precision)
print(auc_prc)

Как и прежде, мы получаем хороший AUC около 90%. Кроме того, модель может достичь высокой точности с полнотой, равной 0, и добиться высокой полноты, поставив под угрозу точность 50%.

Конечные примечания

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

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

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

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

Первоначально опубликовано на https://www.analyticsvidhya.com 3 сентября 2020 г.