Ir al contenido

Naive Bayes

En simple: lee esto primero

Naive Bayes hace una simplificación «ingenua»: supone que cada dato aporta su pista por separado, sin influirse entre sí.

Imagínalo así

Para detectar spam, revisa palabra por palabra: «gratis» suma sospecha, «reunión» la resta… y junta todas las pistas como si fueran independientes. No es del todo cierto, pero funciona sorprendentemente bien.

Lo que tienes que llevarte
  • Al suponer independencia, basta con contar cada característica por separado: muy rápido y necesita pocos datos.
  • Se trabaja con logaritmos para no multiplicar miles de números diminutos (la computadora los redondearía a 0).
  • Suavizado de Laplace: sumar 1 a todos los conteos para que una palabra nunca vista no anule todo.
Palabras raras de esta página
independencia condicional
dentro de cada clase, saber un dato no te dice nada de otro.
suavizado de Laplace
el «+1» a los conteos para evitar probabilidades cero.
log-espacio
sumar logaritmos en vez de multiplicar probabilidades.

Más abajo viene la versión completa, con fórmulas. Si una palabra aparece subrayada con puntos, pasa el mouse (o tócala) para ver qué significa.

Para usar Bayes necesitamos p(x∣y=k)p(\mathbf{x}\mid y=k), una densidad sobre todo el vector x=(x1,…,xd)\mathbf{x}=(x_1,\dots,x_d). En alta dimensión es imposible de estimar: con solo 20 features sí/no (palabras), la conjunta necesita 220≈2^{20}\approx 1 000 000 de probabilidades por clase.

Naive Bayes corta el nudo con una suposición audaz: independencia condicional de las features dada la clase:

p(x∣y=k)=∏j=1dp(xj∣y=k)p(\mathbf{x}\mid y=k) = \prod_{j=1}^d p(x_j\mid y=k)

Con eso bastan 20 números por clase (uno por palabra). «Naive» (ingenuo) porque finge que, sabiendo la clase, las features no llevan información conjunta.

¿Por qué hace falta ser «naive»?

Con d palabras (presente/ausente), la distribución conjunta p(x | y) tiene una probabilidad por cada combinación posible. Naive Bayes solo necesita una por palabra.

conjunta completa
1.05 × 10^6Naive Bayes
20

(barras en escala logarítmica, por clase)

parámetros por clase (conjunta)1.05 × 10^6
parámetros por clase (NB)20
Con d = 20, estimar la conjunta exigiría ver cada una de las 1.05 × 10^6 combinaciones varias veces: imposible (un vocabulario real tiene miles de palabras). Suponer independencia condicional cambia un crecimiento exponencial (2ᵈ) por uno lineal (d). Es falso, pero hace el problema estimable: un ejemplo puro de cambiar sesgo por varianza.

Multiplicar muchas probabilidades chicas se desborda a 0 (30 factores ≈ 0.1 dan 10−3010^{-30}). Tomando logs, los productos se vuelven sumas y el ganador no cambia (el log es creciente):

y^=arg⁡max⁡k[log⁡πk+∑j=1dlog⁡p(xj∣y=k)]\hat y = \arg\max_k\Big[\log\pi_k + \sum_{j=1}^d\log p(x_j\mid y=k)\Big]

La regla es la misma para todo Naive Bayes; solo cambia el modelo por feature:

Tipo de featureVariantep(xj∣y=k)p(x_j\mid y=k)Estimación (MLE)
continuaGaussianoN(xj;μkj,σkj2)\mathcal N(x_j;\mu_{kj},\sigma_{kj}^2)media y varianza de xjx_j en la clase kk
presencia de palabra (0/1)Bernoullifracción de docs de la clase con la palabracontar
conteo de palabrasMultinomialfrecuencia de la palabra en la clasecontar

Cada feature continua es su propia campana 1-D (dos perillas: centro μ\mu y dispersión σ\sigma; el exponente es el z-score al cuadrado). Un producto de campanas por eje da elipses alineadas a los ejes (sin inclinación); aun así la frontera se puede curvar.

Parámetros totales: KK priors (con K−1K-1 libres, porque ∑kπk=1\sum_k\pi_k=1) + 2Kd+\ 2Kd números (media y varianza por clase y feature). Nada más.

Mira la elipse diagonal de NB frente a la inclinada de QDA (modo «Naive Bayes»):

El texto no tiene ejes x1,x2x_1, x_2: primero se convierte en features. Bolsa de palabras: se fija un vocabulario y cada palabra es una feature (presencia en Bernoulli, conteo en Multinomial). Un filtro de spam no analiza gramática: pregunta palabra por palabra «¿aparece más en spam o en ham?» y multiplica los votos. Solo hay que estimar ≈ (vocabulario × clases) números, cada uno un conteo.

Priors πspam=0.40\pi_\text{spam}=0.40, πham=0.60\pi_\text{ham}=0.60. Mensaje: «free money now».

