Kurs uczenia maszynowego od zera · Lekcja 3.2 · 15 z 33 gotowych lekcji · 10 min
Walidacja i walidacja krzyżowa
W skrócie
Wybieranie ustawień na zbiorze testowym go psuje. Walidacja krzyżowa sprawdza model po kolei na każdej części danych i pokazuje, jak stabilny jest wynik.
Rozgrzewka Dwa pytania z wcześniejszych lekcji. Minuta, a lekcji nie blokuje.
W poprzedniej lekcji wybraliśmy najlepszy stopień wielomianu, zerkając na zbiór testowy. Wydawało się to niewinne, ale pomyśl, co to znaczy: wypróbowaliśmy kilka modeli i zostawiliśmy ten, który zbiór testowy lubił najbardziej. Zbiór testowy nie jest już nieznanym egzaminem — stał się sędzią, którego radziliśmy się w trakcie przygotowań. Jak wybierać ustawienia, nie psując jedynego uczciwego pomiaru?
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ź: Rośnie, bo każda część testowa ma mniej win
Dla k = 2 najgorsza część ma 94,4%, a najlepsza 97,8% (różnica 3,4 pkt proc.). Dla k = 10 rozstęp to 83,3% do 100,0% (16,7 pkt proc.), bo część testowa liczy 17 lub 18 win i jedna pomyłka waży ponad 5 punktów. Średnia prawie się nie zmienia (96,1% i 96,7%).
Spróbuj
- Ustaw suwak k na najmniejszą wartość i odczytaj trafność każdego foldu. Jak bardzo foldy różnią się między sobą?
- Podnoś suwak k krok po kroku. Obserwuj średnią i rozrzut i zauważ, że w każdym foldzie jest teraz mniej win.
- Przy dużym k poszukaj foldów z wyjątkowo niską albo wysoką trafnością. Gdy w foldzie jest tylko garstka win, jedna pomyłka mocno rusza jego wynikiem.
- Porównaj rozrzut z różnicami między ustawieniami, które chciałbyś stroić. Czy mały zysk w średniej jest większy niż rozrzut?
Gdy już sprawdzisz to w labie, zobaczmy, co się tam właściwie działo.
Pomysł w prostych słowach
Pierwsze rozwiązanie to trzecia kupka danych. Dzielimy wiersze na zbiór treningowy, walidacyjny i testowy. Kandydatów trenujemy na treningowym, porównujemy na walidacyjnym, wybieramy zwycięzcę i dopiero wtedy otwieramy zbiór testowy, raz, żeby podać końcowy wynik. Zbiór walidacyjny przyjmuje na siebie całe zerkanie, więc testowy nie musi.
Kłopot w tym, że każdy podział kosztuje dane. Przy małym zbiorze zbiór walidacyjny na tyle duży, żeby był wiarygodny, zostawia za mało do nauki, a lekcja 2 pokazała, że mały zbiór daje rozchwiany wynik. Walidacja krzyżowa rozwiązuje to, sprytnie używając tych samych danych wiele razy.
Wyobraź sobie ocenianie nowej kucharki. Jedno danie mówi niewiele: może było jej najlepsze, może najgorsze. Prosisz więc o kilka dań w różne dni i patrzysz na średnią i na to, jak bardzo się różnią. Walidacja krzyżowa robi to samo z modelem: zamiast jednego egzaminu urządza kilka, za każdym razem na innych pytaniach, i dopiero z całej serii wyciąga wniosek.
Dlaczego to działa
W k-krotnej walidacji krzyżowej dane (bez końcowego zbioru testowego) tnie się na k równych części, zwanych foldami. Model trenuje się k razy. Za każdym razem jeden fold odkłada się do walidacji, a pozostałe k − 1 służą do treningu. Na koniec każdy wiersz był w walidacji dokładnie raz, a w treningu k − 1 razy. Każdy trening widzi taką część danych:
część treningowa = (k − 1) / k
Wynikiem nie jest jedna ocena, tylko k ocen, po jednej na fold. Ich średnia jest pewniejszym oszacowaniem niż pojedynczy podział, bo nie zależy od jednego szczęśliwego albo pechowego podziału wierszy. Ich rozrzut jest równie cenny: pokazuje, jak bardzo wynik zależy od tego, które wiersze model akurat dostał. Dwóch modeli, których średnie różnią się mniej niż ten rozrzut, nie da się naprawdę odróżnić.
Wybór k to kompromis. Przy małym k (powiedzmy 2) każdy model uczy się tylko na połowie danych, więc jest słabszy od tego, który na koniec zbudujesz, a oszacowanie jest pesymistyczne. Przy dużym k model uczy się prawie na wszystkim, ale każdy fold jest mały, więc oceny poszczególnych foldów są bardziej rozchwiane, a obliczenia trwają k razy dłużej niż jedno dopasowanie. Częstym kompromisem jest 5 albo 10.
Przykładem w tej lekcji jest zbiór Wine: 178 win z tego samego regionu Włoch, zrobionych z trzech różnych odmian winorośli, każde opisane 13 wynikami analizy chemicznej. Zadanie polega na rozróżnieniu tych trzech odmian.
Częsty błąd
Walidacja krzyżowa chroni cię tylko wtedy, gdy wszystko, czego uczysz się z danych, dzieje się wewnątrz każdego foldu. Jeśli najpierw skalujesz cechy albo wybierasz „najlepsze” cechy na wszystkich wierszach, a dopiero potem robisz walidację krzyżową, informacja z foldów walidacyjnych już przeciekła do treningu i wyniki są zbyt optymistyczne. Drugi błąd to strojenie dziesiątek ustawień walidacją krzyżową i podanie najlepszego wyniku jako końcowego. Po tylu porównaniach zwycięzca miał też trochę szczęścia; dlatego osobny zbiór testowy, użyty raz, wciąż ma znaczenie.
Z uczciwą oceną w zestawie narzędzi możemy badać mocniejsze modele, nie oszukując samych siebie. W następnej lekcji poznamy najbardziej czytelny z nich: drzewo decyzyjne.
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
- Wybieranie ustawień na zbiorze testowym go psuje; zamiast tego używaj zbioru walidacyjnego albo walidacji krzyżowej.
- W k-krotnej walidacji krzyżowej każdy wiersz trafia do walidacji dokładnie raz.
- Średnia ocen foldów szacuje jakość modelu; rozrzut pokazuje, jak bardzo zależy ona od podziału.
- Każda obróbka danych, która się z nich uczy, musi się odbywać wewnątrz foldu, żeby uniknąć wycieku.
Głębiej: wzór, kod, praktyka
Matematyka
W k-krotnej walidacji krzyżowej n wierszy dzielimy na k foldów. Każde dopasowanie uczy się na n · (k − 1) / k wierszach i testuje na pozostałych n / k. Wynik to średnia po foldach: CV = (1/k) · Σ wynik_f. Rozrzut to ich odchylenie standardowe s = √( Σ (wynik_f − CV)² / (k − 1) ).
Fold z m wierszami testowymi daje trafność zmieniającą się skokami co 1 / m. Jeśli prawdziwa trafność to p, jej błąd standardowy wynosi około √( p · (1 − p) / m ). Rośnie on, gdy m maleje, dlatego pojedyncze foldy stają się bardziej zaszumione, gdy k rośnie, choć średnia jest mniej pesymistyczna. Przy 178 winach i k = 10 jedna pomyłka w foldzie z 17 lub 18 win kosztuje od 5,6 do 5,9 punktu.
Wyniki foldów nie są w pełni niezależne: zbiory treningowe się pokrywają. Dlatego s / √k zaniża prawdziwą niepewność średniej.
W kodzie (Python)
178 win, 5 najbliższych sąsiadów i standaryzowane cechy. Żeby zobaczyć prawidłowość stojącą za pojedynczym tasowaniem z laba, różnicę między najgorszym a najlepszym foldem uśredniamy po 20 tasowaniach. Foldy są stratyfikowane i tasowane z ziarnem, więc liczby nie są labowymi 3,4 i 16,7 punktu:
import numpy as np
from sklearn.datasets import load_wine
from sklearn.model_selection import StratifiedKFold, cross_val_score
from sklearn.neighbors import KNeighborsClassifier
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
X, y = load_wine(return_X_y=True)
model = make_pipeline(StandardScaler(), KNeighborsClassifier(n_neighbors=5)) # skaler jest dopasowywany od nowa w każdym foldzie
for k in (2, 10):
runs = [cross_val_score(model, X, y, cv=StratifiedKFold(k, shuffle=True, random_state=s)) for s in range(20)]
gap = np.mean([a.max() - a.min() for a in runs])
print(f"k={k:2d}: mean accuracy {np.mean(runs):.3f}, average worst-to-best gap {gap:.3f}")
Wynik
k= 2: mean accuracy 0.956, average worst-to-best gap 0.020
k=10: mean accuracy 0.966, average worst-to-best gap 0.113
Średnia ledwo się rusza (0,956 i 0,966), ale przeciętna różnica między najgorszym a najlepszym foldem rośnie z 0,020 do 0,113, gdy k idzie od 2 do 10.
Pobierz notebook (.ipynb). Otwórz go w Jupyterze albo wgraj do Google Colab; brakujące dane pobierze sam.
Dla praktyka
- Każdy krok, który uczy się z danych (skalowanie, uzupełnianie braków, wybór cech), dopasowuj wewnątrz każdego foldu. W scikit-learn wstaw je do
Pipelinei podaj go docross_val_score. - W klasyfikacji używaj foldów stratyfikowanych, żeby każdy fold miał wszystkie klasy.
cross_val_scorerobi to domyślnie dla klasyfikatorów, gdycvjest liczbą, ale to domyślne cięcie nie tasuje. - Tasuj przed cięciem na foldy, jeśli wiersze są uporządkowane, np. według klasy albo daty.
load_winejest posortowane według klasy, więc podajStratifiedKFold(k, shuffle=True, random_state=0), jak wyżej. Dla szeregów czasowych nie tasuj: użyj podziału „do przodu”. - Jeśli wiersze należą do grup (kilka wierszy na pacjenta), trzymaj każdą grupę w jednym foldzie przez
GroupKFold. Inaczej ten sam pacjent trafi i do treningu, i do walidacji. - Podawaj średnią i rozrzut. Jeśli dwa modele różnią się mniej niż rozrzut, nie mów, że któryś jest lepszy.
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: