因子旋转的理论基础
- 1. varimax 方法
- 1.1 varimax的理论基础
- 1.2 varimax的缺点
- 2. promax方法
- 2.1 promax方法的理论基础
- 3. Transformation of correlated factors using a pattern matrix
- 4. MATLAB 实现
写本博客的目的是:在使用varimax方法时不知道原理到底是什么?查了好多教材和网上的资料,都没有具体的理论推导,无法真正理解此方法的内核计算。最后终于在factor analysis as a statistical method书中的chapter6找到相关内容,并进行整理,最后给出相关matlab代码。
1. varimax 方法
1.1 varimax的理论基础
在varimax旋转方法出现之前,通常使用旋转的图形方法,目的是消除负的因子载荷(loading)并且尽可能少的非0因子载荷来描述数据。但这种方法具有一定的主观性。
varimax方法与图形方法在某种程度上具有相似的特点。 与原始的因子载荷相比,用这种方法对因子进行旋转得到的新的因子载荷要么相对大要么相对小。正如我们所看到的,这种旋转的方法是通过最大化loading的平方的一个特定函数并且迭代完成的。在Kaiser’s的原始旋转方法中,因子是成对地旋转(两个两个的旋转)直到loadings收敛到最终值。下面我们描述的是"The simultaneously factor varimax solution"(同时因子varimax解),显然,这个方法的最主要特点是在每一次迭代时,所有因子同时被旋转,并非Kaiser’s的成对成对地旋转。它比原始的varimax方法更快,并且没有累积的舍入误差(因为原始方法是成对旋转的)。
将 矩阵 看做是未旋转的因子载荷,则的第列(即 的第行)是一个维的列向量,用表示。 定义是一个的正交旋转矩阵,它的第th列用。新的旋转的因子载荷矩阵,可以通过如下计算:
因此,
定义一个标量:
表示的是的第th列的因子载荷的平方和。
在同时varimax方法中的标准被最大化,形式如下:
从这个定义中,我们可以看出:代表的是与其对应的列均值的偏差平方和。这个的最大化与有关。因为是正交阵,所以它的列满足如下条件:
使用拉格朗日乘子的方法,表达式如下:
系数代表的是不确定的乘子,且.
对关于求导并令其等于0,求解如下:
其中,
经检查发现:是下面矩阵的第th列:
其中,是一个矩阵,其元素为,是的对称矩阵,且元素为,
是对角矩阵,对角元为.因此将的所有值都考虑进去,有:
其中,
因此,最大化的正交矩阵满足如下等式:
可以证明:如果是正定的,由于也是对称的,那么上述的等式对应于的一个最大值。对上式左乘一个,有:
因此,当被最大化时,等式右边应该是对称矩阵。的第th个对角元为:
基于的定义,我们发现:就是的最大值。
满足的,和可以通过迭代获得。我们首先用一个近似的初始矩阵,这将产生一个初始的近似。并且,从中,我们获得,和的近似,和,x现在我们来求对称和正定矩阵和第二个正交旋转矩阵:
注意对上述方程的等式两边分别左乘自己的转置矩阵,有如下等式:
现在,是的对称和正定矩阵,因此我们可以用如下形式来表示:,其中是正交矩阵,且是具有正的对角元素的对角矩阵。因此我们可以用以下形式来表示:
则为:
然后用替代,在对上述程序进行重复,我们会得到一个的矩阵序列。可以证明:当与充分接近时,序列收敛到。且对应的矩阵序列,它的是不断上升并且最终达到一个稳定值,这个稳定值便是标准的最大值。
在实际中,选择一个好的的初始近似并不是必须的,通常情况下, 并且,通常只需要很少的几次迭代就可以了。
Horst建议,在最大化过程开始时,最好对原始的因子载荷矩阵按行标准化,这样每一个行向量就被尺度化为单位长度了。在最大化结束时,当获得后,最终的也需要重新按照行进行标准化,这样communalities的值才是正确的。
1.2 varimax的缺点
varimax有两个主要的缺点:
- 第一个缺点:如果在旋转过程中加入其他额外的因子,则通过varimax方法获得的因子载荷的pattern可能会发生很大的变化。
- 第二个缺点:当在因子中出现一个非常重要的一般因子(general factor)情况下,varimax方法可能并不work;
2. promax方法
在许多情况下,因子载荷的pattern可以通过进一步将因子转化为倾斜或者是相关的因子来进一步简化。可是这种简化需要付出一定的代价因为我们必须估计因子之间的相关系数,在对结果进行解释时也必须考虑这些因素。最终,人们的注意力转向了分析标准的发现,这些标准可以用来产生唯一的、不那么主观的解。有很多这样的方法,我们集中注意力介绍promax方法,因为它在实际中似乎效果更好。
2.1 promax方法的理论基础
promax方法的起始以varimax旋转的结果为起始。假设varimax方法产生的loadings是,并且构造另外一个的矩阵,它的元素按如下公式定义:
其中,是满足的某个整数。因此:如果则 ,否则,和有相同的符号和相同的绝对值。
现在,我们向寻找一个变换矩阵(此矩阵不必是正交的),对于,的第列与的第列在最小二乘的意义上保持最大的一致性。一般来说,是当loadings相对较大时,的目的使其更大;当loadings相对较小时,使其更小。
值的选择是一个反复试错的过程,但经验证明当简化loadings的pattern时,m大于4经常生成高度相关的因子,这在实际中是不被期望的。
将 和的第列分别表示为 和。然后,对于每一个,我们选择的使其最小化以下的表达式:
上式关于求导得到:
令其等于0得到:
因此,考虑所有的,有:
事实上,重新尺度化的列是非常方便的,以至于转换后的因子具有单位方差。这可以通过找对角矩阵来实现,且它的对角元素是正的,且满足:
代替的变换矩阵为:
转换的因子载荷矩阵为:
所以基于上述讨论有以下公式:
其中,
是变换矩阵的协方差矩阵。由的定义,很明显,具有单位对角元素,因此是新因子(被标准化后)的相关矩阵。
3. Transformation of correlated factors using a pattern matrix
4. MATLAB 实现
function [B,T] = rotateFactors(A,varargin)
if nargin > 1
[varargin{:}] = convertStringsToChars(varargin{:});
end
names = {'method' 'normalize' 'reltol' 'maxit'};
dflts = {'varimax' [] [] []};
[method,normalize,reltol,maxit] = internal.stats.parseArgs(names, dflts, varargin{:});
methodNames = {'varimax'};
[method,~] = internal.stats.getParamVal(method,methodNames,'Method');
switch method
case 'varimax'
[B, T] = varimax(A, normalize, reltol, maxit);
end
end
%-----------------------------------------------------------------------
function [B, T] = varimax(A, normalize, reltol, maxit)
% VARIMAX method of orthogonal rotation of FA or PCA loadings.
[d, m] = size(A);
% Defaults to normalized varimax rotation
if nargin < 2 || isempty(normalize), normalize = 'on'; end
if nargin < 3 || isempty(reltol), reltol = sqrt(eps(class(A))); end
if nargin < 4 || isempty(maxit), maxit = 250; end
% Normalize the factor loadings
switch normalize
case {'on',1}
h = sqrt(sum(A.^2, 2));
A = bsxfun(@rdivide, A, h);
case {'off',0}
% A = A;
otherwise
error(message('stats:rotatefactors:BadNormalize'));
end
T = eye(m); % the intial rotation matrix is identity.
R = zeros(m); % the coefficient matrix
converged = false;
for n = 1:maxit
Aold = A;
A = Aold * T;
D = sum(A.^2,1); % the sum of square of the column of B
C = A.^3;
P = Aold'*(C-(1/d).*A.*D);
[U,L] = svd(P'*P);
Rold = R;
R = U.*sqrt(diag(L))'*U';
T = P/R;
if (trace(R)-trace(Rold)< reltol)
B = A;
converged = true;
break;
end
end
if ~converged
error(message('stats:rotatefactors:IterationLimit'));
end
% Unnormalize the rotated loadings
switch normalize
case {'on',1}
B = bsxfun(@times, B, h);
end
end