python - sklearn - Curva de roc y punto de corte. Pitón.
roc curve python (4)
Estoy ejecutando un modelo logístico y predije los valores logit. Solía :
from sklearn import metrics
fpr, tpr, thresholds = metrics.roc_curve(Y_test,p)
Sé que metric.roc_auc_score proporcionará el área debajo de la curva, pero ¿Alguien puede decirme cuál es el comando para 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 (here!) , 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
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]
El post de cgnorthcutt
Dados los umbrales tpr, fpr, de su pregunta, la respuesta para el umbral óptimo es simplemente:
optimo_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]
En este pdf http://www.medicalbiostatistics.com/roccurve.pdf p.6 he encontrado otra posibilidad:
opt_idx = np.argmax(np.sqrt(np.square(1-tpr) + np.square(fpr)))
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]