PCA: jak to wykorzystać w praktyce i co kryje się pod maską?

May 06 2023
PCA (analiza głównych składowych) jest jedną z najprostszych metod redukcji wymiarowości. Może być bardzo przydatny w przypadkach, gdy dane wielowymiarowe muszą zostać ocenione wizualnie na mniejszej przestrzeni niż oryginalny wymiar danych.
Zdjęcie BoliviaInteligente na Unsplash

PCA (analiza głównych składowych) jest jedną z najprostszych metod redukcji wymiarowości. Może być bardzo przydatny w przypadkach, gdy dane wielowymiarowe muszą zostać ocenione wizualnie na mniejszej przestrzeni niż oryginalny wymiar danych. Albo gdy np. chcesz szybko zredukować liczbę predyktorów wprowadzanych do jakiegoś algorytmu ML, ale w taki sposób, aby pozostałe predyktory wyjaśniały jak największy udział w wariancji (odczytaj, zapisz jak najwięcej informacji) oryginału zbiór danych.

Ten artykuł jest podzielony na 2 sekcje. Pierwsza sekcja pokaże, w jaki sposób można zastosować PCA przy użyciu Pythona i scikit-learn na sztucznym zbiorze danych. Druga sekcja pokaże, jak krok po kroku, używając tylko ołówka i kartki papieru, zrobić to samo, co ramy analityczne.

Sekcja 1 — stosowane zastosowanie PCA

W jakich przypadkach PCA jest przydatne z wizualnego punktu widzenia? Na przykład do szybkiej graficznej analizy istniejącego zestawu danych. Załóżmy, że masz hipotezę, że niektóre próbki Twojego zbioru danych muszą w jakiś sposób różnić się od innych próbek opartych na pewnych zmiennych. Zbiory danych zawierające oszukańcze rekordy są dobrym przykładem, ponieważ zachowanie oszustów wyraźnie różni się od zachowania zwykłych ludzi. Cóż, załóżmy, że posiadamy jakiś serwis internetowy, za pomocą którego klienci mogą dokonywać dowolnych zakupów, wpłacać i wypłacać pieniądze — jakiś bank internetowy. I załóżmy, że od czasu do czasu na konta klientów nie wchodzą ich prawdziwi właściciele, ale oszuści, aby ukraść jak najwięcej z kont osobistych ofiar. Cóż, brzmi ciekawie, prawda? Ale co ma do tego PCA?

Załóżmy, że mamy bardzo duży zestaw danych ze zmiennymi ciągłymi, które w jakiś sposób charakteryzują zachowanie naszych użytkowników. Niech wśród tych zmiennych będzie czas od zalogowania do wypłaty w sekundach; stosunek stanu konta po wypłacie środków do stanu rachunku przed wypłatą środków; ilość stron przeglądanych w aplikacji podczas sesji; liczba godzin, które upłynęły od rejestracji klienta, oraz 100 innych losowo generowanych zmiennych, które mogą mieć sens w prawdziwym świecie. Byłoby wspaniale, gdybyśmy mogli wykreślić wszystkie te zmienne na tym samym wykresie w tym samym czasie, ale w prawdziwym świecie jesteśmy ograniczeni do przestrzeni 3D. Dlatego możemy wizualnie analizować nie więcej niż 3 różne zmienne jednocześnie.

Dzięki PCA możemy stworzyć nowy układ współrzędnych, wybrać wymaganą liczbę osi i odzwierciedlić na nich istniejący zbiór danych. W ten sposób możemy przekształcić oryginalny zestaw danych w nowy zestaw danych z zaledwie 2 (na przykład) nowymi zmiennymi, które wyjaśnią maksymalną możliwą część wariancji. A poza tym możemy to wygodnie odzwierciedlić na dwuwymiarowym wykresie. Czasami pozwala to zobaczyć skupiska punktów, co pomaga sformułować pewne hipotezy.

Ponieważ będziemy generować dane, możemy przyjąć kilka założeń dotyczących tego, jak oszuści powinni zachowywać się wobec zwykłych użytkowników. Najprawdopodobniej po zalogowaniu się na cudze konto oszuści będą próbowali wypłacić wszystkie dostępne środki tak szybko, jak to możliwe, aby nie wpaść w algorytmy automatycznego wykrywania. Na podstawie tego założenia możemy wygenerować dwie zmienne: second_from_login oraz ratio_balances:

dane są generowane specjalnie w taki sposób, że pierwsza połowa rekordów ma przesunięcie bliższe zeru, to jest nasze hipotetyczne oszustwo

Rysunek 1 — wykres rozrzutu second_from_login i ratio_balances

Jeśli chodzi o zmienne opisujące liczbę stron przeglądanych w aplikacji oraz liczbę godzin, które upłynęły od momentu rejestracji klienta, będziemy je traktować jako zmienne ciągłe. Na przykład, jeśli liczba przeglądanych stron wynosi 2,134, oznacza to, że trzecia strona została przewinięta tylko o 13,4%. W przypadku tych zmiennych przyjmiemy to samo założenie, że ich wartości powinny różnić się między klasą oszustów a stałymi klientami:

Jeśli chodzi o pozostałe 100 zmiennych, załóżmy, że generalnie mogą one wcale nie różnić się między oszustami i osobami niebędącymi oszustami. Dlatego wygenerujemy je z tej samej dystrybucji:

Zbierzmy dostępne dane w 1 ramce danych i oznaczmy pierwszą połowę wierszy jako fałszywe rekordy, jak uzgodniliśmy powyżej:

Rysunek 2 — pierwsze 5 wierszy danych syntetycznych

Świetnie, mamy zbiór danych ze 104 różnymi zmiennymi ciągłymi i 1 etykietą. Teraz chcemy je wyeksponować na mniejszej przestrzeni. Na przykład na linii prostej lub na płaszczyźnie, aby odzwierciedlić jak najwięcej przydatnych informacji. Z pomocą Pythona i scikit-learn jest to łatwe. W tym celu wystarczy utworzyć obiekt klasy PCA, określając liczbę składowych głównych, o które zostanie skompresowany oryginalny zbiór danych. To znaczy, jeśli określimy 1 składową, to wszystkie 104 zmienne zostaną skompresowane w taki sposób, aby były wyświetlane na 1 osi, zachowując maksimum możliwych informacji; jeśli określimy 2, to na 2 osiach i tak dalej. Jak zbudowane są komponenty i jak dokładnie kompresowana jest przestrzeń, zostanie wyjaśnione w drugiej sekcji wraz z całą matematyką.

Zdjęcie 3 — X odzwierciedlone na 1 głównym komponencie

Rysunek 4 — X odzwierciedlony w 2 głównych komponentach

Słuchaj, w tym konkretnym przypadku możemy dość dobrze oddzielić oszustów od stałych klientów na podstawie zaledwie 1-2 elementów. Wydaje się również, że w danych powstają dokładnie 2 skupienia. W związku z tym można zbudować dobry klasyfikator binarny. Przydatna informacja, prawda? I zrozumieliśmy to wszystko za pomocą kilku linii kodu.

Teraz dowiedzmy się, jaki procent wariancji jest wyjaśniony za pomocą 2 głównych składników:

Rycina 5 — wyjaśniona wariancja

Atrybut Explain_variance_ratio_ dla utworzonego obiektu klasy PCA zwraca procent całej wyjaśnionej wariancji danych, gdzie liczba porządkowa elementu listy jest numerem składnika głównego .

Rysunek 6 — suma wyjaśnionej wariancji

Zatem prawie 100% wariancji jest wyjaśnione tylko przez 2 składowe. I na przykład, budując model klasyfikacyjny, możemy użyć tylko dwuwymiarowego zestawu danych zamiast oryginalnego 104-wymiarowego.

Czy podczas korzystania z PCA musisz ograniczać się do 1–3 głównych komponentów? Oczywiście nie. Komponenty 1–3 są wygodne do wizualizacji, aby zrozumieć niektóre podstawowe wzorce, jeśli takie istnieją, w danych. Jednak analiza wizualna nie jest jedynym zastosowaniem PCA. Możesz skompresować przestrzeń w taki sposób, aby zachować jak najwięcej możliwych do wyjaśnienia wariancji przy minimalnej liczbie funkcji. W takim przypadku skrócisz czas uczenia swoich algorytmów.

W zależności od zbiorów danych liczba głównych składników może się znacznie różnić. Możesz sam określić potrzebną proporcję wyjaśnianej wariancji, na przykład 90% lub 95% i zobaczyć, o ile zmniejszy się przestrzeń.

Teraz będziemy trenować 2 algorytmy RandomForest bez dostrajania hiperparametrów. Pierwszy na oryginalnej przestrzeni danych, drugi na przestrzeni skompresowanej za pomocą PCA. Oceńmy czas szkolenia, a także końcową jakość:

Zdjęcie 7 — Pełne wyjście danych RF

Zdjęcie 8 — Wyjście skompresowanych danych RF

