📘 Lección 4: ¡Entrena tu Primer Modelo! — De la Teoría a la Práctica con Scikit-learn

"Un modelo sin evaluación es como un examen sin calificación: no sabes si aprobaste… o si solo tuviste suerte."


⏱️ Duración estimada de esta lección: 75-90 minutos


🧭 ¿Por qué esta lección es tan importante?

Porque aquí es donde dejas de confiar y empiezas a verificar.

Entrenaste un modelo.
Hizo predicciones.
¡Pero eso no significa que sea bueno!

Muchos principiantes se emocionan con un "98% de accuracy"… y luego descubren que su modelo falla en los casos más importantes.

En esta lección, aprenderás:

  • Por qué la accuracy no lo es todo (¡especialmente en datos desbalanceados!).
  • Qué es una matriz de confusión y cómo leerla como un profesional.
  • Qué significan precisión, recall y F1-score… y cuándo usar cada uno.
  • Cómo interpretar probabilidades, no solo etiquetas.
  • Cómo evitar engañarte a ti mismo/a con métricas superficiales.

⚠️ Advertencia amistosa: Esta lección te hará cuestionar todo lo que creías saber sobre "modelos buenos". Pero eso es bueno. La humildad es la madre de la mejora.


🎯 Objetivos de esta lección

Al finalizar, serás capaz de:

✅ Calcular e interpretar la accuracy de tu modelo.
✅ Construir y entender una matriz de confusión.
✅ Calcular e interpretar precisión, recall y F1-score.
✅ Saber cuándo usar cada métrica según el problema.
✅ Evaluar no solo las predicciones, sino las probabilidades.
✅ Detectar si tu modelo es "tonto" o verdaderamente inteligente.
✅ Sentirte cómodo/a tomando decisiones basadas en métricas, no en intuición.


🛠️ Herramientas que usarás

  • Scikit-learnaccuracy_score, confusion_matrix, classification_report, precision_recall_curve.
  • Matplotlib / Seaborn → Para visualizar métricas.
  • Pandas → Para manipular resultados.

💡 Asegúrate de tener tu modelo entrenado y tus predicciones (y_test, y_pred) listas de la Lección 4. Si no, aquí está el código rápido para ponerte al día:

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

# Cargar y preparar datos
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)

# Entrenar modelo
model = MultinomialNB()
model.fit(X_train_vec, y_train)

# Predecir
y_pred = model.predict(X_test_vec)

📊 Parte 1: La Ilusión de la Accuracy — ¿Realmente es 98%?

Vamos a empezar con la métrica más popular… y más peligrosa.


🔹 Paso 1: Calcular la accuracy

from sklearn.metrics import accuracy_score

acc = accuracy_score(y_test, y_pred)
print(f"Accuracy: {acc:.4f} → {acc*100:.2f}%")

📌 Salida típica:

Accuracy: 0.9821 → 98.21%

→ ¡Guau! 98% de aciertos. ¿Significa que el modelo es excelente?

¡NO! Y aquí está el porqué.


🔍 El problema de los datos desbalanceados

Recuerda: en nuestro dataset, solo el 13.4% son spam. El 86.6% son ham.

Imagina un modelo tonto que siempre predice "ham".
¿Cuál sería su accuracy?

Accuracy = (Verdaderos Ham) / (Total) = 955 / 1115 ≈ 85.65%

→ ¡Un modelo que nunca detecta spam tendría 85.65% de accuracy!

Tu modelo tiene 98.21% → es mejor que el tonto… pero ¿cuánto mejor en lo que realmente importa: detectar spam?

📌 Conclusión: La accuracy engaña cuando hay desbalance. Necesitas métricas más inteligentes.


🧩 Parte 2: La Matriz de Confusión — Tu Microscopio de Errores

Aquí es donde ves exactamente qué aciertos y qué errores está cometiendo tu modelo.


🔹 Paso 2: Construir la matriz de confusión

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 Confusión - Clasificador de Spam", fontsize=16)
plt.ylabel("Etiqueta Real", fontsize=12)
plt.xlabel("Etiqueta Predicha", fontsize=12)
plt.show()

📌 Salida típica (valores aproximados):

          Predicho
          Ham  Spam
Real Ham   950    5
Real Spam   15  145

🔍 ¿Cómo leer esta matriz?

  • Verdaderos Negativos (TN): 950
    → Mensajes ham que el modelo dijo que eran ham. ✅ ¡Perfecto!

  • Falsos Positivos (FP): 5
    → Mensajes ham que el modelo dijo que eran spam. ❌ ¡Error grave! (Marcar un mensaje importante como spam).

  • Falsos Negativos (FN): 15
    → Mensajes spam que el modelo dijo que eran ham. ❌ ¡Error grave! (Dejar pasar spam).

  • Verdaderos Positivos (TP): 145
    → Mensajes spam que el modelo dijo que eran spam. ✅ ¡Perfecto!

📌 ¡Esto es oro! Ahora sabes dónde falla tu modelo. No es un número abstracto… son errores concretos que puedes mejorar.


