Kurs uczenia maszynowego od zera · Lekcja 3.4 · 17 z 33 gotowych lekcji · 12 min
Regularyzacja: ridge i lasso
W skrócie
Kara za duże wagi uspokaja model. Ridge ściąga wszystkie wagi, lasso zeruje je po kolei: przy 3 cechach z 10 R² na teście spada z 0,470 do 0,386.
Rozgrzewka Dwa pytania z wcześniejszych lekcji. Minuta, a lekcji nie blokuje.
W lekcji 3.1 model z wieloma parametrami nauczył się szumu: błąd treningowy spadał, a testowy rósł. Zamiast odbierać modelowi cechy, można mu za nie liczyć. Regularyzacja to kara dopisana do błędu treningowego: im większe wagi, tym większa kara. Siłę kary ustawia liczba α. Dziś sprawdzisz dwie kary na 10 cechach pacjentów z cukrzycą i zobaczysz, że jedna z nich wybiera cechy sama.
Wybierz odpowiedź i pewność.
Odpowiedz, żeby odblokować lab.
Eksperyment
Ten interaktywny eksperyment działa w przeglądarce z włączonym JavaScriptem. Tekst wokół opisuje, co w nim widać.
Pokaż odpowiedź
Poprawna odpowiedź: BMI, czyli wskaźnik masy ciała, bo sam niesie najwięcej informacji
Ostatnie zostaje BMI: przy α = 39,8 to jedyna cecha z wagą. Pierwsza na stałe znika s2 (od α = 0,398). Przy 3 cechach (BMI, ciśnienie i s5) R² na teście spada z 0,470 do 0,386.
Spróbuj
- Przesuwaj α w lasso od najmniejszej wartości. W jakiej kolejności linie wag dochodzą do zera? Ile cech zostaje przy α = 15,8 i ile kosztuje to na teście?
- Obserwuj s3. Kiedy pierwszy raz dotyka zera i co dzieje się z nią potem?
- Przełącz na ridge i przesuń α do końca. Czy którakolwiek waga staje się dokładnie zerem?
Gdy już sprawdzisz to w labie, nazwijmy, co widzisz.
Pomysł w prostych słowach
Zwykła regresja liniowa dobiera wagi tak, żeby błąd na danych treningowych był jak najmniejszy. Regularyzacja dopisuje do tego błędu karę za wielkość wag. Model musi teraz wybrać: lepiej dopasować dane czy mieć mniejsze wagi. Cecha zachowuje dużą wagę tylko wtedy, gdy naprawdę poprawia przewidywania.
Ridge karze sumę kwadratów wag. Ściąga wszystkie wagi w stronę zera, ale żadnej nie zeruje: w labie przy α = 398 R² na teście spada do 0,405, a wagę wciąż ma wszystkie 10 cech. Lasso karze sumę wartości bezwzględnych wag i zeruje je po kolei. Przy α = 15,8 zostają trzy cechy: BMI, ciśnienie i s5. Bez kary R² na teście wynosi 0,470, z trzema cechami 0,386. Model jest prostszy i tańszy w użyciu, ale gorzej przewiduje.
Cechy są wyrażone w odchyleniach standardowych. To ważne: kara liczy wielkość wag, więc cecha mierzona w dużych jednostkach miałaby małą wagę i uciekałaby karze.
Jak to policzono
- Dane: Diabetes, Efron i in. (2004), Annals of Statistics. 442 pacjentów, 10 cech zmierzonych na początku badania, cel: postęp choroby po roku. Autorzy nie podali licencji; zbiór rozpowszechnia scikit-learn (licencja BSD-3-Clause).
- Podział losowy: 309 pacjentów do nauki, 133 do testu. Średnie i odchylenia cech liczone tylko na części treningowej.
- Lasso: 11 wartości α od 0,01 do 100. Ridge: 11 wartości α od 0,1 do 100000 (ridge w scikit-learn liczy karę w innej skali niż lasso, stąd inne liczby).
- R² na teście: jaka część zmienności wyniku pacjentów testowych model wyjaśnia (1 = wszystko, 0 = tyle co średnia).
Dlaczego to działa
Kara lasso rośnie liniowo: zmniejszenie wagi o jednostkę zawsze oszczędza tyle samo kary, czy waga jest duża, czy mała. Jeśli cecha poprawia dopasowanie słabiej, niż kosztuje kara, opłaca się dać jej wagę dokładnie zero. Kara ridge rośnie z kwadratem wagi, więc przy małych wagach prawie nic nie kosztuje. Ridge zmniejsza wagę coraz bardziej, ale nigdy nie musi jej zerować.
Kara uspokaja też wagi cech, które mówią prawie to samo. s1 i s2 to dwa wyniki krwi silnie ze sobą powiązane (w kodzie niżej korelacja wynosi 0,90). Przy najsłabszej karze lasso s1 ma wagę −39,0, a s2 +26,2: dwie duże liczby o przeciwnych znakach, które prawie się znoszą. Takie wagi bardzo zmieniają się od próbki do próbki. Kara je ściąga, a lasso po chwili usuwa s2 w ogóle, bo s1 przenosi prawie tę samą informację.
To nie jest przypadek jednego podziału. W kodzie niżej ten sam eksperyment idzie na 50 losowych podziałach: BMI zostaje ostatnie w 37 z nich, s5 w pozostałych 13. Cecha, która znika pierwsza, zmienia się jeszcze bardziej: wiek w 21 podziałach, s2 w 16.
Częsty błąd
Prawda czy fałsz: „lasso dało cesze wagę zero, więc ta cecha nie ma znaczenia”. Fałsz. s2 znika jako pierwsza, choć jest silnie powiązana z s1: lasso wybiera z pary jedną cechę, a druga dostaje zero, bo nie wnosi nic nowego obok s1. Bez s1 s2 mogłaby być ważna. W labie widać to też na s3: przy α = 0,158 ma wagę zero, a przy α = 0,398 wraca, bo jest powiązana z s4 (r = −0,73) i lasso przerzuca wagę między nimi.
Wybór między skorelowanymi cechami bywa przypadkowy. W kodzie niżej pierwsza znika raz s2, raz wiek, a nawet ostatnie zostaje czasem s5 zamiast BMI, zależnie od tego, którzy pacjenci trafią do nauki. Zero w lasso znaczy: „ta cecha nie była potrzebna temu modelowi, przy tych danych i tym α”. Nie znaczy: „ta cecha nie ma związku z chorobą”.
Quiz
Trzy pytania na sprawdzenie się. Wybierz odpowiedź albo rozwiń odpowiedź pod pytaniem. Z klawiatury: strzałki wybierają, Enter albo spacja zatwierdza.
Najważniejsze wnioski
- Regularyzacja dopisuje do błędu karę za duże wagi; siłę kary ustawia α.
- Ridge ściąga wszystkie wagi i żadnej nie zeruje; lasso zeruje je po kolei i wybiera cechy.
- Prostszy model zwykle kosztuje trochę trafności: α wybierasz na walidacji, nie na teście.
- Waga zero w lasso nie znaczy, że cecha jest bez znaczenia: z pary skorelowanych cech lasso często zostawia jedną.
Głębiej: wzór, kod, praktyka
Matematyka
Ridge: min_w ‖y − Xw‖² + α · Σⱼ wⱼ². Lasso: min_w (1/(2n)) · ‖y − Xw‖² + α · Σⱼ |wⱼ|. Tak liczy scikit-learn, dlatego te same liczby α znaczą w obu karach co innego.
Dlaczego lasso zeruje: przy cechach o średniej 0 i wariancji 1 jedna waga po poprawce ma postać wⱼ = sign(ρⱼ) · max(|ρⱼ| − α, 0), gdzie ρⱼ = (1/n) · xⱼᵀ rⱼ to związek cechy z resztą błędu bez niej. Gdy |ρⱼ| ≤ α, waga jest dokładnie zerem. Ridge daje wⱼ = ρⱼ / (1 + α/n) przy tych samych założeniach: waga maleje, ale zerem staje się tylko wtedy, gdy ρⱼ = 0.
R²: R² = 1 − Σ(yᵢ − ŷᵢ)² / Σ(yᵢ − ȳ)², liczone na pacjentach testowych.
W kodzie (Python)
Ten sam eksperyment w scikit-learn na 50 losowych podziałach (70% do nauki, 30% do testu): która cecha zostaje w lasso ostatnia, która znika pierwsza i ile kosztuje zostawienie najwyżej 3 cech.
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) # zakres kar z labu, gęściej
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") # dokładna ścieżka lasso, od najmocniejszej kary w dół
enters = [np.flatnonzero(coefs[j])[0] if coefs[j].any() else len(path_alphas) for j in range(10)] # gdzie każda cecha pierwszy raz dostaje wagę
last.append(names[np.argmin(enters)]); first.append(names[np.argmax(enters)]) # pierwsza z wagą = ostatnia, która ją traci, gdy kara rośnie
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) # najsłabsza kara, która zostawia najwyżej 3 cechy
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}")
Wynik
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
Podziały są inne niż w labie, więc liczby też są inne. Obraz jest ten sam: BMI zostaje ostatnie w 37 podziałach z 50 (s5 w pozostałych 13), a najwyżej 3 cechy obniżają R² na teście w każdym podziale, średnio z 0,471 do 0,379. Pierwsza znika raz s2, raz wiek: lasso wybiera między powiązanymi cechami, a wybór zależy od tego, którzy pacjenci trafili do nauki.
Pobierz notebook (.ipynb). Otwórz go w Jupyterze albo wgraj do Google Colab; brakujące dane pobierze sam.
Dla praktyka
- W scikit-learn:
Ridge,LassoiElasticNet(mieszanka obu kar, pomocna przy grupach skorelowanych cech). Standaryzację wkładaj do pipeline'u (make_pipeline(StandardScaler(), Lasso())), żeby średnie i odchylenia liczyły się tylko na treningu. - Siłę kary wybieraj walidacją krzyżową:
RidgeCViLassoCVrobią to od razu. Nie wybieraj α po wyniku testu: to strojenie na zbiorze testowym (lekcja 3.5). - Regresja logistyczna w scikit-learn ma karę ridge domyślnie (
penalty="l2"); siłę ustawiaC, czyli odwrotność α: mniejszeCto mocniejsza kara. - Jeśli chcesz mówić o ważności cech, nie czytaj samych zer z lasso. Sprawdź stabilność wyboru na wielu podziałach albo użyj metod z modułu 6.
Czy to było pomocne?
Dzięki! To pomaga nam poprawiać Atlas.
Więcej w Atlasie
Hasła encyklopedii o pojęciach z tej lekcji: