Materiały kursów
Materiały / Machine Learning
Pobierz notatnik (.ipynb)

Ćwiczenie 9: Projekt końcowy

Po co to ćwiczenie?

Przez osiem ćwiczeń poznawaliśmy elementy układanki osobno: podział danych, analizę eksploracyjną, przygotowanie cech (ang. features), regresję, klasyfikację, walidację krzyżową, drzewa, grupowanie. Za każdym razem ktoś prowadził Cię za rękę - był przykład prowadzony, a zadanie sprowadzało się do powtórzenia schematu na innym parametrze.

W prawdziwej pracy nikt nie daje przykładu prowadzonego. Dostajesz plik z danymi, pytanie od zleceniodawcy i termin.

To ćwiczenie jest właśnie takie. Nie ma tu przykładu prowadzonego ani gotowego schematu do skopiowania. Jest opis zadania i rusztowanie z sekcjami do wypełnienia. Cały kod i wszystkie decyzje należą do Ciebie.

Gdy utkniesz, wracaj do ćwiczeń 01-08 - masz tam wszystkie potrzebne elementy, tyle że pokazane osobno. Cała trudność tego projektu polega na złożeniu ich w całość we właściwej kolejności.

Pracujesz też na zbiorze danych, którego wcześniej nie było w kursie. To celowe. Chodzi nie o „znajomość zbioru diabetes.csv", tylko o zdolność zastosowania metody do nowego problemu.

Czego się nauczysz

  1. Jak samodzielnie przejść pełną ścieżkę: dane → zrozumienie → przygotowanie → modele → dobór → uczciwa ocena → wnioski.
  2. Jak zaplanować pracę tak, żeby na końcu dało się komuś wytłumaczyć, dlaczego wybór padł na ten, a nie inny model.
  3. Jak nie popełnić czterech błędów, które unieważniają wynik - nawet jeśli liczba na końcu wygląda świetnie.
  4. Jak napisać wniosek, który jest odpowiedzią na pytanie, a nie wykazem uruchomionych funkcji.

Ten notatnik jest Twoim szkieletem pracy. Wypełniaj go w miejscach oznaczonych # TWÓJ KOD TUTAJ oraz (tutaj Twój komentarz). Możesz dodawać własne komórki; sekcji lepiej nie usuwać, bo każda odpowiada za inny etap pracy.


Zbiór danych: rozpoznawanie odmiany wina

Pracujesz na zbiorze wine wbudowanym w scikit-learn. Nie wymaga pobierania z internetu - wczytuje się jedną funkcją.

Dane pochodzą z analizy chemicznej win pochodzących z jednego regionu Włoch, wyprodukowanych przez trzech różnych producentów. Dla każdej butelki zmierzono 13 wielkości chemicznych (zawartość alkoholu, kwasu jabłkowego, magnezu, flawonoidów, intensywność barwy, zawartość proliny i inne).

Zadanie: na podstawie wyników analizy chemicznej rozpoznać, od którego z trzech producentów pochodzi wino.

To jest klasyfikacja wieloklasowa (ang. multiclass classification) - i to pierwsza rzecz, która odróżnia ten projekt od wszystkiego, co było wcześniej w kursie. Klas nie ma dwóch, tylko trzy. Część rzeczy przenosi się wprost, część wymaga uwagi:

Element Klasyfikacja binarna (ćwiczenia 01-07) Klasyfikacja wieloklasowa (ten projekt)
Macierz pomyłek 2×2 3×3 - błędy dzielą się na więcej rodzajów
Skuteczność (ang. accuracy) działa tak samo działa tak samo
Precyzja, czułość, F1 jedna liczba osobno dla każdej klasy; do jednej liczby trzeba je uśrednić (average='macro' albo 'weighted')
Model odniesienia „zawsze klasa większościowa" to samo, ale poprzeczka jest niżej - klas jest więcej
Krzywa ROC naturalna wymaga podejścia „jedna klasa przeciw reszcie" - w tym projekcie możesz ją pominąć

Druga istotna różnica: zbiór jest mały. To niecałe dwieście butelek - dwa rzędy wielkości mniej niż 10 000 kart pacjentów. Konsekwencje są poważne i trzeba będzie się z nimi zmierzyć:

  • zbiór testowy liczy kilkadziesiąt próbek, więc jedna pomyłka więcej lub mniej zmienia wynik o punkty procentowe,
  • pojedynczy podział danych jest bardzo niestabilny - walidacja krzyżowa przestaje być dobrą praktyką, a staje się koniecznością,
  • stratyfikacja przestaje być kosmetyką (pamiętasz zadanie 7 z ćwiczenia 01? tam przy 10 000 wierszy nie robiła różnicy - tutaj zrobi).
In [ ]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.dummy import DummyClassifier
from sklearn.metrics import ConfusionMatrixDisplay

# Jedno ziarno losowosci na caly projekt. Kazde miejsce, w ktorym sklearn
# losuje (podzial danych, inicjalizacja modelu), dostaje te sama wartosc -
# dzieki temu wynik da sie powtorzyc co do cyfry, takze na innym komputerze.
ZIARNO = 42

wino = load_wine(as_frame=True)

X = wino.data          # 13 cech chemicznych
y = wino.target        # 0, 1, 2 - trzech producentow

print("Liczba probek i cech:", X.shape)
print("Nazwy klas:", list(wino.target_names))
print()
print("Liczebnosc klas:")
print(y.value_counts().sort_index().to_string())
print()
print("Cechy:")
for nazwa in X.columns:
    print("  -", nazwa)

Chcesz trudniej? Zamiast load_wine możesz użyć load_digits - 1797 obrazków odręcznych cyfr, każdy jako 64 piksele (8×8), dziesięć klas. Wszystkie wymagania projektu pozostają te same. Zbiór jest większy i ma dziesięć klas zamiast trzech, więc macierz pomyłek robi się znacznie ciekawsza (które cyfry mylą się ze sobą?), a modele liczą się dłużej. Jeśli wybierasz ten wariant, napisz o tym wprost we wnioskach.

Uwaga o PatientID: w tym zbiorze nie ma identyfikatora - wszystkie 13 kolumn to wyniki pomiarów. Nie znaczy to jednak, że temat znika. Nadal warto sprawdzić i zapisać, że każda użyta kolumna jest faktyczną cechą, a nie artefaktem procesu zbierania danych. Odruch „sprawdzam, czym są moje kolumny, zanim je wrzucę do modelu" jest ważniejszy niż konkretny zbiór.


Zasady gry

Wolno:

  • korzystać z numpy, pandas, matplotlib, scikit-learn - i tylko z nich,
  • wracać do ćwiczeń 01-08 i przepisywać stamtąd kod (to wręcz wskazane),
  • czytać dokumentację scikit-learn,
  • dodawać własne komórki, wykresy i analizy ponad wymagane minimum.

Nie wolno:

  • używać seaborn, plotly, graphviza ani innych bibliotek spoza listy (drzewa rysujemy wyłącznie przez sklearn.tree.plot_tree),
  • pobierać czegokolwiek z internetu - zbiór jest wbudowany,
  • pominąć którejkolwiek z sekcji rusztowania,
  • uznać za skończony notatnika, który nie wykonuje się od początku do końca po Kernel → Restart Kernel and Run All Cells.

Obowiązkowo w każdym kawałku kodu z elementem losowym: random_state=42.


Rusztowanie projektu

Poniżej znajduje się siedem etapów. Każdy ma opis tego, co masz zrobić, oraz pustą komórkę na kod i - gdzie trzeba - na komentarz.

Komentarze liczą się tak samo jak kod. Projekt bez wniosków jest projektem nieukończonym, choćby kod był bezbłędny - bo nikt, łącznie z Tobą za miesiąc, nie odtworzy z samego kodu, dlaczego podjąłeś takie, a nie inne decyzje.

Etap 1: Poznaj dane

Zanim zbudujesz cokolwiek, dowiedz się, z czym pracujesz. Minimum:

  1. Rozmiar zbioru, typy kolumn, braki danych (isna().sum()).
  2. Statystyki opisowe cech (describe()) - ze szczególną uwagą na zakresy. Zwróć uwagę, czy cechy są w porównywalnych skalach.
  3. Rozkład klas - czy zbiór jest zrównoważony (ang. balanced), czy nie.
  4. Co najmniej dwa wykresy: na przykład histogramy wybranych cech w rozbiciu na klasy oraz macierz korelacji między cechami (X.corr() i ax.imshow).

Na koniec napisz trzy do pięciu zdań o tym, czego udało się dowiedzieć. Nie „zbiór ma 13 kolumn" - to widać w kodzie. Raczej: które cechy wyglądają na przydatne, czy coś jest podejrzane, czy konieczne będzie skalowanie i dlaczego.

In [ ]:
# TWÓJ KOD TUTAJ - analiza eksploracyjna

Wnioski z etapu 1:

(tutaj wpisz swoje obserwacje - kliknij dwukrotnie, żeby edytować)

Etap 2: Podział danych

Odłóż zbiór testowy (ang. test set) i nie dotykaj go aż do etapu 6.

  1. Podziel dane na uczące i testowe: test_size=0.25, stratify=y, random_state=42.
  2. Wypisz liczebności obu części oraz rozkład klas w każdej z nich.
  3. Napisz jedno zdanie: dlaczego stratify=y przy tak małym zbiorze nie jest opcjonalne.

To jest najważniejsza komórka w całym projekcie. Od tego momentu X_test i y_test są dla Ciebie zamknięte. Nie patrzysz na nie, nie liczysz na nich statystyk, nie dopasowujesz na nich skalera, nie wybierasz według nich hiperparametrów. Wszystko - absolutnie wszystko - robisz na zbiorze uczącym, korzystając z walidacji krzyżowej.

In [ ]:
# TWÓJ KOD TUTAJ - podział na zbiór uczący i testowy

Etap 3: Przygotowanie danych i model odniesienia

  1. Zbuduj model odniesienia (ang. baseline) - DummyClassifier(strategy="most_frequent"). Zmierz go walidacją krzyżową na zbiorze uczącym. To Twoja poprzeczka: model, który jej nie przeskoczy, nie ma prawa bytu.
  2. Zdecyduj, jak przygotujesz dane. Przy tym zbiorze najważniejsze pytanie brzmi: czy skalować cechy? Odpowiedź nie jest jedna dla wszystkich modeli - patrz tabela niżej.
  3. Zbuduj przygotowanie jako Pipeline, nie jako osobne wywołania.
Rodzina modeli Skalowanie Dlaczego
regresja logistyczna, SVM, k najbliższych sąsiadów konieczne liczą odległości albo sumy waga × cecha w poprzek cech
drzewo, las losowy, boosting zbędne porównują wartość cechy z progiem wewnątrz tej samej cechy

Dlaczego Pipeline, a nie „przeskaluję sobie wcześniej"? Bo skaler uczy się z danych - zapamiętuje średnią i odchylenie standardowe. Jeśli dopasujesz go na całości przed podziałem, informacja ze zbioru testowego wycieknie do procesu uczenia. Pipeline załatwia to automatycznie: w walidacji krzyżowej skaler jest dopasowywany osobno w każdej składce, wyłącznie na jej części uczącej. To nie jest szczegół stylistyczny - to różnica między oceną uczciwą a zawyżoną.

In [ ]:
# TWÓJ KOD TUTAJ - model odniesienia i potoki przygotowania danych

Etap 4: Co najmniej trzy różne modele

Zbuduj i porównaj minimum trzy modele należące do różnych rodzin. Chodzi o różnorodność podejść, nie o trzy warianty tego samego pomysłu.

Przykładowy zestaw (nie musisz trzymać się dokładnie tego):

Model Rodzina Skalowanie
LogisticRegression liniowy tak
KNeighborsClassifier oparty na odległościach tak
DecisionTreeClassifier drzewo nie
RandomForestClassifier zespół drzew (ang. ensemble) nie
SVC margines / jądra tak

Wymagania:

  1. Każdy model oceniasz walidacją krzyżową na zbiorze uczącym (cross_val_score, cv=5, StratifiedKFold z shuffle=True, random_state=42).
  2. Podajesz średnią i odchylenie standardowe wyników ze składek - nie samą średnią. Przy tak małym zbiorze rozrzut między składkami bywa duży i sam w sobie jest informacją.
  3. Zestawiasz wyniki w jednej tabeli (pd.DataFrame) razem z modelem odniesienia.

Trzy modele to minimum, nie cel. Jeśli dorzucisz czwarty i piąty, a przy tym potrafisz powiedzieć, czym się od siebie różnią - tym lepiej.

In [ ]:
# TWÓJ KOD TUTAJ - porównanie modeli walidacją krzyżową

Wnioski z etapu 4:

(który model prowadzi? czy różnice między modelami są większe niż rozrzut między składkami? co to oznacza?)

Etap 5: Dobór hiperparametrów

Wybierz co najmniej dwa modele z etapu 4 i dobierz im hiperparametry (ang. hyperparameters) - czyli ustawienia, których model nie uczy się z danych, tylko dostaje od Ciebie z góry.

  1. Użyj GridSearchCV albo RandomizedSearchCV z tą samą strategią walidacji co w etapie 4.
  2. Przeszukiwanie prowadzisz wyłącznie na zbiorze uczącym.
  3. Wypisz najlepsze znalezione ustawienia (best_params_) i odpowiadający im wynik walidacyjny (best_score_).
  4. Napisz, co dany hiperparametr właściwie robi. „Najlepsze C=10" nie jest wynikiem - wynikiem jest „mniejsze C oznacza silniejszą regularyzację, a przy tak małym zbiorze spodziewałem(-am) się, że pomoże; okazało się, że...".

Punkty startowe (rozszerz je według uznania):

Model Hiperparametr Co kontroluje
LogisticRegression C siłę regularyzacji - mniejsze C to mocniejsze karanie dużych współczynników
KNeighborsClassifier n_neighbors, weights ilu sąsiadów głosuje i czy bliżsi ważą więcej
DecisionTreeClassifier max_depth, min_samples_leaf jak bardzo drzewo może się rozrosnąć
RandomForestClassifier n_estimators, max_features, max_depth liczbę drzew i ich zróżnicowanie
SVC C, gamma, kernel kształt i sztywność granicy decyzyjnej

Uwaga na Pipeline: parametry modelu w potoku adresuje się z przedrostkiem, na przykład {'logisticregression__C': [0.01, 0.1, 1, 10]} przy make_pipeline albo {'model__C': ...}, jeśli krok w Pipeline nosi nazwę model. Sprawdź potok.get_params().keys(), jeśli nie masz pewności, jak nazywa się Twój krok.

In [ ]:
# TWÓJ KOD TUTAJ - dobór hiperparametrów

Wnioski z etapu 5:

(co dał dobór hiperparametrów? czy poprawa jest realna, czy mieści się w rozrzucie między składkami?)

Etap 6: Uczciwa ocena na zbiorze testowym

Dopiero teraz sięgasz po X_test i y_test. Raz.

  1. Wybierz jeden model - ten, który wypadł najlepiej w walidacji krzyżowej. Wybór ma być uzasadniony wynikami z etapów 4-5, a nie wynikiem testowym (którego jeszcze nie znasz).
  2. Naucz go na całym zbiorze uczącym (jeśli w grę wchodzi GridSearchCV, obiekt best_estimator_ jest już nauczony na całości - sprawdź w dokumentacji, co robi refit=True).
  3. Zmierz na zbiorze testowym:
    • skuteczność,
    • classification_report - precyzję, czułość i F1 dla każdej klasy osobno,
    • macierz pomyłek (ConfusionMatrixDisplay).
  4. Porównaj wynik testowy z wynikiem walidacji krzyżowej z etapu 5. Skomentuj różnicę.

Dlaczego „raz"? Bo gdy zmierzysz wynik testowy, zobaczysz go, a potem wrócisz do modelu i coś poprawisz - zbiór testowy przestanie być zbiorem, którego model nie widział. Zacznie brać udział w wyborze modelu za Twoim pośrednictwem. To najsubtelniejsza odmiana przecieku danych (ang. data leakage): nie ma wycieku w kodzie, wyciek przechodzi przez Twoją głowę. Efekt jest ten sam - zawyżony, nieuczciwy wynik.

