ML Atlas

Machine learning desde cero · Lección 3.4 · 17 de 33 lecciones listas · 12 min

Regularización: ridge y lasso

En pocas palabras

Penalizar los pesos grandes calma al modelo. Lasso pone los pesos a cero uno a uno: con 3 de 10 variables el R² de prueba baja de 0,470 a 0,386.

Calentamiento Dos preguntas de lecciones anteriores. Un minuto, y no bloquea la lección.
De la lección 3.3: Curvas de aprendizaje: ¿más datos o un modelo mejor? El entrenamiento da un 100 %, la validación un 82,3 % y la curva de validación sigue subiendo. ¿Qué ayudará con más probabilidad?

Ver la respuesta

Respuesta correcta: Más datos de entrenamiento, porque una brecha grande indica memoria

Brecha grande y validación al alza significan varianza alta. Con todo el entrenamiento el mismo modelo llega al 95,8 % en validación, y la brecha baja a 2,2 puntos.

De la lección 3.2: Validación y validación cruzada El modelo A tiene una exactitud media de validación cruzada algo superior a la del modelo B, pero la dispersión entre pliegues es mucho mayor que la diferencia. ¿Qué se deduce?

Ver la respuesta

Respuesta correcta: Que los datos no muestran una diferencia fiable entre los dos modelos

Cuando la diferencia de medias es menor que la variación entre pliegues, puede deberse fácilmente al azar.

En la lección 3.1 un modelo con muchos parámetros aprendió el ruido: el error de entrenamiento bajaba y el de prueba subía. En lugar de quitarle variables al modelo, puedes cobrarle por ellas. La regularización es una penalización que se suma al error de entrenamiento: cuanto mayores los pesos, mayor la penalización. Su fuerza la fija un número α. Hoy probarás dos penalizaciones con 10 variables de pacientes con diabetes y verás que una de ellas elige las variables por sí sola.

Predice y comprueba Una regresión lineal predice cuánto avanzará la diabetes al cabo de un año a partir de 10 variables: edad, sexo, IMC, presión arterial y seis resultados de análisis de sangre (s1–s6). Lasso es una penalización que, al crecer α, pone a cero los pesos de las variables una a una. ¿Qué variable queda la última?
¿Qué tan seguro estás?

Experimento interactivo

Este experimento interactivo funciona en un navegador con JavaScript activado. El texto que lo rodea describe lo que muestra.

Ver la respuesta

Respuesta correcta: El IMC, índice de masa corporal, porque por sí solo aporta más que nadie

La última es el IMC: con α = 39,8 es la única variable con peso. s2 es la primera que desaparece para siempre (desde α = 0,398). Con 3 variables (IMC, presión arterial y s5) el R² de prueba baja de 0,470 a 0,386.

Prueba

  • Sube α en lasso desde el valor más pequeño. ¿En qué orden llegan a cero las líneas de los pesos? ¿Cuántas variables quedan con α = 15,8 y cuánto cuesta eso en la prueba?
  • Fíjate en s3. ¿Cuándo toca cero por primera vez y qué le pasa después?
  • Cambia a ridge y lleva α hasta el final. ¿Algún peso llega a ser exactamente cero?

Cuando lo hayas comprobado en el lab, pongamos nombre a lo que ves.

La idea en palabras sencillas

La regresión lineal normal elige los pesos que hacen lo más pequeño posible el error con los datos de entrenamiento. La regularización suma a ese error una penalización por el tamaño de los pesos. Ahora el modelo tiene que elegir: ajustarse mejor a los datos o tener pesos más pequeños. Una variable conserva un peso grande solo si de verdad mejora las predicciones.

Ridge penaliza la suma de los cuadrados de los pesos. Lleva todos los pesos hacia cero, pero no anula ninguno: en el lab, con α = 398, el R² de prueba baja a 0,405 y las 10 variables siguen teniendo peso. Lasso penaliza la suma de los valores absolutos de los pesos y los pone a cero uno a uno. Con α = 15,8 quedan tres variables: IMC, presión arterial y s5. Sin penalización el R² de prueba es 0,470; con tres variables, 0,386. El modelo es más simple y más barato de usar, pero predice peor.

Las variables están expresadas en desviaciones típicas. Eso importa: la penalización mide el tamaño de los pesos, así que una variable medida en unidades grandes tendría un peso pequeño y escaparía a la penalización.

Jak to policzono
  • Datos: Diabetes, Efron et al. (2004), Annals of Statistics. 442 pacientes, 10 variables medidas al inicio del estudio, objetivo: avance de la enfermedad un año después. Los autores no indicaron licencia; scikit-learn redistribuye el conjunto (licencia BSD-3-Clause).
  • División aleatoria: 309 pacientes para aprender, 133 para la prueba. Medias y desviaciones de las variables calculadas solo con la parte de entrenamiento.
  • Lasso: 11 valores de α de 0,01 a 100. Ridge: 11 valores de α de 0,1 a 100000 (ridge en scikit-learn mide la penalización en otra escala que lasso, de ahí los números distintos).
  • R² de prueba: qué parte de la variación del resultado de los pacientes de prueba explica el modelo (1 = toda, 0 = lo mismo que la media).

Por qué funciona

La penalización de lasso crece de forma lineal: reducir un peso en una unidad siempre ahorra la misma penalización, sea el peso grande o pequeño. Si una variable mejora el ajuste menos de lo que cuesta la penalización, compensa darle un peso exactamente cero. La penalización de ridge crece con el cuadrado del peso, así que los pesos pequeños casi no cuestan nada. Ridge encoge el peso cada vez más, pero nunca necesita anularlo.

La penalización también calma los pesos de variables que dicen casi lo mismo. s1 y s2 son dos resultados de análisis muy ligados entre sí (en el código de abajo su correlación es 0,90). Con la penalización lasso más débil, s1 tiene un peso de −39,0 y s2 de +26,2: dos números grandes de signo contrario que casi se anulan. Pesos así cambian mucho de una muestra a otra. La penalización los recoge y enseguida lasso elimina s2 del todo, porque s1 lleva casi la misma información.

No es casualidad de una sola división. En el código de abajo el mismo experimento se repite con 50 divisiones aleatorias: el IMC queda el último en 37 de ellas, s5 en las otras 13. La variable que desaparece primero cambia todavía más de una división a otra: la edad en 21 divisiones, s2 en 16.

Error frecuente

Verdadero o falso: «lasso dio a una variable un peso cero, así que esa variable no importa». Falso. s2 desaparece la primera aunque está muy ligada a s1: lasso elige una variable del par y la otra recibe cero porque no aporta nada nuevo junto a s1. Sin s1, s2 podría ser importante. El lab lo muestra también con s3: con α = 0,158 su peso es cero y con α = 0,398 vuelve, porque está ligada a s4 (r = −0,73) y lasso pasa el peso de una a otra.

La elección entre variables correlacionadas puede ser cuestión de suerte. En el código de abajo la primera en desaparecer es unas veces s2 y otras la edad, e incluso la última que queda es a veces s5 en lugar del IMC, según qué pacientes caigan en la parte de entrenamiento. Un cero en lasso significa «este modelo no necesitó esta variable, con estos datos y este α». No significa «esta variable no tiene nada que ver con la enfermedad».

Test

Tres preguntas para comprobar lo aprendido. Elige una respuesta o despliega la solución bajo cada pregunta. Con el teclado: las flechas eligen, Enter o Espacio confirma.

1. ¿En qué se diferencia la penalización ridge de la penalización lasso?
Ver la respuesta

Respuesta correcta: Ridge lleva todos los pesos hacia cero y lasso deja algunos exactamente en cero

Ridge penaliza los cuadrados de los pesos y no anula ninguno; lasso penaliza los valores absolutos y anula los pesos uno a uno. En el lab ridge con α = 398 tiene 10 pesos distintos de cero, lasso con α = 15,8 solo 3.

2. En el lab lasso deja 3 variables y el R² de prueba baja de 0,470 a 0,386. ¿Qué significa?
Ver la respuesta

Respuesta correcta: Que un modelo más simple cuesta algo de precisión: hay que sopesar ambos fines

Menos variables hacen un modelo más fácil de usar y explicar, pero aquí explica una parte menor de la variación del resultado. La fuerza de la penalización se elige en validación, sopesando sencillez y precisión.

3. Verdadero o falso: «lasso dio a una variable un peso cero, así que no tiene relación con la enfermedad».
Ver la respuesta

Respuesta correcta: Falso, porque de un par de variables correlacionadas lasso a menudo deja solo una

s2 desaparece la primera aunque está muy ligada a s1. No aporta nada nuevo junto a s1, así que lasso le da cero. En 50 divisiones la primera en desaparecer es unas veces s2 y otras la edad.

Ideas clave

  • La regularización suma al error una penalización por los pesos grandes; α fija su fuerza.
  • Ridge encoge todos los pesos y no anula ninguno; lasso los anula uno a uno y elige variables.
  • Un modelo más simple suele costar algo de precisión: α se elige en validación, no en la prueba.
  • Un peso cero en lasso no significa que la variable no importe: de un par de variables correlacionadas lasso a menudo deja una.

Más a fondo: fórmula, código, práctica

Las matemáticas

Ridge: min_w ‖y − Xw‖² + α · Σⱼ wⱼ². Lasso: min_w (1/(2n)) · ‖y − Xw‖² + α · Σⱼ |wⱼ|. Así las calcula scikit-learn, y por eso los mismos números de α significan cosas distintas en las dos penalizaciones.

Por qué lasso anula: con variables de media 0 y varianza 1, un peso tras una actualización vale wⱼ = sign(ρⱼ) · max(|ρⱼ| − α, 0), donde ρⱼ = (1/n) · xⱼᵀ rⱼ es la relación de la variable con el error que queda sin ella. Cuando |ρⱼ| ≤ α, el peso es exactamente cero. Ridge da wⱼ = ρⱼ / (1 + α/n) con los mismos supuestos: el peso se encoge, pero solo es cero cuando ρⱼ = 0.

R²: R² = 1 − Σ(yᵢ − ŷᵢ)² / Σ(yᵢ − ȳ)², calculado con los pacientes de prueba.

En código (Python)

El mismo experimento en scikit-learn con 50 divisiones aleatorias (70 % para aprender, 30 % para la prueba): qué variable deja lasso la última, cuál quita la primera y cuánto cuesta quedarse con 3 variables como mucho.

import numpy as np
from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression, Lasso, lars_path
from sklearn.metrics import r2_score

X, y = load_diabetes(return_X_y=True)
names = np.array(["age", "sex", "bmi", "bp", "s1", "s2", "s3", "s4", "s5", "s6"])
alphas = 10 ** np.linspace(-2, 2, 41)  # el rango de penalizaciones del lab, más fino
last, first, r2 = [], [], []
for s in range(50):
    tr, te = train_test_split(np.arange(len(y)), test_size=0.3, random_state=s)
    sc = StandardScaler().fit(X[tr])
    Xtr, Xte = sc.transform(X[tr]), sc.transform(X[te])
    path_alphas, _, coefs = lars_path(Xtr, y[tr] - y[tr].mean(), method="lasso")  # el camino exacto de lasso, desde la penalización más fuerte hacia abajo
    enters = [np.flatnonzero(coefs[j])[0] if coefs[j].any() else len(path_alphas) for j in range(10)]  # dónde recibe peso cada variable por primera vez
    last.append(names[np.argmin(enters)]); first.append(names[np.argmax(enters)])  # la primera en recibir peso = la última en perderlo al crecer la penalización
    W = np.array([Lasso(alpha=a, max_iter=100000).fit(Xtr, y[tr]).coef_ for a in alphas])
    k3 = min(k for k in range(len(alphas)) if (W[k] != 0).sum() <= 3)  # la penalización más débil que deja 3 variables como mucho
    m3 = Lasso(alpha=alphas[k3], max_iter=100000).fit(Xtr, y[tr])
    r2.append((r2_score(y[te], LinearRegression().fit(Xtr, y[tr]).predict(Xte)), r2_score(y[te], m3.predict(Xte))))
r2 = np.array(r2)
print(f"last feature lasso keeps, 50 splits: {', '.join(f'{n} {last.count(n)}' for n in sorted(set(last), key=lambda n: (-last.count(n), n)))}")
print(f"first feature it drops for good: {', '.join(f'{n} {first.count(n)}' for n in sorted(set(first), key=lambda n: (-first.count(n), n)))}")
print(f"test R2: no penalty {r2[:, 0].mean():.3f}, at most 3 features {r2[:, 1].mean():.3f}; lower with 3 in {(r2[:, 1] < r2[:, 0]).sum()} of 50")
print(f"correlation of s1 and s2: {np.corrcoef(X[:, 4], X[:, 5])[0, 1]:.2f}")

Resultado

last feature lasso keeps, 50 splits: bmi 37, s5 13
first feature it drops for good: age 21, s2 16, s4 9, s1 2, s6 2
test R2: no penalty 0.471, at most 3 features 0.379; lower with 3 in 50 of 50
correlation of s1 and s2: 0.90

Las divisiones son otras que en el lab, así que los números también. El cuadro es el mismo: el IMC queda el último en 37 divisiones de 50 (s5 en las otras 13), y quedarse con 3 variables como mucho baja el R² de prueba en todas las divisiones, en promedio de 0,471 a 0,379. La primera en desaparecer es unas veces s2 y otras la edad: lasso elige entre variables ligadas, y la elección depende de qué pacientes cayeron en la parte de entrenamiento.

Para profesionales
  • En scikit-learn: Ridge, Lasso y ElasticNet (una mezcla de ambas penalizaciones, útil con grupos de variables correlacionadas). Mete la estandarización en un pipeline (make_pipeline(StandardScaler(), Lasso())) para que medias y desviaciones se calculen solo con el entrenamiento.
  • Elige la fuerza de la penalización con validación cruzada: RidgeCV y LassoCV lo hacen de una vez. No elijas α por el resultado de la prueba: eso es ajustar con el conjunto de prueba (lección 3.5).
  • La regresión logística de scikit-learn tiene penalización ridge por defecto (penalty="l2"); su fuerza la fija C, la inversa de α: un C más pequeño es una penalización más fuerte.
  • Si quieres hablar de la importancia de las variables, no leas solo los ceros de lasso. Comprueba lo estable que es la elección en muchas divisiones o usa los métodos del módulo 6.

Profundiza en el Atlas

Entradas de la enciclopedia sobre las ideas de esta lección: