ML Atlas

Kurs uczenia maszynowego od zera · Lekcja 5.6 · 31 z 33 gotowych lekcji · 12 min

Który model kiedy?

W skrócie

Pięć modeli, pięć zbiorów, 20 podziałów. Żaden model nie jest w czołówce wszędzie, a różnica 0,3 pkt proc. bywa remisem: 10 do 7 podziałów.

Rozgrzewka Dwa pytania z wcześniejszych lekcji. Minuta, a lekcji nie blokuje.
Z lekcji 5.5: Maszyny wektorów nośnych i jądra Prawda czy fałsz: „zawsze bierz jądro RBF, bo jest najbardziej elastyczne”.

Pokaż odpowiedź

Poprawna odpowiedź: Fałsz, bo na płatkach liniowy trafia tyle samo, a RBF trzeba stroić

Na 20 podziałach oba trafiają średnio 28,5 z 30. Duże γ prowadzi do przeuczenia: na winach przy γ = 1000 trening 89,6%, walidacja 69,6%.

Z lekcji 5.4: Naiwny Bayes: fałszywe założenie, dobre decyzje Co naiwny Bayes mnoży, żeby ocenić, czy kwiat to versicolor?

Pokaż odpowiedź

Poprawna odpowiedź: Prior versicolor i gęstość każdego pomiaru u versicolor, osobno

Prior × gęstość długości × gęstość szerokości, każda liczona tylko ze średniej i wariancji tego pomiaru u versicolor. Wygrywa gatunek z największym iloczynem.

Znasz już pięć rodzin modeli: regresję logistyczną, k najbliższych sąsiadów (kNN), las losowy, gradient boosting i SVM z jądrem RBF. Który wybrać? Uczciwa odpowiedź brzmi: ten, który wypada najlepiej w walidacji na twoich danych. Ta lekcja sprawdza, jak bardzo wynik zależy od danych i jak odróżnić prawdziwą różnicę od szumu. Robimy zoo modeli: każdy z pięciu modeli z ustawieniami domyślnymi, bez strojenia, na pięciu zbiorach, a na każdym zbiorze na tych samych 20 podziałach. Za każdym razem 75% wierszy idzie do nauki, a 25% do walidacji.

Przewidź, potem sprawdź Pięć modeli z ustawieniami domyślnymi porównujemy na pięciu zbiorach: irysy, wina, guzy piersi, pingwiny i cyfry. Każdy model dostaje te same 20 podziałów. Czy jeden model będzie w czołówce na wszystkich pięciu zbiorach?
Jak bardzo jesteś pewny(-a)?

Eksperyment

Ten interaktywny eksperyment działa w przeglądarce z włączonym JavaScriptem. Tekst wokół opisuje, co w nim widać.

Pokaż odpowiedź

Poprawna odpowiedź: Nie: na cyfrach SVM wygrywa z regresją, a na pingwinach z nią przegrywa

Nie. Na cyfrach SVM ma więcej trafień niż regresja logistyczna w 17 podziałach z 20, a regresja więcej niż SVM w 3. Na pingwinach regresja ma więcej trafień w 9 podziałach, SVM w żadnym, a w 11 jest remis. Najlepszą średnią też mają na różnych zbiorach różne modele, ale na czterech zbiorach lider ma więcej trafień niż drugi model najwyżej w 10 z 20 podziałów. To, kto prowadzi, zależy tam w dużej mierze od podziałów.

Spróbuj

  • Na starcie: cyfry, kNN przeciw SVM. Różnica średnich jest mniejsza niż rozrzut kNN między podziałami. W ilu podziałach z 20 SVM ma więcej trafień?
  • Przejdź do guzów piersi i porównaj SVM z gradient boostingiem. Jaka jest różnica średnich, a jak rozkładają się podziały?
  • Znajdź parę modeli, w której na cyfrach prowadzi jeden, a na pingwinach drugi.
  • Na każdym zbiorze sprawdź, jak daleko od siebie leżą najgorszy i najlepszy podział jednego modelu.

Gdy już sprawdzisz to w labie, nazwijmy, co widzisz.

Pomysł w prostych słowach

Ten sam model na tym samym zbiorze dostaje w różnych podziałach różne wyniki, bo do walidacji trafiają raz łatwiejsze, raz trudniejsze przykłady. Na guzach piersi regresja logistyczna ma w pojedynczych podziałach od 89,4% do 96,5%. Różnice między modelami bywają dużo mniejsze. Jeden podział nie wystarczy więc, żeby je uszeregować.

Lepiej porównywać modele parami: na tym samym podziale oba mają tak samo łatwo albo tak samo trudno. Liczymy, w ilu podziałach który ma więcej trafień. Na guzach SVM ma średnio 94,2%, a gradient boosting 93,9%. SVM ma więcej trafień w 10 podziałach, boosting w 7, a w 3 jest remis. Taka różnica 0,3 pkt proc. to remis, nie zwycięstwo. Bywa też odwrotnie. Na cyfrach SVM ma tylko 0,7 pkt proc. więcej niż kNN, a wynik kNN skacze między podziałami od 96,0% do 99,1%. Mimo to SVM ma więcej trafień w 16 podziałach z 20, a kNN w 2. Liczy się, czy przewaga się powtarza, a nie, jak duża jest średnia.

Kiedy przewaga się powtarza? Gdyby oba modele były równie dobre, każdy podział bez remisu byłby jak rzut monetą. Wynik 16 do 2 moneta daje rzadziej niż raz na 100 serii, a 10 do 7 często. Lab nazywa przewagę powtarzalną, gdy taki wynik wypadałby rzadziej niż raz na 100 serii. To test znaków. Remisy go nie obciążają, bo po prostu się ich nie liczy.

Najważniejsze: kolejność zależy od danych. Na cyfrach SVM ma więcej trafień niż regresja logistyczna w 17 podziałach z 20, a regresja więcej niż SVM w 3. Na pingwinach jest odwrotnie: regresja ma więcej trafień w 9 podziałach, SVM w żadnym, a w 11 jest remis. Obie przewagi przechodzą test znaków. Na cyfrach SVM ma więcej trafień niż każdy z pozostałych modeli w co najmniej 16 podziałach.

To wszystko przy ustawieniach domyślnych, bez strojenia, na małych zbiorach (od 150 do 1797 wierszy) z samymi cechami liczbowymi. To nie wyrok o modelach w ogóle. Na większych tabelach, z cechami różnego typu i po strojeniu, kolejność może wyglądać inaczej (o boostingu w lekcji 5.3). Wniosek jest inny: rankingu nie bierze się z cudzej tabeli, tylko sprawdza na swoich danych.

Lidera też łatwo przecenić. Weźmy model z najlepszą średnią na podziałach 1–10 i sprawdźmy, kto prowadzi na podziałach 11–20. Na irysach, winach i pingwinach prowadzi tam już inny model. Gdy kilka modeli leży blisko siebie, o tym, który wyjdzie na prowadzenie, w dużej części decyduje szum, jak przy wyborze ustawień w lekcji 3.5.

Jak to policzono
  • Dane: Iris (Fisher, 1936), Wine (Aeberhard i Forina, 1992), Breast Cancer Wisconsin (Wolberg i in., 1993; 10 pomiarów „mean”) i Digits (Alpaydin i Kaynak, 1998), wszystkie z UCI na licencji CC BY 4.0; Palmer Penguins (Gorman i in., 2014; Horst i in., 2020; licencja CC0 1.0), 342 pingwiny z 4 pomiarami ciała.
  • Modele: ustawienia domyślne scikit-learn bez strojenia. Regresja logistyczna (C = 1), kNN (k = 5), las losowy (100 drzew), gradient boosting (100 drzew, krok 0,1, głębokość 3), SVM z jądrem RBF (C = 1). Regresja, kNN i SVM dostają cechy skalowane w każdym podziale tylko na części do nauki.
  • Zgodność ze scikit-learn na tych samych 20 podziałach: SVM trafia te same wiersze w każdym podziale, regresja i kNN różnią się najwyżej o 3 wiersze w podziale. Drzewa w labie dzielą każdą cechę na najwyżej 32 przedziały, a scikit-learn liczy drzewa dokładnie, więc tu różnice są większe: na guzach las ma ten sam wynik w 3 podziałach z 20, a boosting w 4. Z dokładnymi drzewami najlepszą średnią na guzach ma boosting, nie SVM. Wnioski o parach z tej lekcji wychodzą w obu wersjach tak samo.
  • Podziały: 20 podziałów ze stratyfikacją, 75% do nauki i 25% do walidacji, te same dla każdego modelu. Testu tu nie ma. Wszystkie 500 wyników policzył kod labu, a test przelicza je od nowa. Test znaków jest dwustronny, liczony na podziałach bez remisu, z progiem 1%.

Dlaczego to działa

Twierdzenie „nie ma darmowego obiadu” (Wolpert, 1996) mówi, że uśrednione po wszystkich możliwych zadaniach żaden algorytm uczący nie jest lepszy od innego. Model wygrywa tylko wtedy, gdy jego założenia pasują do konkretnych danych: proste granice do regresji logistycznej, podobieństwo sąsiadów do kNN, progi na pojedynczych cechach do drzew. Dlatego wybór modelu to pomiar, nie wiedza z tabeli.

Porównanie parami działa, bo trudność podziału dotyka obu modeli naraz i w różnicy się znosi. Uwaga: 20 podziałów tego samego zbioru dzieli wiersze, więc to nie 20 niezależnych rzutów monetą. Zwykłe testy statystyczne na takich wynikach bywają zbyt pewne siebie (Dietterich, 1998). Dlatego próg jest surowy, a powtarzalna przewaga to dobra wskazówka, nie dowód.

Model może mieć też własną losowość. Las losuje wiersze i cechy dla każdego drzewa. Na cyfrach, na tych samych 20 podziałach, las z ziarnem losowania 1 ma więcej trafień niż regresja w 15 podziałach i mniej w 5, a z ziarnem 4 więcej w 11 i mniej w 9. Przy żadnym ziarnie od 1 do 5 ta przewaga nie przechodzi testu znaków. Dlatego przykłady w tej lekcji opierają się na modelach bez losowości: regresji, kNN i SVM.

Kod niżej robi to samo w scikit-learn, na innych podziałach i z dokładnymi drzewami. Czołówka się zmienia: SVM ma tam najlepszą średnią na czterech zbiorach, a regresja logistyczna na pingwinach. Kierunek par z tej lekcji zostaje, ale nie każda przewaga przechodzi tam test znaków. To kolejny powód, żeby różnic w granicach szumu nie nazywać zwycięstwem.

Częsty błąd

Prawda czy fałsz: „model ze średnią wyższą o 0,3 pkt proc. jest lepszy”. Fałsz. Na guzach SVM ma 94,2%, a gradient boosting 93,9%, ale SVM ma więcej trafień tylko w 10 podziałach z 20, boosting w 7. W kodzie niżej ta sama para dzieli się podziałami 10 do 7, a różnica średnich to 0,002.

Drugi częsty błąd: „zawsze bierz boosting, na przykład XGBoost”. W tym zoo, z ustawieniami domyślnymi, na winach regresja logistyczna ma więcej trafień niż gradient boosting w 15 podziałach z 20, a boosting więcej niż ona w 2. To nie wyrok przeciw boostingowi, tylko przeciw wybieraniu bez walidacji.

Quiz

Trzy pytania na sprawdzenie się. Wybierz odpowiedź albo rozwiń odpowiedź pod pytaniem. Z klawiatury: strzałki wybierają, Enter albo spacja zatwierdza.

1. Dlaczego wynik z jednego podziału nie wystarczy, żeby wybrać model?
Pokaż odpowiedź

Poprawna odpowiedź: Bo sam podział przesuwa wynik modelu o kilka punktów procentowych

Na guzach regresja logistyczna ma w pojedynczych podziałach od 89,4% do 96,5%. Różnice między modelami bywają dużo mniejsze.

2. Na cyfrach SVM ma więcej trafień niż regresja logistyczna w 17 z 20 podziałów, a na pingwinach w żadnym (regresja w 9, remis w 11). Co z tego wynika?
Pokaż odpowiedź

Poprawna odpowiedź: Który model lepszy, zależy od danych, więc sprawdzasz to na swoich

Kolejność odwraca się między zbiorami. Dlatego model wybiera się walidacją na własnych danych, a nie z cudzego rankingu.

3. Prawda czy fałsz: „model ze średnią wyższą o 0,3 pkt proc. jest lepszy”.
Pokaż odpowiedź

Poprawna odpowiedź: Fałsz: przy takiej różnicy podziały dzielą się prawie po równo

Na guzach SVM ma 94,2%, a gradient boosting 93,9%. SVM ma więcej trafień w 10 podziałach, boosting w 7, w 3 jest remis.

Najważniejsze wnioski

  • Żaden model nie jest w czołówce wszędzie: SVM wygrywa z regresją logistyczną na cyfrach (17 do 3 podziałów), a przegrywa na pingwinach (9 do 0).
  • Sam podział przesuwa wynik o kilka punktów, więc różnica średnich 0,3 pkt proc. bywa remisem (10 do 7 podziałów).
  • Porównuj modele na tych samych podziałach i licz, w ilu który wygrywa; mała, ale powtarzalna przewaga też się liczy (SVM nad kNN na cyfrach: 0,7 pkt proc., 16 do 2).
  • Wybieraj walidacją na swoich danych, przy remisie bierz prostszy model, a test oglądaj raz, na końcu.

Głębiej: wzór, kod, praktyka

Matematyka

Dla podziałów k = 1, …, K różnica w parze to d_k = acc_A(k) − acc_B(k); patrzymy na średnią d̄ = (1/K) · Σ_k d_k i na liczbę podziałów z d_k > 0.

Wariancja różnicy: Var(A − B) = Var(A) + Var(B) − 2 · Cov(A, B). Gdy podział jest trudny dla obu modeli naraz, kowariancja jest duża, więc różnica waha się dużo mniej niż każdy wynik osobno.

Test znaków: model A wygrywa w w podziałach, B w l, remisy pomijamy. Przy równych modelach liczba wygranych A ma rozkład Bin(w + l, ½), a p = min(1, 2 · P(X ≤ min(w, l))). Dla 16 do 2 wychodzi p ≈ 0,001.

W kodzie (Python)

Ten sam eksperyment w scikit-learn: pięć modeli z ustawieniami domyślnymi na pięciu zbiorach i 20 podziałach, potem cztery pary podział po podziale, z testem znaków.

import pandas as pd
from scipy.stats import binomtest
from sklearn.datasets import load_iris, load_wine, load_breast_cancer, load_digits
from sklearn.model_selection import StratifiedShuffleSplit, cross_val_score
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.svm import SVC

body = ["bill_length_mm", "bill_depth_mm", "flipper_length_mm", "body_mass_g"]
peng = pd.read_csv("data/raw/penguins.csv").dropna(subset=body)
cancer = load_breast_cancer()
data = {"iris": load_iris(return_X_y=True), "wine": load_wine(return_X_y=True), "cancer": (cancer.data[:, :10], cancer.target),
        "penguins": (peng[body].values, peng["species"].values), "digits": load_digits(return_X_y=True)}
# skaler siedzi w każdym pipeline'ie, więc średnie liczy tylko z części do nauki każdego podziału
models = {"logistic": make_pipeline(StandardScaler(), LogisticRegression(max_iter=1000)),
          "kNN": make_pipeline(StandardScaler(), KNeighborsClassifier()),
          "forest": RandomForestClassifier(random_state=0),
          "boosting": GradientBoostingClassifier(random_state=0),
          "SVM": make_pipeline(StandardScaler(), SVC())}
