Uczenie maszynowe w Pythonie: praktyczny przewodnik po pierwszym modelu krok po kroku

0
130
Rate this post

Z tego artykuły dowiesz się:

Po co w ogóle ten cały machine learning? Krótki kontekst i oczekiwania

Klasyczne programowanie kontra uczenie maszynowe

W tradycyjnym programowaniu programista pisze zasady: jeśli użytkownik kliknie X, zrób Y; jeśli wartość większa niż 100, wyślij ostrzeżenie. Logika jest zakodowana ręcznie, krok po kroku. Program wykonuje to, co mu wpiszesz – ani grama więcej.

W uczeniu maszynowym jest odwrotnie. Zamiast wypisywać zasady, dajesz komputerowi przykłady. Dostaje dane wejściowe i oczekiwany wynik, a jego zadaniem jest znalezienie wzoru, który łączy jedno z drugim. Ty nie piszesz reguł typu: „jeśli użytkownik kupił A, zaproponuj B”. Model sam wykrywa, że użytkownicy kupujący A często kupują też B.

W praktyce można to sprowadzić do prostej różnicy:

  • Klasyczne programowanie: Reguły + dane → wynik.
  • Uczenie maszynowe: Dane + wyniki → model (który później daje wyniki dla nowych danych).

Dlatego największym „magnesem” ML nie jest magia, tylko możliwość automatycznego znajdowania zależności w danych, których ręcznie nie da się wygodnie rozpisać.

Proste, realne zastosowania pierwszych modeli

Żeby nabrać wyczucia, gdzie taki model się przydaje, wystarczy kilka codziennych przykładów:

  • Rekomendacje produktów lub artykułów – prosty model może np. przewidywać, czy użytkownik kliknie w dany artykuł na podstawie tytułu, kategorii i historii zachowań.
  • Przewidywanie cen – klasyk, czyli ceny mieszkań, samochodów czy wynajmu. Masz metr kwadratowy, lokalizację, rok budowy, piętro i chcesz oszacować cenę.
  • Klasyfikacja maili – rozpoznanie, czy e-mail jest spamem, czy nie. Tu pojawia się zadanie klasyfikacji binarnej: 0 – normalny, 1 – spam.

Te proste scenariusze idealnie nadają się na pierwszy model uczenia maszynowego w Pythonie. Są zrozumiałe „ludzko”, więc łatwiej zauważyć, kiedy model opowiada bzdury.

Co jest w zasięgu początkującego, a co jeszcze nie

Na starcie spokojnie da się zbudować:

  • model przewidujący prostą wartość liczbową (np. cenę),
  • model klasyfikujący coś do dwóch klas (np. spam / nie-spam),
  • prosty model z 10–20 cechami wejściowymi.

Da się też zrozumieć, jak działa podział danych na trening i test, czym jest dokładność czy błąd średniokwadratowy oraz jak sprawdzić, czy model nie uczy się „na pamięć”.
Poza zasięgiem na pierwsze podejście są raczej:

  • złożone sieci neuronowe z milionami parametrów,
  • modele generatywne na poziomie GPT czy obrazowe pokroju Stable Diffusion,
  • skalowanie pipelinów ML na kilkanaście serwerów.

To nie znaczy, że tam nie dojdziesz. Po prostu na pierwszy raz lepiej skręcić w stronę prostych modeli, dzięki którym zrozumiesz fundamenty, zamiast walczyć z konfiguracją GPU i dziwnymi błędami z CUDĄ w nazwie.

Jakiej matematyki i programowania naprawdę potrzeba

Do pierwszego modelu ML nie jest potrzebny doktorat z analizy funkcjonalnej. Wystarczy:

  • podstawy Pythona: zmienne, pętle, funkcje, listy, słowniki,
  • luźne ogarnięcie tablic i ramek danych (np. w pandas),
  • intuicja, czym jest średnia, odchylenie, korelacja, prosta funkcja liniowa.

Sama biblioteka scikit-learn dba o wszystkie wzory pod spodem. Twoim zadaniem jest zrozumienie, co robisz koncepcyjnie: co oznacza trenowanie, testowanie, walidacja krzyżowa, overfitting. Matematyka przyda się bardziej, gdy zaczniesz tuningować modele i chcesz zrozumieć „dlaczego tak, a nie inaczej”, ale na starcie spokojnie wystarczy intuicja.

Pierwszy model jako rower z kółkami bocznymi

Pierwszy model uczenia maszynowego warto traktować jak rower z kółkami bocznymi. Ma:

  • działać na końcu – czyli dawać jakieś rozsądne przewidywania,
  • być zrozumiały – krok po kroku, bez czarnej skrzynki,
  • być prosty – mały zbiór danych, mało cech, klasyczny algorytm.

Nie musi wygrywać konkursów na Kaggle, pobijać benchmarków ani przewidywać kursów kryptowalut z kosmiczną dokładnością. Ma sprawić, że zrozumiesz przepływ: dane → przygotowanie → podział → trenowanie → ocena → poprawa. Kiedy ten „rower” będzie jeździł, dokładanie przerzutek i karbonowej ramy staje się już kwestią czasu.

Narzędzia i środowisko: Python bez bólu głowy

Dlaczego Python wygrał wyścig w ML

Python stał się domyślnym językiem dla uczenia maszynowego z kilku powodów:

  • ma prostą, czytelną składnię, więc szybciej przechodzi się od pomysłu do prototypu,
  • posiada ogromny ekosystem bibliotek: numpy, pandas, scikit-learn, matplotlib, seaborn, PyTorch, TensorFlow,
  • żywa społeczność – na każdy błąd znajdzie się wątek na Stack Overflow, blog czy repozytorium z przykładem,
  • łatwo łączy się z narzędziami webowymi, bazami danych i chmurą.

Jupyter Notebook, VS Code czy Google Colab?

Środowisko pracy ma duży wpływ na komfort nauki. Wybór najpopularniejszych opcji można prosto streścić:

NarzędzieZaletyWadyDla kogo
Jupyter NotebookInteraktywne notatniki, kod + opis w jednym miejscuŁatwo zrobić chaos w wielu plikach .ipynbNauka, prototypowanie
VS CodePełnoprawne IDE, integracja z Git, rozszerzeniaNa start może przytłoczyć opcjamiMałe projekty i późniejszy rozwój
Google ColabNic nie instalujesz lokalnie, darmowe GPU, dostępne w przeglądarceOgraniczenia czasu sesji, zależność od internetuSzybkie testy, nauka bez konfiguracji

Na pierwszy model scikit-learn krok po kroku świetnie sprawdza się Jupyter Notebook albo Google Colab. Można łączyć kod z komentarzami, wstawiać wykresy pod komórką, łatwo krok po kroku eksperymentować.

Wirtualne środowisko i instalacja podstawowych bibliotek

Nie trzeba od razu bawić się w zaawansowane zarządzanie zależnościami, ale proste wirtualne środowisko bardzo pomaga. Dzięki niemu nie namieszasz w systemowym Pythonie i możesz trzymać wersje bibliotek pod kontrolą.

Przykładowy szybki proces (dla Pythona 3.x, w konsoli systemowej):

python -m venv venv
# Windows
venvScriptsactivate
# Linux / macOS
source venv/bin/activate

pip install --upgrade pip
pip install numpy pandas scikit-learn matplotlib jupyter

Po aktywacji środowiska uruchamiasz notatnik:

jupyter notebook

W przeglądarce otworzy się panel, gdzie możesz tworzyć nowe notatniki i pisać kod, który krok po kroku zbuduje pierwszy model uczenia maszynowego w Pythonie.

Struktura mini-projektu ML, żeby nie utonąć w plikach

Nawet mały projekt ML potrafi szybko zamienić się w katalog pełen „final_v2_poprawione_ostateczne.ipynb”. Kilka prostych zasad ratuje zdrowie psychiczne:

  • wydziel katalog projektu, np. first-ml-model/,
  • wewnątrz stwórz podkatalogi:
    • data/ – oryginalne dane,
    • notebooks/ – notatniki eksperymentalne,
    • models/ – zapisane modele (np. pliki .pkl),
    • reports/ – wykresy, raporty z wynikami (opcjonalnie).

Dodatkowo dobra praktyka to użycie jednego głównego notatnika typu 01_first_model.ipynb i ewentualnie kolejnych, jeśli eksperymentów zacznie przybywać. Nazwy z numerami pozwalają łatwo odtworzyć kolejne etapy.

Nawyki, które zwracają się po kilku godzinach

Kilka drobnych przyzwyczajeń bardzo upraszcza życie:

  • Spisuj wersje bibliotek – np. w pliku requirements.txt przez pip freeze > requirements.txt.
  • Notuj konfigurację eksperymentów – liczba cech, parametry modelu, metryki; mogą to być krótkie notatki w osobnej komórce Markdown.
  • Zapisuj ważniejsze wykresy do plików w reports/, żeby porównywać rezultaty.
  • Dbaj o losowość – używaj random_state w funkcjach scikit-learn, żeby wyniki były powtarzalne.

Dzięki takim nawykom łatwiej później odpowiedzieć na pytanie „dlaczego ten model był lepszy od tamtego?” zamiast patrzeć na zagadkowy wykres sprzed tygodnia.

Dane – paliwo dla modelu, czyli skąd je wziąć i jak je ogarnąć

Skąd brać pierwsze zbiory danych

Pierwszy krok przed budową modelu to znalezienie sensownego zbioru danych. Kilka źródeł:

  • Gotowe zbiory ze scikit-learn – np. load_boston (już jako zbiór przykładów historycznych), load_iris, load_diabetes. Są czyste i małe.
  • Kaggle – ogromny portal z zestawami danych i konkursami ML; można pobierać pliki CSV i uczyć się na realniejszych danych.
  • Otwarte dane publiczne – dane miejskie, statystyczne, finansowe, często dostępne jako CSV lub Excel.

Na pierwszy model regresyjny w Pythonie bardzo dobrze działa klasyczny temat: przewidywanie ceny mieszkania na podstawie kilku cech. Tego typu zbiory w wersji „dla początkujących” są dostępne zarówno na Kaggle, jak i w wielu repozytoriach edukacyjnych.

Różnica między danymi z tutoriala a danymi z firmy

Dane z tutoriali są zazwyczaj:

  • czyste – mało braków, spójne typy danych,
  • dobrze opisane – nazwy kolumn sensowne,
  • małe – kilkaset, kilka tysięcy wierszy.

Dane z prawdziwej firmy bywają:

  • pełne braków – puste pola, błędy, wartości „nie dotyczy” w połowie kolumn,
  • dziwnie sformatowane – daty jako tekst w różnych formatach, liczby z przecinkiem zamiast kropki,
  • przeklejane z Excela – dodatkowe nagłówki, zduplikowane wiersze, ukryte kolumny.

Na starcie warto wziąć dane „pod linijkę”, żeby nauczyć się procesu ML bez walki z bałaganem. Dopiero później, mając pierwszy model w ręku, można przejść do trudniejszych datasetów i zobaczyć, jak bardzo sprzątanie danych dominuje czas pracy data scientista.

Jak wygląda typowy zbiór danych: wiersze, kolumny, etykiety

Typowy zbiór danych do ML ma strukturę tabeli:

  • wiersz – jedna obserwacja (np. jedno mieszkanie),
  • kolumna – jedna cecha (np. metraż, liczba pokoi, piętro, rok budowy),
  • etykieta (target) – kolumna, którą chcesz przewidzieć (np. cena).

