Analiza składowych głównych i dekompozycja wartości pojedynczych to jedne z dwóch popularnych pojęć algebry liniowej w uczeniu maszynowym. Czy po zebraniu surowych danych możliwe jest odkrycie ich struktury? Na przykład, jeśli weźmiemy pod uwagę stopy procentowe z poprzedniego tygodnia, czy jest jakiś sposób, aby dowiedzieć się o trendach na rynku?
Pytania te stają się coraz bardziej skomplikowane, gdy dysponujemy dużą ilością danych. Znalezienie odpowiedzi na te pytania jest podobne do szukania igły w stogu siana. Tak więc, używamy rozkładu wartości pojedynczej, aby rozplątać i wydobyć skomplikowane informacje. Ten artykuł pomoże Ci zrozumieć koncepcję dekompozycji wartości pojedynczej w szczegółach.

Dekompozycja wartości pojedynczej

Ta technika statystyki wielowymiarowej pomaga w rozwiązywaniu złożonych problemów w naukach o atmosferze. Empiryczna analiza funkcji ortogonalnych i analiza składowych głównych są podobnymi zestawami procedur dla tej samej techniki wprowadzonej w 1956 roku przez Edwarda Lorenza.
Dekompozycja wartości pojedynczych pomaga zredukować zbiory danych zawierające dużą liczbę wartości. Ponadto, metoda ta jest również pomocna w generowaniu znaczących rozwiązań dla mniejszej liczby wartości. Jednakże, te mniej wartości zawierają również ogromną zmienność dostępną w oryginalnych danych.
Dane ujawniają duże korelacje przestrzenne w naukach geofizycznych i atmosferycznych. Analiza Singular Value Decomposition wspiera i daje wyniki dla bardziej zwartej demonstracji tych korelacji. Używając wielowariantowych zbiorów danych, można uzyskać wgląd w czasowe i przestrzenne wariacje. Wariacje te pokazują dane po analizie.
Nawet jeśli istnieje mniej ograniczeń dla tej techniki, powinieneś je zrozumieć przed obliczeniem Singular Value Decomposition zbiorów danych. Po pierwsze, powinny istnieć anomalie w danych, które pierwsza struktura będzie wychwytywać. Jeśli analizujesz dane w celu znalezienia przestrzennych korelacji niezależnych od trendów, powinieneś odtrendować dane przed zastosowaniem ich do analizy.

Wektory osobliwe i wartości osobliwe

Macierze AAᵀ i AᵀA w algebrze liniowej są bardzo szczególne. Mnożąc Aᵀ z macierzą po rozważeniu ich × n macierzy A, możemy utworzyć AAᵀ i AᵀA indywidualnie. Do macierzy tych należą:
– Kwadratowe
– Symetryczne
– Takie same macierze z obiema dodatnimi wartościami własnymi
– Półdodatnie, oraz
– Takie same r jak A z obiema rangami
Główną własnością macierzy symetrycznych jest to, że są one symetryczne, a wektory własne wybieramy jako ortonormalne. Używamy tych macierzy kowariancji w uczeniu maszynowym bardzo dużo.

Przykład dekompozycji wartości pojedynczej

Aby zrozumieć tę koncepcję, załóżmy, że macierz m × n, A, zbiera zbiór danych treningowych. Te zestawy danych będą miały rząd dla każdego wektora szkoleniowego. Tutaj N wskazuje, że wymiar każdego wektora będzie bardzo duży.

Podając A w algorytmie klasteryzacji, wygenerujesz stałą liczbę centrów klastrów jako wyjście. Ponieważ ‘n’ jest dość duże, algorytm będzie niestabilny lub będzie trwał zbyt długo. Tak więc, wykorzystamy dekompozycję wartości pojedynczych, aby zredukować liczbę zmiennych. Do obliczeń użyjemy przejrzystej metody, biorąc pod uwagę, że nadal rozwiązujemy problem z nieprzekształconymi współrzędnymi.

Krok 1: Wczytanie danych