splits = StratifiedShuffleSplit(n_splits=20, test_size=0.25, random_state=0)
acc = {}
for name, (X, y) in data.items():
    acc[name] = {m: cross_val_score(model, X, y, cv=splits) for m, model in models.items()}
    row = " | ".join(f"{m} {a.mean():.3f}" for m, a in acc[name].items())
    best = max(acc[name], key=lambda m: acc[name][m].mean())
    print(f"{name:8s} {row}  best: {best}")
# test znaków: tylko podziały bez remisu; przy równych modelach każdy z nich to rzut monetą
for name, a, b in [("digits", "SVM", "kNN"), ("digits", "SVM", "logistic"), ("penguins", "logistic", "SVM"), ("cancer", "SVM", "boosting")]:
    d = acc[name][a] - acc[name][b]
    win, lose = (d > 0).sum(), (d < 0).sum()
    print(f"{name}: {a} beats {b} in {win} of 20 splits, loses in {lose}; sign test p = {binomtest(win, win + lose).pvalue:.3f}; mean difference {d.mean():.3f}")

Wynik

iris     logistic 0.955 | kNN 0.945 | forest 0.949 | boosting 0.947 | SVM 0.959  best: SVM
wine     logistic 0.982 | kNN 0.964 | forest 0.981 | boosting 0.946 | SVM 0.986  best: SVM
cancer   logistic 0.931 | kNN 0.938 | forest 0.930 | boosting 0.939 | SVM 0.942  best: SVM
penguins logistic 0.988 | kNN 0.985 | forest 0.978 | boosting 0.973 | SVM 0.983  best: logistic
digits   logistic 0.969 | kNN 0.974 | forest 0.975 | boosting 0.964 | SVM 0.979  best: SVM
digits: SVM beats kNN in 14 of 20 splits, loses in 4; sign test p = 0.031; mean difference 0.006
digits: SVM beats logistic in 17 of 20 splits, loses in 3; sign test p = 0.003; mean difference 0.010
penguins: logistic beats SVM in 7 of 20 splits, loses in 1; sign test p = 0.070; mean difference 0.005
cancer: SVM beats boosting in 10 of 20 splits, loses in 7; sign test p = 0.629; mean difference 0.002

Podziały i implementacja drzew są inne niż w labie, więc czołówka też: SVM ma najlepszą średnią na czterech zbiorach, regresja logistyczna na pingwinach. Też żaden model nie wygrywa wszędzie. Kierunek par z lekcji zostaje: na cyfrach SVM wygrywa z regresją w 17 podziałach z 20, a z kNN w 14, na pingwinach regresja wygrywa z SVM w 7, a przegrywa w 1. Test znaków przechodzi tu tylko pierwsza para (p = 0,003). Dwie pozostałe mają ten sam kierunek, ale na tych podziałach za mało wygranych, więc wniosek z jednego zestawu podziałów warto sprawdzić na drugim. SVM i boosting na guzach znów dzielą się podziałami 10 do 7.

Dla praktyka
  • Zacznij od punktu odniesienia (lekcja 1.3), potem weź kilka modeli różnego rodzaju: liniowy, sąsiedzi, drzewa, jądro. Wszystkie oceniaj na tych samych podziałach (cross_validate z jednym cv) i z przetwarzaniem w pipeline'ie (lekcja 4.6).
  • Patrz na rozrzut i na pary, nie tylko na średnie. Przewagę sprawdzaj testem znaków (binomtest z SciPy) na podziałach bez remisu. Przy remisie wybierz model tańszy w utrzymaniu albo łatwiejszy do wyjaśnienia.
  • Strój dopiero finalistów (lekcja 3.5). Domyślne ustawienia bywają dalekie od najlepszych, zwłaszcza w boostingu i SVM.
  • Rankingi „który model kiedy” z internetu traktuj jak listę kandydatów do walidacji, nie jak wyrok. Test zostaw na sam koniec i oglądaj go raz.

Więcej w Atlasie

Hasła encyklopedii o pojęciach z tej lekcji: