对我来说,还不是很清楚,您要问的是您真正需要的是什么:机器学习中一个常见的预处理步骤是降维+白化,这意味着进行PCA和标准化组件,仅此而已。但是,尽管如此,我还是将重点放在您的问题上,因为它更有趣。
令为中心的n × d数据矩阵,其中数据点在行中,变量在列中。PCA达奇异值分解X = û 小号V ⊤听,说:ü ķ 小号 ķ V ⊤ ķ,其中执行所述维数降低我们只保留ķ组件。这些组件中的一个正交“旋转因子”意味着选择一个正交ķ × ķ矩阵[R ,并将其插入到分解:X ≈ ù ķ 小号 ķ VXn×d
X=USV⊤≈UkSkV⊤k,
kk×kR这里
√X≈UkSkV⊤k=UkRR⊤SkV⊤k=n−1−−−−−√U⊤kRRotatedstandardized scores⋅R⊤SkV⊤k/n−1−−−−−√Rotated loadings⊤.
是旋转的标准化分量,第二项表示转置的旋转载荷。旋转后每个分量的方差由相应的载荷矢量的平方和得出。在旋转之前,它只是
s 2 i /(n-1)。旋转后,还有其他事情。
n−1−−−−−√UkRs2i/(n−1)
现在我们准备用数学术语来表达这个问题:给定非旋转载荷,求出旋转矩阵R,使旋转的载荷LR在每一列中具有相等的平方和。L=VkSk/n−1−−−−−√RLR
让我们解决它。旋转后平方列总和等于的对角元素这是有道理的:根据该公式,旋转只是简单地重新分配了组件之间的方差,这些方差最初由s 2 i /(n−1)给出。我们需要重新分配它们,以使它们都等于其平均值μ。
(LR)⊤大号R=R⊤S2ñ−1R.
s2一世/(n−1)μ
我认为没有封闭的解决方案,实际上有许多不同的解决方案。但是,可以按顺序轻松地构建解决方案:
- 取第一个分量和第个分量。所述第一个具有方差σ 最大 > μ和最后一个具有方差σ 分钟 < μ。ķσ最高>μσ分< μ
- 仅旋转这两个,以使第一个的方差等于。2D旋转矩阵仅取决于一个参数θ,因此很容易写下等式并计算必要的θ。事实上,- [R 2D = (COS θ 罪θ - 罪θ COS θ)和变换后的第一PC将获得方差COS 2 θ &CenterDot;&σ 最大 + 罪2 θ &CenterDot;&σ 分钟 = COS 2 θ &CenterDot;&σμθθ
[R2D= (cosθ− 罪θ罪θcosθ)
从中我们立即获得 COS 2 θ = μ - σ 分钟cos2θ⋅σmax+sin2θ⋅σmin=cos2θ⋅σmax+(1−cos2θ)⋅σmin=μ,
cos2θ=μ−σminσmax−σmin.
- 现在完成第一个分量,它具有方差。μ
- 继续进行下一对,选择方差最大的组件和方差最小的组件。转到#2。
(k−1)R
例
S2/(n−1)
⎛⎝⎜⎜⎜10000060000300001⎞⎠⎟⎟⎟.
5
51+(10−5)=6
53+(6−5)=4
54+(6−1)=5
做完了
我编写了实现此算法的Matlab脚本(请参见下文)。对于此输入矩阵,旋转角度的顺序为:
48.1897 35.2644 45.0000
每个步骤后的组件差异(以行为单位):
10 6 3 1
5 6 3 6
5 5 4 6
5 5 5 5
最终旋转矩阵(三个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
(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
这是代码:
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
这是@feilong提供的Python代码:
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σ2ik