Curva de roc y punto de corte. Pitón

Ejecuté un modelo de regresión logística e hice predicciones de los valores logit. Usé esto para obtener los puntos en la curva ROC:

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

Sé que metrics.roc_auc_score da el área bajo la curva ROC. ¿Alguien puede decirme qué comando encontrará el punto de corte óptimo (valor de umbral)?

Aunque es tarde para responder, el pensamiento podría ser útil. Puedes hacerlo usando el paquete epi en R (¡aquí!) , Sin embargo, no pude encontrar un paquete o ejemplo similar en python.

El punto de corte óptimo sería donde true positive rate es alta y la false positive rate es baja . Basado en esta lógica, he sacado un ejemplo a continuación para encontrar el umbral óptimo.

Código 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([]) 

El punto de corte óptimo es 0.317628, por lo que cualquier cosa por encima de esto se puede etiquetar como 1 más 0. En la salida / gráfica puede ver que donde tpr se cruza 1-fpr, tpr es 63%, fpr es 36% y tpr- ( 1-fpr) es el más cercano a cero en el ejemplo actual.

Salida:

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

introduzca la descripción de la imagen aquí

Espero que esto sea de ayuda.

Editar

Para simplificar y traer reutilización, he hecho una función para encontrar el punto de corte de probabilidad óptimo.

Código 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]]) 

Dados los umbrales tpr, fpr, de su pregunta, la respuesta para el umbral óptimo es simplemente:

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

Implementación Vanilla Python de la puntuación J de Youden

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

El post de cgnorthcutt

Dados los umbrales tpr, fpr, de su pregunta, la respuesta para el umbral óptimo es simplemente:

óptimo_idx = np.argmax (tpr – fpr) optimo umbral = umbrales [optimo_idx]

es casi correcto El valor de abs debe ser tomado.

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

Según la referencia mencionada -> http://www.medicalbiostatistics.com/roccurve.pdf p.6 He encontrado otra posibilidad:

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