W pandasie ładuje się to do DataFrame, który zachowuje się trochę jak Excel sterowany kodem. Dla regresji interesuje Cię, by target był wartością liczbową; dla klasyfikacji – etykietą, która może być liczbą lub tekstem, ale koniec końców sprowadzisz ją do liczb.

Dla jasności dobrze jest od razu rozróżnić dwa zbiory zmiennych: cechy (features), które będą wejściem modelu, oraz etykietę (y, target), która jest jego wyjściem. W kodzie zwykle kończy się to na czymś w stylu X = df[lista_kolumn_cech] i y = df["target"]. Jeżeli target jest w innym pliku (np. osobny CSV z etykietami), trzeba je poprawnie połączyć po wspólnym kluczu – tutaj błędy bywają najbardziej podstępne, bo model „uczy się” wtedy przypadkowego szumu.

Drugie ważne rozróżnienie to cechy numeryczne i kategoryczne. Numeryczne to metraż, cena, liczba pokoi, wynik testu; kategoryczne to dzielnica, typ budynku, kategoria produktu. Te pierwsze możesz od razu wrzucić do wielu modeli, te drugie trzeba zwykle zakodować (np. one-hot encodingiem) na liczby. Zanim zacznie się jakiekolwiek „magiczne” ML, dobrze wypisać choćby krótko: które kolumny są jakiego typu i czy ich znaczenie jest intuicyjne.

Z praktycznego punktu widzenia opłaca się też jak najszybciej obejrzeć kilka wierszy danych. Proste df.head(), df.info() i df.describe() potrafią od razu ujawnić poważne problemy: brakujące wartości w połowie kolumn, liczby trzymane jako tekst czy absurdalne zakresy (mieszkanie o powierzchni „10000” m² albo człowiek z wiekiem „300”). Lepiej złapać to na samym początku niż po godzinie debugowania dziwnych wyników modelu.

Na końcu cały proces przypomina pracę mechanika: najpierw sprawdzasz, czy paliwo w ogóle jest w baku i czy nie ma w nim piasku, dopiero potem odpalasz silnik. Tutaj paliwem są sensownie przygotowane dane – kiedy już je masz, budowa pierwszego modelu w Pythonie staje się raczej sekwencją zrozumiałych kroków niż czarną magią, a kolejne projekty dokładają tylko bardziej zaawansowane narzędzia do tej samej, znajomej układanki.

Pierwsze ładowanie danych w pandas – od pliku do DataFrame

Mając plik z danymi (najczęściej CSV), pierwszym technicznym krokiem jest wciągnięcie go do Pythona. Przykład z klasycznym pandas:

import pandas as pd

df = pd.read_csv("data/mieszkania.csv")
df.head()

Kilka parametrów przydaje się od razu:

  • sep=";" – jeśli dane są rozdzielone średnikami zamiast przecinków,
  • decimal="," – gdy liczby mają przecinek jako separator dziesiętny,
  • encoding="utf-8" lub "cp1250" – żeby polskie znaki się nie posypały.
df = pd.read_csv(
    "data/mieszkania.csv",
    sep=";",
    decimal=",",
    encoding="cp1250"
)

Po wczytaniu warto szybko zrobić trzy rzeczy:

df.head()       # pierwsze wiersze
df.info()       # typy kolumn, liczba niepustych wartości
df.describe()   # podstawowe statystyki dla kolumn numerycznych

Te trzy linijki często mówią więcej niż dziesięć pięknych wykresów, szczególnie o brakach i dziwnych typach danych.

Typy danych w pandasie a modele ML

Modele scikit-learn oczekują na wejściu liczb. Tymczasem w DataFrame łatwo wylądują ciągi znaków, daty, wartości logiczne albo mieszanka wszystkiego naraz. Kilka typowych przypadków i reakcji obronnych:

  • Liczby jako tekst – kolumna "powierzchnia" w typie object:
    df["powierzchnia"] = (
        df["powierzchnia"]
          .str.replace(",", ".", regex=False)
          .astype(float)
    )
  • Daty – sensowniejsze niż trzymanie ich jako tekst:
    df["data_transakcji"] = pd.to_datetime(df["data_transakcji"])

    Można potem wyciągnąć z nich rok, miesiąc, dzień tygodnia:

    df["rok"] = df["data_transakcji"].dt.year
    df["miesiac"] = df["data_transakcji"].dt.month
    
  • Booleany (np. czy_windа) – większość modeli nie ma z nimi problemu, ale często wygodniej zamienić na 0/1:
    df["czy_winda"] = df["czy_winda"].astype(int)

Im wcześniej ustawisz sensowne typy, tym mniej później dziwnych błędów typu „could not convert string to float”.

Brakujące dane – ignorować, uzupełniać czy wyrzucać?

Braki w danych są normą, nie wyjątkiem. Najpierw dobrze jest zobaczyć ich skalę:

df.isna().mean().sort_values(ascending=False)

Ta linijka pokaże procent braków w każdej kolumnie. Dalej kilka prostych strategii na start:

  • Rzadka kolumna z samymi brakami (np. 90% NaN) – często po prostu:
    df = df.drop(columns=["jakas_kolumna_bez_danych"])
  • Pojedyncze braki w ważnej kolumnie numerycznej – prosty imputing średnią lub medianą:
    df["powierzchnia"] = df["powierzchnia"].fillna(df["powierzchnia"].median())
  • Kategoryczne kolumny z brakami – dodanie kategorii typu „brak”:
    df["material"] = df["material"].fillna("brak")

Na tym etapie nie trzeba wymyślać wyrafinowanych metod imputacji. Kluczowe, żeby model dostał kompletne dane i nie wybuchł przy pierwszym NaN.

Prosty EDA – szybkie zerknięcie na rozkłady i zależności

Eksploracyjna analiza danych (EDA) może być bardzo rozbudowana, ale na pierwszy model wystarczy kilka prostych kroków. Zacznij od wykresów rozkładu dla wybranych cech i targetu:

import matplotlib.pyplot as plt

df["cena"].hist(bins=30)
plt.xlabel("cena")
plt.ylabel("liczba mieszkań")
plt.show()

df["powierzchnia"].hist(bins=30)
plt.xlabel("powierzchnia")
plt.show()

Dla cech kategorycznych przydaje się rozkład częstości:

df["dzielnica"].value_counts().head(10)

Jeżeli target i cecha są numeryczne, można szybko zerknąć na prosty wykres punktowy:

plt.scatter(df["powierzchnia"], df["cena"], s=5, alpha=0.5)
plt.xlabel("powierzchnia")
plt.ylabel("cena")
plt.show()

Taki szybki podgląd często ujawni ekstremalne wartości, dziwne skupiska albo to, że jakaś kolumna w praktyce nie niesie informacji (np. prawie wszyscy mają tę samą wartość).

Wybór zadania: klasyfikacja, regresja, a może coś innego?

Jak rozpoznać, z jakim typem problemu masz do czynienia

Najprostszy filtr: popatrz na target, czyli kolumnę, którą chcesz przewidywać.

  • Regresja – target jest liczbą ciągłą:
    • cena mieszkania,
    • wysokość rachunku,
    • przewidywany czas dostawy (w godzinach).
  • Klasyfikacja – target to kategorie:
    • czy klient odejdzie: 0/1,
    • gatunek kwiatu: setosa, versicolor, virginica,
    • segment klienta: „budżetowy”, „standard”, „premium”.

Jeżeli target jest tekstem, ale opisuje kategorię, model i tak sprowadzisz to do liczb, np. przez LabelEncoder lub mapowanie słownika.

Typowe przykłady z codziennej pracy

Dobrze jest przywiązać abstrakcyjny „typ zadania” do konkretnych przykładów:

  • Regresja:
    • przewidywanie wartości koszyka klienta na podstawie historii zakupów,
    • szacowanie zapełnienia hotelu na dany dzień.
  • Klasyfikacja binarna:
    • wczesne wykrywanie rezygnacji klienta z usługi (churn),
    • filtracja spamu w skrzynce e-mail: spam / nie-spam.
  • Klasyfikacja wieloklasowa:
    • przypisanie zgłoszenia do odpowiedniego działu supportu,
    • rozpoznawanie typu produktu na podstawie opisu.

Istnieją też inne rodzaje zadań – szeregowanie czasowe, klasteryzacja, wykrywanie anomalii – ale na pierwszy model bezpieczniej zostać przy klasyfikacji lub regresji nad klasyczną tabelką.

Dlaczego jasne zdefiniowanie zadania oszczędza nerwy

Zdarza się sytuacja: ktoś chce „przewidywać przyszłość sprzedaży”, a dane to zsumowane wartości tygodniowe bez żadnych cech. To wygląda jak szereg czasowy, ale próbuje się rozwiązywać problem jako zwykłą regresję na tabelce. Efekt: model nie uwzględnia faktu, że dane są ułożone w czasie.

Przed pierwszą linijką kodu dobrze jest odpowiedzieć sobie pisemnie:

  • co dokładnie przewiduję (dokładna definicja targetu),
  • jakiego typu jest target (ciągły, kategoria, liczba całkowita),
  • do czego wynik ma być używany (rekomendacja, alarm, raport?).

Ta krótka notatka broni przed pół dnia walki z niewłaściwym typem modelu albo nieadekwatną metryką.

Przygotowanie danych: sprzątanie, podział na zbiory i pierwsze pułapki

Podział na zbiór treningowy i testowy – po co to całe zamieszanie

Serce dobrej praktyki ML to rozdzielenie danych na:

  • zbiór treningowy – na nim model „uczy się” wzorców,
  • zbiór testowy – na nim ocenisz, jak model radzi sobie z nowymi danymi.

Jeżeli oceniasz model na tych samych danych, na których się uczył, dostajesz zbyt optymistyczny wynik. To jak sprawdzian z pytaniami, które wcześniej podano jako odpowiedzi.

from sklearn.model_selection import train_test_split

X = df[["powierzchnia", "liczba_pokoi", "pietro", "rok_budowy"]]
y = df["cena"]

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

Parametr test_size=0.2 oznacza, że 20% danych trafi do zbioru testowego. random_state zapewnia powtarzalność podziału.

Stratyfikacja przy klasyfikacji

Przy klasyfikacji dobrze jest zadbać, żeby proporcje klas były podobne w zbiorze treningowym i testowym. Służy do tego stratify:

X_train, X_test, y_train, y_test = train_test_split(
    X, y,
    test_size=0.2,
    random_state=42,
    stratify=y
)

Bez tego w skrajnych przypadkach można trafić na test set prawie bez przykładów jednej z klas i metryki natychmiast się wypaczą.

Duplikaty i oczywiste błędy – szybkie sito

Zanim dane trafią do modelu, można je przepuścić przez proste sito:

Dla osoby, która zaczyna przygodę z ML, to po prostu najkrótsza droga do działającego modelu. Jeżeli dodatkowo interesują Cię więcej o informatyka i nowe technologie, Python staje się uniwersalnym językiem, który „spina” różne obszary: od analizy danych po automatyzację.

# Duplikaty wierszy
df = df.drop_duplicates()

# Wartości poza zdrowym zakresem
df = df[df["powierzchnia"] > 0]
df = df[df["cena"] > 0]

Czasem trzeba dodać własne biznesowe reguły, np. maksymalny sensowny metraż albo cenę, która nie jest ewidentną literówką.

Skalowanie cech numerycznych – kiedy jest potrzebne