En 02-05 construimos un detector de fraude con el teorema de Bayes: partíamos de un prior (qué fracción de pedidos son fraudulentos), observábamos una evidencia y actualizábamos hacia el posterior. Aquella máquina de actualizar creencias era, sin saberlo, un clasificador a medio construir: le faltaba poder combinar varias evidencias a la vez sin que las cuentas explotaran. Naive Bayes completa la construcción con una suposición descaradamente falsa — que todas las features son independientes entre sí — que, contra todo pronóstico, produce uno de los clasificadores más rápidos, frugales y útiles de la práctica. En esta lección harás el viaje completo: del teorema al clasificador, un ejemplo numérico a mano con pedidos de MercaFresh, las tres variantes y cuándo usar cada una, y la implementación con scikit-learn.

Contenido

  1. Del teorema de Bayes al clasificador
  2. El supuesto "naive" y por qué funciona pese a ser falso
  3. Ejemplo numérico a mano: ¿es fraudulento este pedido?
  4. Suavizado de Laplace
  5. Las tres variantes: Gaussian, Multinomial, Bernoulli
  6. Implementación con scikit-learn
  7. Fortalezas y debilidades

Del teorema de Bayes al clasificador

Recordatorio exprés de 02-05, en vocabulario de clasificación:

$$P(\text{clase} \mid \text{datos}) = \frac{P(\text{datos} \mid \text{clase}) \cdot P(\text{clase})}{P(\text{datos})}$$

Pieza Nombre En el detector de fraude
$P(\text{clase})$ Prior Fracción histórica de pedidos fraudulentos (p. ej. 1%)
$P(\text{datos} \mid \text{clase})$ Verosimilitud Con qué frecuencia los fraudes presentan esta evidencia
$P(\text{clase} \mid \text{datos})$ Posterior Lo que queremos: probabilidad de fraude dado lo observado
$P(\text{datos})$ Evidencia Normalizador: igual para todas las clases

El clasificador bayesiano es directo: calcula el posterior de cada clase y elige la de posterior máximo. Como $P(\text{datos})$ es idéntico para todas las clases, ni hace falta calcularlo — basta comparar $P(\text{datos} \mid \text{clase}) \cdot P(\text{clase})$.

Nota la diferencia de filosofía con la regresión logística (04-02): aquella aprendía $P(\text{clase} \mid \mathbf{x})$ directamente, ajustando pesos; Naive Bayes la construye por piezas — aprende cómo se distribuyen los datos dentro de cada clase y deja que el teorema haga la síntesis. Por eso se dice que la logística es un modelo discriminativo y Naive Bayes uno generativo.

El supuesto "naive" y por qué funciona pese a ser falso

El obstáculo: con varias features, la verosimilitud es una probabilidad conjunta — $P(x_1, x_2, \dots, x_n \mid \text{clase})$. Estimarla honestamente exige haber visto muchas veces cada combinación de valores, y las combinaciones crecen exponencialmente: con 15 features es imposible (es otra cara de la maldición de la dimensionalidad de 04-05).

La salida "ingenua": suponer que, dentro de cada clase, las features son independientes entre sí. Entonces la conjunta se factoriza en un producto de términos individuales, cada uno trivial de estimar:

$$P(x_1, \dots, x_n \mid c) \approx P(x_1 \mid c) \cdot P(x_2 \mid c) \cdots P(x_n \mid c)$$

El supuesto es falso casi siempre — en MercaFresh, el importe de un pedido y su número de artículos están claramente correlacionados (02-03). ¿Por qué funciona entonces? Dos razones:

  • Clasificar solo exige ordenar bien. No necesitamos que el posterior sea exacto, solo que la clase correcta quede por encima de las demás. Las violaciones de independencia distorsionan las probabilidades (suelen volverlas demasiado extremas: la evidencia correlacionada se "cuenta dos veces"), pero a menudo distorsionan a todas las clases en direcciones parecidas, y el ranking sobrevive.
  • Menos parámetros, menos varianza. Estimar n distribuciones univariantes por clase requiere pocos datos y produce estimaciones estables; un modelo que respetara todas las dependencias necesitaría muchísimos más datos para no alucinar. Con datos escasos, el modelo sesgado-pero-estable gana al fiel-pero-tembloroso — un anticipo del compromiso sesgo-varianza de 06-05.

Consecuencia práctica: usa las etiquetas de Naive Bayes con confianza, y sus probabilidades con pinzas (tienden al 0.99 o al 0.01 injustificados).

Ejemplo numérico a mano: ¿es fraudulento este pedido?

