"Um modelo sem avaliação é como um exame sem nota: você não sabe se passou... ou se apenas teve sorte."
Porque aqui é onde você deixa de confiar e começa a verificar.
Você treinou um modelo.
Ele fez previsões.
Mas isso não significa que é bom!
Muitos iniciantes se empolgam com uma "acurácia de 98%"... e depois descobrem que seu modelo falha nos casos mais importantes.
Nesta lição, você aprenderá:
⚠️ Aviso amigável: Esta lição fará você questionar tudo o que achava saber sobre "bons modelos". Mas isso é bom. A humildade é a mãe da melhoria.
Ao final, você será capaz de:
✅ Calcular e interpretar a acurácia do seu modelo.
✅ Construir e entender uma matriz de confusão.
✅ Calcular e interpretar precisão, revocação e F1-score.
✅ Saber quando usar cada métrica de acordo com o problema.
✅ Avaliar não apenas previsões, mas probabilidades.
✅ Detectar se seu modelo é "burro" ou verdadeiramente inteligente.
✅ Sentir-se confortável tomando decisões baseadas em métricas, não em intuição.
accuracy_score, confusion_matrix, classification_report, precision_recall_curve.💡 Certifique-se de ter seu modelo treinado e suas previsões (
y_test,y_pred) prontas da Lição 4. Se não, aqui está o código rápido para acompanhar:
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
# Carregar e preparar dados
url = "https://raw.githubusercontent.com/justmarkham/DAT8/master/data/sms.tsv"
data = pd.read_csv(url, sep='\t', names=['label', 'message'])
data['label_encoded'] = data['label'].map({'ham': 0, 'spam': 1})
X = data['message']
y = data['label_encoded']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)
vectorizer = CountVectorizer()
X_train_vec = vectorizer.fit_transform(X_train)
X_test_vec = vectorizer.transform(X_test)
# Treinar modelo
model = MultinomialNB()
model.fit(X_train_vec, y_train)
# Prever
y_pred = model.predict(X_test_vec)
Vamos começar com a métrica mais popular... e mais perigosa.
from sklearn.metrics import accuracy_score
acc = accuracy_score(y_test, y_pred)
print(f"Acurácia: {acc:.4f} → {acc*100:.2f}%")
📌 Saída típica:
Acurácia: 0.9821 → 98.21%
→ Uau! 98% corretos. Isso significa que o modelo é excelente?
NÃO! E aqui está o porquê.
Lembre-se: em nosso conjunto de dados, apenas 13,4% são spam. 86,6% são ham.
Imagine um modelo burro que sempre prevê "ham".
Qual seria sua acurácia?
Acurácia = (Hams Verdadeiros) / (Total) = 955 / 1115 ≈ 85.65%
→ Um modelo que nunca detecta spam teria 85,65% de acurácia!
Seu modelo tem 98,21% → é melhor que o burro... mas quanto melhor no que realmente importa: detectar spam?
📌 Conclusão: A acurácia engana quando há desequilíbrio. Você precisa de métricas mais inteligentes.
Aqui é onde você vê exatamente quais acertos e quais erros seu modelo está cometendo.
from sklearn.metrics import confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt
cm = confusion_matrix(y_test, y_pred)
# Visualizar
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=['Ham (Pred)', 'Spam (Pred)'],
yticklabels=['Ham (Real)', 'Spam (Real)'])
plt.title("Matriz de Confusão - Classificador de Spam", fontsize=16)
plt.ylabel("Rótulo Verdadeiro", fontsize=12)
plt.xlabel("Rótulo Previsto", fontsize=12)
plt.show()
📌 Saída típica (valores aproximados):
Previsto
Ham Spam
Real Ham 950 5
Real Spam 15 145
Verdadeiros Negativos (VN): 950
→ Mensagens ham que o modelo disse que eram ham. ✅ Perfeito!
Falsos Positivos (FP): 5
→ Mensagens ham que o modelo disse que eram spam. ❌ Erro grave! (Marcar uma mensagem importante como spam).
Falsos Negativos (FN): 15
→ Mensagens spam que o modelo disse que eram ham. ❌ Erro grave! (Deixar spam passar).
Verdadeiros Positivos (VP): 145
→ Mensagens spam que o modelo disse que eram spam. ✅ Perfeito!
📌 Isso é ouro! Agora você sabe onde seu modelo falha. Não é um número abstrato... são erros concretos que você pode melhorar.
Agora, vamos quantificar esses erros com métricas profissionais.
from sklearn.metrics import classification_report
report = classification_report(y_test, y_pred,
target_names=['Ham', 'Spam'],
output_dict=False)
print(report)
📌 Saída típica:
precision recall f1-score support
Ham 0.98 0.99 0.99 955
Spam 0.97 0.91 0.94 160
accuracy 0.98 1115
macro avg 0.98 0.95 0.96 1115
weighted avg 0.98 0.98 0.98 1115
"De todos aqueles que eu disse que eram spam, quantos realmente eram?"
Precisão (Spam) = VP / (VP + FP) = 145 / (145 + 5) = 145/150 ≈ 0.97
→ 97% de precisão em spam: quando o modelo diz "spam", está certo 97% das vezes. Excelente!
📌 Quando a precisão importa?
Quando o custo de um falso positivo é alto.
Exemplo: Marcar um email importante como spam → o usuário pode perder informações críticas.
"De todo o spam que existia, quantos eu detectei?"
Revocação (Spam) = VP / (VP + FN) = 145 / (145 + 15) = 145/160 ≈ 0.91
→ 91% de revocação em spam: detectou 91% de todo o spam. Muito bom!
📌 Quando a revocação importa?
Quando o custo de um falso negativo é alto.
Exemplo: Deixar spam fraudulento passar → o usuário pode clicar e perder dinheiro.
"Média harmônica entre precisão e revocação. Ideal quando você quer equilíbrio."
F1 = 2 * (Precisão * Revocação) / (Precisão + Revocação)
= 2 * (0.97 * 0.91) / (0.97 + 0.91) ≈ 0.94
→ 94% de F1-score: um bom equilíbrio entre não incomodar o usuário (precisão) e protegê-lo (revocação).
📌 Quando usar F1?
Quando você não sabe o que é mais importante, ou quando quer uma única métrica que resuma o desempenho em classes desbalanceadas.
Seu modelo não apenas prevê "spam" ou "ham." Ele também lhe dá probabilidades.
Isso é poderoso. Porque às vezes, você não quer uma decisão binária... você quer saber o quão certo o modelo está.
# Obter probabilidades para cada classe
y_proba = model.predict_proba(X_test_vec)
# Para spam (classe 1), é a segunda coluna
y_proba_spam = y_proba[:, 1]
# Ver as primeiras 10 probabilidades
for i in range(10):
print(f"Mensagem {i+1}: Probabilidade de spam = {y_proba_spam[i]:.4f} → Previsão: {'Spam' if y_pred[i] == 1 else 'Ham'}")
📌 Saída típica:
Mensagem 1: Probabilidade de spam = 0.0002 → Previsão: Ham
Mensagem 2: Probabilidade de spam = 0.9998 → Previsão: Spam
Mensagem 3: Probabilidade de spam = 0.0015 → Previsão: Ham
...
→ Incrível! O modelo não apenas diz "spam," ele lhe diz "tenho 99,98% de certeza."
O que acontece se você mudar o limiar de decisão?
Por padrão, se probabilidade > 0.5 → spam.
Mas e se você usar 0.7? Ou 0.3?
from sklearn.metrics import precision_recall_curve
import matplotlib.pyplot as plt
precision, recall, thresholds = precision_recall_curve(y_test, y_proba_spam)
plt.figure(figsize=(10, 6))
plt.plot(recall, precision, marker='.', label='Naive Bayes')
plt.xlabel('Revocação')
plt.ylabel('Precisão')
plt.title('Curva Precision-Recall')
plt.legend()
plt.grid(True)
plt.show()
📌 O que você vê?
Uma curva que mostra a compensação entre precisão e revocação para diferentes limiares.
Ideal para escolher um limiar que se adapte às suas necessidades (mais precisão ou mais revocação).
☐ Calcular e interpretar a acurácia.
☐ Construir e ler uma matriz de confusão.
☐ Calcular e interpretar precisão, revocação e F1-score.
☐ Saber quando priorizar precisão vs revocação de acordo com o problema.
☐ Obter e analisar probabilidades de previsão.
☐ Entender que um modelo "bom" depende do contexto, não apenas de um número.
☐ Sentir-se confortável avaliando modelos com rigor profissional.
"Não meça seu modelo pelo quanto ele acerta... meça-o pelo quanto o que ele acerta importa."
← Anterior: Lição 3: Exploração de Dados | Próximo: Lição 5: Avalie Seu Modelo →
Course: AI-course0
Language: PT
Lesson: 4 train model