Wczytywanie danych możemy rozpocząć od wypełnienia pola A. Zacznijmy więc od tutorialu w języku C:
//subroutine header for performing cluster analysis:
#include “cluster.h”//maksymalna liczba klastrów:
#define MAX_CLUSTER 10int main(intargc, char **argv) {
char *infile; //plik wejściowy
char *outfile; //plik wyjściowy
FILE *fs; //wskaźnik do pliku
double **a; //macierz danych treningowych/U
int m; //liczba wierszy w macierzy
int n; //liczba kolumn w macierzy
intnsv; //liczba wartości singularnych if (argc!=4) {
printf(“syntax: cluster_svdnsv train centr”);
printf(” where:\n”);
printf(“nsv = number of singular values (0 = use untransformed data)\n”);
printf(“infile = plik wejściowy ASCII zawierający dane treningowe”);
printf(“output = plik wyjściowy ASCII zawierający centra klastrów”);
printf(“\”);
printf(“format pliku:\n”);
printf(“- jednowierszowy nagłówek zawierający liczbę wierszy i liczbę kolumn”);
printf(“- lista głównych wierszy każdego elementu macierzy”);
exit(1);
} if (sscanf(argv[1], “%d”, &nsv)!=1) {
fprintf(stderr, “Błąd parsowania pierwszego argumentu wiersza poleceń”);
exit(1);
}
infile=argv[2];
outfile=argv[3]; fs=fopen(infile, “r”);
if (fs==NULL) {
fprintf(stderr, “Błąd otwarcia pliku wejściowego, %s\n”, infile);
exit(1);
} if (fscanf(fs, “%d %d”, &m, &n)!=2) {
fprintf(stderr, “Błąd formatu w pliku wejściowym: %s linia 0”, infile);
exit(1);
}
if (nsv>n) {
fprintf(stderr, “Parametr wiersza poleceń nsv=%d poza zakresem”, nsv);
exit(1);
} a=new double *[m];
a[0]=new double[m*n];
for (inti=1; i<m; i++) a[i]=a[0]+i*n;
for (inti=0; i<m; i++) {
for (int j=0; j<n; j++) {
if (fscanf(fs, “%lg”, a[i]+j)!=1) {
fprintf(stderr, “Błąd formatu w pliku wejściowym, %s, linia %d\n”, infile, i);
exit(1);
}
}
} fclose(fs);

Krok 2: Przeprowadzenie SVD

Teraz użyjemy sztucznej procedury dekompozycji wartości pojedynczych, którą zawiera plik nagłówkowy svd.h:
#ifndef SVD_H
#define SVD_H/ /podprogram do rozkładu wartości pojedynczych:
int //zwraca kod błędu (0 dla powodzenia)
svd (double **a, //macierz wejściowa – zastąpiona przez U na wyjściu
int m, //liczba wierszy
int n, //liczba kolumn
double *s, /wartości sinusoidalne
double **vt); //V–prawe wektory singularne#endif
Procedury dekompozycji wartości pojedynczych są skomplikowane pod względem typu używanej macierzy i wektora. Można jednak łatwo podsumować całe kodowanie poprzez funkcję wrappera. Rutyna będzie równie prosta, gdy oprzemy się na procedurze rozkładu wartości pojedynczych. Dodamy następujące kody po poprzedniej sekcji:
double *ave;
double *s; /wartości jednokrotne
double **vt; //prawe wektory singularne //Najpierw obliczymy i usuniemy średnie arytmetyczne:
ave=new double[n];
for (inti=0; i<n; i++) ave[i]=0;
for (inti=0; i<m; i++) {
for (int j=0; j<n; j++) {
ave[j]+=a[i][j];
}
}
for (inti=0; i<n; i++) ave[i]/=m;
for (inti=0; i<m; i++) {
for (int j=0; j<n; j++) {
a[i][j]-=ave[j];
}
} if (nsv>0) {
/zrób miejsce dla wartości pojedynczych:
s=new double[n]; //make space for right singular vectors:
vt=new double *[n];
vt[0]=new double[n*n];
for (inti=1; i<n; i++) vt[i]=vt[0]+i*n; //przeprowadź dekompozycję:
int err=svd(a, m, n, s, vt);
if (err!=0) {
fprintf(stderr, “Error in svd subroutine”);
exit(err);
}
}