Histórico de 1 000 pedidos de MercaFresh: 20 fraudulentos (prior del 2%) y 980 legítimos. Tres features binarias por pedido, con sus frecuencias en cada clase:

Feature P(sí | fraude) P(sí | legítimo)
importe_alto (> percentil 95) 0.70 0.10
direccion_nueva 0.80 0.15
madrugada (2:00–6:00) 0.50 0.05

Llega un pedido con importe_alto = sí, direccion_nueva = sí, madrugada = no. Puntuación de cada clase (prior × producto de verosimilitudes, usando $P(\text{no}) = 1 - P(\text{sí})$):

  • Fraude: $0.02 \times 0.70 \times 0.80 \times (1 - 0.50) = 0.02 \times 0.28 = 0.0056$
  • Legítimo: $0.98 \times 0.10 \times 0.15 \times (1 - 0.05) = 0.98 \times 0.01425 = 0.01397$

Gana legítimo (0.01397 > 0.0056). Normalizando para obtener el posterior: $P(\text{fraude}) = \frac{0.0056}{0.0056 + 0.01397} \approx 0.29$.

Dos lecturas valiosas:

  • El prior pesa muchísimo: pese a dos señales de alarma de tres, el 2% de partida mantiene el fraude por debajo del 50%. Es la misma lección de los falsos positivos de 02-05: con eventos raros, la evidencia tiene que ser abrumadora. Aun así, un posterior del 29% frente al 2% basal — el pedido es 14 veces más sospechoso que la media — justifica de sobra una revisión manual.
  • Cada feature multiplica: la ausencia de madrugada favoreció a "legítimo" (0.95 contra 0.50). En Naive Bayes ninguna evidencia es neutral: todas empujan.

Esto es todo el algoritmo. Entrenar = contar frecuencias (o medias y varianzas). Predecir = multiplicar y comparar. De ahí su velocidad imbatible.

Suavizado de Laplace

Un fallo mortal del conteo puro: si en el histórico ningún fraude ocurrió en madrugada, entonces $P(\text{madrugada} \mid \text{fraude}) = 0$, y ese cero aniquila el producto entero — ningún pedido de madrugada podría ser clasificado jamás como fraude, por escandalosas que fueran sus demás señales. Un solo hueco en los datos vetaría una clase completa.

El suavizado de Laplace lo evita sumando un pequeño conteo ficticio $\alpha$ (típicamente 1) a cada casilla: en lugar de $\frac{\text{casos}}{\text{total}}$, se estima $\frac{\text{casos} + \alpha}{\text{total} + \alpha \cdot k}$ (con k valores posibles). Así ninguna probabilidad estimada es exactamente 0 ni 1 — "no haberlo visto aún" se trata como "muy raro", no como "imposible". En sklearn es el parámetro alpha de las variantes de conteo.

Las tres variantes: Gaussian, Multinomial, Bernoulli

Lo único que cambia entre variantes es cómo se modela $P(x_i \mid c)$ según el tipo de feature:

Variante Features que espera Cómo modela cada feature Caso de uso típico
GaussianNB Continuas Una normal por clase: media y varianza (02-02) Datos tabulares como el churn de MercaFresh
MultinomialNB Conteos (enteros ≥ 0) Frecuencias relativas suavizadas Texto: veces que aparece cada palabra
BernoulliNB Binarias (0/1) Probabilidad de "sí" por clase Presencia/ausencia: flags como las del ejemplo a mano

GaussianNB estima, para cada feature y cada clase, la media y la desviación de una campana de Gauss — la distribución normal de 02-02 trabajando de verosimilitud — y evalúa la densidad del valor observado en cada campana. MultinomialNB es el rey histórico de la clasificación de texto (spam, sentimientos): cada documento se representa como conteo de palabras, y la verosimilitud de cada palabra en cada clase se estima con Laplace; lo reencontrarás en el proyecto de análisis de sentimientos (09-03). Si tus features son mixtas, la vía pragmática es discretizar/binarizar hacia una variante, o dividir y combinar — aunque en tabular mixto suelen rendir mejor los árboles (04-03).

Implementación con scikit-learn

GaussianNB sobre el churn de MercaFresh, con el patrón de Pipeline habitual. Matiz de preprocesamiento: Naive Bayes no usa distancias, así que el escalado le es indiferente (como al árbol, 03-05); en cambio la transformación Yeo-Johnson de 03-03 le viene especialmente bien, porque acerca cada feature a la normalidad que GaussianNB presupone:

from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.naive_bayes import GaussianNB

# 'preprocesador': el ColumnTransformer de 03-06 (la rama Yeo-Johnson
# ayuda aqui de verdad; el RobustScaler ni ayuda ni estorba)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, stratify=y, random_state=42)

nb = Pipeline([
    ("prep", preprocesador),
    ("modelo", GaussianNB()),
])
nb.fit(X_train, y_train)     # entrenar = estimar medias/varianzas por clase
print(f"Accuracy en test: {nb.score(X_test, y_test):.2%}")

# Lo que ha aprendido: una campana por feature y clase
modelo = nb.named_steps["modelo"]
print("Priors aprendidos:", modelo.class_prior_.round(3))   # [P(fiel), P(churn)]
print("Media de cada feature en la clase churn:", modelo.theta_[1].round(2))

# Posterior para priorizar revisiones, como en 02-05
p_churn = nb.predict_proba(X_test)[:, 1]

Puntos de lectura:

  • class_prior_ son los priors estimados del train — la proporción de cada clase, el "2%" de nuestro ejemplo a mano.
  • theta_ y var_ guardan la media y varianza de cada feature en cada clase: todo el modelo cabe en dos tablas pequeñas. Compara con K-NN (04-05), que carga el dataset entero: son los dos extremos del espectro memoria/síntesis.
  • Velocidad: entrenar es una pasada de conteos y momentos — Naive Bayes entrena en milisegundos donde la SVM (04-04) tarda minutos. Por eso es el clasificador de referencia para líneas base instantáneas y para sistemas con reentrenamiento continuo.
  • Para texto, el mismo esqueleto con MultinomialNB(alpha=1.0) tras una vectorización de conteos — la receta completa, en 09-03.

Fortalezas y debilidades

Fortalezas Debilidades
Entrenamiento y predicción rapidísimos, escalan linealmente Probabilidades mal calibradas (demasiado extremas)
Rinde decentemente con muy pocos datos (pocos parámetros) El supuesto de independencia penaliza cuando las dependencias son la señal
Maneja miles de features con naturalidad (texto) GaussianNB sufre con features muy alejadas de la normal
Sin hiperparámetros críticos (solo alpha en las variantes de conteo) Rara vez es el modelo más preciso en tabular; es la línea base honesta
Incremental: puede aprender por lotes (partial_fit) Features irrelevantes ruidosas empujan igual que las buenas (selección en 03-06 ayuda)

Errores Comunes y Consejos

  • Tomar predict_proba al pie de la letra. Un 0.998 de Naive Bayes no significa 99.8% real: la evidencia correlacionada se contó varias veces. Para decidir etiquetas y ordenar riesgos vale; para comunicar probabilidades al negocio, no sin calibrar.
  • Usar MultinomialNB con features continuas o negativas. Espera conteos; con la salida del RobustScaler (valores negativos) directamente falla. Cada variante con su tipo de feature — la tabla del apartado 5 es el mapa.
  • Olvidar el suavizado con categorías raras. Con alpha=0, una categoría nunca vista en una clase veta esa clase para siempre. Deja el alpha=1 por defecto salvo motivo fundado.
  • Descartarlo por "demasiado simple". En texto y en líneas base sigue siendo competitivo, y como primer modelo de un proyecto da en segundos la referencia que los demás deben batir.
  • Consejo: cuando GaussianNB rinda mal, dibuja el histograma por clase de tus features (02-01). Si ves bimodalidades o asimetrías brutales, la campana que el modelo asume no se parece a la realidad — y la transformación de 03-03 o el binning pueden recuperar varios puntos de accuracy.

Ejercicios

Ejercicio 1. Con las tablas del ejemplo a mano, clasifica el pedido (importe_alto = no, direccion_nueva = sí, madrugada = sí) y calcula su posterior de fraude normalizado.

Ejercicio 2. En el histórico, ningún pedido fraudulento usó pago_contrareembolso (0 de 20). Sin suavizado, ¿qué posterior de fraude tendría un pedido con contrareembolso, importe alto, dirección nueva y madrugada? Recalcula $P(\text{contrareembolso} \mid \text{fraude})$ con Laplace ($\alpha = 1$, feature binaria) y explica el cambio cualitativo.

Ejercicio 3. Entrena sobre el churn GaussianNB, la regresión logística (04-02) y el árbol de 04-03, cronometrando el fit de cada uno (time.perf_counter). Compara accuracy y tiempo, y razona en qué escenario de negocio elegirías Naive Bayes aun no siendo el más preciso.

Soluciones

Ejercicio 1

  • Fraude: $0.02 \times (1-0.70) \times 0.80 \times 0.50 = 0.02 \times 0.12 = 0.0024$
  • Legítimo: $0.98 \times (1-0.10) \times 0.15 \times 0.05 = 0.98 \times 0.00675 = 0.006615$

Gana legítimo; posterior de fraude $= \frac{0.0024}{0.0024 + 0.006615} \approx 0.27$. Curioso: dos señales de alarma (dirección nueva y madrugada) contra una tranquilizadora (importe normal) dejan al pedido en zona de sospecha moderada — de nuevo el prior del 2% haciendo de ancla, como en 02-05.

Ejercicio 2

Sin suavizado, $P(\text{contrareembolso} \mid \text{fraude}) = 0/20 = 0$, y la puntuación de fraude es $0.02 \times 0 \times \dots = 0$: posterior de fraude exactamente 0, por alarmantes que sean las otras tres features. El cero actúa de veto absoluto. Con Laplace: $\frac{0 + 1}{20 + 1 \cdot 2} = \frac{1}{22} \approx 0.045$. La puntuación de fraude renace: $0.02 \times 0.045 \times 0.70 \times 0.80 \times 0.50 \approx 2.5 \times 10^{-4}$, comparable ya con la de legítimo (que también incorpora su término de contrareembolso). El cambio cualitativo: "nunca visto" pasa de imposible a muy improbable, y la decisión vuelve a depender del conjunto de la evidencia en vez de un solo veto.

Ejercicio 3

import time
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier

candidatos = {
    "GaussianNB": GaussianNB(),
    "LogisticRegression": LogisticRegression(max_iter=1000),
    "DecisionTree(d=4)": DecisionTreeClassifier(max_depth=4, random_state=42),
}
for nombre, modelo in candidatos.items():
    pipe = Pipeline([("prep", preprocesador), ("modelo", modelo)])
    t0 = time.perf_counter()
    pipe.fit(X_train, y_train)
    t = time.perf_counter() - t0
    print(f"{nombre:20s} | fit: {t*1000:6.1f} ms | "
          f"test: {pipe.score(X_test, y_test):.2%}")

Resultado típico: Naive Bayes es el más rápido con diferencia y queda cerca (algo por debajo) de los otros en accuracy. Escenarios donde ganaría el puesto pese a ello: (1) reentrenamiento muy frecuente o incremental — p. ej. un filtro que se actualiza con cada tanda de pedidos usando partial_fit; (2) muy pocos datos etiquetados — el fraude confirmado de MercaFresh puede ser un puñado de casos, y NB es de lo poco que no sobreajusta ahí; (3) como línea base instantánea que fija el listón antes de invertir en modelos caros. La precisión no es el único eje: coste, latencia y frescura del modelo también deciden (lo retomaremos en 08-02).

Conclusión

Has cerrado el círculo abierto en 02-05: el teorema de Bayes, con el supuesto ingenuo de independencia como pegamento, se convierte en un clasificador completo — priors por conteo, verosimilitudes por feature (campanas gaussianas, frecuencias suavizadas con Laplace o Bernoullis según la variante), y el posterior máximo como decisión. Sabes hacer las cuentas a mano, sabes por qué el modelo funciona aunque su supuesto sea mentira, y sabes situarlo: el clasificador más rápido y frugal del módulo, ideal como línea base y para texto, con probabilidades que hay que mirar con escepticismo.

Con esto tienes seis algoritmos supervisados, cada uno con una idea-fuerza distinta: ajustar rectas, curvar probabilidades, encadenar preguntas, maximizar márgenes, votar entre vecinos, multiplicar evidencias. La última lección del módulo presenta a la familia que puede aprender la idea que haga falta: pequeñas unidades de cálculo — cada una sospechosamente parecida a la regresión logística — conectadas en capas que componen funciones arbitrariamente complejas. Llegan las redes neuronales, y con ellas el cierre y la comparativa final del módulo.

Curso de Machine Learning

Módulo 1: Introducción al Machine Learning

Módulo 2: Fundamentos de Estadística y Probabilidad

Módulo 3: Preprocesamiento de Datos

Módulo 4: Algoritmos de Machine Learning Supervisado

Módulo 5: Algoritmos de Machine Learning No Supervisado

Módulo 6: Evaluación y Validación de Modelos

Módulo 7: Técnicas Avanzadas y Optimización

Módulo 8: Implementación y Despliegue de Modelos

Módulo 9: Proyectos Prácticos

Módulo 10: Recursos Adicionales

© Copyright 2026. Todos los derechos reservados