Avaliando Modelos de Aprendizado de Máquina com Curvas ROC e AUC: Um Guia Abrangente
No campo do aprendizado de máquina, selecionar o modelo certo para o seu conjunto de dados é crucial para alcançar previsões precisas e confiáveis. Uma das maneiras mais eficazes de avaliar e comparar modelos é através da Curva Característica de Operação do Receptor (ROC) e da Área Sob a Curva (AUC). Este guia aprofunda-se na compreensão das curvas ROC, no cálculo da AUC e na utilização dessas métricas para escolher o modelo com melhor desempenho para suas tarefas de classificação binária. Vamos acompanhar um exemplo prático usando um Jupyter Notebook, demonstrando como implementar esses conceitos utilizando vários algoritmos de aprendizado de máquina.
Índice
- Introdução à Curva ROC e AUC
- Por que AUC em vez de Precisão?
- Visão Geral do Conjunto de Dados
- Pré-processamento de Dados
- Treinamento e Avaliação do Modelo
- Escolhendo o Melhor Modelo
- Conclusão
- Recursos
Introdução à Curva ROC e AUC
O que é uma Curva ROC?
Uma Curva Característica de Operação do Receptor (ROC) é uma representação gráfica que ilustra a capacidade diagnóstica de um sistema de classificador binário à medida que seu limiar de discriminação varia. A curva ROC plota dois parâmetros:
- Taxa de Verdadeiros Positivos (TPR): Também conhecida como sensibilidade ou recall, mede a proporção de positivos reais corretamente identificados.
- Taxa de Falsos Positivos (FPR): Mede a proporção de negativos reais que foram incorretamente identificados como positivos.
A curva ROC permite a visualização do trade-off entre sensibilidade e especificidade (1 – FPR) em diferentes configurações de limiar.
Compreendendo a AUC
Área Sob a Curva (AUC) quantifica a capacidade geral do modelo de discriminar entre classes positivas e negativas. O valor da AUC varia de 0 a 1:
- AUC = 1: Classificador perfeito.
- AUC = 0.5: Sem discriminação (equivalente a um palpite aleatório).
- AUC < 0.5: Predição inversamente correlacionada (pior do que o aleatório).
Uma AUC mais alta indica um modelo com melhor desempenho.
Por que AUC em vez de Precisão?
Enquanto a precisão mede a proporção de previsões corretas em relação a todas as previsões feitas, ela pode ser enganosa, especialmente em casos de desbalanceamento de classes. Por exemplo, se 95% dos dados pertencem a uma classe, um modelo que prediz apenas essa classe alcançará 95% de precisão, mas não conseguirá capturar a classe minoritária.
AUC, por outro lado, fornece uma avaliação mais detalhada ao considerar o desempenho do modelo em todos os limiares de classificação, tornando-a uma métrica mais confiável para conjuntos de dados desbalanceados.
Visão Geral do Conjunto de Dados
Para nossa análise, utilizaremos o Conjunto de Dados de Tempo do Kaggle. Este conjunto de dados contém vários atributos relacionados ao tempo registrados diariamente em diferentes localidades australianas.
Objetivo: Prever se irá chover amanhã (RainTomorrow
) com base nas condições climáticas de hoje.
Tipo: Classificação Binária (Yes
/No
).
Pré-processamento de Dados
O pré-processamento eficaz de dados é a base para a construção de modelos robustos de aprendizado de máquina. Aqui está uma divisão passo a passo:
1. Importando Bibliotecas e Dados
1 2 3 4 5 6 |
import pandas as pd import seaborn as sns # Load the dataset data = pd.read_csv('weatherAUS.csv') data.tail() |
2. Separando Características e Alvo
1 2 3 4 5 |
# Features (All columns except the last one) X = data.iloc[:, :-1] # Target variable y = data.iloc[:, -1] |
3. Tratamento de Dados Ausentes
a. Características Numéricas
1 2 3 4 5 6 7 8 9 |
import numpy as np from sklearn.impute import SimpleImputer # Identify numeric columns numerical_cols = list(np.where((X.dtypes == np.int64) | (X.dtypes == np.float64))[0]) # Impute missing values with mean imp_mean = SimpleImputer(missing_values=np.nan, strategy='mean') X.iloc[:, numerical_cols] = imp_mean.fit_transform(X.iloc[:, numerical_cols]) |
b. Características Categóricas
1 2 3 4 5 6 |
# Identify object (categorical) columns string_cols = list(np.where((X.dtypes == object))[0]) # Impute missing values with the most frequent value imp_mode = SimpleImputer(missing_values=np.nan, strategy='most_frequent') X.iloc[:, string_cols] = imp_mode.fit_transform(X.iloc[:, string_cols]) |
4. Codificação de Variáveis Categóricas
a. Codificação de Rótulos para Alvo
1 2 3 4 5 |
from sklearn.preprocessing import LabelEncoder # Initialize Label Encoder le = LabelEncoder() y = le.fit_transform(y) |
b. Codificação de Características
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
from sklearn.compose import ColumnTransformer from sklearn.preprocessing import OneHotEncoder # Function to perform One-Hot Encoding def OneHotEncoderMethod(indices, data): columnTransformer = ColumnTransformer( [('encoder', OneHotEncoder(), indices)], remainder='passthrough' ) return columnTransformer.fit_transform(data) # Identify columns for One-Hot Encoding based on the number of unique categories def EncodingSelection(X, threshold=10): string_cols = list(np.where((X.dtypes == object))[0]) one_hot_encoding_indices = [] for col in string_cols: unique_vals = len(pd.unique(X[X.columns[col]])) if unique_vals == 2 or unique_vals > threshold: X[X.columns[col]] = le.fit_transform(X[X.columns[col]]) else: one_hot_encoding_indices.append(col) X = OneHotEncoderMethod(one_hot_encoding_indices, X) return X X = EncodingSelection(X) |
5. Seleção de Características
Para reduzir a complexidade do modelo e melhorar o desempenho, selecionaremos as 10 principais características usando o teste Qui-Quadrado (Chi2).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
from sklearn.feature_selection import SelectKBest, chi2 from sklearn.preprocessing import MinMaxScaler # Initialize SelectKBest kbest = SelectKBest(score_func=chi2, k=10) scaler = MinMaxScaler() # Scale features X_scaled = scaler.fit_transform(X) # Fit SelectKBest kbest.fit(X_scaled, y) # Get top 10 feature indices best_features = np.argsort(kbest.scores_)[-10:] # Select top features X = X[:, best_features] |
6. Dividindo o Conjunto de Dados
1 2 3 4 5 6 |
from sklearn.model_selection import train_test_split # Split data into training and testing sets (80-20 split) X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.20, random_state=1 ) |
7. Escalonamento de Características
Padronizar as características garante que cada uma contribua igualmente para o resultado.
1 2 3 4 5 |
from sklearn.preprocessing import StandardScaler sc = StandardScaler(with_mean=False) X_train = sc.fit_transform(X_train) X_test = sc.transform(X_test) |
Treinamento e Avaliação do Modelo
Vamos treinar vários modelos de classificação e avaliar seu desempenho usando tanto Precisão quanto AUC.
K-Nearest Neighbors (KNN)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import accuracy_score, roc_curve, auc import matplotlib.pyplot as plt from sklearn import metrics # Initialize and train KNN knnClassifier = KNeighborsClassifier(n_neighbors=3) knnClassifier.fit(X_train, y_train) # Predict and evaluate y_pred_knn = knnClassifier.predict(X_test) accuracy_knn = accuracy_score(y_pred_knn, y_test) print(f'KNN Accuracy: {accuracy_knn:.2f}') # Plot ROC Curve metrics.plot_roc_curve(knnClassifier, X_test, y_test) plt.title('KNN ROC Curve') plt.show() |
Saída:
1 |
KNN Accuracy: 0.82 |

