Para mí no está completamente claro que lo que está preguntando es lo que realmente necesita: un paso de preprocesamiento común en el aprendizaje automático es la reducción de dimensionalidad + blanqueamiento, lo que significa hacer PCA y estandarizar los componentes, nada más. Sin embargo, me centraré en su pregunta, ya que está formulada, porque es más interesante.
Sea la matriz de datos n × d centrada con puntos de datos en filas y variables en columnas. PCA equivale a la descomposición de valores singulares X = U S V ⊤ ≈ U k S k V ⊤ k , donde para realizar la reducción de dimensionalidad solo conservamos k componentes. Un "factor de rotación" ortogonal de estos componentes implica elegir una matriz ortogonal k × k R y conectarla a la descomposición: X ≈ U k S k VXn×d
X=USV⊤≈UkSkV⊤k,
kk×kRAquí
√X ≈ UkSkV⊤k= UkR R⊤SkV⊤k= n - 1-----√U⊤kRRotadopuntajes estandarizados⋅ R⊤SkV⊤k/ n - 1-----√Cargas rotadas⊤.
son componentes estandarizados rotados y el segundo término representa cargas rotadas transpuestas. La varianza de cada componente después de la rotación viene dada por la suma de cuadrados del vector de carga correspondiente; antes de la rotación es simplemente
s 2 i /(n-1). Después de la rotación es otra cosa.
n - 1-----√UkRs2yo/(n−1)
Ahora estamos listos para formular el problema en términos matemáticos: dadas cargas no rotadas , encuentre la matriz de rotaciónRtal que las cargas rotadas,LR, tengan la misma suma de cuadrados en cada columna.L=VkSk/n−1−−−−−√RLR
Vamos a resolverlo Las sumas de cuadrados de la columna después de la rotación son iguales a los elementos diagonales de Esto tiene sentido: la rotación simplemente redistribuye las variaciones de los componentes, que originalmente se dan pors 2 i /(n-1), entre ellos, de acuerdo con esta fórmula. Necesitamos redistribuirlos para que todos sean iguales a su valor promedioμ.
(LR)⊤LR=R⊤S2n−1R.
s2i/(n−1)μ
No creo que haya una solución de forma cerrada para esto, y de hecho hay muchas soluciones diferentes. Pero una solución se puede construir fácilmente de manera secuencial:
- Tome el primer componente y el componente -ésimo. El primero tiene la varianza σ max > μ y el último tiene la varianza σ min < μ .kσmax> μσmin< μ
- Gire solo estos dos de modo que la varianza del primero sea igual a . Matriz de rotación en 2D sólo depende de un parámetro θ y es fácil de escribir la ecuación y calcular la necesaria θ . De hecho, R 2D = ( cos θ sen θ - sin θ cos θ ) y después de la transformación, la primera PC obtendrá varianza cos 2 θ ⋅ σ max + sin 2 θ ⋅ σ min = cos 2 θ ⋅ σμθθ
R2D= ( cosθ- pecadoθpecadoθcosθ)
de donde obtenemos inmediatamente cos 2 θ = μ - σ mincos2θ ⋅ σmax+ pecado2θ ⋅ σmin= cos2θ ⋅ σmax+ ( 1 - cos2θ ) ⋅ σmin= μ ,
cos2θ = μ - σminσmax- σmin.
- El primer componente ya está hecho, tiene una varianza .μ
- Continúe con el siguiente par, tomando el componente con la varianza más grande y el que tiene la varianza más pequeña. Ir a # 2.
Esto redistribuirá todas las variaciones por igual por una secuencia de rotaciones 2D. Multiplicar todas estas matrices de rotación juntas producirá la R general .( k - 1 )R
Ejemplo
Considere la siguiente matriz : ( 10 0 0 0 0 6 0 0 0 0 3 0 0 0 0 1 ) . La varianza media es 5 . Mi algoritmo procederá de la siguiente manera:S2/ (n-1)
⎛⎝⎜⎜⎜100 00 00 00 06 60 00 00 00 030 00 00 00 01⎞⎠⎟⎟⎟.
5 5
5 51 + ( 10 - 5 ) = 6
5 53 + ( 6 - 5 ) = 4
5 54 + ( 6 - 1 ) = 5
Hecho.
Escribí el script de Matlab que implementa este algoritmo (ver más abajo). Para esta matriz de entrada, la secuencia de ángulos de rotación es:
48.1897 35.2644 45.0000
Desviaciones de componentes después de cada paso (en filas):
10 6 3 1
5 6 3 6
5 5 4 6
5 5 5 5
La matriz de rotación final (producto de tres matrices de rotación 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
Aquí está el código:
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
Aquí está el código en Python proporcionado por @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σ2yok