Кривая Roc и точка отсечки. питон

Я запустил модель логистической регрессии и сделал прогноз значений логита. Я использовал это, чтобы получить точки на кривой ROC:

 from sklearn import metrics
 fpr, tpr, thresholds = metrics.roc_curve(Y_test,p)

Я знаю, что metrics.roc_auc_score дает площадь под кривой ROC. Может кто-нибудь сказать мне, какая команда найдет оптимальную точку отсечения (пороговое значение)?

Ответ 1

Несмотря на то, что поздно ответить, мысль может быть полезна. Вы можете сделать это, используя пакет epi в R (здесь!), однако я не смог найти подобный пакет или пример в python.

Оптимальная точка отсечки будет где true positive rate высокий, а false positive rate низкий. Основываясь на этой логике, я привел пример ниже, чтобы найти оптимальный порог.

Код Python:

import pandas as pd
import statsmodels.api as sm
import pylab as pl
import numpy as np
from sklearn.metrics import roc_curve, auc

# read the data in
df = pd.read_csv("http://www.ats.ucla.edu/stat/data/binary.csv")

# rename the 'rank' column because there is also a DataFrame method called 'rank'
df.columns = ["admit", "gre", "gpa", "prestige"]
# dummify rank
dummy_ranks = pd.get_dummies(df['prestige'], prefix='prestige')
# create a clean data frame for the regression
cols_to_keep = ['admit', 'gre', 'gpa']
data = df[cols_to_keep].join(dummy_ranks.ix[:, 'prestige_2':])

# manually add the intercept
data['intercept'] = 1.0

train_cols = data.columns[1:]
# fit the model
result = sm.Logit(data['admit'], data[train_cols]).fit()
print result.summary()

# Add prediction to dataframe
data['pred'] = result.predict(data[train_cols])

fpr, tpr, thresholds =roc_curve(data['admit'], data['pred'])
roc_auc = auc(fpr, tpr)
print("Area under the ROC curve : %f" % roc_auc)

####################################
# The optimal cut off would be where tpr is high and fpr is low
# tpr - (1-fpr) is zero or near to zero is the optimal cut off point
####################################
i = np.arange(len(tpr)) # index for df
roc = pd.DataFrame({'fpr' : pd.Series(fpr, index=i),'tpr' : pd.Series(tpr, index = i), '1-fpr' : pd.Series(1-fpr, index = i), 'tf' : pd.Series(tpr - (1-fpr), index = i), 'thresholds' : pd.Series(thresholds, index = i)})
roc.ix[(roc.tf-0).abs().argsort()[:1]]

# Plot tpr vs 1-fpr
fig, ax = pl.subplots()
pl.plot(roc['tpr'])
pl.plot(roc['1-fpr'], color = 'red')
pl.xlabel('1-False Positive Rate')
pl.ylabel('True Positive Rate')
pl.title('Receiver operating characteristic')
ax.set_xticklabels([])

Оптимальная точка отсечения составляет 0,317628, поэтому все выше этого может быть помечено как 1 else 0. На выходе/диаграмме видно, что при tpr пересекает 1-fpr, tpr составляет 63%, fpr - 36% и tpr- (1-fpr) ближе всего к нулю в текущем примере.

Вывод:

        1-fpr       fpr        tf     thresholds       tpr
  171  0.637363  0.362637  0.000433    0.317628     0.637795

введите описание изображения здесь

Надеюсь, что это будет полезно.

Изменить

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

Код Python:

def Find_Optimal_Cutoff(target, predicted):
    """ Find the optimal probability cutoff point for a classification model related to event rate
    Parameters
    ----------
    target : Matrix with dependent or target data, where rows are observations

    predicted : Matrix with predicted data, where rows are observations

    Returns
    -------     
    list type, with optimal cutoff value

    """
    fpr, tpr, threshold = roc_curve(target, predicted)
    i = np.arange(len(tpr)) 
    roc = pd.DataFrame({'tf' : pd.Series(tpr-(1-fpr), index=i), 'threshold' : pd.Series(threshold, index=i)})
    roc_t = roc.ix[(roc.tf-0).abs().argsort()[:1]]

    return list(roc_t['threshold']) 


# Add prediction probability to dataframe
data['pred_proba'] = result.predict(data[train_cols])

# Find optimal probability threshold
threshold = Find_Optimal_Cutoff(data['admit'], data['pred_proba'])
print threshold
# [0.31762762459360921]

# Find prediction to the dataframe applying threshold
data['pred'] = data['pred_proba'].map(lambda x: 1 if x > threshold else 0)

# Print confusion Matrix
from sklearn.metrics import confusion_matrix
confusion_matrix(data['admit'], data['pred'])
# array([[175,  98],
#        [ 46,  81]])

Ответ 2

Учитывая tpr, fpr, пороги из вашего вопроса, ответ для оптимального порога справедлив:

optimal_idx = np.argmax(tpr - fpr)
optimal_threshold = thresholds[optimal_idx]

Ответ 3

Vanilla Python Реализация показателя Youden J-Score

def cutoff_youdens_j(fpr,tpr,thresholds):
    j_scores = tpr-fpr
    j_ordered = sorted(zip(j_scores,thresholds))
    return j_ordered[-1][1]

Ответ 4

Должность cgnorthcutt

Учитывая tpr, fpr, пороги из вашего вопроса, ответ для оптимального порога просто:

оптимальный_идекс = np.argmax(tpr - fpr) оптимальный_порог = пороговые значения [оптимальный_идекс]

почти правильно. Значение абс должно быть принято.

optimal_idx = np.argmin(np.abs(tpr - fpr)) // Edit: Change to argmin!
optimal_threshold = thresholds[optimal_idx]

Согласно упомянутой ссылке → http://www.medicalbiostatistics.com/roccurve.pdf стр .6 Я нашел другую возможность:

opt_idx = np.argmin(np.sqrt(np.square(1-tpr) + np.square(fpr)))