Nie jest dla mnie do końca jasne, że to, o co pytasz, jest tym, czego naprawdę potrzebujesz: wspólnym krokiem wstępnego przetwarzania w uczeniu maszynowym jest redukcja wymiarów + wybielanie, co oznacza robienie PCA i standaryzację komponentów, nic więcej. Niemniej jednak skupię się na twoim pytaniu w formie, w jakiej zostało sformułowane, ponieważ jest bardziej interesujące.
Niech będzie wyśrodkowaną macierzą danych z punktami danych w wierszach i zmiennymi w kolumnach. PCA równa się rozkładowi liczby pojedynczej gdzie do wykonania zmniejszenia wymiarów trzymamy tylko komponentów. Ortogonalna „rotacja czynnikowa” tych składników oznacza wybranie ortogonalnej macierzy macierzy i podłączenie jej do rozkładu:Xn×d
X=USV⊤≈UkSkV⊤k,
kk×kRX≈UkSkV⊤k=UkRR⊤SkV⊤k=n−1−−−−−√U⊤kRRotatedstandardized scores⋅R⊤SkV⊤k/n−1−−−−−√Rotated loadings⊤.
Tutaj są obróconymi znormalizowanymi komponentami, a drugi termin oznacza obrócone obciążenia obrócone. Wariancja każdego składnika po obrocie jest dana przez sumę kwadratów odpowiedniego wektora obciążenia; przed obrotem jest to po prostu . Po rotacji jest to coś innego.
n−1−−−−−√UkRs2i/(n−1)
Teraz jesteśmy gotowi sformułować problem w kategoriach matematycznych: biorąc pod uwagę , znajdź macierz obrotu tak, że obrócone ładunki , ma równą sumę kwadratów w każdej kolumnie.L=VkSk/n−1−−−−−√RLR
Rozwiążmy to. Sumy kolumn kwadratów po obrocie są równe elementom ukośnym Ma to sens: obrót po prostu redystrybuuje wariancje składników, które pierwotnie podano przez , między nimi, zgodnie z tym wzorem. Musimy je redystrybuować, aby wszystkie stały się równe ich średniej wartości .
(LR)⊤LR=R⊤S2n−1R.
s2i/(n−1)μ
Nie sądzę, aby istniało rozwiązanie w formie zamkniętej, a tak naprawdę istnieje wiele różnych rozwiązań. Ale rozwiązanie można łatwo zbudować sekwencyjnie:
- Weź pierwszy składnik i ty składnik. Pierwszy ma wariancję a ostatni ma wariancję .kσmax>μσmin<μ
- Obróć tylko te dwa, aby wariancja pierwszego stała się równa . Macierz rotacji w 2D zależy tylko od jednego parametru i łatwo jest zapisać równanie i obliczyć niezbędną . Rzeczywiście, a po transformacji pierwszy komputer otrzyma wariancję z którego natychmiast otrzymujemyμθθ
R2D=(cosθ−sinθsinθcosθ)
cos2θ⋅σmax+sin2θ⋅σmin=cos2θ⋅σmax+(1−cos2θ)⋅σmin=μ,
cos2θ=μ−σminσmax−σmin.
- Pierwszy komponent jest już gotowy, ma wariancję .μ
- Przejdź do następnej pary, biorąc komponent o największej wariancji i ten o najmniejszej wariancji. Idź do 2.
Spowoduje to równomierne rozłożenie wszystkich wariancji przez sekwencję obrotów 2D. Mnożenie macierzy rotacji wszystkie te wspólnie uzyskując całkowitą .(k−1)R
Przykład
Rozważ następującą :Średnia wariancja wynosi . Mój algorytm będzie działał w następujący sposób:S2/(n−1)
⎛⎝⎜⎜⎜10000060000300001⎞⎠⎟⎟⎟.
5
Krok 1: Obróć PC1 i PC4, aby PC1 otrzymało wariancję . W rezultacie PC4 dostaje wariancję .51+(10−5)=6
Krok 2: obróć PC2 (nowa maksymalna wariancja) i PC3, aby PC2 otrzymało wariancję . W rezultacie PC3 otrzymuje wariancję .53+(6−5)=4
Krok 3: obróć PC4 (nowa maksymalna wariancja) i PC3, aby PC4 otrzymało wariancję . W rezultacie PC3 otrzymuje wariancję .54+(6−1)=5
Gotowy.
Napisałem skrypt Matlab, który implementuje ten algorytm (patrz poniżej). Dla tej macierzy wejściowej sekwencja kątów obrotu wynosi:
48.1897 35.2644 45.0000
Warianty komponentów po każdym kroku (w rzędach):
10 6 3 1
5 6 3 6
5 5 4 6
5 5 5 5
Ostateczna macierz obrotu (iloczyn trzech macierzy obrotu 2D):
0.6667 0 0.5270 0.5270
0 0.8165 0.4082 -0.4082
0 -0.5774 0.5774 -0.5774
-0.7454 0 0.4714 0.4714
I ostatnia to:(LR)⊤LR
5.0000 0 3.1623 3.1623
0 5.0000 1.0000 -1.0000
3.1623 1.0000 5.0000 1.0000
3.1623 -1.0000 1.0000 5.0000
Oto kod:
S = diag([10 6 3 1]);
mu = mean(diag(S));
R = eye(size(S));
vars(1,:) = diag(S);
Supdated = S;
for i = 1:size(S,1)-1
[~, maxV] = max(diag(Supdated));
[~, minV] = min(diag(Supdated));
w = (mu-Supdated(minV,minV))/(Supdated(maxV,maxV)-Supdated(minV,minV));
cosTheta = sqrt(w);
sinTheta = sqrt(1-w);
R2d = eye(size(S));
R2d([maxV minV], [maxV minV]) = [cosTheta sinTheta; -sinTheta cosTheta];
R = R * R2d;
Supdated = transpose(R2d) * Supdated * R2d;
vars(i+1,:) = diag(Supdated);
angles(i) = acosd(cosTheta);
end
angles %// sequence of 2d rotation angles
round(vars) %// component variances on each step
R %// final rotation matrix
transpose(R)*S*R %// final S matrix
Oto kod w Pythonie dostarczony przez @feilong:
def amoeba_rotation(s2):
"""
Parameters
----------
s2 : array
The diagonal of the matrix S^2.
Returns
-------
R : array
The rotation matrix R.
Examples
--------
>>> amoeba_rotation(np.array([10, 6, 3, 1]))
[[ 0.66666667 0. 0.52704628 0.52704628]
[ 0. 0.81649658 0.40824829 -0.40824829]
[ 0. -0.57735027 0.57735027 -0.57735027]
[-0.74535599 0. 0.47140452 0.47140452]]
http://stats.stackexchange.com/a/177555/87414
"""
n = len(s2)
mu = s2.mean()
R = np.eye(n)
for i in range(n-1):
max_v, min_v = np.argmax(s2), np.argmin(s2)
w = (mu - s2[min_v]) / (s2[max_v] - s2[min_v])
cos_theta, sin_theta = np.sqrt(w), np.sqrt(1-w)
R[:, [max_v, min_v]] = np.dot(
R[:, [max_v, min_v]],
np.array([[cos_theta, sin_theta], [-sin_theta, cos_theta]]))
s2[[max_v, min_v]] = [mu, s2[max_v] + s2[min_v] - mu]
return R
Zauważ, że ten problem jest całkowicie równoważny z następującym: biorąc pod uwagę zmiennych nieskorelowanych z wariancjami , znajdź obrót (tj. Nową podstawę ortogonalną), który da zmiennych o równych wariancjach (ale oczywiście już nieskorelowanych).kσ2ik