
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.
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.
¿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.
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.
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.
- 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.
- 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
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
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
- 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 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
A un cuarto del tiempo real.
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
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_fitactualiza 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
- Maron, M. E. y Kuhns, J. L. (1960). «On Relevance, Probabilistic Indexing and Information Retrieval». Journal of the ACM, 7(3), 216–244. DOI 10.1145/321033.321035.
- Domingos, P. y Pazzani, M. (1997). «On the Optimality of the Simple Bayesian Classifier under Zero-One Loss». Machine Learning, 29, 103–130. DOI 10.1023/A:1007413511361.
- Hand, D. J. y Yu, K. (2001). «Idiot’s Bayes — Not So Stupid After All?». International Statistical Review, 69(3), 385–398. DOI 10.1111/j.1751-5823.2001.tb00465.x.
- Ng, A. Y. y Jordan, M. I. (2001). «On Discriminative vs. Generative Classifiers: A comparison of logistic regression and naive Bayes». Advances in Neural Information Processing Systems 14.
- Niculescu-Mizil, A. y Caruana, R. (2005). «Predicting Good Probabilities with Supervised Learning». ICML ‘05, 625–632. DOI 10.1145/1102351.1102430.
- Sahami, M., Dumais, S., Heckerman, D. y Horvitz, E. (1998). «A Bayesian Approach to Filtering Junk E-Mail». AAAI Workshop on Learning for Text Categorization.
- scikit-learn 1.7, Naive Bayes.
- NASA POWER, Daily API y fuentes de datos.
Comentarios
Todavía no hay comentarios. El primero es tuyo.