Machine Learning: Entendendo a Matriz de Confusão
Aprenda o que é uma matriz de confusão, como construí-la em Python com scikit-learn, visualizá-la com seaborn e derivar precisão, recall e F1-score a partir dela.
Uma matriz de confusão é uma tabela que resume os resultados de predição de um modelo de classificação, comparando os rótulos reais com os rótulos previstos. Ela é o ponto de partida para calcular precisão, recall, F1-score e a maioria das outras métricas de classificação.
Este capítulo aborda:
- O que significam as quatro células (TP, FP, TN, FN) e por que cada uma importa
- Como calcular métricas comuns a partir dessas células
- Construção e visualização de uma matriz de confusão em Python com scikit-learn e seaborn
- Matrizes de confusão multi-classe
- Armadilhas comuns — especialmente em conjuntos de dados desbalanceados
O que é uma Matriz de Confusão?
Para um classificador binário (duas classes possíveis: positiva e negativa), a matriz de confusão é uma tabela 2×2:
| Previsto Positivo | Previsto Negativo | |
|---|---|---|
| Real Positivo | True Positive (TP) | False Negative (FN) |
| Real Negativo | False Positive (FP) | True Negative (TN) |
Cada célula conta um tipo específico de resultado:
| Termo | Abreviação | Significado |
|---|---|---|
| True Positive | TP | Modelo diz positivo; realidade é positiva ✓ |
| True Negative | TN | Modelo diz negativo; realidade é negativa ✓ |
| False Positive | FP | Modelo diz positivo; realidade é negativa ✗ (Erro Tipo I) |
| False Negative | FN | Modelo diz negativo; realidade é positiva ✗ (Erro Tipo II) |
Um recurso mnemônico rápido: a primeira palavra (True / False) indica se a predição foi correta; a segunda palavra (Positive / Negative) indica o que o modelo previu.
Métricas Derivadas da Matriz
Os quatro contadores alimentam todas as métricas de classificação padrão:
| Métrica | Fórmula | O que mede |
|---|---|---|
| Acurácia | (TP + TN) / (TP + TN + FP + FN) | Fração geral de predições corretas |
| Precisão | TP / (TP + FP) | De todas as predições positivas, quantas estavam corretas |
| Recall (Sensibilidade) | TP / (TP + FN) | De todos os positivos reais, quantos foram encontrados |
| Especificidade | TN / (TN + FP) | De todos os negativos reais, quantos foram corretamente descartados |
| F1-Score | 2 × Precisão × Recall / (Precisão + Recall) | Média harmônica de precisão e recall |
Quando priorizar precisão vs. recall
- Priorize o recall quando perder um caso positivo é custoso — triagem médica, detecção de fraudes, filtros de spam que precisam capturar todas as mensagens de spam.
- Priorize a precisão quando falsos alarmes são custosos — recomendações cirúrgicas, marcação de documentos jurídicos, sistemas de notificação push.
- F1-score equilibra ambos e é a métrica padrão quando o conjunto de dados é desbalanceado.
Exemplo Numérico Trabalhado
Suponha que um modelo rastreie 100 pacientes para uma doença:
- TP = 50 (pacientes doentes corretamente identificados)
- FP = 5 (pacientes saudáveis incorretamente sinalizados como doentes)
- FN = 10 (pacientes doentes não detectados)
- TN = 35 (pacientes saudáveis corretamente liberados)
Cálculos passo a passo:
Accuracy = (50 + 35) / 100 = 0.85 (85 %)
Precision = 50 / (50 + 5) ≈ 0.909 (90.9 %)
Recall = 50 / (50 + 10) ≈ 0.833 (83.3 %)
F1-Score = 2 × 0.909 × 0.833 / (0.909 + 0.833) ≈ 0.869 (86.9 %)Observe que a acurácia (85 %) parece razoável, mas o recall é de apenas 83 % — o que significa que 10 dos 60 pacientes doentes foram perdidos. Em um contexto médico, essa diferença importa muito mais do que o número de acurácia isolado.
Construindo uma Matriz de Confusão em Python
Usando scikit-learn
sklearn.metrics fornece confusion_matrix() e um relatório de texto pronto via classification_report().
from sklearn.metrics import confusion_matrix, classification_report
# Ground-truth labels and model predictions
y_true = [1, 1, 0, 0, 1, 0, 1, 0, 1, 0]
y_pred = [1, 0, 0, 1, 1, 0, 1, 0, 1, 1]
cm = confusion_matrix(y_true, y_pred)
print("Confusion Matrix:")
print(cm)
print()
print(classification_report(y_true, y_pred, target_names=["Negative", "Positive"]))confusion_matrix() retorna um array NumPy. Por padrão, as linhas são as classes reais e as colunas são as classes previstas (correspondendo ao layout da tabela mostrado acima). O layout do array é:
[[TN FP]
[FN TP]]Calculando métricas manualmente
Você pode extrair as quatro células e calcular as métricas por conta própria para verificar:
from sklearn.metrics import confusion_matrix
y_true = [1, 1, 0, 0, 1, 0, 1, 0, 1, 0]
y_pred = [1, 0, 0, 1, 1, 0, 1, 0, 1, 1]
tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel()
accuracy = (tp + tn) / (tp + tn + fp + fn)
precision = tp / (tp + fp)
recall = tp / (tp + fn)
f1 = 2 * precision * recall / (precision + recall)
print(f"TP={tp}, FP={fp}, FN={fn}, TN={tn}")
print(f"Accuracy : {accuracy:.3f}")
print(f"Precision: {precision:.3f}")
print(f"Recall : {recall:.3f}")
print(f"F1-Score : {f1:.3f}")Saída esperada:
TP=4, FP=2, FN=1, TN=3
Accuracy : 0.700
Precision: 0.667
Recall : 0.800
F1-Score : 0.727Visualizando com seaborn
Um mapa de calor torna a matriz de confusão mais fácil de ler, especialmente para problemas multi-classe:
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.metrics import confusion_matrix
y_true = [1, 1, 0, 0, 1, 0, 1, 0, 1, 0]
y_pred = [1, 0, 0, 1, 1, 0, 1, 0, 1, 1]
cm = confusion_matrix(y_true, y_pred)
sns.heatmap(
cm,
annot=True,
fmt="d",
cmap="Blues",
xticklabels=["Negative", "Positive"],
yticklabels=["Negative", "Positive"],
)
plt.xlabel("Predicted label")
plt.ylabel("True label")
plt.title("Confusion Matrix")
plt.tight_layout()
plt.savefig("confusion_matrix.png", dpi=150)
plt.show()annot=True imprime o contagem dentro de cada célula; fmt="d" formata-os como inteiros.
Matrizes de Confusão Multi-Classe
Quando há mais de duas classes, a matriz de confusão se expande para uma grade N×N. Cada linha ainda representa as classes reais; cada coluna representa as classes previstas. As células da diagonal são predições corretas; as células fora da diagonal são erros.
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
import matplotlib.pyplot as plt
# Three classes: cat, dog, rabbit
y_true = ["cat", "dog", "rabbit", "cat", "dog", "rabbit",
"cat", "dog", "cat", "rabbit"]
y_pred = ["cat", "dog", "rabbit", "dog", "dog", "cat",
"cat", "rabbit", "cat", "rabbit"]
labels = ["cat", "dog", "rabbit"]
cm = confusion_matrix(y_true, y_pred, labels=labels)
print(cm)
disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=labels)
disp.plot(cmap="Blues")
plt.title("Multi-Class Confusion Matrix")
plt.tight_layout()
plt.savefig("cm_multiclass.png", dpi=150)
plt.show()ConfusionMatrixDisplay (adicionado no scikit-learn 0.24) é uma alternativa conveniente de uma única linha ao mapa de calor do seaborn e não requer a dependência do seaborn.
Para problemas multi-classe, precisão e recall são calculados por classe e depois calculados em média. classification_report() oferece três estratégias de média:
macro— média não ponderada entre as classes (trata todas as classes igualmente).weighted— média ponderada pelo suporte (número de instâncias reais por classe).micro— agrega TP/FP/FN em todas as classes antes de dividir (fornece acurácia geral para conjuntos de dados balanceados).
Armadilhas Comuns
A acurácia é enganosa em conjuntos de dados desbalanceados
Considere um conjunto de dados onde 95 % das amostras são negativas. Um modelo que sempre prevê negativo atinge 95 % de acurácia, mas tem recall zero — nunca captura um caso positivo. A matriz de confusão revela isso imediatamente: toda a primeira linha (Real Positivo) será composta apenas de FN.
Sempre combine acurácia com precisão, recall ou F1-score em dados desbalanceados. Consulte o capítulo Train/Test Split para saber como criar uma divisão representativa, e o capítulo AUC-ROC Curve para uma métrica de avaliação independente de limiar.
Escolhendo a estratégia de média errada
Usar a média macro quando as classes são muito desbalanceadas infla a pontuação das classes raras. Use weighted para uma visão realista da qualidade geral do modelo no conjunto de dados completo.
Esquecendo a normalização
As contagens brutas dependem do tamanho do conjunto de dados. Ao comparar modelos treinados em conjuntos de dados de tamanhos diferentes, normalize a matriz dividindo cada linha pela sua soma (passe normalize='true' para confusion_matrix()):
cm_normalized = confusion_matrix(y_true, y_pred, normalize="true")
print(cm_normalized.round(2))Cada linha agora soma 1,0, mostrando a fração de cada classe real prevista corretamente.
Matriz de Confusão vs. Outras Ferramentas de Avaliação
| Ferramenta | Melhor para |
|---|---|
| Matriz de confusão | Entender os tipos específicos de erros que um modelo comete |
| AUC-ROC Curve | Comparar classificadores em todos os limiares de decisão |
| Cross-Validation | Estimar o quão bem a matriz generaliza para dados não vistos |
| Grid Search | Ajustar hiperparâmetros usando uma métrica escolhida (por exemplo, F1-score) |
Principais Conclusões
- Uma matriz de confusão divide as predições em TP, FP, TN e FN — quatro contadores que revelam quais erros um modelo comete, não apenas quantos.
- A acurácia isolada é insuficiente; sempre verifique precisão, recall e F1-score, especialmente em dados desbalanceados.
- Use
sklearn.metrics.confusion_matrix()para o cálculo e seaborn ouConfusionMatrixDisplaypara a visualização. - Matrizes multi-classe seguem a mesma convenção linha = real, coluna = previsto e escalam para N×N.
- Combine a estratégia de média (
macro,weighted,micro) com a distribuição de classes do seu conjunto de dados.