Python uczenie maszynowe klasyfikacja
W artykule przedstawiam uczenie maszynowe w Pythonie. Prezentuję algorytm klasyfikacji k-najbliższych sąsiadów dla zbioru danych Iris. Analizę przeprowadzam w aplikacji Spyder.
Import modułów języka Python
Do przeprowadzenia analizy potrzebujesz zainstalować bibliotekę Anaconda. Informacje, w jaki sposób ją zainstalować znajdziesz w artykule Python Anaconda instalacja
Instalator pobiera z Internetu i zapisuje na dysku Anacondę i wszystkie dostępne w niej moduły. Podczas instalacji automatycznie importuje się tylko część modułów. Pozostałe, w miarę potrzeby, należy zaimportować.
Do przeprowadzenia analizy potrzebne nam będą moduły:
- sys
- numpy
- pandas
- matplotlib
- sklearn
W/w moduły musimy zaimportować, gdyż nie są one importowane automatycznie.
Do importu modułów i przeprowadzenia analizy możesz użyć aplikacji Spyder lub Jupyter Notebook. Modele tworzę w Jupyter Notebook i zapisuję w nim finalne efekty pracy, gdyż aplikacja ta umożliwia przechowywanie kodu i notatek. Spydera używam na tzw. etapie roboczym do eksperymentowania np. sprawdzania zmiennych.
W tym artykule posłużę się Spyderem do przeprowadzenia analizy.
Wyszukaj w menu Start Spyder i otwórz aplikację. Aplikację instaluje instalator Anaconda.
Wpisz #%% i kliknij Enter aby utworzyć nową komórkę. W komórce wklej poniższe polecenia i kliknij Ctrl + Enter aby je uruchomić:
import sys print(f"Python version: {sys.version}") import numpy as np import pandas as pd print(f"NumPy version: {np.__version__}") print(f"pandas version: {pd.__version__}") import matplotlib.pyplot as plt import matplotlib print(f"matplotlib version: {matplotlib.__version__}") import sklearn print("scikit-learn version: {}".format(sklearn.__version__))
Opis poleceń:
Polecenie | Opis |
---|---|
import sys | import modułu sys |
import sys | import modułu sys |
print(f”Python version: {sys.version}”) | sprawdzenie wersji Pythona |
import numpy as np | import modułu numpy |
import pandas as pd | import modułu pandas |
print(f”NumPy version: {np.__version__}”) | sprawdzenie wersji modułu numpy |
print(f”pandas version: {pd.__version__}”) | sprawdzenie wersji modułu pandas |
import matplotlib.pyplot as plt | import modułu pyplot z biblioteki matplotlib |
import matplotlib | import całej biblioteki matplotlib |
print(f”matplotlib version: {matplotlib.__version__}”) | sprawdzenie wersji biblioteki matplotlib |
import sklearn | import biblioteki sklearn |
print(„scikit-learn version: {}”.format(sklearn.__version__)) | sprawdzenie wersji biblioteki sklearn |
Polecenia w aplikacji Spyder:
Uczenie maszynowe – klasyfikacja
Klasyfikacja w uczeniu maszynowym to problem modelowania predykcyjnego, w którym przewidujemy etykietę klasy dla danych wejściowych.
Najbardziej popularne algorytmy klasyfikacji to:
- klasyfikacja binarna – możliwe są tylko dwa wyniki: prawda lub fałsz np. klient spłaci pożyczkę lub nie, klient złoży rezygnację lub nie.
- klasyfikcja wieloklasowa – istnieje więcej niż jedna klasa np. kwalifkujemy książki do trzech klas: liryka, epika dramat lub kwalifkujemy recenzje do trzech klas: pozytywna, neutralna, negatywna.
Zbiór Iris – algorytm klasyfikacji
W przykładzie załadujemy zbiór Iris. Jest to zbiór często wykorzystywany z uczeniu maszynowym i statystyce. Mamy w nim zbiór danych zawierających informacje o kwiatach irys. Posiadamy zmierzone w centymetrach:
- długość i szerokość płatków (ang. petal)
- długość i szerokość łodygi płatka (ang. sepal)
W danych wejściowych posiadamy również pomiary irysów dla gatunków setosa, versicolor i virginica. Zakładamy, że są to jedyne gatunki, do których możemy zakwalifikować irysy.
Celem projektu jest zbudowanie modelu uczenia maszynowego, który może uczyć się na podstawie pomiarów irysów, dla których gatunek jest znany i przewidywać na tej podstawie gatunek dla nowych irysów.
W Spyder utwórz nową komórkę, wklej poniższy kod i uruchom go, aby załadować zbiór Iris z modułu sklearn.
from sklearn import datasets iris = datasets.load_iris() iris.keys() # klucze zawierające dane
Budujemy ramkę danych w Pandasie. Pierwsze cztery kolumny to cechy rośliny. Ostatnia kolumna to kolumna wynikowa (ang. target). W kolumnie target mamy informację, do której odmiany dany iris należy – setosa, versicolor, virginica.
df = pd.DataFrame(data=np.c_[iris['data'], iris['target']], columns= iris['feature_names'] + ['target']) df.head() print(df.head())
sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) | target | |
---|---|---|---|---|---|
0 | 5.1 | 3.5 | 1.4 | 0.2 | 0.0 |
1 | 4.9 | 3.0 | 1.4 | 0.2 | 0.0 |
2 | 4.7 | 3.2 | 1.3 | 0.2 | 0.0 |
3 | 4.6 | 3.1 | 1.5 | 0.2 | 0.0 |
4 | 5.0 | 3.6 | 1.4 | 0.2 | 0.0 |
W programie Spyder możemy odczytywać zawartość zmiennych. Aby to zrobić:
- kliknij opcję Variable Explorer po prawej stronie okna
- kliknij dwuklikiem lewego przyciku myszy na wierszu ze zmienną df. Wyświetli się wówczas okienko zawierające wartości znajdujące się w zmiennej df.
Za pomocą poniższego polecenia wyświetlamy wartości znajdujące się w kolumnie target.
print(df['target'].values)
Podział na zbiór treningowy i testowy
Za pomocą poniższego kodu:
- importujemy z modułu sklearn.model_selection funkcję train_test_split, za pomocą której podzielimy zbiór na testowy i treningowy
- do zmiennej X przypisujemy wszystkie dane ze zbioru Iris
- do zmiennej y przypisujemy kolumnę target ze zbioru Iris
- dzielimy dane ze zmiennej X na zbiór treningowy (X_train) i zbiór testowy (X_test)
- dzielimy dane ze zmiennej y na zbiór treningowy (y_train) i zbiór testowy (y_test)
from sklearn.model_selection import train_test_split X = iris['data'] y = iris['target'] X_train, X_test, y_train, y_test = train_test_split(X, y)
Za pomocą poniższego kodu wyświetlamy informację o zawartości zbioru treningowego X oraz y.
print(f"X_train shape: {X_train.shape}") print(f"y_train shape: {y_train.shape}")
W zbiorze treningowym jest 112 wierszy i 4 kolumny.
Za pomocą poniższego kodu budujemy dataframe o nazwie df_iris, do którego przypisujemy dane ze zbioru X_train. W dataframe X_train nie ma nazw kolumn. Nazwy column są potrzebne do funkcji scatter_matrix.
Za pomocą funkcji pd.plotting.scatter_matrix rysujemy macierz punktową (wykres par), która przedstawia wszystkie zmienne numeryczne ze zbioru danych względem siebie.
Scatter_matrix (macierz punktowa, wykres par) służy do generowania grupy wykresów punktowych pomiędzy wszystkimi parami cech numerycznych w zbiorze. Tworzy wykres dla każdej cechy numerycznej w stosunku do każdej innej cechy numerycznej oraz histogram dla każdej z nich.
Argumenty funkcji pd.plotting.scatter_matrix:
- c=y_train – kolory na wykresie
- figsize=(15, 15) – kontroluje rozmiar wykresu
- marker=’o’ – rysuje punkty dla wykresu punktowego
- hist_kwds={’bins’: 20} – kontroluje rozmiar histogramu
- s=60 – kontroluje rozmiar punktów dla wykresu punktowego
- alpha=.8 – kontroluje przezroczystość dla wykresu punktowego
df_iris = pd.DataFrame(X_train,columns=iris.feature_names) # create a scatter matrix from the dataframe # color by y_train pd.plotting.scatter_matrix(df_iris, c=y_train, figsize=(15, 15), marker='o', hist_kwds={'bins': 20}, s=60, alpha=.8)
Model k-najbliższych sąsiadów
Model budujemy z użyciem algorytmu k-najbliższych sąsiadów (k-Nearest Neighbors, k-NN).
Algorytm k-najbliższych sąsiadów (KNN, k-NN) należy do algorytmów uczenia nadzorowanego. Możemy używać go do rozwiązywania problemów klasyfikacji i regresji.
Budowanie modelu k-najbliższych sąsiadów polega jedynie na przechowywaniu zestawu uczącego. Aby dokonać prognozy dla nowego punktu danych, algorytm znajduje punkt w zbiorze uczącym, który jest najbliższy nowemu punktowi. Następnie przypisuje etykietę tego punktu treningowego do nowego punktu danych.
Wartość k w k-najbliżsi sąsiedzi oznacza, że zamiast używać tylko najbliższego sąsiada nowego punktu danych, możemy wziąć pod uwagę dowolną stałą liczbę k sąsiadów w uczeniu (na przykład trzech lub pięciu najbliższych sąsiadów). Następnie możemy przewidzieć, używając klasy większości spośród tych sąsiadów.
Wszystkie modele uczenia maszynowego w scikit-learn są zaimplementowane we własnych klasach, które nazywane są klasami estymatorami (ang. Estimator classes). Algorytm klasyfikacji k-Nearest Neighbors jest zaimplementowany w klasie KNeighborsClassifier w module neighbors.
Zanim będziemy mogli użyć modelu, musimy utworzyć instancję klasy w obiekcie. Wtedy ustawimy dowolne parametry modelu. Najważniejszy parametr KNeighborsClassifier to liczba sąsiadów, którą w przykładzie ustawimy na 1.
Poniższy kod z biblioteki sklearn importuje klasyfikator KNeighborsClassifier, Przypisujemy go do obiektu knn i ustawiamy liczbę sąsiadów na 1.
from sklearn.neighbors import KNeighborsClassifier knn = KNeighborsClassifier(n_neighbors=1)
Obiekt knn zawiera algorytm, który zostanie użyty do zbudowania modelu z danych uczących, a także algorytm do przewidywania nowych punktów danych. Będzie również zawierał informacje, które algorytm wyodrębnił z danych treningowych. W przypadku KNeighborsClassifier przechowa zestaw treningowy.
Aby zbudować model na zbiorze uczącym, wywołujemy metodę fit obiektu knn, która jako argumenty przyjmuje tablicę NumPy X_train zawierającą dane uczące oraz tablicę NumPy y_train odpowiednich etykiet uczących:
knn.fit(X_train, y_train)
Metoda fit zwraca sam obiekt knn (i modyfikuje go w miejscu), więc otrzymujemy ciąg znaków reprezentujący nasz klasyfikator. Reprezentacja pokazuje, jakie parametry zostały użyte przy tworzeniu modelu. Prawie wszystkie z nich są wartościami domyślnymi, ale można również znaleźć n_neighbors=1, który jest parametrem przez nas przekazanym.
Większość modeli w scikit-learn ma wiele parametrów, ale większość z tych parametrów służy do optymalizacji szybkości działania lub do obsłużenia specjalnych przypadków użycia.
KNN – wyliczanie predykcji
Dokonujemy teraz prognoz przy użyciu modelu na nowych danych. W przykładzie w tablicy X_new umieszczamy poniższe dane irysa:
- długość płatka 5 cm, szerokość płatka 2,9 cm
- długość łodygi płatka 1 cm, szerokość łodygi płatka 0,2 cm
Próbujemy przewidzieć, do jakiego gatunku iris o w/w cechach należy.
Umieściliśmy pomiary w rzędzie w dwuwymiarowej tablicy NumPy, gdyż scikit-learn zawsze oczekuje dwuwymiarowych tablic dla danych.
X_new = np.array([[5, 2.9, 1, 0.2]])
Aby dokonać przewidywania, wywołujemy metodę przewidywania obiektu knn:
prediction = knn.predict(X_new) print(f"Prediction: {prediction}") print(f"Predicted target name: {iris['target_names'][prediction]}")
Model przewiduje, że ta nowy iris należy do klasy 0, co oznacza, że jest to gatunek setosa.
Ocena skuteczności modelu klasyfikacji
Aby ocenić, czy model klasyfikacji działa prawidłowo, uruchamiamy go na danych testowych, których nie widział i sprawdzamy jak dużą część przypadków przewidział prawidłowo.
y_pred = knn.predict(X_test) print(f"Test set predictions:\n{y_pred}")
print("Test set score: {:.2f}".format(np.mean(y_pred == y_test)))
Wynik: Test set score: 0.97
Możemy również użyć metody punktacji obiektu knn, która obliczy dla nas dokładność zestawu testowego:
print("Test set score: {:.2f}".format(knn.score(X_test, y_test)))
Wynik: Test set score: 0.97
Dla tego modelu dokładność zestawu testowego wynosi około 0,97, co oznacza, że dokonaliśmy prawidłowej prognozy dla 97% irysów w zestawie testowym. Funkcja knn.score uruchomiona została na modelu w zmiennej knn.
Jeśli nie mamy modelu, ale mamy jedynie predykcję, możemy wyliczyć dokładność tych predykcji za pomocą funkcji accuracy_score():
from sklearn.metrics import accuracy_score print(f'Dokładność: {accuracy_score(y_test, y_pred):.2f}')
Dokładność: 0.97
Tak obliczona wartość dokładności może być jednak myląca, jeśli zbiór danych wejściowych jest niesymetryczny tzn. liczba obserwacji w poszczególnych klasach nie jest zbliżona. Na przykład jeśli mamy 90% obserwacji klasy 0 i 10% obserwacji klasy 1, dokładność na poziomie 90% można uzyskać przewidując same klasy 1. Jest to słabo działający model, ale uzyskuje złudnie wysoką dokładność.
W takiej sytuacji warto jest obliczyć macierz konfuzji (ang. confussion matrix), za pomocą której możemy zrobić wizualizację działania algorytmu. Macierz (tablica) zawiera dwa wymiary (rzeczywisty i przewidywany). Ułatwia ona sprawdzenie, czy algortym nie myli dwóch klas tzn. często błędnie oznacza jedną jako drugą.
W przykładzie poniżej:
- na przekątnej zawarte są poprawne predykcje dla poszczególnych klas
- w pionie jest liczba obserwacji w poszczególnych klasach (ground truth)
- w poziomie liczba przewidzianych
from sklearn.metrics import ConfusionMatrixDisplay ConfusionMatrixDisplay.from_predictions(y_test, y_pred);
Podstawowe informacje na temat przetwarzania danych i ich przygotowania do analizy oraz narzędzia Spyder znajdziesz w artykule Python podstawy analizy danych.