Non è del tutto chiaro per me che ciò che stai chiedendo sia ciò di cui hai veramente bisogno: un passo di preelaborazione comune nell'apprendimento automatico è la riduzione della dimensionalità + lo sbiancamento, che significa fare PCA e standardizzare i componenti, nient'altro. Ma mi concentrerò comunque sulla tua domanda così come è formulata, perché è più interessante.
Sia la matrice di dati n × d centrata con punti dati in righe e variabili in colonne. La PCA equivale alla decomposizione del valore singolare X = U S V ⊤ ≈ U k S k V ⊤ k , dove per eseguire la riduzione dimensionale manteniamo solo k componenti. Una "rotazione fattoriale" ortogonale di questi componenti implica la scelta di una matrice ortogonale k × k R e il suo inserimento nella decomposizione: X ≈ U k S k VXn×d
X=USV⊤≈UkSkV⊤k,
kk×kRQui
√X≈UkSkV⊤k=UkRR⊤SkV⊤k=n−1−−−−−√U⊤kRRotatedstandardized scores⋅R⊤SkV⊤k/n−1−−−−−√Rotated loadings⊤.
sono componenti standardizzati ruotati e il secondo termine rappresenta i carichi ruotati trasposti. La varianza di ciascun componente dopo la rotazione è data dalla somma dei quadrati del vettore di caricamento corrispondente; prima della rotazione è semplicemente
s 2 i /(n-1). Dopo la rotazione è qualcos'altro.
n−1−−−−−√UkRS2io/ (n-1)
Ora siamo pronti a formulare il problema in termini matematici: dati i caricamenti non ruotati , trova la matrice di rotazioneR in modotale che i carichi ruotati,LR, abbiano la stessa somma dei quadrati in ciascuna colonna.L = VKSK/ n - 1-----√RL R
Risolviamolo. Le somme delle colonne dei quadrati dopo la rotazione sono uguali agli elementi diagonali di Questo ha senso: la rotazione ridistribuisce semplicemente le varianze dei componenti, che sono originariamente dati das 2 i /(n-1), tra loro, secondo questa formula. Dobbiamo ridistribuirli in modo che diventino tutti uguali al loro valore medioμ.
( L R )⊤L R = R⊤S2n - 1R .
S2io/ (n-1)μ
Non credo che ci sia una soluzione a forma chiusa a questo, e in effetti ci sono molte soluzioni diverse. Ma una soluzione può essere facilmente costruita in modo sequenziale:
- Prendi il primo componente e il componente -esimo. Il primo ha varianza σ max > μ e l'ultimo ha la varianza σ min < μ .Kσmax> μσmin< μ
- Ruota solo questi due in modo tale che la varianza della prima diventi uguale a . La matrice di rotazione in 2D dipende solo da un parametro θ ed è facile scrivere l'equazione e calcolare il necessario θ . Infatti, R 2D = ( cos θ sin θ - sin θ cos θ ) e dopo la trasformazione il primo PC otterrà la varianza cos 2 θ ⋅ σ max + sin 2 θ ⋅ σ min = cos 2 θ ⋅ σμθθ
R2D= ( cosθ- peccatoθpeccatoθcosθ)
da cui si ottiene immediatamente cos 2 θ = μ - σ mincos2θ ⋅ σmax+ sin2θ ⋅ σmin= cos2θ ⋅ σmax+ ( 1 - cos2θ ) ⋅ σmin= μ ,
cos2θ = μ - σminσmax- σmin.
- Il primo componente è ora fatto, ha varianza .μ
- Passa alla coppia successiva, prendendo il componente con la varianza più grande e quello con la varianza più piccola. Vai a # 2.
Ciò ridistribuirà equamente tutte le varianze mediante una sequenza di rotazioni 2D. Moltiplicando tutte queste matrici di rotazione insieme si otterrà la R complessiva .( k - 1 )R
Esempio
Considera la seguente matrice : ( 10 0 0 0 0 6 0 0 0 0 3 0 0 0 0 1 ) . La varianza media è 5 . Il mio algoritmo procederà come segue:S2/ (n-1)
⎛⎝⎜⎜⎜10000060000300001⎞⎠⎟⎟⎟.
5
51 + ( 10 - 5 ) = 6
53 + ( 6 - 5 ) = 4
54 + ( 6 - 1 ) = 5
Fatto.
Ho scritto lo script Matlab che implementa questo algoritmo (vedi sotto). Per questa matrice di input, la sequenza degli angoli di rotazione è:
48.1897 35.2644 45.0000
Varianti dei componenti dopo ogni passaggio (in righe):
10 6 3 1
5 6 3 6
5 5 4 6
5 5 5 5
La matrice di rotazione finale (prodotto di tre matrici di rotazione 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
( L R )⊤L R
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
Ecco il codice:
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
Ecco il codice in Python fornito da @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
Kσ2ioK