In [ ]:
# TWÓJ KOD TUTAJ - ocena końcowa na odłożonym zbiorze testowym

Wnioski z etapu 6:

(jaki wynik osiągnął model? które klasy myli ze sobą? czy wynik testowy jest zbliżony do walidacyjnego, wyższy czy niższy - i co z tego wynika?)

Etap 7: Wnioski i uzasadnienie wyboru

To jest część, którą przeczytałby zleceniodawca - i jedyna, która zostaje, gdy zamkniesz notatnik. Napisz kilkanaście zdań (nie kod) odpowiadające na poniższe pytania:

  1. Który model został wybrany i dlaczego? Odwołaj się do liczb z etapów 4-5, nie do ogólnych opinii o algorytmach.
  2. Czy model jest użyteczny? Porównaj z modelem odniesienia. O ile jest lepszy i czy ta różnica jest warta zachodu.
  3. Jakie błędy popełnia? Które klasy myli i czy te pomyłki mają jakieś wyjaśnienie.
  4. Jak bardzo ufasz temu wynikowi? Zbiór testowy liczy kilkadziesiąt próbek - ile z nich to jeden punkt procentowy? Co to mówi o precyzji Twojego pomiaru?
  5. Co zrobiłbyś(-abyś) dalej, mając jeszcze tydzień? Wymień dwie, trzy konkretne rzeczy.
  6. Czego ten wynik nie mówi? Jedno ograniczenie, którego z samych liczb nie widać.

Punkt 4 jest w tym projekcie ważniejszy niż gdzie indziej i nie da się go obejść. Przy test_size=0.25 zbiór testowy liczy 45 butelek, więc jedna pomyłka to ponad dwa punkty procentowe. Różnica „model A ma 97,8%, model B ma 95,6%" oznacza jedną butelkę. Student, który na tej podstawie ogłasza zwycięzcę, nie zrozumiał, czym jest niepewność pomiaru - i to jest jedna z najważniejszych rzeczy, jakie ten projekt ma sprawdzić.

Wnioski końcowe:

(tutaj wpisz swoje podsumowanie - kliknij dwukrotnie, żeby edytować)

  1. Wybrany model i uzasadnienie:
  2. Użyteczność względem modelu odniesienia:
  3. Rodzaje popełnianych błędów:
  4. Zaufanie do wyniku i niepewność pomiaru:
  5. Co dalej:
  6. Czego wynik nie mówi:

Co powinien zawierać dobry projekt

Poniższa tabela to lista samokontrolna. Kolumna „minimum" opisuje to, bez czego projekt nie odpowiada na postawione pytanie. Kolumna „poziom, do którego warto dążyć" pokazuje, czym różni się praca porządna od pracy dobrej.

Przejdź przez nią, gdy uznasz projekt za skończony. Jeśli któryś wiersz budzi wątpliwość - wróć do tego etapu.

Obszar Minimum Poziom, do którego warto dążyć
1. Analiza danych Rozmiar zbioru, braki danych, statystyki opisowe, rozkład klas, dwa wykresy, kilka zdań wniosków Świadoma analiza korelacji między cechami i wnioski z niej dla wyboru modelu; wykresy z opisanymi osiami, tytułem i komentarzem, co z nich wynika
2. Podział i przygotowanie danych Poprawny podział ze stratyfikacją i random_state=42; skalowanie zastosowane tam, gdzie jest potrzebne; zbiór testowy nietknięty do etapu 6 Całe przygotowanie zamknięte w Pipeline; wyjaśnione, dlaczego części modeli skalowanie jest zbędne
3. Modele Co najmniej trzy modele z różnych rodzin, ocenione walidacją krzyżową, zestawione w tabeli razem z modelem odniesienia Więcej modeli albo świadomie dobrany zestaw; podane odchylenie standardowe ze składek i użyte w interpretacji
4. Dobór hiperparametrów GridSearchCV (lub odpowiednik) dla co najmniej dwóch modeli, wyłącznie na zbiorze uczącym; wypisane best_params_ Wyjaśnione, co robi każdy strojony hiperparametr i dlaczego dobrany zakres ma sens; sprawdzone, czy poprawa mieści się w rozrzucie między składkami
5. Ocena końcowa Jednokrotny pomiar na zbiorze testowym: skuteczność, classification_report, macierz pomyłek Analiza macierzy pomyłek klasa po klasie z próbą wyjaśnienia pomyłek; porównanie wyniku testowego z walidacyjnym i komentarz do różnicy
6. Wnioski Odpowiedzi na wszystkie sześć pytań z etapu 7, oparte na liczbach z projektu Wnioski, które ktoś nieznający kodu zrozumie bez pytań dodatkowych; uczciwie nazwane ograniczenia; sensowny plan dalszych kroków

Czego na tej liście świadomie nie ma: wysokości wyniku liczbowego. Projekt z uczciwie zmierzoną skutecznością 92% jest wart więcej niż projekt z 99% uzyskanym przez podglądanie zbioru testowego. W pracy zawodowej jest dokładnie tak samo - z tą różnicą, że tam nikt nie zagląda do Twojego notatnika, a błąd wychodzi dopiero na produkcji.


Cztery błędy, które unieważniają wynik

Przejdź przez tę listę, zanim uznasz projekt za skończony. Każdy z tych czterech błędów sprawia, że liczba, którą podajesz na końcu, jest nieprawdziwa - i żadna jakość reszty pracy tego nie naprawia.

To nie jest lista zakazów wymyślona na potrzeby ćwiczenia. Każdy z tych błędów zdarza się w prawdziwych projektach i każdy kończy się tak samo: model, który świetnie wypadł w notatniku, zawodzi na pierwszych prawdziwych danych.

1. Ocena na zbiorze uczącym

Objaw: w projekcie pojawia się model.score(X_ucz, y_ucz) podane jako wynik modelu.

Dlaczego to błąd: model widział te dane podczas uczenia. Mierzysz, jak dobrze je zapamiętał, a nie jak dobrze radzi sobie z nowymi butelkami. Drzewo bez ograniczeń osiągnie tu 100% i nie będzie to znaczyło nic (ćwiczenie 01, zadanie 3).

