Uma breve descrição e uso da Curva ROC para Classificação

Definição

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.

Probabilidades

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:

  • Falso Positivo: A saída é verdadeira quando na realidade não é.
  • Falso Negativo: A saída não é verdadeira quando na realidade é.

Por exemplo, eu vou desenvolver um modelo para realizar previsões de pessoas com pneumonia, vamos supor duas situações:

  1. O modelo diz que a pessoa "A" TEM pneumonia quando na verdade não tem, então se eu confiar no modelo a pessoa será medicada e tratada, sem ter a doença.
  2. O modelo diz que a pessoa "B" NÃO tem pneumonia quando na verdade ela tem, então se eu confiar nessa saida, o que acontecerá com a pessoa se a doença for grave?

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.

Do que precisamos para plotar a Curva ROC?

Precisamos realizar os seguintes cálculos:

$$TPR = {TP \over TP + FN}$$
  • TPR: *True Positive Rate** ou Taxa de Verdadeiros Positivos
  • TP: True Positive ou Verdadeiros Positivos
  • FN: False Negative ou Falsos Negativos

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}$$
  • FPR: *False Negative Rate** ou Taxa de Falsos Negativos
  • FP: False Positive ou Falsos Positivos
  • TN: True Negative ou Verdadeiros Negativos

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}$$
  • Specificity: ou Especificidade
  • TN: True Negative ou Verdadeiros Negativos
  • FP: False Positive ou Falsos Positivos

Onde:

$$FPR = {1 - Specificity}$$

Vantagens

  • Podemos comparar diversos modelos através dos respectivos limites das probabilidades;
  • A área sob a curva (AUC) resume a performance do modelo;
  • A forma da curva mostra a taxa de falsos positivos esperada e a taxa de falsos negativos;
  • É apropriada quando as observações são balanceadas entre as classes.

Resumindo

  • Quanto menores os valores no eixo x indica menos falsos positivos e mais verdadeiros negativos.
  • Quanto maiores os valores no eixo y indica mais verdadeiros positivos e menos falsos negativos.

Exemplo: Plotando a Curva ROC

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.

In [1]:
# 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}')
Baseline: ROC AUC = 0.500
Logistic: ROC AUC = 0.903
Random Forest: ROC AUC = 0.909
In [2]:
# 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()

Conclusão

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.