В этом уроке мы пройдемся по нескольким метрикам классификации в Scikit-Learn Python и напишем наши собственные функции с нуля, чтобы понять математику, стоящую за некоторыми из них.
Одной из основных областей прогнозного моделирования в науке о данных является классификация. Классификация состоит в попытке предсказать, из какого класса поступает конкретная выборка из популяции. Например, если мы пытаемся предсказать, будет ли конкретный пациент повторно госпитализирован, два возможных класса: стационарный (положительный) и не госпитализированный (отрицательный). Затем модель классификации пытается предсказать, будет ли каждый пациент госпитализирован или не госпитализирован. Другими словами, классификация просто пытается предсказать, какой сегмент (прогнозируемый положительный или предсказанный отрицательный) должен быть размещен конкретной выборкой из совокупности, как показано ниже.
Когда вы тренируете свою классификационную прогностическую модель, вы захотите оценить, насколько она хороша. Интересно, что существует множество разных способов оценки производительности. Большинство исследователей данных, которые используют Python для прогнозного моделирования, используют пакет Python, называемый scikit-learn. Scikit-learn содержит множество встроенных функций для анализа производительности моделей. В этом уроке мы рассмотрим некоторые из этих метрик и напишем наши собственные функции с нуля, чтобы понять математику, лежащую в основе некоторых из них. Если вы предпочитаете просто прочитать о показателях производительности, см. Мой предыдущий пост на Вот,
Этот учебник будет охватывать следующие показатели изsklearn.metrics
:
Для примера набора данных и ноутбука Jupyter, пожалуйста, посетите мой GitHub Вот, Мы напишем наши собственные функции с нуля, предполагая двухклассовую классификацию. Обратите внимание, что вам нужно будет заполнить части, помеченные как# your code here
Давайте загрузим образец набора данных, который имеет фактические метки (actual_label) и вероятности прогнозирования для двух моделей (model_RF и model_LR). Здесь вероятности - это вероятность быть 1-м классом.
import pandas as pd
df = pd.read_csv('data.csv')
df.head()
В большинстве проектов по науке о данных вы будете определять пороговое значение, чтобы определить, какие вероятности прогнозирования помечены как прогнозируемый положительный или предсказанный отрицательный. А пока давайте предположим, что порог равен 0,5. Давайте добавим два дополнительных столбца, которые преобразуют вероятности в предсказанные метки.
thresh = 0.5
df['predicted_RF'] = (df.model_RF >= 0.5).astype('int')
df['predicted_LR'] = (df.model_LR >= 0.5).astype('int')
df.head()
Учитывая фактическую метку и прогнозируемую метку, первое, что мы можем сделать, это разделить наши выборки на 4 сегмента:
Эти сегменты могут быть представлены следующим изображением (первоисточник https://en.wikipedia.org/wiki/Precision_and_recall#/media/File:Precisionrecall.svg) и мы будем ссылаться на это изображение во многих расчетах ниже.
Эти сегменты также могут отображаться с использованием матрицы путаницы, как показано ниже:
Мы можем получить матрицу путаницы (в виде массива 2x2) из scikit-learn, которая принимает в качестве входных данных фактические метки и предсказанные метки
from sklearn.metrics import confusion_matrixconfusion_matrix(df.actual_label.values, df.predicted_RF.values)
где было 5047 истинных положительных результатов, 2360 ложных положительных результатов, 2832 ложных отрицательных и 5519 истинных отрицательных. Давайте определим наши собственные функции для проверкиconfusion_matrix
, Обратите внимание, что я заполнил первый, а вам нужно заполнить остальные 3.
def find_TP(y_true, y_pred):
# counts the number of true positives (y_true = 1, y_pred = 1)
return sum((y_true == 1) & (y_pred == 1))
def find_FN(y_true, y_pred):
# counts the number of false negatives (y_true = 1, y_pred = 0)
return # your code here
def find_FP(y_true, y_pred):
# counts the number of false positives (y_true = 0, y_pred = 1)
return # your code here
def find_TN(y_true, y_pred):
# counts the number of true negatives (y_true = 0, y_pred = 0)
return # your code here
Вы можете проверить свои результаты на соответствие
print('TP:',find_TP(df.actual_label.values, df.predicted_RF.values))
print('FN:',find_FN(df.actual_label.values, df.predicted_RF.values))
print('FP:',find_FP(df.actual_label.values, df.predicted_RF.values))
print('TN:',find_TN(df.actual_label.values, df.predicted_RF.values))
Давайте напишем функцию, которая вычислит все четыре из них для нас, и другую функцию для дублированияconfusion_matrix
import numpy as np
def find_conf_matrix_values(y_true,y_pred):
# calculate TP, FN, FP, TN
TP = find_TP(y_true,y_pred)
FN = find_FN(y_true,y_pred)
FP = find_FP(y_true,y_pred)
TN = find_TN(y_true,y_pred)
return TP,FN,FP,TN
def my_confusion_matrix(y_true, y_pred):
TP,FN,FP,TN = find_conf_matrix_values(y_true,y_pred)
return np.array([[TN,FP],[FN,TP]])
Проверьте соответствие результатов с
my_confusion_matrix(df.actual_label.values, df.predicted_RF.values)
Вместо того, чтобы сравнивать вручную, давайте проверим, что наши функции работают, используя встроенные в Pythonassert
и Numpy'sarray_equal
функции
assert np.array_equal(my_confusion_matrix(df.actual_label.values, df.predicted_RF.values), confusion_matrix(df.actual_label.values, df.predicted_RF.values) ), 'my_confusion_matrix() is not correct for RF'assert np.array_equal(my_confusion_matrix(df.actual_label.values, df.predicted_LR.values),confusion_matrix(df.actual_label.values, df.predicted_LR.values) ), 'my_confusion_matrix() is not correct for LR'
Учитывая эти четыре сегмента (TP, FP, FN, TN), мы можем вычислить многие другие показатели производительности.
Наиболее распространенным показателем для классификации является точность, то есть доля выборок, правильно спрогнозированных, как показано ниже:
Мы можем получить оценку точности из scikit-learn, которая принимает в качестве входных данных фактические метки и прогнозируемые метки.
from sklearn.metrics import accuracy_scoreaccuracy_score(df.actual_label.values, df.predicted_RF.values)
Ваш ответ должен быть 0.6705165630156111
Определите свою собственную функцию, которая дублируетaccuracy_score
, используя формулу выше.
def my_accuracy_score(y_true, y_pred):
# calculates the fraction of samples predicted correctly
TP,FN,FP,TN = find_conf_matrix_values(y_true,y_pred)
return # your code hereassert my_accuracy_score(df.actual_label.values, df.predicted_RF.values) == accuracy_score(df.actual_label.values, df.predicted_RF.values), 'my_accuracy_score failed on RF'
assert my_accuracy_score(df.actual_label.values, df.predicted_LR.values) == accuracy_score(df.actual_label.values, df.predicted_LR.values), 'my_accuracy_score failed on LR'
print('Accuracy RF: %.3f'%(my_accuracy_score(df.actual_label.values, df.predicted_RF.values)))
print('Accuracy LR: %.3f'%(my_accuracy_score(df.actual_label.values, df.predicted_LR.values)))
Используя точность в качестве показателя производительности, модель RF является более точной (0,67), чем модель LR (0,62). Так что мы должны остановиться здесь и сказать, что модель RF - лучшая модель? Нет! Точность не всегда является наилучшей метрикой для оценки моделей классификации. Например, допустим, что мы пытаемся предсказать то, что происходит только 1 из 100 раз. Мы могли бы построить модель, которая получит точность 99%, сказав, что событие никогда не происходило. Тем не менее, мы ловим 0% событий, которые нас интересуют. Показатель 0% здесь является еще одним показателем производительности, известным как отзыв
Напомним (также известный как чувствительность) является доля положительных событий, которые вы правильно предсказали, как показано ниже:
Мы можем получить оценку точности из scikit-learn, которая принимает в качестве входных данных фактические метки и прогнозируемые метки.
from sklearn.metrics import recall_scorerecall_score(df.actual_label.values, df.predicted_RF.values)
Определите свою собственную функцию, которая дублируетrecall_score
, используя формулу выше.
def my_recall_score(y_true, y_pred):
# calculates the fraction of positive samples predicted correctly
TP,FN,FP,TN = find_conf_matrix_values(y_true,y_pred)
return # your code hereassert my_recall_score(df.actual_label.values, df.predicted_RF.values) == recall_score(df.actual_label.values, df.predicted_RF.values), 'my_accuracy_score failed on RF'
assert my_recall_score(df.actual_label.values, df.predicted_LR.values) == recall_score(df.actual_label.values, df.predicted_LR.values), 'my_accuracy_score failed on LR'
print('Recall RF: %.3f'%(my_recall_score(df.actual_label.values, df.predicted_RF.values)))
print('Recall LR: %.3f'%(my_recall_score(df.actual_label.values, df.predicted_LR.values)))
Один из способов повысить отзыв - увеличить количество выборок, которые вы определяете как прогнозируемые положительные, путем снижения порога для прогнозируемых положительных результатов. К сожалению, это также увеличит количество ложных срабатываний. Другой показатель производительности, называемый точностью, учитывает это.
Точность - это доля ожидаемых положительных событий, которые на самом деле являются положительными, как показано ниже:
Мы можем получить оценку точности из scikit-learn, которая принимает в качестве входных данных фактические метки и прогнозируемые метки.
from sklearn.metrics import precision_scoreprecision_score(df.actual_label.values, df.predicted_RF.values)
Определите свою собственную функцию, которая дублируетprecision_score
, используя формулу выше.
def my_precision_score(y_true, y_pred):
# calculates the fraction of predicted positives samples that are actually positive
TP,FN,FP,TN = find_conf_matrix_values(y_true,y_pred)
return # your code hereassert my_precision_score(df.actual_label.values, df.predicted_RF.values) == precision_score(df.actual_label.values, df.predicted_RF.values), 'my_accuracy_score failed on RF'
assert my_precision_score(df.actual_label.values, df.predicted_LR.values) == precision_score(df.actual_label.values, df.predicted_LR.values), 'my_accuracy_score failed on LR'
print('Precision RF: %.3f'%(my_precision_score(df.actual_label.values, df.predicted_RF.values)))
print('Precision LR: %.3f'%(my_precision_score(df.actual_label.values, df.predicted_LR.values)))
В этом случае, похоже, что радиочастотная модель лучше как по отзыву, так и по точности. Но что бы вы сделали, если бы одна модель лучше запоминалась, а другая была точнее. Один метод, который используют некоторые ученые данных, называют счетом F1.
Оценка f1 является гармоническим средним значением запоминания и точности, с более высокой оценкой в качестве лучшей модели. Оценка f1 рассчитывается по следующей формуле:
Мы можем получить оценку f1 из scikit-learn, которая принимает в качестве входных данных фактические метки и прогнозируемые метки
from sklearn.metrics import f1_scoref1_score(df.actual_label.values, df.predicted_RF.values)
Определите свою собственную функцию, которая дублируетf1_score
, используя формулу выше.
def my_f1_score(y_true, y_pred):
# calculates the F1 score
recall = my_recall_score(y_true,y_pred)
precision = my_precision_score(y_true,y_pred)
return # your code hereassert my_f1_score(df.actual_label.values, df.predicted_RF.values) == f1_score(df.actual_label.values, df.predicted_RF.values), 'my_accuracy_score failed on RF'
assert my_f1_score(df.actual_label.values, df.predicted_LR.values) == f1_score(df.actual_label.values, df.predicted_LR.values), 'my_accuracy_score failed on LR'
print('F1 RF: %.3f'%(my_f1_score(df.actual_label.values, df.predicted_RF.values)))
print('F1 LR: %.3f'%(my_f1_score(df.actual_label.values, df.predicted_LR.values)))
До сих пор мы предполагали, что мы определили порог 0,5 для выбора, какие образцы прогнозируются как положительные Если мы изменим этот порог, показатели производительности изменятся. Как показано ниже:
print('scores with threshold = 0.5')
print('Accuracy RF: %.3f'%(my_accuracy_score(df.actual_label.values, df.predicted_RF.values)))
print('Recall RF: %.3f'%(my_recall_score(df.actual_label.values, df.predicted_RF.values)))
print('Precision RF: %.3f'%(my_precision_score(df.actual_label.values, df.predicted_RF.values)))
print('F1 RF: %.3f'%(my_f1_score(df.actual_label.values, df.predicted_RF.values)))
print(' ')
print('scores with threshold = 0.25')
print('Accuracy RF: %.3f'%(my_accuracy_score(df.actual_label.values, (df.model_RF >= 0.25).astype('int').values)))
print('Recall RF: %.3f'%(my_recall_score(df.actual_label.values, (df.model_RF >= 0.25).astype('int').values)))
print('Precision RF: %.3f'%(my_precision_score(df.actual_label.values, (df.model_RF >= 0.25).astype('int').values)))
print('F1 RF: %.3f'%(my_f1_score(df.actual_label.values, (df.model_RF >= 0.25).astype('int').values)))
Как мы оцениваем модель, если мы не выбрали порог? Одним из наиболее распространенных методов является использование кривой рабочих характеристик приемника (ROC).
Кривые ROC ОЧЕНЬ помогают понять баланс между истинно положительными показателями и ложноположительными показателями. Sci-kit learn имеет встроенные функции для кривых ROC и их анализа. Входы в эти функции (roc_curve
а такжеroc_auc_score
) фактические метки и прогнозируемые вероятности (не прогнозируемые метки). И то и другоеroc_curve
а такжеroc_auc_score
обе сложные функции, поэтому мы не будем писать эти функции с нуля. Вместо этого мы покажем вам, как использовать функции Sci-Kit Learn и объясним ключевые моменты. Давайте начнем с использованияroc_curve
сделать сюжет РПЦ.
from sklearn.metrics import roc_curvefpr_RF, tpr_RF, thresholds_RF = roc_curve(df.actual_label.values, df.model_RF.values)
fpr_LR, tpr_LR, thresholds_LR = roc_curve(df.actual_label.values, df.model_LR.values)
roc_curve
Функция возвращает три списка:
Мы можем построить кривую ROC для каждой модели, как показано ниже.
import matplotlib.pyplot as pltplt.plot(fpr_RF, tpr_RF,'r-',label = 'RF')
plt.plot(fpr_LR,tpr_LR,'b-', label= 'LR')
plt.plot([0,1],[0,1],'k-',label='random')
plt.plot([0,0,1,1],[0,1,1,1],'g-',label='perfect')
plt.legend()
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.show()
Есть несколько вещей, которые мы можем наблюдать из этой фигуры:
Для анализа производительности мы будем использовать метрику площади под кривой.
from sklearn.metrics import roc_auc_scoreauc_RF = roc_auc_score(df.actual_label.values, df.model_RF.values)
auc_LR = roc_auc_score(df.actual_label.values, df.model_LR.values)print('AUC RF:%.3f'% auc_RF)
print('AUC LR:%.3f'% auc_LR)
Как вы можете видеть, площадь под кривой для модели RF (AUC = 0,738) лучше, чем LR (AUC = 0,666). Когда я строю кривую ROC, мне нравится добавлять AUC к легенде, как показано ниже.
import matplotlib.pyplot as plt
plt.plot(fpr_RF, tpr_RF,'r-',label = 'RF AUC: %.3f'%auc_RF)
plt.plot(fpr_LR,tpr_LR,'b-', label= 'LR AUC: %.3f'%auc_LR)
plt.plot([0,1],[0,1],'k-',label='random')
plt.plot([0,0,1,1],[0,1,1,1],'g-',label='perfect')
plt.legend()
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.show()
В целом, в этом игрушечном примере модель RF побеждает с каждым показателем производительности.
В прогнозирующей аналитике при выборе между двумя моделями важно выбрать одну метрику производительности. Как вы видите здесь, вы можете выбирать из множества (точность, отзыв, точность, f1-оценка, AUC и т. Д.). В конечном счете, вы должны использовать метрику производительности, которая наиболее подходит для рассматриваемой бизнес-задачи. Многие исследователи данных предпочитают использовать AUC для анализа производительности каждой модели, поскольку она не требует выбора порога и помогает сбалансировать истинный положительный показатель и ложноположительный показатель.
Пожалуйста, оставьте комментарий, если у вас есть предложения, как улучшить этот учебник.