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.

  1. Przypomnij sobie z wykładu:
    1. sposób działania SVM liniowego (przypadek dwuklasowy one-vs-rest i wieloklasowy one-vs-one),
    2. różnicę w podejściu SVM a liniową (LDA) i kwadratową (QDA) analizą dyskryminacyjną,
    3. popularne funkcje jądrowe stosowane w SVM,
    4. ideę "sztuczki jądrowej",
    5. 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).
  2. 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.
  3. Zapoznaj się z możliwościami GridSearchCV do dostrajania wartości hiperparametrów. Przeanalizuj fragment kodu używający GridSearchCV w tym przykładzie.
  4. 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"?
  5. 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?
  6. 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?
  7. 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?
  8. 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).
  9. Czy metoda SVM jest wrażliwa na zakres wartości atrybutów i powinno się prowadzić ich normalizację? Uzasadnij dlaczego.
  10. 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.
  11. 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])))