FA:根据“简单结构标准”选择旋转矩阵

时间:2010-01-26 13:44:01

标签: algorithm matlab r factor-analysis

使用因子分析的一个最重要的问题是它的解释。因子分析通常使用因子旋转来增强其解释。在满意的旋转之后,旋转因子加载矩阵 L'将具有表示相关矩阵的相同能力,并且它可以用作因子加载矩阵,而不是未旋转矩阵 L < /强>

旋转的目的是使旋转因子加载矩阵具有一些理想的属性。使用的方法之一是旋转因子加载矩阵,使旋转的矩阵具有简单结构

升。 L.瑟斯顿介绍了简单结构原理,作为因子轮换的一般指南:

简单结构标准:

  1. 因子矩阵的每一行应包含至少一个零
  2. 如果有多个共同因素,则因子矩阵的每列应至少具有m个零
  3. 对于因子矩阵中的每对列,应该有几个变量,其中一个列中的条目接近零而另一个列中没有
  4. 对于因子矩阵中的每对列,当有四个或更多因素时,很大一部分变量应该在两列中的条目接近零
  5. 对于因子矩阵中的每对列,两列中只应有少量非零条目的变量
  6. 理想的简单结构是:

    1. 每个项目仅在一个因素和
    2. 上具有高或有意义的加载
    3. 每个因素仅对某些项目有很高或有意义的负载。
    4. 问题在于,尝试几种旋转方法组合以及每种方法接受的参数(特别是对于倾斜的参数),候选矩阵的数量增加,很难看出哪一种更符合上述标准。

      当我第一次遇到这个问题时,我意识到我无法通过“看”它们来选择最佳匹配,而我需要一个算法来帮助我做出决定。在项目截止日期的压力下,我能做的最多就是在MATLAB中编写以下代码,它一次接受一个旋转矩阵并返回(在某些假设下)是否满足每个标准。 一个新版本(如果我试图升级它)会接受一个3d矩阵(一组2d矩阵)作为参数,算法应该返回一个更符合上述标准的算法。

      我只是在征求你的意见(我也认为这个方法本身的用处受到了批评),也许还有更好的方法来解决旋转矩阵选择问题。如果有人想提供一些代码,我更喜欢R或MATLAB。

      P.S。上述Simple Structure Criteria formulation可以在PETT,M.,LACKEY,N.,SULLIVAN,J。的“理解因子分析”一书中找到。

      PS2(来自同一本书):“成功因子分析的测试是它可以重现原始corr矩阵的程度。如果你也使用了倾斜解决方案,在所有选择产生的最高和最低要素负荷的最大数量。“ 这听起来像算法可以使用的另一个约束。

      function [] = simple_structure_criteria (my_pattern_table)
      %Simple Structure Criteria
      %Making Sense of Factor Analysis, page 132
      
      disp(' ');
      disp('Simple Structure Criteria (Thurstone):');
      disp('1. Each row of the factor matrix should contain at least one zero');
      disp( '2. If there are m common factors, each column of the factor matrix should have at least m zeros');
      disp( '3. For every pair of columns in the factor matrix, there should be several variables for which entries approach zero in the one column but not in the other');
      disp( '4. For every pair of columns in the factor matrix, a large proportion of the variables should have entries approaching zero in both columns when there are four or more factors');
      disp( '5. For every pair of columns in the factor matrix, there should be only a small number of variables with nonzero entries in both columns');
      disp(' ');
      disp( '(additional by Pedhazur and Schmelkin) The ideal simple structure is such that:');
      disp( '6. Each item has a high, or meaningful, loading on one factor only and');
      disp( '7. Each factor have high, or meaningful, loadings for only some of the items.');
      
      disp('')
      disp('Start checking...')
      
      %test matrix
      %ct=[76,78,16,7;19,29,10,13;2,6,7,8];
      %test it by giving: simple_structure_criteria (ct)
      
      ct=abs(my_pattern_table);
      
      items=size(ct,1);
      factors=size(ct,2);
      my_zero = 0.1;
      approach_zero = 0.2;
      several = floor(items / 3);
      small_number = ceil(items / 4);
      large_proportion = 0.30;
      meaningful = 0.4;
      some_bottom = 2;
      some_top = floor(items / 2);
      
      % CRITERION 1
      disp(' ');
      disp('CRITERION 1');
      for i = 1 : 1 : items
          count = 0;
          for j = 1 : 1 : factors
              if (ct(i,j) < my_zero)
                  count = count + 1;
                  break
              end
          end
          if (count == 0)
              disp(['Criterion 1 is NOT MET for item ' num2str(i)])
          end
      end
      
      
      % CRITERION 2
      disp(' ');
      disp('CRITERION 2');
      for j = 1 : 1 : factors 
          m=0;
          for i = 1 : 1 : items
              if (ct(i,j) < my_zero)
                  m = m + 1;
              end
          end
          if (m < factors)
              disp(['Criterion 2 is NOT MET for factor ' num2str(j) '. m = ' num2str(m)]);
          end
      end
      
      % CRITERION 3
      disp(' ');
      disp('CRITERION 3');
      for c1 = 1 : 1 : factors - 1
          for c2 = c1 + 1 : 1 : factors
              test_several = 0;
              for i = 1 : 1 : items
                  if ( (ct(i,c1)>my_zero && ct(i,c2)<my_zero) || (ct(i,c1)<my_zero && ct(i,c2)>my_zero) ) % approach zero in one but not in the other
                      test_several = test_several + 1;
                  end
              end
              disp(['several = ' num2str(test_several) ' for factors ' num2str(c1) ' and ' num2str(c2)]);
              if (test_several < several)
                  disp(['Criterion 3 is NOT MET for factors ' num2str(c1) ' and ' num2str(c2)]);
              end
          end
      end
      
      % CRITERION 4
      disp(' ');
      disp('CRITERION 4');
      if (factors > 3)
          for c1 = 1 : 1 : factors - 1
              for c2 = c1 + 1 : 1 : factors
                  test_several = 0;
                  for i = 1 : 1 : items
                      if (ct(i,c1)<approach_zero && ct(i,c2)<approach_zero) % approach zero in both
                          test_several = test_several + 1;
                      end
                  end
                  disp(['large proportion = ' num2str((test_several / items)*100) '% for factors ' num2str(c1) ' and ' num2str(c2)]);
                  if ((test_several / items) < large_proportion)
                      pr = sprintf('%4.2g',  (test_several / items) * 100 );
                      disp(['Criterion 4 is NOT MET for factors ' num2str(c1) ' and ' num2str(c2) '. Proportion is ' pr '%']);
                  end
              end
          end
      end
      
      % CRITERION 5
      disp(' ');
      disp('CRITERION 5');
      for c1 = 1 : 1 : factors - 1
          for c2 = c1 + 1 : 1 : factors
              test_number = 0;
              for i = 1 : 1 : items
                  if (ct(i,c1)>approach_zero && ct(i,c2)>approach_zero) % approach zero in both
                      test_number = test_number + 1;
                  end
              end
              disp(['small number = ' num2str(test_number) ' for factors ' num2str(c1) ' and ' num2str(c2)]);
              if (test_number > small_number)
                  disp(['Criterion 5 is NOT MET for factors ' num2str(c1) ' and ' num2str(c2)]);
              end
          end
      end
      
      % CRITERION 6
      disp(' ');
      disp('CRITERION 6');
      for i = 1 : 1 : items
          count = 0;
          for j = 1 : 1 : factors
              if (ct(i,j) > meaningful)
                  count = count + 1;
              end
          end
          if (count == 0 || count > 1)
              disp(['Criterion 6 is NOT MET for item ' num2str(i)])
          end
      end
      
      % CRITERION 7
      disp(' ');
      disp('CRITERION 7');
      for j = 1 : 1 : factors 
          m=0;
          for i = 1 : 1 : items
              if (ct(i,j) > meaningful)
                  m = m + 1;
              end
          end
          disp(['some items = ' num2str(m) ' for factor ' num2str(j)]);
          if (m < some_bottom || m > some_top)
              disp(['Criterion 7 is NOT MET for factor ' num2str(j)]);
          end
      end
      disp('')
      disp('Checking completed.')
      return
      

1 个答案:

答案 0 :(得分:1)

我知道这不是你所要求的,但即使在其他情况下你也可能觉得这很有用:

MATLAB只应在真正不可避免的情况下使用循环。例如,你的代码

%// CRITERION 6
disp(' ');
disp('CRITERION 6');
for i = 1 : 1 : items
    count = 0;
    for j = 1 : 1 : factors
        if (ct(i,j) > meaningful)
            count = count + 1;
        end
    end
    if (count == 0 || count > 1)
        disp(['Criterion 6 is NOT MET for item ' num2str(i)])
    end
end

应该写成

%// CRITERION 6
disp(' ');
disp('CRITERION 6');
ct_lg_meaningful = sum(ct > meaningful,2)   %// check where ct>meaningful, and sum along 2nd axis - gives a column vector of number of times each row was larger than meaningful.
criteria_not_met = find((ct_lg_meaningful == 0)|(ct_lg_meaningful>1))   %// in this vector find elements that are 0 or >1
if length(criteria_not_met)>0   %// if we found any elements, display them.
    disp(['Criterion 6 is NOT MET for items ' num2str(criteria_not_met')])   %' <- to fix SO syntax highlighting
end