Krok 3: Przeprowadzenie analizy skupień

Proces algorytmu klasteryzacji wygeneruje zbiór c centrów klastrów przy użyciu {ᵢ ; i ∈ [1, c]}:
#ifndef CLUSTER_H
#define CLUSTER_Hint //zwraca liczbę centrów klastra
cluster (double ** x, //wektory treningowe
int m, //liczba wektorów treningowych
int n, /wymiar każdego wektora
intmax_nc, /maksymalna liczba centrów klastrów
double **mu); //zwrócone centra klastrów#endif
Kontynuujemy powyższy rozdział i wygenerujemy centra klastrów:
double **mu_p; //macierz centrów klastrów
intnc; //liczba centrów klastrów /zrób miejsce na centra klastrów:
mu_p=new double *[MAX_CLUSTER];
mu_p[0]=new double[MAX_CLUSTER*n];
for (inti=1; i<MAX_CLUSTER; i++) mu_p[i]=mu_p[0]+i*n; if (nsv>0) {
/zrób miejsce na centra klastrów:
nc=cluster(a, m, nsv, MAX_CLUSTER, mu_p);
} else {
//Zrób miejsce na centra klastrów:
nc=cluster(a, m, n, MAX_CLUSTER, mu_p);
} if (nc<= 0) {
fprintf(stderr, “Algorytm klastrowy nie powiódł się”);
exit(-1);
}
Ponieważ będziemy używać przekształconych danych treningowych do algorytmu klasteryzacji, przekształcony system będzie zawierał centra klastrów.

Krok 4: Przechowywanie wyników

Teraz możesz przechowywać centra klastrów, używając następującego równania w nieprzekształconym układzie współrzędnych.

P w tym równaniu oznacza liczbę współrzędnych.
double **mu; //środki skupisk w nieprzekształconych współrzędnych //alokacja miejsca na nieprzekształcone środki skupisk:
mu=new double *[nc];
mu[0]=new double[nc*n];
for (inti=1; i<nc; i++) mu[i]=mu[0]+i*n; //przeprowadź transformację współrzędnych:
for (inti=0; i<nc; i++) {
for (int j=0; j<n; j++) {
mu[i][j]=ave[j];
if (nsv>0) {
for (int k=0; k<nsv; k++) mu[i][j]+=vt[k][j]*s[k]*mu_p[i][k];
} else {
mu[i][j]+=mu_p[i][j];
}
}
} //zapisujemy wyniki do pliku:
fs=fopen(outfile, “w”);
if (fs==NULL) {
fprintf(stderr, “Error opening output file, %s\n”, outfile);
exit(1);
} fprintf(fs, “%d %d\n”, nc, n);
for (inti=0; i<nc; i++) {
for (int j=0; j<n; j++) fprintf(fs, “%16.8lg”, mu[i][j]);
fprintf(fs, “%16.8lg”, mu[i][j]);
} fclose(fs); //sprzątnij:
delete [] mu[0];
delete [] mu; delete [] mu_p[0];
delete [] mu_p; delete [] ave;
delete [] a[0];
delete [] a;
if (nsv>0) {
delete [] s;
delete [] vt[0];
delete [] vt;
} return 0;
}

Podsumowanie

W tym artykule wyjaśniliśmy definicję dekompozycji wartości pojedynczych oraz pomogliśmy zrozumieć budowę modelu w języku C. Możesz wykorzystać tę metodę do odzyskiwania zmiennych atmosferycznych na podstawie pomiarów satelitarnych. Możesz również użyć tej techniki do interpolacji rzadkich pomiarów lub do algorytmu uczenia maszynowego. Ta technika pomaga w regresji i klasyfikacji zbioru danych.