Straciliśmy trochę na jakości, ale skróciliśmy czas szkolenia o 64%. W prawdziwym świecie często zdarzają się sytuacje, w których trzeba wypróbować wiele różnych prototypów w ograniczonym czasie. W takich sytuacjach skrócenie czasu nauki może być bardzo ważne, zwłaszcza jeśli prawie nie tracimy na jakości.

Sekcja 2 — tworzenie PCA od podstaw

W tej sekcji krok po kroku zbudujemy PCA, korzystając z matematyki stojącej za tą metodą. Zdecydowanie radzę wziąć kartkę papieru i długopis, ponieważ rozwiązując wszystko samodzielnie, można znacznie lepiej zanurzyć się w logice, która jest w tej metodzie. Polecam również obejrzenie tego filmu autorstwa 3Blue1Brown, aby zrozumieć intuicję metody.

Jako zbiór danych użyjemy dwuwymiarowej macierzy 10x2 składającej się z 2 wektorów x i y:

Odzwierciedlajmy ten zestaw danych na płaszczyźnie:

Rysunek 9 — x i y na płaszczyźnie

Zwróć uwagę na niebieski krzyż. Jest to punkt, którego współrzędne są odpowiednio średnią z x i y.

Krok 1 — wyśrodkowanie danych

Aby wyśrodkować zestaw danych, musisz ustawić średnią wartość wektora x i y na 0, w tym celu od każdego x[i] musisz odjąć średnią x, od każdego y[i] musisz odjąć średnią y:

Rysunek 10 — dane oryginalne i wyśrodkowane

Zwróć uwagę na niebieski krzyż. Po wyśrodkowaniu przesuwa się w miejsce pomarańczowego krzyża i staje się początkiem układu współrzędnych (0; 0). Odpowiednie przesunięcie jest wykonywane przez każdą niebieską kropkę, zastępując pomarańczową.

Rysunek 11 — od danych pierwotnych do wyśrodkowanych

Krok 2 — oblicz macierz kowariancji

Macierz kowariancji to macierz, w której wariancje znajdują się na głównej przekątnej, a kowariancje między rozpatrywanymi zmiennymi w pozostałych komórkach.

Kowariancja jest miarą liniowej zależności między rozpatrywanymi zmiennymi losowymi. Podobnie jak w przypadku korelacji liniowej, tylko jej wartości mogą być mniejsze niż -1 i większe niż 1.

Kowariancję oblicza się za pomocą następującego wzoru, gdzie n jest długością odpowiedniej kolumny:

Formuła 1 — kowariancja

Ponieważ jednak dane już wyśrodkowaliśmy, a średnie x i y wynoszą 0, wzór upraszcza się do postaci:

Wzór 2 — kowariancja na danych wyśrodkowanych

A sama macierz kowariancji będzie wyglądać tak:

Wzór 3 — macierz kowariancji

Używając Pythona, obliczenie macierzy kowariancji jest bardzo łatwe, wystarczy wywołać jedną funkcję:

Rysunek 12 — obliczona macierz kowariancji przy użyciu Pythona

Ale ponieważ mamy pod ręką wszystkie niezbędne formuły i zmienne, obliczmy to samo ręcznie, aby upewnić się, że ta czarna skrzynka wcale nie jest tak niezrozumiała, jak mogłoby się wydawać:

Równanie 1

Wartości są zgodne. Dlatego zadbaliśmy o to, aby nie było w nim żadnej magii.

Krok 3 — oblicz wartości własne macierzy kowariancji

Mówiąc prościej, gdy mnożymy macierz przez wektor, stosujemy transformację liniową do przestrzeni, w której znajduje się wektor. Transformacje te mogą być różne: obrót, skalowanie, zniekształcenie itp. Jeśli po zastosowaniu transformacji liniowej do wektor pozostaje na tej samej osi, to ten wektor nazywamy wektorem własnym. A współczynnik, według którego skalowano długość tego wektora, nazywa się wartością własną macierzy.

Kanał 3Blue1Brown ma świetne wyjaśnienie tej koncepcji. Tutaj postaram się pokrótce wyjaśnić istotę na małym przykładzie:

Zdjęcie 13 — odbicie w równoległoboku

Mamy oryginalną figurę ABCD, którą odbijamy wzdłuż osi y. W rezultacie figura zajmuje miejsce AB*C*D*. Jak widać wektor x pozostał na tej samej osi, tylko zmienił kierunek (stał się x*). Dlatego ten wektor jest wektorem własnym, a wartość własna tego wektora będzie wynosić -1.

Teraz spójrzmy na wektor y i jego lustrzane odbicie — y*. Oczywiście leżą one na zupełnie innych osiach. Dlatego wektor y nie jest wektorem własnym tej liniowej transformacji.