freemoneynow
spam0.800.700.55
ham0.100.080.30
spam: 0.40×0.80×0.70×0.55=0.1232ham: 0.60×0.10×0.08×0.30=0.00144\text{spam: } 0.40\times0.80\times0.70\times0.55 = 0.1232\qquad \text{ham: } 0.60\times0.10\times0.08\times0.30 = 0.00144 P(spam∣palabras)=0.12320.1232+0.00144≈0.99(odds≈86:1)P(\text{spam}\mid\text{palabras}) = \frac{0.1232}{0.1232+0.00144}\approx 0.99\quad(\text{odds}\approx 86{:}1)

¿Es spam? Naive Bayes a mano

Haz clic en las palabras para ponerlas o quitarlas del correo. Cada likelihood es solo una fracción contada: correos de la clase que contienen la palabra / correos de la clase.

palabraen el correop(w | spam)p(w | ham)voto
freesí(32+α)/(40+2α) = 0.800(6+α)/(60+2α) = 0.100spam
moneysí(28+α)/(40+2α) = 0.700(5+α)/(60+2α) = 0.083spam
nowsí(22+α)/(40+2α) = 0.550(18+α)/(60+2α) = 0.300spam
lotteryno1 − (12+α)/(40+2α) = 0.7001 − (0+α)/(60+2α) = 1.000—
meetingno1 − (4+α)/(40+2α) = 0.9001 − (30+α)/(60+2α) = 0.500—
projectno1 − (2+α)/(40+2α) = 0.9501 − (27+α)/(60+2α) = 0.550—
reportno1 − (3+α)/(40+2α) = 0.9251 − (24+α)/(60+2α) = 0.600—
0.40⋅0.800⋅0.700⋅0.550⏟score spam=1.232e−10.60⋅0.100⋅0.083⋅0.300⏟score ham=1.500e−3\underbrace{0.40\cdot 0.800\cdot 0.700\cdot 0.550}_{\text{score spam}} = 1.232e-1\qquad \underbrace{0.60\cdot 0.100\cdot 0.083\cdot 0.300}_{\text{score ham}} = 1.500e-3
log score spam-2.09
log score ham-6.50
P(spam | palabras)0.9880
veredictoSPAM
En la práctica se suman logaritmos (30 factores ≈ 0.1 dan 10⁻³⁰ y se desbordan a 0). El log cambia los números, no el ganador. Ojo: la independencia condicional es falsa («free» y «money» van juntas), así que el 0.99 suele ser sobreconfiado; confía en la etiqueta, no en la probabilidad.

Si «lottery» nunca apareció en ningún ham, p(lottery∣ham)=0p(\text{lottery}\mid\text{ham}) = 0 y ese solo cero anula todo el producto de ham, por muy «ham» que sean las otras palabras. Suavizado de Laplace (add-α):

p(w∣y=k)=count(w,k)+αtotal(k)+αVp(w\mid y=k) = \frac{\text{count}(w,k)+\alpha}{\text{total}(k)+\alpha V}

con VV el tamaño del vocabulario (en Bernoulli, V=2V=2 resultados por palabra) y α=1\alpha=1 típico. Es una estimación MAP: el +α+\alpha actúa como un prior de α\alpha conteos imaginados por palabra; ninguna probabilidad vuelve a ser 0.

Con los datos de la tabla, el mensaje es solo «now». ¿Qué clase gana? ¿Y si el prior de spam fuera 0.2?

Ver solución
  • π=0.4\pi=0.4: spam 0.4×0.55=0.220.4\times0.55 = 0.22; ham 0.6×0.30=0.180.6\times0.30=0.18 ⇒ spam (0.22/0.40=0.550.22/0.40 = 0.55).
  • π=0.2\pi=0.2: spam 0.2×0.55=0.110.2\times0.55 = 0.11; ham 0.8×0.30=0.240.8\times0.30 = 0.24 ⇒ ham. Con evidencia débil, el prior decide.

Autoevaluación

0/5 correctas · 0 respondidas
1. La suposición «naive» es…
2. ¿Por qué se suman logaritmos?
3. Con una palabra nunca vista en ham y α=0\alpha = 0…
4. Las elipses de NB gaussiano son…
5. El suavizado de Laplace es un ejemplo de…
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB, BernoulliNB, GaussianNB
from sklearn.pipeline import make_pipeline
spam = make_pipeline(CountVectorizer(), MultinomialNB(alpha=1.0)) # α = Laplace
spam.fit(textos_tr, y_tr)
spam.predict_proba(['free money now']) # [[P(ham), P(spam)]]
nb_bin = make_pipeline(CountVectorizer(binary=True), BernoulliNB(alpha=1.0)) # presencia 0/1
g = GaussianNB().fit(X_tr, y_tr) # features continuas
g.theta_, g.var_, g.class_prior_ # μₖⱼ, σ²ₖⱼ y πₖ: contar y promediar

Fuente ·ML_Course_Generative_Probabilistic_Models.pdf (slides 16–23) · ML_Course/session-05a-gaussian-naive-bayes.ipynb