Kurs Python · Moduł 9: Machine Learning
Scikit-learn - tropiciel gatunków
W tej lekcji8
Wyobraź sobie że wracasz z wyprawy z notatnikiem pełnym pomiarów: długość kła, rozpiętość skrzydeł, waga. Chcesz, by komputer sam rozpoznawał, jakie to zwierzę. Dokładnie tym zajmuje się klasyczne uczenie maszynowe - a jego najpopularniejszym narzędziem w Pythonie jest scikit-learn.
1pip install scikit-learnJeden rytuał, wiele modeli
Zanim poznasz konkretne modele, zapamiętaj najważniejszą rzecz z tej lekcji. Każdy model w scikit-learn - niezależnie czy to drzewo, las, czy sieć sąsiadów - mówi tymi samymi trzema czasownikami:
fit(X, y)- ucz się: pokaż modelowi pomiaryXi prawidłowe odpowiedziy.predict(X)- rozpoznaj: dla nowych pomiarów zwróć przewidywany gatunek.score(X, y)- oceń: sprawdź, jaki procent zgadł poprawnie.
To jak wspólny język tropicieli: gdy nauczysz się go raz, każdy nowy model jest tylko innym tropicielem mówiącym tą samą mową. Poniższe modele różnią się sposobem myślenia, ale obsługujesz je identycznie.
Drzewo decyzyjne - tropiciel zadający pytania
Najprostszy tropiciel to ten, który zadaje serię pytań: "Czy waży ponad 100 kg? Czy ma grzywę?". Tak działa drzewo decyzyjne - dzieli zwierzęta pytaniami, aż zostanie jeden gatunek.
1from sklearn.tree import DecisionTreeClassifier
2from sklearn.datasets import load_iris
3
4iris = load_iris()
5X, y = iris.data, iris.target
6
7tree = DecisionTreeClassifier(max_depth=3, random_state=42)
8tree.fit(X_train, y_train)
9
10accuracy = tree.score(X_test, y_test)Zwróć uwagę, że pojawiły się nasze trzy czasowniki: fit uczy, score ocenia. Parametr max_depth=3 ogranicza liczbę pytań w łańcuchu - im głębsze drzewo, tym bardziej dopasowuje się do danych treningowych, ale tym łatwiej się "przeucza" i gubi na nowych zwierzętach. To pierwszy kompromis ML, który poczujesz w praktyce.
Wielką zaletą drzewa jest to, że możesz je zobaczyć - dosłownie narysować jego pytania:
1from sklearn.tree import plot_tree
2import matplotlib.pyplot as plt
3
4plt.figure(figsize=(20, 10))
5plot_tree(tree, feature_names=iris.feature_names, class_names=iris.target_names, filled=True)
6plt.show()Ten rysunek to Twój najlepszy przyjaciel przy tłumaczeniu decyzji modelu innym - każda gałąź to jedno pytanie, które model zadał.
Las losowy - narada wielu tropicieli
Jedno drzewo bywa kapryśne. A gdyby zapytać stu tropicieli i przyjąć odpowiedź większości? To właśnie las losowy (RandomForest) - buduje setki różnych drzew i głosuje.
1from sklearn.ensemble import RandomForestClassifier
2
3forest = RandomForestClassifier(
4 n_estimators=100, # liczba drzew w naradzie
5 max_depth=10,
6 min_samples_split=5,
7 random_state=42
8)
9forest.fit(X_train, y_train)
10
11importance = forest.feature_importances_
12for name, imp in zip(feature_names, importance):
13 print(f"{name}: {imp:.4f}")n_estimators=100 to liczba tropicieli w naradzie - więcej drzew zwykle znaczy stabilniejszą odpowiedź, kosztem czasu. Las daje też prezent, którego drzewo nie miało tak łatwo: feature_importances_ mówi, które pomiary najbardziej pomagały rozpoznać gatunek. Zapamiętaj tę własność - w praktyce to ona podpowiada, co w ogóle warto mierzyć.
SVM - tropiciel wytyczający granicę
Inny sposób myślenia: zamiast pytań, narysuj na mapie pomiarów granicę oddzielającą gatunki. SVM (Support Vector Machine) szuka takiej linii, by margines między grupami był jak najszerszy.
1from sklearn.svm import SVC
2
3svm = SVC(
4 kernel='rbf', # kształt granicy: 'linear', 'poly', 'rbf'
5 C=1.0,
6 gamma='scale',
7 probability=True # pozwala pytać o prawdopodobieństwo
8)
9svm.fit(X_train, y_train)
10
11proba = svm.predict_proba(X_test)Parametr kernel decyduje, czy granica jest prosta (linear), czy potrafi się wyginać (rbf). Włączenie probability=True daje coś cennego: predict_proba zwróci nie tylko gatunek, ale i pewność modelu - np. "80% lew, 20% gepard". To przydaje się, gdy chcesz odrzucać niepewne rozpoznania zamiast zgadywać na siłę.
KNN - tropiciel patrzący na sąsiadów
Najbardziej intuicyjny tropiciel nie uczy się prawie wcale. KNN (K-Nearest Neighbors) dla nowego zwierzęcia po prostu patrzy, do jakich znanych okazów jest najbardziej podobne, i przyjmuje ich gatunek.
1from sklearn.neighbors import KNeighborsClassifier
2
3knn = KNeighborsClassifier(
4 n_neighbors=5, # ilu sąsiadów pytamy
5 weights='uniform',
6 metric='euclidean'
7)
8knn.fit(X_train, y_train)
9predictions = knn.predict(X_test)n_neighbors=5 znaczy "spójrz na 5 najbliższych znanych zwierząt i przyjmij większość". Uwaga na pułapkę: KNN mierzy odległości, więc jeśli jeden pomiar jest w tonach, a inny w milimetrach, ten pierwszy zdominuje wynik. Dlatego za chwilę poznasz skalowanie danych - dla KNN jest ono obowiązkowe.
Regresja - gdy odpowiedzią jest liczba
Do tej pory zgadywaliśmy gatunek (kategorię). A gdy chcesz przewidzieć liczbę - wagę zwierzęcia na podstawie wymiarów? To regresja, i korzysta z tych samych trzech czasowników.
1from sklearn.linear_model import LinearRegression, Ridge, Lasso
2
3linear = LinearRegression()
4linear.fit(X_train, y_train)
5
6ridge = Ridge(alpha=1.0) # kara za zbyt duże współczynniki (L2)
7ridge.fit(X_train, y_train)
8
9lasso = Lasso(alpha=0.1) # potrafi wyzerować nieważne cechy (L1)
10lasso.fit(X_train, y_train)
11
12print(f"Coefficients: {linear.coef_}")
13print(f"Intercept: {linear.intercept_}")LinearRegression szuka prostej zależności między pomiarami a wynikiem. Ridge i Lasso to jej ostrożniejsze wersje - dokładają karę za przesadę, żeby model nie dopasował się zbyt kurczowo do danych treningowych. Różnica: Lasso potrafi całkiem wyzerować nieprzydatne cechy, więc bywa też narzędziem do wyboru, które pomiary w ogóle zatrzymać.
Gdy zależność nie jest prosta, ten sam las co przy klasyfikacji ma wersję dla liczb:
1from sklearn.ensemble import RandomForestRegressor
2
3rf_reg = RandomForestRegressor(n_estimators=100, random_state=42)
4rf_reg.fit(X_train, y_train)
5predictions = rf_reg.predict(X_test)Zauważ, że kod jest bliźniaczo podobny do klasyfikatora - zmienił się tylko koniec nazwy (Regressor zamiast Classifier). To znów ten sam wspólny język: opanowawszy jeden model, drugi rozpoznajesz w locie.
Skalowanie - wyrównaj jednostki przed treningiem
Wróćmy do pułapki z KNN. Modele mierzące odległości gubią się, gdy cechy mają różne skale. Skalowanie sprowadza wszystkie pomiary do wspólnej miary, zanim model je zobaczy.
1from sklearn.preprocessing import StandardScaler, MinMaxScaler, LabelEncoder, OneHotEncoder
2
3scaler = StandardScaler() # średnia 0, odchylenie 1
4X_scaled = scaler.fit_transform(X_train)
5X_test_scaled = scaler.transform(X_test)
6
7minmax = MinMaxScaler() # ściśnij do zakresu 0-1
8X_normalized = minmax.fit_transform(X_train)
9
10le = LabelEncoder() # 'lion'/'cheetah' -> 0/1/2
11y_encoded = le.fit_transform(['lion', 'elephant', 'cheetah'])
12
13ohe = OneHotEncoder(sparse_output=False) # kategorie -> kolumny 0/1
14species_onehot = ohe.fit_transform(species_array.reshape(-1, 1))Jest tu jedna zasada, którą łatwo złamać, a która psuje wyniki: skaler uczysz tylko na danych treningowych (fit_transform), a dane testowe jedynie przekształcasz (transform). Inaczej model "podejrzy" dane testowe i ocena będzie zawyżona. Dwa dolne narzędzia zamieniają nazwy gatunków na liczby, bo modele rozumieją tylko liczby - LabelEncoder dla odpowiedzi, OneHotEncoder dla cech kategorycznych.
Pipeline - spakuj wszystko w jeden rytuał
Skoro przed każdym modelem trzeba skalować dane, łatwo o pomyłkę: przeskalować trening inaczej niż test, albo zapomnieć o kroku. Pipeline skleja przygotowanie danych i model w jeden obiekt, który sam pilnuje kolejności.
1from sklearn.pipeline import Pipeline
2from sklearn.preprocessing import StandardScaler
3from sklearn.ensemble import RandomForestClassifier
4
5pipeline = Pipeline([
6 ('scaler', StandardScaler()),
7 ('classifier', RandomForestClassifier(n_estimators=100))
8])
9
10pipeline.fit(X_train, y_train)
11predictions = pipeline.predict(X_test)Najważniejsze: pipeline też mówi naszymi trzema czasownikami - fit na całym łańcuchu naraz skaluje i trenuje, a predict automatycznie skaluje nowe dane tym samym skalerem. Dzięki temu pułapka ze skalowaniem znika sama, bo nie da się już zrobić tego w złej kolejności.
Pamiętaj z tej lekcji jedną rzecz: w scikit-learn nie uczysz się dziesięciu różnych narzędzi, tylko jednego wspólnego języka - fit, predict, score - którym mówią wszystkie modele. Reszta to wybór tropiciela pasującego do zadania.
Widzisz błąd w tej lekcji?
Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. Czym jest Random Forest?
2. Do czego służy Support Vector Machine (SVM)?
To 2 z 3 pytań do tej lekcji. Pozostałe rozwiążesz w grze.
Zadania praktyczne w grze
- Układanie w poziomie
Ułóż w kolejności kod trenujący model Random Forest:
- Edytor kodu
Utwórz RandomForestClassifier z n_estimators=100, wytrenuj i oceń.
- Klikanie w kolejności
Kliknij w kolejności aby złożyć wywołanie predykcji modelu:
- Układanie w pionie
Ułóż kroki tworzenia Pipeline w sklearn:
- Układanie w pionie
Uporządkuj kroki:
- Klikanie w kolejności
Kliknij w przyciski, aby standaryzować dane: