因子分析: 変量に対する最小2乗法
簡単な解説とプログラム(実行形式ファイルとソースコードファイル)
因子分析は、因子という潜在変数の1次式によってデータ(変量)の変動を説明するモデルであり、次式(1)
(1)
によって表わされ、多くのものが提案されている。よく用いられるものとして、主因子解および最尤法による解があげられる。主因子解では、残差項の独立性の仮定のもとで、相関係数の対角要素を共通性の推定値で置き換えたものに対して最小2乗法の基準で解が求められる。最尤法では、多変量正規分布に従うという仮定の下で最尤法を適用して、相関行列から解が求められる。これらに対して、残差項の独立性あるいは多変量正規分布などの仮定をおくことなく直接(1)式に最小2乗法を適用する方法がある(Okamoto (2005),"On the Special Type of Principal Component Analysis: It should belong to factor analysis")。この方法をここでは因子分析の直接最小2乗解と呼んでおく。
直接最小2乗解では次式
(2)
を最小にするものとして因子の値と因子パターンAを求める。これらは、行列に対する特異値分解による近似として求めることができる(岡本安晴(2009)「統計学を学ぶための数学入門[下]」培風館; Pp. 100 – 101 参照)。すなわち、データを行列
で、因子得点を行列
で、因子パターンを行列
で表わすとき、次式
(3)
を最小にするFとAは、Xの特異値分解
から求めることができる。いま、因子分析における慣例に従い、データは、平均値0、分散1に標準化されているものとする(本ウェブサイトに用意されているプログラムでは、素データを入力として読み込み、プログラム内で素データの標準化を行っている)。また、因子得点も平均値0、分散1に標準化されたものを求めるものとする。このとき、FとAは次式で与えられる。
(4)
ここで、、、は、特異値分解において特異値の大きいものに対応するものを、、からq組を選んだものである。
プログラムでは
SVD( x, rnk, U, V, lambda ); // 特異値分解
と特異値分解を行って、
for (int i = 0; i < p; i++)
for (int j = 0; j < q; j++)
A[i][j] = V[i][j] * lambda[j][0] /
Math::Sqrt(n); // パターン行列
for (int i = 0; i < n; i++)
for (int j = 0; j < q; j++)
F[i][j] = U[i][j] * Math::Sqrt(n); // 因子得点
とパターン行列Aと因子得点行列Fを求めている。
式(3)を最小にするものとして与えられる式(4)の値は、Xの主成分分析から得られる式と同じである。しかし、数式の表面的な類似性から実質科学的解釈を行うことは危険である。物理学において、数式の表面的類似に基づいて議論を展開することの危険が指摘されている(サイフェ(著)・林大(訳)「宇宙を復号する」早川書房,2007、p. 100)。因子分析の場合の因子は潜在変数として想定されているものであり、主成分分析における主成分は射影によって得られる(別の観点からいえば重み付き)合成量であるという実質科学的に異なる性質の量であることに注意しなければならない。
なお、次元を圧縮する最適な正射影を求めるという観点からの主成分分析の説明は、別のウェブサイトで行っている。
プログラムfa_lse.exeは、式(2)すなわち式(3)の値を最小にするものとして因子の値と因子パターンAを求めるものである。プログラムは.NET Framework3.5対応の実行形式のファイルであるので、ファイル名fa_lse.exeをクリックしてダウンロード・実行することができる。実行すると図1のフォームが表示される。
図1
ラジオボタンは、「PrintData」にチェックが入っていると、読み込んだデータがファイルに出力される。出力されたファイルを見ることによって、データが正しく読み込まれているか確認することができる。因子数は、求める因子の数qを設定する。rはプロマックス回転におけるパラメータである。通常はでよいが、他の値を試すこともできる。「GO」ボタンをクリックすると、図1のフォームに設定された条件で因子分析が行われる。まず、入力データファイル名の設定を求めるダイアログウィンドウが表示される(図2)。
図2
入力データファイルは、以下のような形式で用意する。
======================= 入力データファイルの例 ===========================
No of variables = 12
/
12
ID Var_1 Var_12 Var_2 Var_11 Var_3 Var_10 Var_4 Var_9 Var_5 Var_8 Var_6 Var_7
1
0.290
-2.523 0.779 -2.322 0.310 -2.796 0.968 0.253 0.144 0.102 0.198 0.222
2 -1.271 -1.003 -1.378 -0.841 -1.137 -0.968 -1.398 -1.635 -1.294 -1.836 -1.897 -1.979
3
0.553
-0.180 0.135 0.213 0.948 -0.177 0.796 0.750 0.551 0.630 0.959 0.887
4
0.090
-0.799 0.363 -1.224 -0.150 -0.817 -0.157 1.176 -0.073 1.087 1.184 1.251
5
1.476
0.398
1.480
0.715
1.397
0.634
1.235
0.439
1.425 0.661 0.434 0.741
・
・
・
198 0.203 0.569 0.198 1.006 0.169 0.603 0.135 -3.055 0.179 -3.449 -3.113 -3.456
199 0.114 0.309 -0.231 0.429 0.362 0.525 0.180 0.901 0.148 1.131 0.935 1.378
200 -0.785 0.851 -0.682 1.054 -1.269 0.721 -0.650 -0.184 -0.773 -0.698 -0.428 -0.833
/
======================== 入力データファイルの例 =========================
データは、スラッシュ「/」で始まる行で挟む。最初のスラッシュ「/」で始まる行の次の行に、因子分析を行うデータの変量の数pを書く。次の行に各変量のラベルを空白で区切って書く。データはその次の行から、1行に1ケースのデータを書いていく。各行の第1変量はデータのケース番号を書く。このケース番号は分析には用いられないが、データの入力を解りやすくするための番号である。また、ケース番号は文字列として読み込まれているので、英字などを含んだ「abc123」のようなものでもよい。ケース番号は区切り文字を含まないものであるが、区切り文字は次のコードで指定されている。
array<wchar_t> ^ separator = { ' ', '\t', ',',' ','/' };
詳しい説明は<岡本安晴「大学生のための心理学VC++プログラミング入門」勁草書房、p. 209 >を参照されたい。
各ケースのデータの変量の値は2番目から書く。データの最終行の次の行は、スラッシュ「/」で始まる行を置く。この2つのスラッシュで始まる行で挟まれた部分以外はプログラムでは無視されるのでコメントなどを書くことができる。
図2の入力ファイル名を設定するダイアログウィンドウでファイル名を設定して「開く」ボタンをクリックすると、次に出力ファイル名の設定を求めるダイアログウィンドウが表示される(図3)。
図3
適当なテキストファイル名を設定して「保存」ボタンをクリックする。「保存」ボタンをクリックすると計算が始まり、計算が終了すると計算結果を出力ファイルに保存したことを知らせるダイアログウィンドウが表示される(図4)。
図4
図4の「OK」ボタンのクリックでプログラムの実行が終了する。実行後、出力ファイルを開くと以下のようになっている。
まず、入力ファイル名が出力されている。
Data File =
F:\yasuharu\www\LaCoocan\VCpp\fa_lse\fa_lse\fa_lse\DataCor200.txt
入力ファイル名の出力に続いて、スラッシュで始まる行まで、読み込んだ行がそのまま出力されている。
No of variables = 12
/
次に、読み込んだ変量名と読み込んだケース数nが出力される。変量名の順序は、データを作成するときに昇順と降順が混在するように作成されている。これは、プログラムの出力においてパターン行列が見やすくなるように並べ替えが行われているかどうかをチェックするためである。入力データファイルでの変量名の並びがわざと入れ替えた形になっているということである。変量Var_1からVar_5までが1つのグループ、Var_6からVar_9までが第2グループ、Var_10からVar_12までが第3グループとなるようにデータが作成されている。バリマックス回転およびプロマックス回転後のパターン行列の出力が、これらのグループごとにまとめられて出力されることを確認する。
Vars = Var_1 Var_12 Var_2 Var_11 Var_3 Var_10 Var_4 Var_9 Var_5 Var_8 Var_6 Var_7
n = 200
各変量の平均値と標準偏差が出力される。
mean sd
Var_1
0.036 1.331
Var_12
0.002
1.101
Var_2
0.059
1.320
Var_11
0.001
1.093
Var_3
0.050
1.299
Var_10
0.009
1.098
Var_4
0.059
1.330
Var_9
0.076
1.466
Var_5
0.056
1.338
Var_8
0.094
1.467
Var_6
0.096
1.477
Var_7
0.108
1.455
eigen
valueとして、特異値の2乗をケース数nで割った値が出力される。これは、和が変量の数になるように調整したもので、各特異値に対応する因子がデータの変動量の説明率になるようにしたものである。
Eigen values...
Eigen value(1) = 6.60509
Eigen value(2) = 2.91881
Eigen value(3) = 2.26891
Eigen value(4) = 0.03812
Eigen value(5) = 0.03225
Eigen value(6) = 0.02605
Eigen value(7) = 0.02282
Eigen value(8) = 0.02133
Eigen value(9) = 0.01857
Eigen value(10) = 0.01807
Eigen value(11) = 0.01561
Eigen value(12) = 0.01436
Sum = 12
特異値分解から算出される因子パターン が出力される。
因子パターン
Factor-1 Factor-2 Factor-3
Var_1
0.89775 0.09664 -0.41142
Var_12 -0.12354 0.97822 0.08995
Var_2
0.89048 0.09503 -0.42421
Var_11 -0.11485 0.97908 0.08148
Var_3
0.89666 0.10057 -0.41168
Var_10 -0.10794 0.97612 0.10273
Var_4
0.89231 0.09724 -0.41959
Var_9
0.79888 -0.04203 0.58815
Var_5
0.90163 0.09262 -0.40007
Var_8
0.79975 -0.00994 0.58979
Var_6
0.80070 -0.03397 0.58648
Var_7
0.79623 -0.03071 0.59252
上のパターンをバリマックス回転(直交回転)したものが次に出力される。
バリマックス回転後の因子パターン
Factor-1 Factor-2 Factor-3 Communalities
Var_2
-0.96507 0.22384 -0.02196
0.98195
Var_4
-0.96392 0.22852 -0.01943
0.98174
Var_1
-0.96301 0.23830 -0.01961
0.98456
Var_3
-0.96283 0.23730 -0.01566
0.98360
Var_5 -0.95849 0.24970 -0.02272
0.98156
Var_7
-0.24756 0.96107 -0.03265
0.98601
Var_8
-0.25465 0.96049 -0.01263
0.98755
Var_9
-0.25086 0.95968 -0.04454
0.98589
Var_6
-0.25434 0.95926 -0.03687 0.98623
Var_12
0.02591 -0.03788 0.98902
0.98026
Var_11
0.01383 -0.03907 0.98829
0.97844
Var_10
0.02198 -0.01809 0.98702
0.97502
Contri.
4.889
3.968
2.936
バリマックス回転は、次のようにクラス型VariMaxによって行っている。
VariMax Rot( A, p, q, commu, Contri );
Rot.Rotate(); // バリマックス回転
この回転後のパターンは、見やすくするために以下のコードで並べ替えられている。
/*** 因子の並べ替え ***/
for (int j = 0; j
< q-1; j++){
int k = j;
for (int j1 = j+1; j1
< q; j1++)
if (Contri[k] < Contri[j1])
k
= j1;
if (j < k){
swap(
Contri[j], Contri[k] );
for (int j1 = 0; j1
< p; j1++)
swap(
F[j1][j], F[j1][k] );
}
}
/*** 変数の並べ替え ***/
for (int i = 0; i
< p-1; i++){
int k = i;
for (int j = i+1; j
< p; j++)
if (RhLargerLh(j, k)) k = j;
if (i < k){
SwapString(
VLabel[i], VLabel[k] );
for (int j1 = 0; j1
< q; j1++)
swap(
F[i][j1], F[k][j1] );
swap(
h[i], h[k] );
}
}
バリマックス回転の次に、プロマックス回転(斜交回転)されたパターン行列と因子相関行列が出力される。
プロマックス回転後の因子パターン
Factor-1 Factor-2 Factor-3
Var_2
-0.99542 -0.00987 -0.00242
Var_4 -0.99287 -0.00433 0.00023
Var_3
-0.98924 0.00576 0.00426
Var_1
-0.98910 0.00670 0.00034
Var_5
-0.98087 0.02037 -0.00250
Var_7
0.00040 0.99310 -0.00100
Var_8
-0.00782 0.99118 0.01913
Var_9
-0.00345 0.99033 -0.01291
Var_6
-0.00750 0.98918 -0.00520
Var_12
0.00412 -0.00539 0.98949
Var_11 -0.00947 -0.00993 0.98888
Var_10
0.00542 0.01532 0.98812
因子相関行列...
Factor-1 Factor-2 Factor-3
Factor-1
1.00000 -0.47012
0.04764
Factor-2
-0.47012
1.00000 -0.06804
Factor-3
0.04764 -0.06804
1.00000
プロマックス回転は次のようにクラス型ProMaxによって行っている。
ProMax promax( Rot.Ftemp, p, q, r );
promax.Rotate(); // プロマックス回転
プログラムについての詳しい内容はソースコードを参照されたい。ソースコードファイルなどは圧縮ファイルfa_lse.zipとしてまとめた。圧縮ファイル名fa_lse.zipをクリックしてダウンロードすることができる。ダウンロードした圧縮ファイルは、Windows VistaあるいはWindows7の場合は、マウスの右ボタンクリックで表示されるメニュから「展開」あるいは「解凍」を選んで解凍することができる。解凍したファイルはVisual C++2008などで開くことができる。
岡本安晴 作