Il n'est pas tout à fait clair pour moi que ce que vous demandez est ce dont vous avez vraiment besoin: une étape de prétraitement courante dans l'apprentissage automatique est la réduction de dimensionnalité + le blanchiment, ce qui signifie faire de l'ACP et standardiser les composants, rien d'autre. Mais je vais néanmoins me concentrer sur votre question telle qu'elle est formulée, car elle est plus intéressante.
Soit la matrice de données n × d centrée avec des points de données en lignes et des variables en colonnes. PCA équivaut à une décomposition en valeurs singulières X = U S V ⊤ ≈ U k S k V ⊤ k , où pour effectuer la réduction de dimensionnalité, nous ne gardons que k composantes. Une «rotation factorielle» orthogonale de ces composantes implique de choisir une matrice orthogonale k × k R et de la brancher dans la décomposition: X ≈ U k S k VXn × d
X = U S V⊤≈ UkSkV⊤k,
kk × kRIci
√X≈UkSkV⊤k=UkRR⊤SkV⊤k=n−1−−−−−√U⊤kRRotatedstandardized scores⋅R⊤SkV⊤k/n−1−−−−−√Rotated loadings⊤.
sont des composants normalisés tournés et le deuxième terme représente des chargements tournés transposés. La variance de chaque composante après rotation est donnée par la somme des carrés du vecteur de chargement correspondant; avant la rotation, il s'agit simplement de
s 2 i /(n-1). Après la rotation, c'est autre chose.
n−1−−−−−√UkRs2je/ (n-1)
Nous sommes maintenant prêts à formuler le problème en termes mathématiques: compte tenu des chargements non rotatifs , trouver la matrice de rotationRtelle que les chargements tournés,LR, ont une somme égale de carrés dans chaque colonne.L = VkSk/ n - 1-----√RL R
Résolvons-le. Les sommes des colonnes des carrés après rotation sont égales aux éléments diagonaux de Cela a du sens: la rotation redistribue simplement les variances des composantes, qui sont à l'origine données pars 2 i /(n-1), entre elles, selon cette formule. Nous devons les redistribuer de sorte qu'ils deviennent tous égaux à leur valeur moyenneμ.
( L R )⊤L R = R⊤S2n - 1R .
s2je/ (n-1)μ
Je ne pense pas qu'il existe une solution de forme fermée à cela, et en fait, il existe de nombreuses solutions différentes. Mais une solution peut être facilement construite de manière séquentielle:
- Prenez le premier composant et le composant -ème. Le premier a la variance σ max > μ et le dernier a la variance σ min < μ .kσmax> μσmin< μ
- Tournez seulement ces deux pour que la variance du premier devienne égale à . La matrice de rotation en 2D ne dépend que d'un seul paramètre θ et il est facile d'écrire l'équation et de calculer le θ nécessaire . En effet, R 2D = ( cos θ sin θ - sin θ cos θ ) et après transformation le premier PC obtiendra la variance cos 2 θ ⋅ σ max + sin 2 θ ⋅ σ min = cos 2 θ ⋅ σμθθ
R2D= ( cosθ- péchéθpéchéθcosθ)
partir duquel on obtient immédiatement cos 2 θ = μ - σ mincos2θ ⋅ σmax+ péché2θ ⋅ σmin= cos2θ ⋅ σmax+ ( 1 - cos2θ ) ⋅ σmin= μ ,
cos2θ = μ - σminσmax- σmin.
- Le premier composant est maintenant terminé, il a la variance .μ
- Passez à la paire suivante, en prenant le composant avec la plus grande variance et celui avec la plus petite variance. Allez à # 2.
( k - 1 )R
Exemple
S2/ (n-1)
⎛⎝⎜⎜⎜dix000060000300001⎞⎠⎟⎟⎟.
5
51 + ( 10 - 5 ) = 6
53 + ( 6 - 5 ) = 4
54 + ( 6 - 1 ) = 5
Terminé.
J'ai écrit le script Matlab qui implémente cet algorithme (voir ci-dessous). Pour cette matrice d'entrée, la séquence des angles de rotation est:
48.1897 35.2644 45.0000
Variations des composants après chaque étape (en lignes):
10 6 3 1
5 6 3 6
5 5 4 6
5 5 5 5
La matrice de rotation finale (produit de trois matrices de rotation 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
Voici le code:
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
Voici le code en Python fourni par @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σ2jek