W3docs

Curva AUC - ROC

Aprenda a calcular e plotar curvas AUC-ROC em Python com sklearn. Entenda TPR, FPR, limiares e quando usar AUC em vez de acurácia.

A curva AUC-ROC (Área Sob a Curva Característica de Operação do Receptor) é uma das métricas mais importantes para avaliar modelos de classificação binária. Ela captura a capacidade do modelo de separar exemplos positivos e negativos em cada limiar de decisão possível, fornecendo uma visão muito mais rica do que uma única pontuação de acurácia.

Este capítulo aborda:

  • O que é a curva ROC e como ela é construída
  • Como interpretar TPR, FPR e os termos da matriz de confusão por trás deles
  • Como calcular a AUC-ROC com o scikit-learn do Python
  • Como plotar a curva ROC com o matplotlib
  • Quando a AUC-ROC é a métrica correta e quando não é

Termos Principais: TP, FP, TN, FN

Antes de mergulhar na curva em si, é importante entender os quatro resultados que um classificador binário pode produzir. Para qualquer previsão, o rótulo real é positivo (P) ou negativo (N), e o rótulo previsto é positivo ou negativo:

Previsto PositivoPrevisto Negativo
Real PositivoVerdadeiro Positivo (TP)Falso Negativo (FN)
Real NegativoFalso Positivo (FP)Verdadeiro Negativo (TN)

Essas quatro células são os blocos fundamentais de cada métrica de avaliação abordada neste capítulo. Para uma introdução mais aprofundada, consulte o capítulo Matriz de Confusão.

O que é a Curva ROC?

Um classificador geralmente produz uma pontuação de probabilidade (um número entre 0 e 1) em vez de um rótulo direto. Você escolhe um limiar — digamos, 0.5 — e tudo acima do limiar é previsto como positivo.

Alterar o limiar muda o equilíbrio entre capturar verdadeiros positivos e sinalizar incorretamente verdadeiros negativos:

  • Um limiar muito baixo captura mais positivos (alto recall), mas também produz mais falsos alarmes.
  • Um limiar muito alto é seletivo (alta precisão), mas perde positivos reais.

A curva ROC representa essa troca para cada limiar possível de uma só vez:

  • Eixo X — Taxa de Falsos Positivos (FPR): que fração dos negativos reais são sinalizados incorretamente como positivos.
  • Eixo Y — Taxa de Verdadeiros Positivos (TPR), também chamada de Recall ou Sensibilidade: que fração dos positivos reais são identificados corretamente.

TPR = TP / (TP + FN) e FPR = FP / (FP + TN)

Cada ponto na curva ROC é uma configuração de limiar. Juntos, eles traçam um caminho de (0, 0) — o limiar mais seletivo, sem prever nada como positivo — a (1, 1) — o limiar menos seletivo, prevendo tudo como positivo.

O que é AUC?

A AUC (Área Sob a Curva) resume toda a curva ROC em um único número entre 0 e 1:

AUCSignificado
1.0Classificador perfeito — separa cada positivo de cada negativo
0.5Sem habilidade — equivalente a adivinhação aleatória
< 0.5Pior que aleatório (suas probabilidades previstas estão invertidas)
0.7 – 0.8Aceitável para muitos problemas práticos
0.8 – 0.9Bom
> 0.9Excelente

Intuitivamente, a AUC é a probabilidade de o modelo classificar um exemplo positivo escolhido aleatoriamente acima de um exemplo negativo escolhido aleatoriamente.

Calculando AUC-ROC com scikit-learn

O módulo sklearn.metrics fornece roc_curve() para obter os valores de TPR/FPR por limiar e roc_auc_score() para obter o número único da AUC.

Exemplo mínimo funcional

from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score, roc_curve

# 1. Create a toy binary-classification dataset
X, y = make_classification(n_samples=500, n_features=10, random_state=42)

# 2. Split into train / test sets
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42
)

# 3. Train a logistic regression model
model = LogisticRegression(random_state=42)
model.fit(X_train, y_train)

# 4. Get probability scores for the positive class (column 1)
y_proba = model.predict_proba(X_test)[:, 1]

# 5. Compute AUC
auc = roc_auc_score(y_test, y_proba)
print(f"AUC-ROC: {auc:.3f}")

# 6. Get the (fpr, tpr, thresholds) arrays for plotting
fpr, tpr, thresholds = roc_curve(y_test, y_proba)
print(f"Number of threshold points: {len(thresholds)}")

A saída será próxima de:

AUC-ROC: 0.944
Number of threshold points: 30

O valor exato varia ligeiramente dependendo da sua versão do scikit-learn, mas deve estar no intervalo de 0.90–0.97 para este conjunto de dados.

Plotando a curva ROC

import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score, roc_curve

X, y = make_classification(n_samples=500, n_features=10, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

model = LogisticRegression(random_state=42)
model.fit(X_train, y_train)

y_proba = model.predict_proba(X_test)[:, 1]
auc = roc_auc_score(y_test, y_proba)
fpr, tpr, _ = roc_curve(y_test, y_proba)

plt.figure(figsize=(7, 5))
plt.plot(fpr, tpr, color="steelblue", lw=2, label=f"ROC curve (AUC = {auc:.2f})")
plt.plot([0, 1], [0, 1], color="gray", linestyle="--", label="Random baseline (AUC = 0.50)")
plt.xlabel("False Positive Rate (FPR)")
plt.ylabel("True Positive Rate (TPR)")
plt.title("ROC Curve")
plt.legend(loc="lower right")
plt.tight_layout()
plt.savefig("roc_curve.png", dpi=120)
plt.show()

A linha diagonal tracejada representa um classificador aleatório. Quanto mais a curva ROC se curva em direção ao canto superior esquerdo, melhor o modelo.

Comparando Múltiplos Modelos

Um fluxo de trabalho comum é treinar vários modelos e comparar suas curvas ROC no mesmo gráfico:

from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score, roc_curve
import matplotlib.pyplot as plt

X, y = make_classification(n_samples=500, n_features=10, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

models = {
    "Logistic Regression": LogisticRegression(random_state=42),
    "Decision Tree": DecisionTreeClassifier(max_depth=3, random_state=42),
}

plt.figure(figsize=(7, 5))
for name, clf in models.items():
    clf.fit(X_train, y_train)
    y_proba = clf.predict_proba(X_test)[:, 1]
    fpr, tpr, _ = roc_curve(y_test, y_proba)
    auc = roc_auc_score(y_test, y_proba)
    plt.plot(fpr, tpr, lw=2, label=f"{name} (AUC = {auc:.2f})")

plt.plot([0, 1], [0, 1], "k--", label="Random (AUC = 0.50)")
plt.xlabel("False Positive Rate")
plt.ylabel("True Positive Rate")
plt.title("ROC Curve Comparison")
plt.legend(loc="lower right")
plt.tight_layout()
plt.savefig("roc_comparison.png", dpi=120)
plt.show()

O modelo com a maior área sob sua curva geralmente é a melhor escolha para este conjunto de dados. Para um fluxo de seleção de modelos rigoroso, combine isso com validação cruzada.

Escolhendo um Ponto de Operação (Limiar)

A AUC resume todos os limiares, mas eventualmente você precisará escolher um limiar para produção. Duas estratégias comuns:

1. Estatística J de Youden

O J de Youden maximiza TPR − FPR, encontrando o único ponto na curva ROC mais distante da diagonal:

from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_curve
import numpy as np

X, y = make_classification(n_samples=500, n_features=10, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

model = LogisticRegression(random_state=42)
model.fit(X_train, y_train)
y_proba = model.predict_proba(X_test)[:, 1]

fpr, tpr, thresholds = roc_curve(y_test, y_proba)
j_scores = tpr - fpr
best_idx = int(np.argmax(j_scores))
best_threshold = thresholds[best_idx]

print(f"Best threshold (Youden's J): {best_threshold:.3f}")
print(f"TPR at best threshold: {tpr[best_idx]:.3f}")
print(f"FPR at best threshold: {fpr[best_idx]:.3f}")

2. Limiar orientado pelo negócio

Na detecção de fraudes, você pode tolerar mais falsos positivos para capturar mais fraudes (limiar mais baixo). Na triagem médica, você pode querer muito poucos falsos negativos (também limiar mais baixo). Escolher o limiar é, em última análise, uma decisão de negócio informada pelo custo de cada tipo de erro.

AUC-ROC vs. Outras Métricas

MétricaMelhor quando...Atenção...
AcuráciaAs classes estão equilibradasEnganosa em conjuntos de dados desbalanceados
Precisão / RecallVocê se preocupa principalmente com uma classeRequer um limiar
F1-ScoreEquilíbrio harmônico entre precisão e recallAinda dependente de limiar
AUC-ROCComparando modelos ou ajustando limiaresNão significativa para multi-classe sem extensão
AUC-PR (AUC Precisão-Recall)Forte desequilíbrio de classes (positivos raros)Menos intuitiva que a ROC

Para dados severamente desbalanceados — por exemplo, 1% de positivos — a curva AUC-PR (precisão vs. recall) é frequentemente mais informativa do que a AUC-ROC, porque a FPR pode parecer pequena mesmo quando muitos negativos são sinalizados incorretamente.

Armadilhas Comuns

Passar rótulos diretos em vez de probabilidades. O roc_auc_score precisa de pontuações de probabilidade, não de rótulos 0/1. Use model.predict_proba(X_test)[:, 1], não model.predict(X_test).

Esquecer de especificar a classe positiva. Por padrão, roc_curve e roc_auc_score tratam o rótulo inteiro maior como positivo. Passe pos_label=1 explicitamente quando seus rótulos não forem inteiros 0/1.

Sobreajuste à AUC no conjunto de treinamento. Sempre avalie em um conjunto de teste separado ou use validação cruzada para obter uma estimativa confiável de AUC. O capítulo Grid Search mostra como passar scoring='roc_auc' diretamente para o GridSearchCV.

AUC ≈ 0.5 nem sempre significa que o modelo é ruim. Pode significar que os exemplos positivos e negativos genuinamente se sobrepõem no espaço de características, ou que suas características não são informativas para a tarefa.

Exemplo Prático: Previsão de Doenças

O exemplo completo a seguir usa o conjunto de dados de câncer de mama que acompanha o scikit-learn:

from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import roc_auc_score, roc_curve
import matplotlib.pyplot as plt

# Load dataset (569 samples, 30 features, binary labels: malignant=0 / benign=1)
data = load_breast_cancer()
X, y = data.data, data.target

# Scale features — important for logistic regression
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

X_train, X_test, y_train, y_test = train_test_split(
    X_scaled, y, test_size=0.2, random_state=42, stratify=y
)

classifiers = {
    "Logistic Regression": LogisticRegression(max_iter=1000, random_state=42),
    "Random Forest": RandomForestClassifier(n_estimators=100, random_state=42),
}

plt.figure(figsize=(7, 5))
for name, clf in classifiers.items():
    clf.fit(X_train, y_train)
    y_proba = clf.predict_proba(X_test)[:, 1]
    auc = roc_auc_score(y_test, y_proba)
    fpr, tpr, _ = roc_curve(y_test, y_proba)
    plt.plot(fpr, tpr, lw=2, label=f"{name} (AUC = {auc:.3f})")

plt.plot([0, 1], [0, 1], "k--", label="Random (AUC = 0.50)")
plt.xlabel("False Positive Rate")
plt.ylabel("True Positive Rate")
plt.title("ROC Curve — Breast Cancer Dataset")
plt.legend(loc="lower right")
plt.tight_layout()
plt.savefig("breast_cancer_roc.png", dpi=120)
plt.show()

Ambos os classificadores devem produzir pontuações AUC acima de 0.98 neste conjunto de dados, confirmando que as características do câncer de mama são altamente preditivas.

Tópicos Relacionados

  • Matriz de Confusão — os blocos fundamentais TP/FP/TN/FN usados ao longo deste capítulo
  • Regressão Logística — o modelo mais comum combinado com avaliação por AUC-ROC
  • Validação Cruzada — como obter estimativas confiáveis de AUC que generalizam além de uma única divisão treino/teste
  • Grid Search — como ajustar hiperparâmetros com scoring='roc_auc'
  • Árvore de Decisão — outro classificador binário cujas saídas de probabilidade podem ser avaliadas com AUC-ROC

Resumo

ConceitoPonto Principal
Curva ROCPlota TPR vs. FPR em cada limiar de decisão
AUCÁrea sob a curva ROC; 1.0 = perfeito, 0.5 = aleatório
roc_auc_scorePasse pontuações de probabilidade, não rótulos diretos
roc_curveRetorna arrays (fpr, tpr, thresholds) para plotagem
Seleção de limiarUse o J de Youden ou conhecimento do domínio para escolher um limiar de produção
Quando preferir AUC-PRConjuntos de dados severamente desbalanceados com positivos raros

A AUC-ROC fornece um único número independente de limiar que resume a capacidade discriminativa do modelo em todos os pontos de operação. Use-a para comparar modelos, ajustar hiperparâmetros e comunicar a qualidade do classificador — depois escolha o limiar específico que corresponde à tolerância da sua aplicação para falsos positivos versus falsos negativos.

Was this page helpful?