Uczenie Maszynowe – metoda wektorów nośnych (Support Vector Machines, SVM)
W tym ćwiczeniu prowadzimy praktyczne eksperymenty z klasyfikatorem SVM – praktyczne, więc przy okazji mamy do czynienia ze zbiorem danych trudniejszym niż iryski (kosaćce).
"Quiz" (czyli raport z tych eksperymentów) w moodle można dowolnie wiele razy edytować i zapisywać przed upłynięciem terminu.
- Przypomnij sobie z wykładu:
- sposób działania SVM liniowego (przypadek dwuklasowy one-vs-rest i wieloklasowy one-vs-one),
- różnicę w podejściu SVM a liniową (LDA) i kwadratową (QDA) analizą dyskryminacyjną,
- popularne funkcje jądrowe stosowane w SVM,
- ideę "sztuczki jądrowej",
- sposób działania parametru "C" (wymyśl tutaj swój własny mnemonik – skojarzenie, żeby łatwo i trwale zapamiętać jak działa rosnące C).
- Przeczytaj dokumentację implementacji SVM w scikit-learn: LinearSVC, SVC i NuSVC. Kiedy będziemy chcieli użyć SGDClassifier w roli SVM? Zwróć uwagę na istnienie LinearSVR, SVR i NuSVR.
- Zapoznaj się z możliwościami GridSearchCV do dostrajania wartości hiperparametrów. Przeanalizuj fragment kodu używający
GridSearchCV
w tym przykładzie. - Pobierz zbiór danych o nazwie odpowiadającej Twojemu numerowi albumu i przeprowadź jego wstępną eksplorację: proporcja klas, liczba i rodzaje atrybutów, ich zakresy i rozkłady wartości. Nie musisz załączać wykresów rozkładów do sprawozdania – wystarczy, że je obejrzysz i opiszesz wnioski. Alternatywnie możesz oprócz min,max użyć jakichś podstawowych statystyk charakteryzujących rozkład typu średnia, odchylenie standardowe, itp. – i analizując takie charakteryzujące parametry rozkładu pogrupować (o ile to możliwe) atrybuty pisząc np. "73 atrybuty są takie a takie, 22 atrybuty charakteryzują się tym a tym, wyjątkowy jest atrybut taki a taki", itp. Możesz też pokazać wszystkie atrybuty obok siebie na jednym szerokim wykresie pudełkowym. Jaką trafność i jakie G-mean uzyskałby klasyfikator "Zero Rule"?
- Stosując wiedzę nabytą na laboratorium z transformacji przestrzeni atrybutów, zwizualizuj ten zbiór w 2D i 3D podając procent wariancji zachowany przy rzutowaniu oryginalnej przestrzeni do 2D i 3D. Na wykresach pokaż przypadki obu klas jako kropki o dwóch różnych kolorach; klasę mniejszościową rysuj nad większościową. Czy to rzutowanie uwzględnia podczas konstrukcji nowych wymiarów informację o podziale na klasy? Co możesz powiedzieć o tym problemie klasyfikacji i o spodziewanym zachowaniu SVM?
- Domyślnie metoda StratifiedKFold nie miesza przypadków. Zastanów się, jak włączanie/wyłączanie mieszania może wpływać na uzyskaną trafność. Dla jakich zbiorów włączenie mieszania podwyższy uzyskaną z tej metody trafność? Czy jest w tym jakieś niebezpieczeństwo i lepiej zostawić domyślne ustawienie "bez mieszania"? Jeśli tak, to kiedy jest takie niebezpieczeństwo, a kiedy nie?
- Zapoznaj się z działaniem parametru
class_weight
(w szczególności z wartością'balanced'
). Czy ten parametr wpływa na sposób liczenia jakiejkolwiek trafności metodą CV poprzez odpowiednie ważenie pomyłek w macierzy pomyłek? Czy balanced_accuracy jest po prostu liniowo przeskalowanym accuracy? (tj. czy mnożąc accuracy przez stały, specyficzny dla danego zbioru danych współczynnik, dostaniemy balanced_accuracy niezależnie od użytego klasyfikatora?) Czy mając zbiór 15k przypadków i 2 zrównoważone klasy, normalnie uczony klasyfikator (drzewo, SVM, sieć neuronowa, itp.) może z 10-krotnej stratified CV z losowym mieszaniem przypadków uzyskiwać średnie balanced_accuracy<0.5? Jeśli tak, to w jakiej sytuacji? - Postaraj się uzyskać na swoim zbiorze danych jak najwyższą trafność klasyfikacji metodami SVM używając oryginalnych (niezmienionych) atrybutów. Opisz dokładnie przeprowadzone próby i sposób, w jaki mierzysz jakość; rozważ tradycyjną trafność oraz G-mean (jeśli wolisz tradycyjną średnią zamiast geometrycznej, zamiast accuracy i G-mean możesz użyć
['accuracy', 'balanced_accuracy']
). W rozdziale 3.3.1.4 przeczytasz, jak uzyskać wartości dwóch (lub więcej) metryk podczas uruchomienia GridSearchCV. Użyj 10-fold stratified CV. W miarę możliwości przedstaw wyniki graficznie, np. za pomocą zestawu heatmap dla par zmieniających się parametrów (przekrojów przez 3D lub 4D – zależnie od tego ile hiperparametrów optymalizujesz używając GridSearchCV). Podając średnie wyniki skomentuj zawsze ich odchylenia standardowe (jeśli używasz wykresów, możesz nanieść słupki odchyleń lub zastosować wykresy pudełkowe). - Czy metoda SVM jest wrażliwa na zakres wartości atrybutów i powinno się prowadzić ich normalizację? Uzasadnij dlaczego.
- Powtórz cały poprzedni eksperyment (poszukiwanie najwyższej jakości) jeszcze dwukrotnie, aby porównać wyniki (robiąc np. wykres różnic) wykorzystania oryginalnych atrybutów oraz atrybutów znormalizowanych i ustandaryzowanych. Opcjonalnie możesz jako czwarty wypróbować PowerTransformer. Opisz wnioski. Efekt różnych metod skalujących jest ładnie zilustrowany tutaj. Zwróć uwagę, jak należy podejść do skalowania, kiedy mamy zbiór uczący i testujący, i nie wolno nam "dotykać" zbioru testowego podczas uczenia.
- Sprawdź, jak wyglądają macierze pomyłek dla najlepszych uzyskanych klasyfikatorów i podsumuj wnioski: Jaka funkcja jądrowa i jakie parametry SVM oraz funkcji jądrowej dały najlepszą G-mean/balanced accuracy? Jak mają się najlepsze wartości trafności i G-mean do zawartości macierzy pomyłek? Czy Twoje najlepsze klasyfikatory dają inną trafność dla stratified CV z mieszaniem i bez mieszania przypadków, a jeśli tak, to dlaczego? Jak duże są odchylenia standardowe wartości zwracanych przez 10-fold stratified CV i czy różnice w jakościach omawianych klasyfikatorów są istotne?
Kawałki źródła dla inspiracji:
scoring = 'balanced_accuracy' #albo G-mean scores = cross_val_score(clf, X, y, scoring=scoring, cv = StratifiedKFold(n_splits=FOLDS, shuffle=SHUFFLE)) print(" %.3f +- %.3f (%.3f .. %.3f)" % (np.mean(scores), np.std(scores), np.min(scores), np.max(scores)))
scoring_methods = ['accuracy', 'balanced_accuracy'] #dla porównania efektów scores = cross_validate(clf, X, y, cv=FOLDS, scoring=scoring_methods) # czy ustawione tak w tej funkcji cv miesza czy nie miesza przypadków? czy ten argument działa tak samo jak argument cross_val_score()? for m in scoring_methods: print("%s: %.3f +- %.3f" % (m, np.mean(scores['test_'+m]), np.std(scores['test_'+m])))