1.3 Proces uczenia i predykcja

Skoro dysponujemy już podziałem zbioru, możemy przystąpić do procesu uczenia. W tym celu posłużymy się popularnym, prostym klasyfikatorem k najbliższych sąsiadów (kNN).

W problemie klasyfikacji, naszym zadaniem jest stworzenie algorytmu (programu), który na podstawie znanych sobie, opisanych wzorców, będzie w stanie efektywnie rozpoznawać wzorce nieopisane i dotąd sobie nieznane.

Dziś nie będziemy jeszcze zajmować się projektowaniem własnych algorytmów, a nauczymy się wykorzystywać te, które znajdują się już w pakiecie scikit-learn. Wszystkie znajdujące tam rozwiązania są pogrupowane w moduły, związane wprost z rodzinami algorytmów. My, na początek, skorzystamy z algorytmu k najbliższych sąsiadów (k-NN), będącego częścią modułu neighbors. Zaimportujmy więc go do naszego skryptu.

from sklearn import neighbors

Po zaimportowaniu modułu, możemy uzyskać od niego obiekt konkretnego klasyfikatora. Przyjętą konwencją jest przypisywanie takiego obiektu do zmiennej clf.

clf = neighbors.KNeighborsClassifier()

Dysponując podzielonym w poprzedniej części zbiorem danych i klasyfikatorem, możemy wytrenować go używając naszego zbioru uczącego. W konwencji sklearn, dla zapewnienia spójności nazwy metody dla algorytmów poświęconych różnym zadaniom rozpoznawania wzorców, uczenie nazywa się dopasowaniem, stąd posłużymy się metodą fit(), przekazując do niej przestrzeń cech i zbiór etykiet zbioru.

clf.fit(X_train, y_train)

Model klasyfikatora został wyuczony i teoretycznie moglibyśmy już określić jego jakość, używając wbudowanej w każdy klasyfikator metody score(), przyjmującej zbiór testowy.

score = clf.score(X_test, y_test)
print(score)
0.98

Uzyskaliśmy miarę 0.98. Z kilku przyczyn nie jest to jednak przesadnie dobre rozwiązanie. Możemy co prawda w przypadku większości klasyfikatorów założyć, że miara ta to dokładność klasyfikatora (odsetek poprawnie sklasyfikowanych próbek), ale programiści mają zupełną dowolność w doborze miary zwracanej z tej metody. Ponadto, nie uzyskujemy w ten sposób faktycznych decyzji podjętych wobec każdego wzorca ze zbioru testowego, co mogłoby okazać się przydatne zarówno w wyliczeniu innych miar jakości, jak i w ewentualnej konstrukcji komitetów klasyfikatorów, o których opowiemy sobie na jednych z kolejnych zajęć.

Wyliczmy więc jakość naszego klasyfikatora w bardziej cywilizowany sposób. Większość algorytmów klasyfikacji jest zdolna do zwrócenia, oprócz prostej decyzji o przynależności wzorca do jednej z klasy, również tak zwanego wektora wsparcia. Określa on prawdopodobieństwo przynależności obiektu do każdej z możliwych klas i zawsze sumuje się do jedynki. W wypadku zbioru iris powinniśmy więc móc uzyskać po trzy wartości dla każdej próbki ze zbioru testowego.

Do wyliczania wektora wsparć dla zbioru służy metoda predict_proba() klasyfikatora. Przekażmy do niej nasz zbiór testowy.

# Uzyskanie wektora wsparć
support_vector = clf.predict_proba(X_test)
print(support_vector)
[[0.  0.  1. ]
 [0.  1.  0. ]
 [1.  0.  0. ]
 ...
 [0.  0.  1. ]
 [0.  0.4 0.6]
 [0.  0.  1. ]]

Wynik klasyfikacji (przypisanie wzorca do klasy) nazywamy predykcją. Możemy ją uzyskać wyliczając indeks najwyższej wartości w wektorze wsparcia (funkcja argmax) dla każdej sklasyfikowanej próbki.

# Wyznaczenie predykcji
prediction = np.argmax(support_vector,axis = 1)
print(prediction)
[2 1 0 ... 2 2 2]

Choć często klasy w zbiorach danych są oznaczane przez kolejne liczby całkowite, licząc od zera, w zbiorze iris były one łańcuchami znakowymi. Obiekt klasyfikatora przechowuje wszystkie klasy znalezione w zbiorze uczącym w atrybucie classes_. Możemy więc posłużyć się nim do przetłumaczenia indeksów klas predykcji na odpowiadające im łańcuchy znakowe.

prediction = clf.classes_[prediction]
print(prediction)
['Iris-virginica' 'Iris-versicolor' 'Iris-setosa' ... 'Iris-virginica'
 'Iris-virginica' 'Iris-virginica']

Last updated