
Regresión logística explicada: 16 números para decidir si llueve mañana
Qué es la regresión logística, cómo convierte una suma en probabilidad y cuándo engaña, medida con clima diario de siete ciudades de Chile entre 1984 y 2026. Una recta da probabilidades negativas en el 9 % de los días; con umbral 0,5 la logística atrapa solo la mitad de las lluvias; y promete más lluvia de la que cae.
Una regresión logística cabe en 16 números: 15 pesos y una constante. Con ellos decidí si llovía mañana en siete ciudades de Chile, y ordenó los días casi tan bien como un bosque de 200 árboles con 1,5 millones de nodos. Pero con el umbral por defecto avisó solo la mitad de las lluvias, y cuando decía “30 %” llovía menos que eso.
Es la cuarta entrega de la serie, con los mismos datos diarios de NASA POWER que usé en Random Forest, regresión lineal y K-Means. La pregunta es la misma que respondió el bosque: ¿lloverá al menos 1 mm mañana? Entrené con 74.145 filas ciudad-día de 1984 a 2012 y evalué con 27.256 de 2016 a 2026, en un contenedor con 8 CPU.
¿Qué es la regresión logística?
La regresión logística estima una probabilidad. Suma las variables del día, cada una con su peso, igual que una regresión lineal. La diferencia está al final: esa suma pasa por la sigmoide, una curva en forma de S que convierte cualquier número en un valor entre 0 y 1. Una suma muy negativa queda cerca de 0, una muy positiva cerca de 1 y una suma de 0 queda en 0,5.
Los pesos no se eligen con mínimos cuadrados, sino maximizando la verosimilitud: los pesos que hacen más probable lo que de verdad pasó. scikit-learn agrega por defecto un castigo L2 suave a los pesos; en estos datos, debilitarlo hasta C = 10 no cambió las métricas a cuatro decimales. Cox la formuló como regresión para secuencias binarias en 1958, y Berkson ya había usado la función logística en bioensayos en 1944.
Por qué no alcanza una recta
La tentación es ajustar una regresión lineal a una columna de 0 y 1. Funciona a medias, y el gráfico muestra dónde se rompe.
- tasa observada
- recta sobre 0 y 1
- regresión logística
Con las quince variables, la recta dio una probabilidad negativa en el 9,1 % de los días de 2016-2026 y una mayor que 1 en el 0,4 %, entre -0,10 y 2,28. Ordenó los días casi igual de bien (AUC 0,847 sobre la salida sin recortar, contra 0,847), pero un número negativo no es una probabilidad.
Con la humedad sola, la tasa real de lluvia sube despacio y después se dispara en los días más húmedos. La recta no puede doblarse: se pasa bajo cero en los días secos. Con las quince variables, dio probabilidades negativas en el 9,1 % de los días de 2016-2026 y una de 2,28 en el peor caso. Para ordenar días sirvió casi igual que la logística (AUC de 0,847 en ambas, calculado sobre la salida sin recortar), pero un número negativo no se puede usar como probabilidad.
Qué dicen los pesos
Cada peso de la logística se lee como una razón de momios. Los momios son la probabilidad de que llueva dividida por la de que no llueva; un peso convertido a razón de momios dice por cuánto se multiplican cuando la variable sube y las demás quedan fijas.
- lluvia hoy×2,19
- viento N-S (cos)×1,94
- latitud×0,58
- viento máximo×0,76
- mínima hoy×0,83
- punto de rocío×1,18
- día del año (cos)×0,86
- cambio de presión×0,88
- lluvia ayer×1,14
- presión×1,12
- radiación×1,11
- máxima hoy×0,92 · signo inestable
- humedad×1,06 · signo inestable
- día del año (sen)×1,04
- viento E-O×1,02 · signo inestable
los mismos pesos en unidades reales (los momios se multiplican por)
- ×6,29dirección del viento 0° en vez de 180°
- ×2,135 mm más de lluvia hoy
- ×1,36presión 1 kPa más baja que ayer
- ×1,0310 puntos más de humedad
- ×0,815 °C más de mínima
La humedad, con la que por sí sola la tasa de lluvia sube con claridad, queda con un peso cuyo intervalo cruza el 1 (0,90 a 1,22) probablemente porque otras variables cargan información parecida (en el post de regresión lineal su VIF fue 33). Los pesos describen este modelo con estas variables, no causas.
Con las variables estandarizadas, la lluvia de hoy multiplicó los momios de lluvia mañana por 2,19 por cada desviación estándar, y el componente norte-sur de la dirección del viento por 1,94. En unidades reales: 5 mm más de lluvia hoy los multiplicaron por 2,13; una presión 1 kPa más baja que ayer, por 1,36; y una dirección cercana a 0° en vez de 180°, por 6,29. En la convención meteorológica habitual, 0° es viento que viene del norte, pero no verifiqué qué convención usa NASA POWER, así que lo dejo como dirección y no como causa.
La humedad es el caso interesante. Sola, la tasa de lluvia sube con claridad a medida que aumenta, como se vio en el gráfico anterior; dentro del modelo, 10 puntos más apenas multiplicaron los momios por 1,03, y en 200 remuestreos su intervalo cruzó el 1 (el peso cambió de signo en el 20,5 % de ellos). Probablemente se debe a que otras variables cargan información parecida: en la regresión lineal medí que la humedad se puede explicar casi entera con las demás (VIF de 33). Un peso es el efecto de mover una variable con las otras fijas, no su importancia por sí sola.
El umbral lo decide el costo
La logística entrega una probabilidad. Decidir “aviso lluvia” requiere un umbral, y el que viene por defecto, 0,5, no tiene por qué ser el correcto.
umbral 0,05
umbral 0,10
umbral 0,15
umbral 0,20
umbral 0,25
umbral 0,30
umbral 0,35
umbral 0,40
umbral 0,45
umbral 0,50
umbral 0,55
umbral 0,60
umbral 0,65
umbral 0,70
umbral 0,75
umbral 0,80
umbral 0,85
umbral 0,90
umbral 0,95
umbral 0,49
umbral 0,23
umbral 0,13
Umbral 0,49 elegido en 2010-2012. En 2016-2026: sensibilidad 50 %, precisión 58 %, alarma en el 17 % de los días. Costo por día 0,175, contra 0,203 sin avisar nunca y 0,797 avisando siempre.
Umbral 0,23 elegido en 2010-2012. En 2016-2026: sensibilidad 80 %, precisión 45 %, alarma en el 36 % de los días. Costo por día 0,318, contra 0,608 sin avisar nunca y 0,797 avisando siempre.
Umbral 0,13 elegido en 2010-2012. En 2016-2026: sensibilidad 92 %, precisión 35 %, alarma en el 53 % de los días. Costo por día 0,497, contra 2,026 sin avisar nunca y 0,797 avisando siempre.
Con 0,5 el modelo avisa en pocos días y atrapa el 48 % de las lluvias, con 82,6 % de exactitud; no avisar nunca ya logra 79,7 %. La exactitud engaña cuando llueve uno de cada cinco días: el umbral que tiene sentido depende de cuánto cuesta no avisar una lluvia.
Con 0,5, el modelo avisó en pocos días: atrapó el 48,1 % de las lluvias con 58,7 % de precisión y 82,6 % de exactitud. Suena bien hasta ver que no avisar nunca ya logra 79,7 % de exactitud, porque llueve uno de cada cinco días. Por eso la exactitud engaña con clases desbalanceadas.
Para elegir el umbral sin mirar los datos de prueba, entrené hasta 2009 y lo elegí con 2010-2012. Si no avisar una lluvia cuesta lo mismo que una falsa alarma, el umbral fue 0,49 y el costo en 2016-2026 bajó de 0,203 por día (no avisar nunca) a 0,175. Si no avisar cuesta tres veces más, el umbral bajó a 0,23: atrapó el 80,2 % de las lluvias, con alarmas en el 36 % de los días. Si cuesta diez veces más, a 0,13: atrapó el 92,5 %, avisando en más de la mitad de los días, y aun así costó menos que avisar siempre (0,497 contra 0,797).
¿Una probabilidad de 30 % se cumple el 30 % de las veces?
Una probabilidad solo sirve si significa lo que dice. Eso es la calibración, y se mide agrupando días por probabilidad predicha y contando cuántos terminaron con lluvia. Brier propuso en 1950 una forma de puntuar estos pronósticos, justamente para el tiempo.
AUC 0,847 · Brier 0,119 · mejora de Brier contra predecir siempre la tasa de entrenamiento 0,279 · PR-AUC 0,573
AUC 0,848 · Brier 0,156 · mejora de Brier contra predecir siempre la tasa de entrenamiento 0,057 · PR-AUC 0,571
AUC 0,882 · Brier 0,106 · mejora de Brier contra predecir siempre la tasa de entrenamiento 0,357 · PR-AUC 0,660
logística entrenada hasta 2009: tasa real de lluvia contra probabilidad media predicha
- real
- predicha media
La regresión logística predijo en promedio 24,1 % de lluvia y llovió en el 20,3 % de los días. En los 11.010 días a los que dio menos de 10 %, llovió en el 2,6 %; en los 874 a los que dio entre 70 y 80 %, en el 56,9 %. Aprendió de 1984-2012, cuando llovía más seguido. Con class_weight='balanced' atrapa más lluvia, pero sus probabilidades dejan de significar lo que dicen (promedio 38,5 %). El bosque es el mejor calibrado de los tres.
La logística prometió más lluvia de la que cayó. En promedio predijo 24,1 % y llovió en el 20,3 % de los días. En los 11.010 días a los que dio menos de 10 %, llovió en el 2,6 %; en los 874 a los que dio entre 70 y 80 %, en el 56,9 %. Parte del desfase es de época: aprendió de 1984-2012, cuando llovía en el 26,6 % de los días. El modelo entrenado hasta 2009 predijo más lluvia de la observada en todos los años de 2016 a 2026.
Balancear las clases con class_weight='balanced' es una receta común para atrapar más lluvias, y lo hace: su exactitud balanceada subió de 0,70 a 0,78. Pero su probabilidad media fue 38,5 % y, en los días a los que dio entre 50 y 60 %, llovió en el 33 %. Si se van a usar las probabilidades, eso obliga a recalibrar. El bosque quedó mejor calibrado que ambas, algo que ya se había visto en el post de Random Forest.
Qué variables sobreviven al castigo
La regularización castiga los pesos grandes. L2 (Ridge) los achica; L1 (lasso, de Tibshirani, 1996) puede dejarlos exactamente en cero, lo que la convierte en una forma de elegir variables.
C = 1015 variables vivas · pérdida log. 0,3782 · AUC 0,847
- máxima
- mínima
- lluvia hoy
- lluvia ayer
- viento
- viento E-O
- viento N-S
- radiación
- humedad
- presión
- cambio presión
- rocío
- día (sen)
- día (cos)
- latitud
C = 115 variables vivas · pérdida log. 0,3782 · AUC 0,847
- máxima
- mínima
- lluvia hoy
- lluvia ayer
- viento
- viento E-O
- viento N-S
- radiación
- humedad
- presión
- cambio presión
- rocío
- día (sen)
- día (cos)
- latitud
C = 0,315 variables vivas · pérdida log. 0,3782 · AUC 0,847
- máxima
- mínima
- lluvia hoy
- lluvia ayer
- viento
- viento E-O
- viento N-S
- radiación
- humedad
- presión
- cambio presión
- rocío
- día (sen)
- día (cos)
- latitud
C = 0,115 variables vivas · pérdida log. 0,3782 · AUC 0,847
- máxima
- mínima
- lluvia hoy
- lluvia ayer
- viento
- viento E-O
- viento N-S
- radiación
- humedad
- presión
- cambio presión
- rocío
- día (sen)
- día (cos)
- latitud
C = 0,0314 variables vivas · pérdida log. 0,3782 · AUC 0,847
- máxima
- mínima
- lluvia hoy
- lluvia ayer
- viento
- viento E-O
- viento N-S
- radiación
- humedad
- presión
- cambio presión
- rocío
- día (sen)
- día (cos)
- latitud
C = 0,0112 variables vivas · pérdida log. 0,3780 · AUC 0,847
- máxima
- mínima
- lluvia hoy
- lluvia ayer
- viento
- viento E-O
- viento N-S
- radiación
- humedad
- presión
- cambio presión
- rocío
- día (sen)
- día (cos)
- latitud
C = 0,00311 variables vivas · pérdida log. 0,3772 · AUC 0,848
- máxima
- mínima
- lluvia hoy
- lluvia ayer
- viento
- viento E-O
- viento N-S
- radiación
- humedad
- presión
- cambio presión
- rocío
- día (sen)
- día (cos)
- latitud
C = 0,0018 variables vivas · pérdida log. 0,3781 · AUC 0,848
- máxima
- mínima
- lluvia hoy
- lluvia ayer
- viento
- viento E-O
- viento N-S
- radiación
- humedad
- presión
- cambio presión
- rocío
- día (sen)
- día (cos)
- latitud
C = 0,00035 variables vivas · pérdida log. 0,3935 · AUC 0,842
- máxima
- mínima
- lluvia hoy
- lluvia ayer
- viento
- viento E-O
- viento N-S
- radiación
- humedad
- presión
- cambio presión
- rocío
- día (sen)
- día (cos)
- latitud
C = 0,00012 variables vivas · pérdida log. 0,4621 · AUC 0,802
- máxima
- mínima
- lluvia hoy
- lluvia ayer
- viento
- viento E-O
- viento N-S
- radiación
- humedad
- presión
- cambio presión
- rocío
- día (sen)
- día (cos)
- latitud
C = 1015 variables vivas · pérdida log. 0,3782 · AUC 0,847
- máxima
- mínima
- lluvia hoy
- lluvia ayer
- viento
- viento E-O
- viento N-S
- radiación
- humedad
- presión
- cambio presión
- rocío
- día (sen)
- día (cos)
- latitud
C = 115 variables vivas · pérdida log. 0,3782 · AUC 0,847
- máxima
- mínima
- lluvia hoy
- lluvia ayer
- viento
- viento E-O
- viento N-S
- radiación
- humedad
- presión
- cambio presión
- rocío
- día (sen)
- día (cos)
- latitud
C = 0,315 variables vivas · pérdida log. 0,3782 · AUC 0,847
- máxima
- mínima
- lluvia hoy
- lluvia ayer
- viento
- viento E-O
- viento N-S
- radiación
- humedad
- presión
- cambio presión
- rocío
- día (sen)
- día (cos)
- latitud
C = 0,115 variables vivas · pérdida log. 0,3782 · AUC 0,847
- máxima
- mínima
- lluvia hoy
- lluvia ayer
- viento
- viento E-O
- viento N-S
- radiación
- humedad
- presión
- cambio presión
- rocío
- día (sen)
- día (cos)
- latitud
C = 0,0315 variables vivas · pérdida log. 0,3781 · AUC 0,847
- máxima
- mínima
- lluvia hoy
- lluvia ayer
- viento
- viento E-O
- viento N-S
- radiación
- humedad
- presión
- cambio presión
- rocío
- día (sen)
- día (cos)
- latitud
C = 0,0115 variables vivas · pérdida log. 0,3780 · AUC 0,847
- máxima
- mínima
- lluvia hoy
- lluvia ayer
- viento
- viento E-O
- viento N-S
- radiación
- humedad
- presión
- cambio presión
- rocío
- día (sen)
- día (cos)
- latitud
C = 0,00315 variables vivas · pérdida log. 0,3778 · AUC 0,847
- máxima
- mínima
- lluvia hoy
- lluvia ayer
- viento
- viento E-O
- viento N-S
- radiación
- humedad
- presión
- cambio presión
- rocío
- día (sen)
- día (cos)
- latitud
C = 0,00115 variables vivas · pérdida log. 0,3777 · AUC 0,847
- máxima
- mínima
- lluvia hoy
- lluvia ayer
- viento
- viento E-O
- viento N-S
- radiación
- humedad
- presión
- cambio presión
- rocío
- día (sen)
- día (cos)
- latitud
C = 0,000315 variables vivas · pérdida log. 0,3800 · AUC 0,846
- máxima
- mínima
- lluvia hoy
- lluvia ayer
- viento
- viento E-O
- viento N-S
- radiación
- humedad
- presión
- cambio presión
- rocío
- día (sen)
- día (cos)
- latitud
C = 0,000115 variables vivas · pérdida log. 0,3891 · AUC 0,844
- máxima
- mínima
- lluvia hoy
- lluvia ayer
- viento
- viento E-O
- viento N-S
- radiación
- humedad
- presión
- cambio presión
- rocío
- día (sen)
- día (cos)
- latitud
Con L1 y C = 0,0001 quedan solo lluvia hoy y viento N-S, con AUC 0,802. Con C = 0,001, 8 de 15 variables ya dan una pérdida logarítmica de 0,3781, prácticamente la misma que las 15 con un L1 débil (C = 10) (0,3782). C no se eligió con estas cifras de prueba; solo muestran el recorrido.
Con L1 y el castigo más fuerte que probé, quedaron solo dos variables: la lluvia de hoy y el componente norte-sur del viento, con AUC de 0,802. Con 8 variables, la pérdida en 2016-2026 ya fue prácticamente la misma que con las 15 y un L1 débil (C = 10). En estos datos, sobra casi la mitad de las columnas para ordenar días; no elegí el castigo con estas cifras, solo muestran el recorrido.
Escalar antes de resolver
La logística no tiene solución cerrada: se resuelve por iteraciones, y ahí vuelve la escala de las variables que ya apareció en la regresión lineal.
Cuatro veces más lento que el tiempo real.
A tiempo real.
Todos llegaron a un rendimiento muy parecido (AUC de 0,847 a 0,848). Sin escalar, lbfgs, el que usa scikit-learn por defecto, necesitó 819 iteraciones y 33 veces más tiempo que con las variables escaladas.
En esa medición con un hilo, con las variables escaladas, todos los algoritmos terminaron en menos de 0,21 segundos. Sin escalar, lbfgs pasó de 26 a 819 iteraciones y de 0,045 a 1,51 segundos, y saga de 0,20 a 1,29. Llegaron a un rendimiento muy parecido (pérdida logarítmica de 0,377 a 0,378). Sin escalar, las variables tienen rangos muy distintos, como la presión en kilopascales junto al seno del día del año, algo que suele frenar a los métodos de primer orden como lbfgs y saga.
Regresión logística o Random Forest
El bosque de 200 árboles ordenó mejor los días: AUC de 0,882 contra 0,847, y PR-AUC de 0,660 contra 0,573. También quedó mejor calibrado (mejora de Brier de 0,357 contra 0,279 respecto de predecir siempre la tasa de entrenamiento). Lo que cuesta esa diferencia se ve en todo lo demás.
A la mitad del tiempo real.
En una corrida aparte con 8 hilos, el bosque tardó 3,26 s. Los 16 parámetros de la logística ocupan 355 bytes en JSON; el bosque serializado, 124 MB.
Con un hilo, la logística entrenó en 0,049 segundos y el bosque en 23,8, unas 490 veces más. Puntuar una fila tardó 0,39 ms con scikit-learn y 0,003 ms con una operación directa de NumPy, contra 3,1 ms del bosque. Y la logística aprende rápido: con 2.000 filas ya tuvo AUC de 0,840, a 0,007 de su valor con las 74.145; el bosque subió de 0,866 a 0,882 con más datos.
Dónde vive una regresión logística en un sistema real
Los 16 parámetros de la logística caben en 0,4 KB de JSON; el bosque de 200 árboles serializado ocupa 124,3 MB. Una fila puntuada con NumPy puro tardó 0,0029 ms (0,394 ms pasando por scikit-learn), con una diferencia respecto de scikit-learn menor que 10⁻¹⁵.
- Puntajes de riesgo. Crédito, fraude o riesgo clínico: una probabilidad por caso, pesos que se pueden auditar y un umbral que fija el negocio según lo que cuesta cada error.
- Filtros y alertas. Spam, alertas de lluvia o de fallas: se entrena fuera de línea y se puntúa en línea con una suma y una sigmoide, sin cargar un modelo pesado.
- Línea base. Antes de un bosque o una red, una logística entrenada en milisegundos dice cuánto aporta lo demás. Aquí, el bosque le sacó 0,035 de AUC.
- Monitoreo de calibración. El lazo que casi siempre falta: comparar la probabilidad media con lo que pasó. Aquí habría detectado el desfase desde el primer año.
Cuándo la elegiría: cuando necesito probabilidades rápidas, pesos auditables y un umbral ajustable por costo. Cuándo no: con relaciones muy no lineales o interacciones fuertes, donde un bosque ordena mejor, o cuando no puedo vigilar la calibración en el tiempo.
Fuentes
- Cox, D. R. (1958). «The Regression Analysis of Binary Sequences». Journal of the Royal Statistical Society: Series B, 20(2), 215–232. DOI 10.1111/j.2517-6161.1958.tb00292.x.
- Berkson, J. (1944). «Application of the Logistic Function to Bio-Assay». Journal of the American Statistical Association, 39(227), 357–365. DOI 10.1080/01621459.1944.10500699.
- Brier, G. W. (1950). «Verification of Forecasts Expressed in Terms of Probability». Monthly Weather Review, 78(1), 1–3. DOI 10.1175/1520-0493(1950)078<0001:VOFEIT>2.0.CO;2.
- Niculescu-Mizil, A. y Caruana, R. (2005). «Predicting good probabilities with supervised learning». Proceedings of the 22nd International Conference on Machine Learning, 625–632. DOI 10.1145/1102351.1102430.
- Tibshirani, R. (1996). «Regression Shrinkage and Selection via the Lasso». Journal of the Royal Statistical Society: Series B, 58(1), 267–288. DOI 10.1111/j.2517-6161.1996.tb02080.x.
- scikit-learn,
LogisticRegression(solvers,class_weighty regularización) y la guía de calibración. - NASA POWER, Daily API y fuentes de datos.
Comentarios
Todavía no hay comentarios. El primero es tuyo.