Regressão Logística
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
from sklearn.linear_model import LogisticRegression # Initialize and train Logistic Regression LRM = LogisticRegression(random_state=0, max_iter=200) LRM.fit(X_train, y_train) # Predict and evaluate y_pred_lr = LRM.predict(X_test) accuracy_lr = accuracy_score(y_pred_lr, y_test) print(f'Logistic Regression Accuracy: {accuracy_lr:.2f}') # Plot ROC Curve metrics.plot_roc_curve(LRM, X_test, y_test) plt.title('Logistic Regression ROC Curve') plt.show() |
Saída:
1 |
Logistic Regression Accuracy: 0.84 |

Nota: Se você encontrar um aviso de convergência, considere aumentar max_iter
ou padronizar seus dados.
Gaussian Naive Bayes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
from sklearn.naive_bayes import GaussianNB # Initialize and train GaussianNB model_GNB = GaussianNB() model_GNB.fit(X_train, y_train) # Predict and evaluate y_pred_gnb = model_GNB.predict(X_test) accuracy_gnb = accuracy_score(y_pred_gnb, y_test) print(f'Gaussian Naive Bayes Accuracy: {accuracy_gnb:.2f}') # Plot ROC Curve metrics.plot_roc_curve(model_GNB, X_test, y_test) plt.title('Gaussian Naive Bayes ROC Curve') plt.show() |
Saída:
1 |
Gaussian Naive Bayes Accuracy: 0.81 |

Máquina de Vetores de Suporte (SVM)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
from sklearn.svm import SVC # Initialize and train SVM model_SVC = SVC(probability=True) model_SVC.fit(X_train, y_train) # Predict and evaluate y_pred_svc = model_SVC.predict(X_test) accuracy_svc = accuracy_score(y_pred_svc, y_test) print(f'SVM Accuracy: {accuracy_svc:.2f}') # Plot ROC Curve metrics.plot_roc_curve(model_SVC, X_test, y_test) plt.title('SVM ROC Curve') plt.show() |
Saída:
1 |
SVM Accuracy: 0.84 |

Árvore de Decisão
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
from sklearn.tree import DecisionTreeClassifier # Initialize and train Decision Tree model_DTC = DecisionTreeClassifier() model_DTC.fit(X_train, y_train) # Predict and evaluate y_pred_dtc = model_DTC.predict(X_test) accuracy_dtc = accuracy_score(y_pred_dtc, y_test) print(f'Decision Tree Accuracy: {accuracy_dtc:.2f}') # Plot ROC Curve metrics.plot_roc_curve(model_DTC, X_test, y_test) plt.title('Decision Tree ROC Curve') plt.show() |
Saída:
1 |
Decision Tree Accuracy: 0.78 |

Random Forest
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
from sklearn.ensemble import RandomForestClassifier # Initialize and train Random Forest model_RFC = RandomForestClassifier(n_estimators=500, max_depth=5) model_RFC.fit(X_train, y_train) # Predict and evaluate y_pred_rfc = model_RFC.predict(X_test) accuracy_rfc = accuracy_score(y_pred_rfc, y_test) print(f'Random Forest Accuracy: {accuracy_rfc:.2f}') # Plot ROC Curve metrics.plot_roc_curve(model_RFC, X_test, y_test) plt.title('Random Forest ROC Curve') plt.show() |
Saída:
1 |
Random Forest Accuracy: 0.84 |

AdaBoost
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
from sklearn.ensemble import AdaBoostClassifier # Initialize and train AdaBoost model_ABC = AdaBoostClassifier() model_ABC.fit(X_train, y_train) # Predict and evaluate y_pred_abc = model_ABC.predict(X_test) accuracy_abc = accuracy_score(y_pred_abc, y_test) print(f'AdaBoost Accuracy: {accuracy_abc:.2f}') # Plot ROC Curve metrics.plot_roc_curve(model_ABC, X_test, y_test) plt.title('AdaBoost ROC Curve') plt.show() |
Saída:
1 |
AdaBoost Accuracy: 0.84 |

XGBoost
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import xgboost as xgb from sklearn.exceptions import ConvergenceWarning import warnings # Suppress warnings warnings.filterwarnings("ignore", category=ConvergenceWarning) warnings.filterwarnings("ignore", category=UserWarning) # Initialize and train XGBoost model_xgb = xgb.XGBClassifier(use_label_encoder=False, eval_metric='logloss') model_xgb.fit(X_train, y_train) # Predict and evaluate y_pred_xgb = model_xgb.predict(X_test) accuracy_xgb = accuracy_score(y_pred_xgb, y_test) print(f'XGBoost Accuracy: {accuracy_xgb:.2f}') # Plot ROC Curve metrics.plot_roc_curve(model_xgb, X_test, y_test) plt.title('XGBoost ROC Curve') plt.show() |
Saída:
1 |
XGBoost Accuracy: 0.85 |

Escolhendo o Melhor Modelo
Após avaliar todos os modelos, observamos as seguintes precisões:
Modelo | Precisão | AUC |
---|---|---|
K-Nearest Neighbors | 0.82 | 0.80 |
Regressão Logística | 0.84 | 0.86 |
Gaussian Naive Bayes | 0.81 | 0.81 |
SVM | 0.84 | 0.86 |
Árvore de Decisão | 0.78 | 0.89 |
Random Forest | 0.84 | 0.85 |
AdaBoost | 0.84 | 0.86 |
XGBoost | 0.85 | 0.87 |
Observações Principais:
- XGBoost surge como o principal desempenho com a maior precisão (85%) e uma AUC forte (0.87).
- Regressão Logística, SVM e AdaBoost também demonstram desempenho digno com precisões em torno de 84% e AUCs de 0.86.
- Árvore de Decisão apresenta a menor precisão (78%) mas tem uma AUC relativamente alta (0.89), indicando potencial para distinguir classes apesar da menor precisão na predição.
Conclusão: Enquanto a precisão fornece uma métrica direta, a AUC oferece uma visão mais aprofundada sobre o desempenho do modelo em vários limiares. Neste cenário, XGBoost se destaca como o modelo mais confiável, equilibrando alta precisão e forte capacidade discriminativa.
Conclusão
Avaliando modelos de aprendizado de máquina requer uma abordagem multifacetada. Confiar apenas na precisão pode ser enganoso, especialmente em conjuntos de dados com desbalanceamento de classes. Curvas ROC e AUC fornecem uma avaliação mais abrangente do desempenho de um modelo, destacando sua capacidade de distinguir efetivamente entre classes.
Neste guia, exploramos como pré-processar dados, treinar múltiplos modelos de classificação e avaliá-los usando curvas ROC e AUC. A implementação prática utilizando um Jupyter Notebook demonstrou os pontos fortes de cada modelo, demonstrando, por fim, que XGBoost foi a escolha superior para prever a chuva com base no conjunto de dados fornecido.
Recursos
- Curva ROC na Wikipedia
- AUC Explicado
- Conjunto de Dados de Tempo do Kaggle
- Documentação do Scikit-Learn
- Documentação do XGBoost
Compreendendo e utilizando curvas ROC e AUC, cientistas de dados e profissionais de aprendizado de máquina podem tomar decisões mais informadas ao selecionar modelos, garantindo maior desempenho e confiabilidade em suas tarefas preditivas.