Curva ROC (receiver operating characteristic): Demonstra a performance entre diferentes limites de probabilidades para predição de um modelo de classificação, entre as taxas de verdadeiro positivo e falso positivo.
O padrão para os modelos de probabilidades é a divisão de 0.5 ou 50% para definição de uma classe, caso o resultado da classe apresente valor menor que o limite (0.0 à 0.49) o resultado (binário) será 0, caso contrário, se der maior que o limite (0.5 à 1) o resultado será 1. Porém, esse valor de limite ou conhecido também como threshold pode ser ajustado, de acordo com o comportamento desejado para as predições.
Esse comportamento desejado tem a ver com dois tipos de erros, que podem ocorrer:
Por exemplo, eu vou desenvolver um modelo para realizar previsões de pessoas com pneumonia, vamos supor duas situações:
Qual das duas situações é "menos pior"? Melhor ser diagnosticada pelo Falso Positivo com a doença, mesmo não tendo, pois nesse caso a chance de sobreviver é maior, do que ter a doença e não ser tratado por causa do Falso Negativo.
Assim podemos alterar os limites, minimizando as chances de Falsos Negativos.
Precisamos realizar os seguintes cálculos:
$$TPR = {TP \over TP + FN}$$Isso descreve o quão bom nosso modelo é acertar a previsão das classes positivas, quando a saída for positiva. O TPR também é conhecido como Sensitivity ou Sensibilidade.
$$FPR = {FP \over FP + TN}$$Também conhecido como taxa de alarmes falsos, que é a frequência de classes positivas previstas, quando resultado verdadeiro é negativo. Pode-se calcular como o inverso da Specificity ou Especificidade.
$$Specificity = {TN \over TN + FP}$$Onde:
$$FPR = {1 - Specificity}$$Vamos desenvolver um modelo ficticio, criando um fake dataset com a biblioteca sklearn.datasets e utilizaremos dois modelos para testarmos, um modelo de Regressão logística e um modelo de Floresta Aleatória.
Separaremos o conjunto de dados com train_test_split e o plot será com base no predict_proba ou seja a probabilidade da saída ser de uma classe ou outra.
# importando as bibliotecas
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_curve
from sklearn.metrics import roc_auc_score
import matplotlib.pyplot as plt
# gerando um dataset com duas classes para demonstração
X, y = make_classification(n_samples=1000, n_classes=2, random_state=1)
# separando em treino e teste
Xtrain, Xtest, ytrain, ytest = train_test_split(X, y, test_size=0.5, random_state=2)
# gerando uma baseline
baseline = [0 for _ in range(len(ytest))]
# instanciando o modelo
model_lr = LogisticRegression(solver='lbfgs')
model_rf = RandomForestClassifier(n_estimators=1000)
# treinando o modelo
model_lr.fit(Xtrain, ytrain)
model_rf.fit(Xtrain, ytrain)
# prevendo as probabilidades
lr_probs = model_lr.predict_proba(Xtest)
rf_probs = model_rf.predict_proba(Xtest)
# mantendo as probabilidades somente para saída positiva
lr_probs_pos = lr_probs[:, 1]
rf_probs_pos = rf_probs[:, 1]
# calculando os scores
baseline_auc = roc_auc_score(ytest, baseline)
lr_auc = roc_auc_score(ytest, lr_probs_pos)
rf_auc = roc_auc_score(ytest, rf_probs_pos)
# printando os scores
print(f'Baseline: ROC AUC = {baseline_auc :.3f}')
print(f'Logistic: ROC AUC = {lr_auc :.3f}')
print(f'Random Forest: ROC AUC = {rf_auc :.3f}')
# calculando a curva ROC
base_fpr, base_tpr, _ = roc_curve(ytest, baseline)
lr_fpr, lr_tpr, _ = roc_curve(ytest, lr_probs_pos)
rf_fpr, rf_tpr, _ = roc_curve(ytest, rf_probs_pos)
# configurando a área de plotagem
plt.figure(figsize=(8, 6))
# plotando a curva ROC
plt.plot(base_fpr, base_tpr, linestyle='--', label='Baseline')
plt.plot(lr_fpr, lr_tpr, linestyle='-', label='Logistic')
plt.plot(rf_fpr, rf_tpr, linestyle='-', label='Random Forest')
# rotulando os eixos
plt.xlabel('Taxa de Falsos Positivos')
plt.ylabel('Taxa de Verdadeiros Positivos')
# inserindo o titulo
plt.title('Curva ROC', fontsize=20)
# mostrando a legenda
plt.legend()
# plotando
plt.show()
Podemos observar que os dois modelos apresentaram bons resultados, quanto mais acima à esquerda melhor será a performance do modelo. Avaliar as probabilidades de cada classe, se torna mais flexivel em função de poder calibrar os limites para o resultado desejado.