🎯 Parte 3: Precisión, Recall y F1-Score — Las 3 Métricas que Importan

Ahora, vamos a cuantificar esos errores con métricas profesionales.


🔹 Paso 3: Calcular el reporte de clasificación

from sklearn.metrics import classification_report

report = classification_report(y_test, y_pred, 
                               target_names=['Ham', 'Spam'], 
                               output_dict=False)
print(report)

📌 Salida 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

🔍 ¿Qué significan estas métricas?

1. Precisión (Precision)

"De todos los que dije que eran spam, ¿cuántos realmente lo eran?"

Precision (Spam) = TP / (TP + FP) = 145 / (145 + 5) = 145/150 ≈ 0.97

97% de precisión en spam: cuando el modelo dice "spam", tiene razón el 97% de las veces. ¡Excelente!

📌 ¿Cuándo importa la precisión?
Cuando el costo de un falso positivo es alto.
Ejemplo: Marcar un email importante como spam → el usuario podría perder información crítica.


2. Recall (Sensibilidad, Tasa de Verdaderos Positivos)

"De todos los spam que existían, ¿cuántos detecté?"

Recall (Spam) = TP / (TP + FN) = 145 / (145 + 15) = 145/160 ≈ 0.91

91% de recall en spam: detectó el 91% de todos los spam. ¡Muy bueno!

📌 ¿Cuándo importa el recall?
Cuando el costo de un falso negativo es alto.
Ejemplo: Dejar pasar un spam fraudulento → el usuario podría hacer clic y perder dinero.


3. F1-Score

"Promedio armónico entre precisión y recall. Ideal cuando quieres equilibrio."

F1 = 2 * (Precision * Recall) / (Precision + Recall)
   = 2 * (0.97 * 0.91) / (0.97 + 0.91) ≈ 0.94

94% de F1-score: un buen equilibrio entre no molestar al usuario (precisión) y protegerlo (recall).

📌 ¿Cuándo usar F1?
Cuando no sabes qué es más importante, o cuando quieres una sola métrica que resuma el rendimiento en clases desbalanceadas.


📈 Parte 4: Más Allá de las Etiquetas — Evaluando Probabilidades

Tu modelo no solo predice "spam" o "ham". También te da probabilidades.

Esto es poderoso. Porque a veces, no quieres una decisión binaria… quieres saber qué tan seguro está el modelo.


🔹 Paso 4: Obtener probabilidades

# Obtener probabilidades para cada clase
y_proba = model.predict_proba(X_test_vec)

# Para spam (clase 1), es la segunda columna
y_proba_spam = y_proba[:, 1]

# Ver las primeras 10 probabilidades
for i in range(10):
    print(f"Mensaje {i+1}: Probabilidad de spam = {y_proba_spam[i]:.4f} → Predicción: {'Spam' if y_pred[i] == 1 else 'Ham'}")

📌 Salida típica:

Mensaje 1: Probabilidad de spam = 0.0002 → Predicción: Ham
Mensaje 2: Probabilidad de spam = 0.9998 → Predicción: Spam
Mensaje 3: Probabilidad de spam = 0.0015 → Predicción: Ham
...

→ ¡Increíble! El modelo no solo dice "spam", sino que te dice "estoy 99.98% seguro".


🔹 Paso 5: Curva Precision-Recall (opcional, pero reveladora)

¿Qué pasa si cambias el umbral de decisión?

Por defecto, si probabilidad > 0.5 → spam.
Pero ¿y si usas 0.7? ¿o 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('Recall')
plt.ylabel('Precision')
plt.title('Curva Precision-Recall')
plt.legend()
plt.grid(True)
plt.show()

📌 ¿Qué ves?
Una curva que muestra el trade-off entre precisión y recall para diferentes umbrales.
Ideal para elegir un umbral que se adapte a tus necesidades (más precisión o más recall).


❌ Errores Comunes en esta Lección (¡Evítalos!)

  1. Confiar solo en la accuracy → Te pierdes errores críticos.
  2. Ignorar la matriz de confusión → No ves dónde falla el modelo.
  3. No entender la diferencia entre precisión y recall → Tomas decisiones equivocadas.
  4. Olvidar que las métricas dependen del problema → En medicina, recall es vital; en publicidad, precisión.
  5. No usar probabilidades → Pierdes información valiosa sobre la confianza del modelo.

✅ Checklist de esta lección — ¿Qué debes saber hacer ahora?

☐ Calcular e interpretar la accuracy.
☐ Construir y leer una matriz de confusión.
☐ Calcular e interpretar precisión, recall y F1-score.
☐ Saber cuándo priorizar precisión vs recall según el problema.
☐ Obtener y analizar probabilidades de predicción.
☐ Entender que un modelo "bueno" depende del contexto, no de un número.
☐ Sentirte cómodo/a evaluando modelos con rigor profesional.


🎯 Frase para recordar:

"No midas tu modelo por cuánto acierta… mídelo por cuánto importa lo que acierta."


Course Info

Course: AI-course0

Language: ES

Lesson: 4 train model