Jak sprawdzić: przeszukaj notatnik pod kątem score(X_ucz i score(X_train. Wynik na zbiorze uczącym wolno pokazać wyłącznie jako ilustrację przeuczenia, wyraźnie jako taki opisaną.

2. Dobór hiperparametrów na zbiorze testowym

Objaw: pętla po wartościach hiperparametru, w której za każdym razem liczony jest wynik na X_test, a potem wybór najlepszego.

Dlaczego to błąd: zbiór testowy przestaje być bezstronny, bo brał udział w wyborze modelu. Raportowany wynik jest zawyżony i nie przewiduje zachowania na prawdziwie nowych danych. To ten sam błąd, który celowo popełniliśmy w ćwiczeniu 01 (zadanie 4) i naprawiliśmy w ćwiczeniu 06.

Jak zrobić poprawnie: hiperparametry dobiera się walidacją krzyżową na zbiorze uczącym. Zbiór testowy dotykasz raz, na samym końcu, jednym pomiarem.

Odmiana subtelna, równie groźna: wynik testowy zostaje zmierzony, nie podoba się, więc wracasz i poprawiasz model. Wtedy zbiór testowy uczestniczy w doborze modelu przez Ciebie - i przestaje być testowy, nawet jeśli w kodzie nie widać niczego złego.

3. Skalowanie (albo cokolwiek innego) przed podziałem danych

Objaw: StandardScaler().fit_transform(X) przed train_test_split.

Dlaczego to błąd: skaler wylicza średnią i odchylenie standardowe. Jeśli liczy je na całym zbiorze, do przekształcenia danych uczących trafia informacja ze zbioru testowego. To przeciek danych (ang. data leakage) - subtelny, bo nic się nie wysypie, a wynik wyjdzie odrobinę lepszy niż prawdziwy.

Jak zrobić poprawnie: najpierw podział, potem Pipeline(StandardScaler(), model). Wewnątrz walidacji krzyżowej skaler jest dopasowywany osobno w każdej składce - Pipeline pilnuje tego za Ciebie i to jest jego główny powód istnienia.

Dotyczy nie tylko skalowania: tak samo jest z uzupełnianiem braków danych, selekcją cech, PCA i każdym innym krokiem, który uczy się czegoś z danych.

4. Identyfikator jako cecha

Objaw: w X znajduje się kolumna będąca numerem porządkowym, identyfikatorem, datą rejestracji albo indeksem wiersza.

Dlaczego to błąd: identyfikator jest unikalny, więc model może zapamiętać po nim każdą próbkę z osobna. Na danych uczących wygląda to znakomicie, na nowych - katastrofalnie, bo ich identyfikatorów model nigdy nie widział.

W tym konkretnym zbiorze kolumny identyfikatora nie ma - wszystkie 13 cech to wyniki pomiarów chemicznych. Sprawdzenie i tak należy wykonać i opisać. Odruch „patrzę, czym są moje kolumny, zanim je wrzucę do modelu" jest tym, co sprawdzamy; brak identyfikatora w tym zbiorze to szczęśliwy zbieg okoliczności, a nie reguła.

Szerzej: usunąć trzeba wszystko, co nie będzie dostępne w momencie predykcji albo co niesie informację o odpowiedzi pochodzącą z przyszłości. W danych medycznych to na przykład kolumna „zalecone leczenie" - wypełniana po postawieniu diagnozy.


Lista kontrolna na koniec

Odhacz wszystko, zanim uznasz projekt za skończony:

  • Kernel → Restart Kernel and Run All Cells wykonuje się bez błędu od początku do końca
  • Wszystkie komórki # TWÓJ KOD TUTAJ są wypełnione
  • Wszystkie komórki z komentarzem są wypełnione (żadnego pozostawionego (tutaj wpisz...))
  • random_state=42 wszędzie, gdzie występuje losowość
  • Zbiór testowy użyty dokładnie raz, w etapie 6
  • Żaden wynik na zbiorze uczącym nie jest podany jako wynik modelu
  • Skalowanie odbywa się wewnątrz Pipeline, nie przed podziałem
  • Każdy wykres ma tytuł i opisane osie
  • Wnioski odwołują się do konkretnych liczb z projektu
  • Żadnych bibliotek spoza numpy, pandas, matplotlib, scikit-learn

Pytania do przemyślenia

Na te pytania odpowiadasz słowami, nie kodem. Warto wrócić do nich po skończeniu projektu.

  1. Twój model osiągnął pewien wynik na zbiorze testowym. Gdyby powtórzyć cały projekt z random_state=7 zamiast 42, jak bardzo zmieniłby się ten wynik? Od czego to zależy?
  2. Walidacja krzyżowa dała jeden ranking modeli, zbiór testowy potwierdził go albo nie. Jeśli nie - który z pomiarów jest bliższy prawdy i dlaczego?
  3. Dlaczego nie wolno wybrać modelu na podstawie wyniku testowego, skoro to właśnie ten wynik najbardziej nas interesuje?
  4. Zbiór wine ma 178 próbek. Które z wniosków Twojego projektu byłyby inne, gdyby miał 178 000 próbek? A które zostałyby takie same?
  5. Model odniesienia w tym zadaniu ma niższą poprzeczkę niż w zbiorze diabetes (trzy klasy zamiast dwóch). Czy to znaczy, że zadanie jest łatwiejsze, czy trudniejsze?
  6. Twój najlepszy model osiąga wynik bliski ideałowi. Czy to powód do radości, czy do podejrzliwości? Co sprawdzić, zanim ogłosisz sukces?
  7. Zleceniodawca pyta: „czy mogę na tym polegać przy nowych butelkach z tego regionu?". Co dokładnie mu odpowiesz i czego nie możesz obiecać?

Chcesz wiedzieć więcej

W kolejnych ćwiczeniach (10 - Od notatnika do skryptu i 11 - Jakość kodu w ML) zajmiemy się tym, co zrobić z modelem po projekcie: jak wyjąć go z notatnika, zapisać na dysk, uruchamiać z wiersza poleceń i przetestować. Jeśli podczas tego projektu choć raz zginął wynik przez uruchomienie komórek w złej kolejności - właśnie widać, po co te dwa ćwiczenia istnieją.