Regresión logística
El clasificador lineal por excelencia: la sigmoide, la entropía cruzada, cómo se entrena por descenso de gradiente y por qué el umbral de decisión es una decisión de negocio.
01Qué es
La regresión logística es un modelo de clasificación, a pesar de su nombre. Calcula una suma ponderada de las variables, como la regresión lineal, y la pasa por la función sigmoide, que la convierte en una probabilidad entre 0 y 1. Si la probabilidad supera un umbral (normalmente 0,5), predice la clase positiva.
Es el punto de partida de cualquier problema de clasificación y, además, cada neurona con activación sigmoide de una red es exactamente una regresión logística.
02Intuición
El modelo traza una frontera recta (un hiperplano) que separa las dos clases. Los puntos lejos de la frontera reciben probabilidades cercanas a 0 o a 1; los que están cerca, alrededor de 0,5. Así no solo dice «maligno» o «benigno», sino con cuánta seguridad.
Cada peso indica cuánto cambian las odds (probabilidad a favor frente a en contra) cuando la variable sube una unidad: multiplicarlas por .
Juega con la sigmoide en el laboratorio de la función sigmoide, y mira en el de frontera de decisión cómo una red sin capas ocultas (que es una regresión logística) solo sabe trazar rectas.
03Fundamento matemático
Los pesos se eligen maximizando la verosimilitud de los datos, que equivale a minimizar la entropía cruzada (log loss):
Su gradiente tiene una forma sorprendentemente limpia, igual que la de la regresión lineal pero con p en lugar de la predicción:
No existe una fórmula cerrada como la ecuación normal, pero la pérdida es convexa: el descenso de gradiente (o métodos de segundo orden como L-BFGS, el que usa scikit-learn por defecto) llega siempre al mismo mínimo global.
04Algoritmo paso a paso
- Estandariza las variables: el optimizador converge mucho mejor y la regularización trata a todas por igual.
- Inicializa los pesos a cero.
- Calcula la probabilidad de cada ejemplo con la sigmoide.
- Calcula el gradiente y actualiza los pesos en sentido contrario.
- Repite hasta que la pérdida deje de bajar.
- Elige el umbral de decisión según el coste de cada tipo de error.
05Pseudocódigo
función AJUSTAR(X, y, η, λ, iteraciones):
w ← 0 ; b ← 0
repetir iteraciones veces:
p ← σ(X·w + b)
w ← w − η · ( Xᵀ(p − y)/n + λ·w )
b ← b − η · media(p − y)
devolver w, b
función PREDECIR(w, b, x, umbral):
devolver 1 si σ(w·x + b) ≥ umbral, si no 006Implementación desde cero en Python
import numpy as np
from sklearn.preprocessing import StandardScaler
sc = StandardScaler().fit(X_tr)
Xs, Xts = sc.transform(X_tr), sc.transform(X_te)
sigmoide = lambda z: 1 / (1 + np.exp(-z))
w, b, eta, lam = np.zeros(X.shape[1]), 0.0, 0.1, 0.01
for it in range(3000):
p = sigmoide(Xs @ w + b) # probabilidad de la clase 1
grad_w = Xs.T @ (p - y_tr) / len(y_tr) + lam * w # gradiente de la entropía cruzada + L2
grad_b = (p - y_tr).mean()
w -= eta * grad_w
b -= eta * grad_b
prob_test = sigmoide(Xts @ w + b)
pred_test = (prob_test >= 0.5).astype(int)Esta implementación consigue un 98,6 % de acierto y un ROC-AUC de 0,9975 en test, prácticamente lo mismo que scikit-learn.
07Implementación con Scikit-learn
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline
modelo = make_pipeline(StandardScaler(), LogisticRegression(max_iter=5000))
modelo.fit(X_tr, y_tr)
modelo.predict_proba(X_te)[:, 1] # probabilidad de «benigno»
modelo[-1].coef_ # un peso por variable (en unidades estandarizadas)Sin StandardScaler, el optimizador no converge en 100 iteraciones con estos datos y scikit-learn avisa con un ConvergenceWarning: las variables van desde centésimas (como mean fractal dimension) hasta más de 4.000 (worst area). En scikit-learn 1.8 el parámetro penalty está obsoleto: la regularización se controla con C (inversa de λ) y l1_ratio.
08Dataset de ejemplo
El mismo que en el artículo de Random Forest: Breast Cancer Wisconsin (Diagnostic), 569 biopsias con 30 variables numéricas (212 malignas, 357 benignas), y la misma partición estratificada 75/25 con random_state=42. Así los resultados de los dos modelos son directamente comparables.
09Entrenamiento
Con variables estandarizadas, L-BFGS converge en milisegundos. La regularización por defecto (C = 1) ya funciona bien aquí; en otros problemas conviene buscar C con LogisticRegressionCV.
10Evaluación
from sklearn.metrics import accuracy_score, roc_auc_score, log_loss, confusion_matrix
from sklearn.model_selection import cross_val_score
prob = modelo.predict_proba(X_te)[:, 1]
print(accuracy_score(y_te, prob >= 0.5)) # 0.986
print(roc_auc_score(y_te, prob)) # 0.998
print(log_loss(y_te, prob)) # 0.068
print(confusion_matrix(y_te, prob >= 0.5)) # [[52 1]
# [ 1 89]]| Modelo (misma partición) | Acierto en test | ROC-AUC | Validación cruzada (5) |
|---|---|---|---|
| Árbol de decisión | 92,3 % | — | — |
| Random Forest, 300 árboles | 95,8 % | 0,995 | 96,1 % ± 2,5 |
| Regresión logística | 98,6 % | 0,998 | 98,1 % ± 0,7 |
El modelo lineal gana al bosque en estos datos. No es una rareza: las 30 variables ya son medidas bien elegidas de los núcleos celulares y la frontera entre clases es casi lineal. Un modelo más flexible no aporta nada y añade varianza. Por eso siempre hay que probar primero el modelo sencillo.
11Métricas
El ROC-AUC es la probabilidad de que un caso positivo elegido al azar reciba más probabilidad que uno negativo: 0,998 significa que el modelo ordena casi perfectamente. El log loss mide además si las probabilidades son fiables, no solo si el orden es bueno.
El umbral es una decisión, no un dato
prob_maligno = 1 - modelo.predict_proba(X_te)[:, 1]
for umbral in (0.5, 0.3, 0.1):
alerta = prob_maligno >= umbral
print(umbral, (alerta & (y_te == 0)).sum(), (alerta & (y_te == 1)).sum())| Umbral de alerta (prob. de maligno) | Malignos detectados | Falsas alarmas |
|---|---|---|
| 0,5 | 52 de 53 | 1 |
| 0,3 | 52 de 53 | 6 |
| 0,1 | 53 de 53 | 11 |
Con el umbral por defecto se escapa un tumor maligno. Bajando el umbral al 10 % se detectan los 53, a cambio de 11 falsas alarmas entre 90 casos benignos. Qué umbral elegir depende del coste de cada error, y eso lo decide el problema, no el modelo.
12Visualización
13Ventajas
- Da probabilidades, normalmente bien calibradas.
- Rápida, estable y con un único óptimo.
- Interpretable mediante los coeficientes y los odds ratios.
- Funciona muy bien con muchas variables y pocos datos si se regulariza.
- Se extiende a varias clases con softmax (regresión logística multinomial).
14Limitaciones
- Frontera lineal: no captura interacciones ni relaciones curvas sin ingeniería de variables.
- Sensible a variables en escalas muy distintas (hay que estandarizar).
- Con clases perfectamente separables, sin regularización los pesos crecen sin límite.
- Los coeficientes pierden interpretabilidad con variables muy correlacionadas.
15Hiperparámetros
| Parámetro | Por defecto | Efecto |
|---|---|---|
C | 1.0 | Inversa de la fuerza de regularización. Menor C, pesos más pequeños. |
l1_ratio | 0.0 | 0 = L2 (Ridge), 1 = L1 (Lasso); valores intermedios, Elastic Net (con solver saga). |
solver | "lbfgs" | Método de optimización. "saga" admite L1 y datasets grandes. |
max_iter | 100 | Iteraciones máximas del optimizador. Súbelo si aparece ConvergenceWarning. |
class_weight | None | "balanced" compensa clases desbalanceadas. |
penalty | "deprecated" | Obsoleto desde scikit-learn 1.8: usa C y l1_ratio. |
16Casos de uso
- Scoring de crédito y de riesgo, donde se exige explicar cada decisión.
- Diagnóstico médico con variables clínicas.
- Predicción de clics o conversiones en publicidad.
- Clasificación de texto con variables TF-IDF (spam, sentimiento).
- Línea base para cualquier clasificador.
17Aplicaciones industriales
- Telecomunicaciones: probabilidad de baja de cada cliente para priorizar retenciones.
- Banca: modelos de riesgo regulados, que deben ser explicables.
- Industria: probabilidad de pieza defectuosa a partir de parámetros de proceso, con el umbral fijado por el coste de inspección.
- Seguridad: primera capa de detección de fraude o intrusiones.
18Ejercicio práctico
Dibuja la curva precisión-recall de la clase maligna y encuentra el umbral más alto que detecta los 53 casos. Compara sus falsas alarmas con las del Random Forest en el mismo punto.
# Ejercicio: la curva precisión-recall de la clase maligna.
from sklearn.metrics import precision_recall_curve
prec, rec, umbrales = precision_recall_curve(y_te == 0, 1 - modelo.predict_proba(X_te)[:, 1])
# 1) Dibuja rec frente a prec.
# 2) Encuentra el umbral más alto que da recall = 1 y cuenta sus falsas alarmas.19Código completo
Todos los experimentos de esta página, listos para ejecutar:
20Referencias y papers
- J. Berkson (1944). «Application of the Logistic Function to Bio-Assay». Journal of the American Statistical Association, 39(227), 357–365.
- D. R. Cox (1958). «The Regression Analysis of Binary Sequences». Journal of the Royal Statistical Society, Series B, 20(2), 215–242.
- W. N. Street, W. H. Wolberg, O. L. Mangasarian (1993). «Nuclear feature extraction for breast tumor diagnosis». Proc. SPIE 1905, Biomedical Image Processing and Biomedical Visualization. (Origen del dataset).
- D. W. Hosmer, S. Lemeshow, R. X. Sturdivant (2013). Applied Logistic Regression, 3.ª ed. Wiley.
- T. Hastie, R. Tibshirani, J. Friedman (2009). The Elements of Statistical Learning, 2.ª ed., capítulo 4. Springer.