17°
Portada del artículo: Naive Bayes explicado: entrenó en 0,008 s y pesa 1,3 KB, pero el 62 % de sus probabilidades quedó en los bordes
Machine learningAlgoritmosPythonDatos

Naive Bayes explicado: entrenó en 0,008 s y pesa 1,3 KB, pero el 62 % de sus probabilidades quedó en los bordes

Qué es Naive Bayes, qué significa la suposición de independencia y cuándo falla, medido con clima diario de siete ciudades de Chile entre 1984 y 2026. Ajustar con 74.145 filas tomó 0,008 s y el modelo ocupa 1,3 KB, con AUC 0,822; por tramos llegó a 0,844, sin diferencia concluyente con la regresión logística. El 62 % de sus probabilidades quedó bajo 0,01 o sobre 0,99, y calibrarlo bajó la pérdida logarítmica de 1,09 a 0,39.

Efrain Garay 15 de septiembre de 2026

Reproduciendo el resumen

Ajustar este modelo con 74.145 filas de clima tomó 0,008 segundos y el artefacto serializado ocupa 1,3 KB: dos números por variable y clase. Con eso llegó a AUC 0,822 en la prueba de 2016-2026, y midiendo las variables por tramos, a 0,844, sin diferencia concluyente con una regresión logística. El precio está en otra parte: el 62 % de sus probabilidades quedó bajo 0,01 o sobre 0,99.

Es la novena entrega de la serie, con los mismos datos diarios de NASA POWER de siete ciudades de Chile que usé en Random Forest, regresión lineal, K-Means, regresión logística, árbol de decisión, gradient boosting, SVM y KNN. La pregunta sigue siendo si lloverá al menos 1 mm mañana. Entrené con 1984-2012 y evalué en la prueba de 2016-2026, en un contenedor con 8 CPU y scikit-learn 1.7.2. La representación de las variables, el número de tramos y el suavizado los elegí ajustando con 1984-2009 (hasta el 30 de diciembre, porque la etiqueta del 31 es la lluvia del 1 de enero de 2010) y midiendo en 2010-2012. Los modelos de comparación usan la configuración de sus propios posts, y las curvas y ejemplos de 2016-2026 son descriptivos.

En 50 segundos y narrado: el modelo entero pesa 1,3 kilobytes y se ajustó en ocho milésimas de segundo; cómo mira cada variable por separado dentro de cada clase; qué pasa cuando una columna se duplica siete veces; por qué seis de cada diez días reciben una probabilidad pegada a cero o a uno; y cómo se comporta con solo treinta filas de entrenamiento. Sin sonido por defecto: actívalo en los controles.Verlo en el visualizador de reels →

¿Qué es Naive Bayes?

El teorema de Bayes invierte la pregunta: en vez de modelar directamente la probabilidad de lluvia dado el día, modela cómo se ven los días dentro de cada clase y después le da vuelta el cálculo. El problema es que describir en conjunto quince variables pide muchísimos datos. La versión ingenua lo resuelve suponiendo que, dentro de cada clase, las variables son independientes entre sí: así basta describir cada variable por separado y multiplicar. Es una idea con raíces en la indexación probabilística de documentos que Maron y Kuhns publicaron en 1960.

Cómo ve Naive Bayes dos variablesLos mismos 200 días y las mismas dos variables estandarizadas de los posts de SVM y KNN. El bucle pasa por los días, la campana ajustada a los días secos, la de los días con lluvia y la línea donde la probabilidad cruza 0,5.
seco al día siguientelluvia al día siguienteprobabilidad 0,5AUC 2010-12 0,795humedad (estandarizada)lluvia de hoy, escala log (estandarizada)

El modelo ajusta una media y una varianza por variable y clase, así que cada campana sale con los ejes alineados: supone que las dos variables son independientes dentro de cada clase. En estos días no lo son, con una correlación de 0,40 entre los días secos y de 0,42 entre los de lluvia. Aun así, en 2010-2012 llegó a AUC 0,795 contra 0,803 de una regresión logística con las mismas dos variables.

Con dos variables, humedad y lluvia de hoy, y los mismos 200 días de los posts anteriores, el modelo ajusta una campana por clase, con los ejes alineados porque supone que las dos variables no se relacionan dentro de la clase. En esos días sí se relacionan, con una correlación de 0,40 entre los secos y 0,42 entre los de lluvia. Aun así, en 2010-2012 llegó a AUC 0,795 contra 0,803 de una regresión logística con las mismas dos variables.

Una predicción, abierta en sumandos

Como todo es una multiplicación, tomar logaritmos la convierte en una suma: el log-odds de lluvia es el término del prior más un término por variable.

Una predicción, abierta en sumandosLog-odds de lluvia para Santiago el 28 de mayo de 2010, como el término del prior más un término por variable. Positivo empuja hacia lluvia; negativo, hacia día seco.
prior (tasa base)−0,99lluvia de hoy+4,29presión−2,90viento norte-sur+2,00lluvia de ayer−0,88radiación+0,84humedad−0,76latitud−0,63día del año (cos)+0,46cambio de presión−0,40mínima+0,36viento−0,24viento este-oeste+0,18punto de rocío+0,16máxima−0,04día del año (sen)−0,02total+1,42 · probabilidad de lluvia 81 %

Naive Bayes suma un logaritmo de cociente de verosimilitudes por variable, y por eso una predicción se puede leer término a término. Ese día la lluvia ya caída empujó +4,29 hacia lluvia y la presión −2,90 en contra; partiendo de un prior de −0,99, los términos suman 1,42, que es una probabilidad de 81 %. El log-odds que entrega el propio modelo es 1,42, el mismo número. Al día siguiente llovió.

Para un día de Santiago de mayo de 2010, la lluvia ya caída aportó +4,29 y la presión −2,90; partiendo de un prior de −0,99, los quince términos suman 1,42, que es una probabilidad de 81 %. El log-odds que entrega el propio modelo es 1,42, el mismo número: la explicación no es una aproximación, es la cuenta. Al día siguiente llovió.

La suposición que no se cumple

En las 66.466 filas de 1984-2009, dentro de la clase de días secos, el 10,5 % de los pares de variables supera 0,5 de correlación en valor absoluto: radiación y día del año 0,81, humedad y presión 0,80, máxima y humedad −0,71. Dentro de los días con lluvia, el 7,6 %.

Lo que eso cuesta se ve mejor exagerándolo: copié la humedad dentro de la tabla, para que el modelo cuente la misma evidencia varias veces.

Contar dos veces la misma evidenciaLa humedad copiada 0, 1, 3 y 7 veces más. Naive Bayes y la regresión logística ajustados con 1984-2009 y medidos en 2010-2012.
AUCpérdida log.0,800,820,840120,821+01,26+00,818+11,37+10,814+31,64+30,805+72,29+7copias extra de la humedad
  • Naive Bayes
  • logística

Naive Bayes multiplica una verosimilitud por columna, así que una columna copiada vuelve a contar su evidencia. Con 7 copias extra su AUC bajó de 0,821 a 0,805, la pérdida logarítmica subió de 1,26 a 2,29 y el promedio del log-odds en valor absoluto pasó de 8,5 a 16,5: el modelo quedó mucho más seguro del mismo día. La regresión logística, que ajusta las columnas juntas, se quedó en AUC 0,850 y pérdida 0,400.

Con siete copias extra, el AUC en 2010-2012 bajó de 0,821 a 0,805 y la pérdida logarítmica subió de 1,26 a 2,29. El promedio del log-odds en valor absoluto pasó de 8,5 a 16,5: el modelo quedó el doble de seguro con la misma información. La regresión logística, que ajusta las columnas juntas, no se movió de 0,850. Es lo que Domingos y Pazzani mostraron en 1997: Naive Bayes puede clasificar bien aunque sus probabilidades estén mal, porque el orden aguanta la violación de la suposición mucho mejor que el número. Hand y Yu revisaron en 2001 por qué sigue funcionando tan seguido.

La campana contra los datos

La versión gaussiana supone además que cada variable, dentro de su clase, se distribuye como una campana. La lluvia no.

La campana contra los datosDías de 1984-2009 seguidos de lluvia y días seguidos de tiempo seco, con la curva normal que GaussianNB le ajusta a cada clase: misma media, misma varianza.
033lluvia de hoy (mm)04log(1 + lluvia de hoy)1797humedad (%)
  • lluvia al día siguiente
  • seco al día siguiente
  • normal ajustada

La lluvia de hoy no tiene forma de campana: el 33 % de la columna de días seguidos de lluvia cae en el primer tramo y la cola se estira a la derecha, con una asimetría de 3,63. La normal que se le ajusta, con media 5,44 y varianza 71,6, reparte densidad bajo cero, donde no existe ningún día. Tomar el logaritmo acerca la forma a una campana, y la humedad ya se parece a una. Esta es la suposición que suelta la versión del modelo por tramos.

En 1984-2009, el 34 % de los días tiene exactamente cero milímetros y la asimetría de la lluvia es 6,0. La normal que se le ajusta a los días seguidos de lluvia tiene media 5,4 y varianza 71,6, así que reparte densidad bajo cero, donde no existe ningún día. Probé tres formas de arreglarlo, eligiendo en 2010-2012: tomar el logaritmo de las dos columnas de lluvia subió el AUC de 0,821 a 0,827; una transformación por cuantiles a forma normal, a 0,825; y cortar cada variable en 40 tramos por cuantiles y contar frecuencias con CategoricalNB, con suavizado alpha = 10 elegido en la misma rejilla, a 0,843. Con esa última, reentrenada con 1984-2012, la prueba de 2016-2026 dio 0,844 contra 0,822 de la gaussiana cruda. Salirse de la campana costó 26,7 KB en vez de 1,3 KB.

No hay que escalar, pero el suavizado sí mira las unidades

El suavizado sí mira las unidadesGaussianNB ajusta una media y una varianza por variable y clase, así que reescalar una columna no cambia nada por sí solo. Pero var_smoothing le suma a cada varianza un épsilon igual a 1e-9 por la varianza más grande de la tabla.
0,60,70,80,821kPaε 3,5e-70,821Pa (×1.000)ε 1,7e-20,675×1.000.000ε 1,7e40,615×1.000.000.000ε 1,7e10la presión escrita en · épsilon sumado a cada varianza

Con la presión en kPa, el épsilon fue 3,5e-7 contra una varianza mínima de 0,140, y el AUC en 2010-2012 fue 0,821; en Pa, 0,821. Multiplicada por un millón, el épsilon llegó a 1,7e4, muy por encima de todas las demás varianzas, cada variable quedó aplanada en casi la misma campana y el AUC bajó a 0,675; por mil millones, 0,615. Estandarizar todas las variables dio 0,821, lo mismo que en kPa.

Una media y una varianza por variable y clase no cambian nada si una columna se multiplica por mil: estandarizar todas las variables dio el mismo 0,821 que los datos crudos, y escribir la presión en pascales, 0,8205. El detalle está en var_smoothing, que le suma a todas las varianzas un épsilon igual a 1e-9 por la varianza más grande de la tabla. Con la presión multiplicada por un millón, ese épsilon llegó a 17.167, muy por encima de la varianza más chica de la tabla, 0,140: todas las variables quedaron aplanadas en casi la misma campana y el AUC cayó a 0,675. Por mil millones, 0,615.

Ese mismo parámetro, barrido de 1e-12 a 0,1 en validación, casi no movió el AUC hasta 1e-4 (0,820); con 1e-3 bajó a 0,813 y con 0,1 a 0,796, mientras la pérdida logarítmica bajaba de 1,26 a 0,53, porque aplanar las campanas vuelve el modelo menos confiado. Dejé el valor por defecto: el mejor del barrido, 1e-7, mejoró el AUC en 7e-7.

Probabilidades al borde

Ordena bien y miente al decir cuántoFiabilidad en la prueba de 2016-2026: por cada décima de probabilidad predicha, la proporción real de días con lluvia. La diagonal es el acuerdo perfecto.
0,00,00,50,51,01,0días bajo 0,01 o sobre 0,9961,9 %Naive Bayes gaussianopérdida 1,092,2 %calibrado (isotónica)pérdida 0,390,2 %regresión logísticapérdida 0,3814,6 %boostingpérdida 0,33

Multiplicar quince verosimilitudes empuja el resultado a los bordes: el 61,9 % de los días de prueba recibió una probabilidad bajo 0,01 o sobre 0,99, y la pérdida logarítmica fue 1,09 contra 0,378 de la regresión logística, aunque sus AUC son 0,822 y 0,847. Una calibración isotónica ajustada en 2010-2012 dejó el orden intacto, AUC 0,822, y bajó la pérdida a 0,391. Para decidir con el número hay que usar la versión calibrada.

Multiplicar quince verosimilitudes, varias de ellas correlacionadas, empuja el resultado a los extremos: el 61,9 % de los días de prueba recibió una probabilidad bajo 0,01 o sobre 0,99. La pérdida logarítmica fue 1,09 contra 0,38 de la regresión logística, aunque sus AUC son 0,822 y 0,847. Con la versión por tramos, 1,01.

Calibrar aparte lo arregla sin tocar el orden. Ajustando la calibración en 2010-2012 sobre un modelo entrenado en 1984-2009, una sigmoide dejó la pérdida en 0,402 y una isotónica en 0,391, con AUC 0,823 y 0,822; sobre la versión por tramos, la isotónica llegó a 0,383, cerca del 0,378 de la logística. Es lo que Niculescu-Mizil y Caruana midieron en 2005 para varias familias de modelos. Cambiar solo el prior, usando la tasa de lluvia de 2010-2012 en vez de la de 1984-2012, casi no ayudó: 1,07.

Con pocas filas es difícil de ganar

Con pocas filas, pocos parámetros aguantan mejorAUC en la prueba de 2016-2026 contra el número de filas de entrenamiento, tomadas al azar de 1984-2012. Mediana de hasta 20 sorteos, con el rango intercuartílico sombreado. Es descriptivo: con esta curva no se eligió nada.
301001.00010.00074.1450,50,60,70,80,9filas de entrenamiento (log)
  • Naive Bayes gaussiano
  • Naive Bayes en bins
  • regresión logística
  • boosting, 594 rondas

Con 30 filas, Naive Bayes gaussiano llegó a una mediana de AUC de 0,795 y la regresión logística a 0,790, mientras el boosting se quedó en 0,500: con tan pocos datos no alcanzó ni a ordenar los días. Desde las 300 filas la logística va adelante, y con las 74.145 el boosting llega a 0,883 mientras Naive Bayes gaussiano se queda en 0,822. Naive Bayes ajusta dos números por variable y clase: tiene poco que estimar y también poco margen para mejorar.

Naive Bayes estima dos números por variable y clase, así que tiene poco que estimar. Con 30 filas de entrenamiento, su AUC mediano en la prueba fue 0,795 y el de la regresión logística 0,790, mientras el boosting se quedó en 0,500: con tan pocos datos no alcanzó ni a ordenar los días. Con 100 filas, 0,817 contra 0,809 y 0,801. Desde las 300 la logística va adelante y el boosting se despega, hasta 0,883 con todas las filas mientras la gaussiana se queda en 0,822. Es la comparación que Ng y Jordan formalizaron en 2001: el modelo generativo llega antes a su techo, y ese techo es más bajo.

Aprender de a un año

Con un año ya llegaEl modelo se entrena con partial_fit, de a un año entre 1984 y 2012, sin volver a mirar los años anteriores. Después de cada año, el AUC en la prueba de 2016-2026 (descriptivo).
0,8120,8180,8240,83019841991199820052012años vistosAUC 2016-26

Con 1984 solo, 2.562 filas, ya dio 0,826; con las 74.145 filas terminó en 0,822, y el mejor año del camino fue 0,826. Cada actualización anual tomó una mediana de 1,21 ms, porque solo suma conteos, sumas y sumas de cuadrados. El modelo entrenado por partes coincide con uno ajustado de una vez: la mayor diferencia en la probabilidad predicha es 5e-9.

El ajuste son conteos, sumas y sumas de cuadrados, así que se puede hacer por partes. Entrené con partial_fit año por año, sin volver a mirar los anteriores: después de 1984 solo, 2.562 filas, ya daba 0,826, más que el 0,822 final con las 74.145. Cada actualización tomó una mediana de 1,2 ms, y el modelo entrenado por partes coincide con uno ajustado de una vez: la mayor diferencia en la probabilidad predicha es 5e-9.

Naive Bayes, logística, KNN, bosque y boosting

Las mismas 74.145 filas, con un hiloMediana de 3 ajustes, salvo el bosque (una medición). AUC medido en la prueba de 2016-2026. Cambia de escenario para ver el costo al puntuar.
Naive Bayes gaussiano · AUC 0,8220,0081 s
KNN, k = 100 · AUC 0,8700,0142 s
Regresión logística · AUC 0,8470,0496 s
Naive Bayes en tramos · AUC 0,8440,0581 s
Árbol, profundidad 7 · AUC 0,8620,3703 s
Boosting, 594 rondas · AUC 0,8832,6182 s
Bosque, 200 árboles · AUC 0,88223,9211 s

A un cuarto del tiempo real.

Naive Bayes gaussiano0,0023 s
Naive Bayes en tramos0,0151 s
Árbol, profundidad 70,0015 s
Regresión logística0,0016 s
Bosque, 200 árboles0,3248 s
Boosting, 594 rondas0,5834 s
KNN, k = 1005,7856 s

Las 27.256 filas, en tiempo real.

Serializados, Naive Bayes gaussiano ocupa 1,3 KB, la versión en tramos 26,7 KB, la regresión logística 1,8 KB, el boosting 2,1 MB y el bosque 124 MB. Puntuar un día tomó 0,38 ms a la gaussiana y 3,2 ms al boosting.

Con las mismas filas, remuestreé 2.000 veces los bloques ciudad-año de 2016-2026 para comparar el AUC en pares. La versión en tramos quedó 0,003 bajo la regresión logística, con un intervalo del 95 % de −0,008 a 0,001, el único que cruza el cero: en capacidad de ordenar, la diferencia no es concluyente. Contra el árbol de profundidad 7 quedó 0,018 abajo, contra KNN 0,026 y contra el boosting 0,039 (de −0,044 a −0,035). Sobre la gaussiana cruda quedó 0,021 arriba.

Dónde vive Naive Bayes en un sistema real

Dónde vive Naive BayesConteos y sumas por clase, un artefacto de pocos kilobytes y un desvío obligatorio por la calibración.
Dónde vive Naive Bayestabla74.145 filasconteos y sumaspor claseartefacto1,3 KBlote nuevopartial_fitfiltro en línea1 fila · 0,38 mscalibraciónantes de decidirlínea baseAUC 0,822

Medido con un hilo sobre las 74.145 filas: Naive Bayes gaussiano se ajusta en 0,008 s, serializado ocupa 1,3 KB, puntúa una fila en 0,38 ms y todo el período de prueba en 0,002 s, con AUC 0,822 y pérdida logarítmica 1,09. Calibrado en 2010-2012, la pérdida baja a 0,391. La regresión logística: 0,050 s, AUC 0,847, pérdida 0,378. El boosting: 2,6 s, 2,1 MB, AUC 0,883.

  • Filtros y triaje en línea. Puntuar una fila toma 0,38 ms y el modelo entero cabe en 1,3 KB: sirve donde hay que decidir rápido y barato, como en los filtros de correo, uno de los primeros trabajos académicos en aplicarlo fue el de Sahami y coautores en 1998.
  • Datos que llegan de a poco. partial_fit actualiza el modelo con cada lote sin guardar lo anterior.
  • Muy pocos ejemplos. Con decenas de filas ya ordena, donde los modelos con más parámetros todavía no arrancan.
  • Calibración obligatoria si el número se usa. Sin calibrar, sus probabilidades viven en los bordes.
  • Línea base. Es la referencia contra la que se justifica cualquier modelo más caro.

Cuándo lo elegiría: como primera medición de un problema nuevo, para conjuntos chicos, para texto con muchas columnas escasas, o cuando el modelo debe ser diminuto y actualizable. Cuándo no: cuando hace falta una probabilidad creíble sin un paso extra de calibración, cuando las variables están muy correlacionadas entre sí, o cuando hay datos de sobra y el techo importa. En estos datos, con las 74.145 filas, un boosting quedó 0,039 de AUC por encima y con menos de un tercio de su pérdida logarítmica.

Fuentes

Comentarios

Todavía no hay comentarios. El primero es tuyo.

Se revisa antes de publicarse. El correo no se guarda ni aparece en ninguna parte.