Aby obliczyć wektory własne i wartości własne, należy użyć następującego wzoru:

Wzór 4 — wzór na wektor własny i wartość własną

gdzie A jest macierzą transformacji liniowej, wektor x jest wektorem własnym tej macierzy, lambda jest wartością własną wektora własnego x.

W PCA macierz A jest macierzą kowariancji cov , którą zdefiniowaliśmy w kroku 2, więc nasz wzór będzie wyglądał następująco:

Wzór 5 — wzór na wektor własny i wartość własną (2)

Rozwiązując to równanie, znajdujemy wartości własne macierzy kowariancji:

Wzór 6 — równanie charakterystyczne

W tym przypadku albo wektor x jest równy 0 (co nas nie interesuje, bo szukamy wektorów niezerowych), albo macierz (cov-lambda*I) = 0 (a w tym przypadku właśnie potrzebujemy). Macierz może być równa zero, gdy jej wyznacznik jest równy 0. A wyznacznik macierzy jest równy 0, gdy w macierzy są proporcjonalne lub zerowe wiersze lub kolumny, co po prostu wskazuje na kompresję pierwotnej przestrzeni. Zatem:

Równanie 2

Rozwiązując to równanie kwadratowe, znajdujemy jego pierwiastki:

lambda1 = 1,3

lambda2 = 3,3

Sprawdźmy obliczenia za pomocą numpy:

Rysunek 14 — wartości własne obliczone za pomocą numpy

Świetnie, znaleźliśmy wartości własne zastosowanej transformacji liniowej! Teraz na ich podstawie znajdziemy same wektory własne.

Krok 4 — znajdź wektory własne macierzy kowariancji

Aby znaleźć wektory własne, należy podstawić znalezione wartości własne do równania, które we wzorze 6 jest zaznaczone na czerwono. Rozwiązując kolejno otrzymane układy równań, znajdziemy po prostu wektory własne zastosowanej transformacji liniowej.

Dla lambdy1:

Równanie 3

Powiedzmy, że x1 = 1, to:

wektor własny 1

W przypadku lambda2 jest to rozpatrywane w podobny sposób. Podczas obliczeń otrzymujemy, że drugi wektor własny będzie równy:

wektor własny 2

Teraz każdy z wektorów własnych należy podzielić przez jego normę (długość). Długość wektora oblicza się za pomocą następującego wzoru:

Formuła 7 — norma wektora

Podstawiając współrzędne każdego wektora własnego do wzoru, otrzymujemy, że norma pierwszego wektora = 1,31, norma drugiego wektora wynosi 1,55. Dzieląc każdy wektor własny przez jego normę, otrzymujemy, że znormalizowane współrzędne pierwszego wektora to:

Wektor własny 1 (znormalizowany)

A znormalizowane współrzędne drugiego wektora to:

Wektor własny 2 (znormalizowany)

Macierz wektorów własnych jest zapisywana zgodnie ze spadkiem odpowiednich wartości własnych, dlatego w naszym przypadku macierz będzie wyglądać następująco:

Macierz wektorów własnych

Upewnijmy się, że nasze obliczenia są poprawne za pomocą numpy:

Rysunek 15 — wektory własne obliczone przez numpy

Skorygowane o błędy zaokrągleń, to dokładnie te wektory, które obliczyliśmy!

Nie daj się zwieść faktowi, że nasze wektory wydają się być pomnożone przez -1, ponieważ są to dokładnie te same wektory, ponieważ leżą na tej samej prostej. Dla tych, którzy chcą bardziej szczegółowych wyjaśnień, istnieje wiele tematów dotyczących stackoverflow: link1 , link2 , link3 .

Krok 5 — przekształć pierwotną przestrzeń

Aby wyświetlić oryginalne dane na podstawie znalezionych głównych składowych, konieczne jest pomnożenie wyśrodkowanej oryginalnej macierzy przez macierz wektorów własnych. Ponadto macierz wektorów własnych powinna mieć tyle kolumn, ile głównych składowych chcesz wyświetlić oryginalne dane:

Zdjęcie 16 — PCA X ręcznie

Sprawdź, czy nasze obliczenia są poprawne, używając klasy PCA ze sklearn:

Zdjęcie 17 — PCA X ze sklearnem

Biorąc pod uwagę błąd zaokrąglenia, otrzymaliśmy dokładnie taką samą macierz, jaką zwraca sklearn PCA.

Podsumowując

Jak widzieliśmy, PCA ma bardzo przydatne praktyczne zastosowanie i wcale nie jest „czarną skrzynką”. Wszystkie kroki obliczeniowe są dość proste i zrozumiałe i wymagają jedynie dokładności