特異値分解と主成分分析 (1)
ー MATLAB 版
ベータ版 3.0
早稲田大学教育・総合科学学術院 新井仁之
概要
今回は特異値分解を主成分分析に応用する.前回の「特異値分解のアルゴリズムと次元圧縮」(URLは本ノート末尾参照)の続編である。特異値分解による主成分分析についての数学の解説は
新井仁之,線形代数 基礎と応用,日本評論社,2006
の第17章「多変量解析と線形代数」を元にしている.
本ノートはMATLABのライブエディターを使用して作成した.
必要な用語解説
をデータからなる行列とする.ここで N は個体数(観測対象)の個数であり,p は変量(観測値)の個数である.たとえばある学校(あるいはクラス)の生徒の成績をイメージしてほしい.ここで N は生徒数 p は教科数, は学生番号 j の生徒の科目 k の点数を表す. 変量 k の平均値を とおき, とおく. とおく. を平均偏差行列という. を分散共分散行列という. とおくと となっている. また,相関係数 を用いて を相関係数行列という. データ X(:,j) と X(:,k) は相関係数 が 1 に近いときに相関は強いといい, のとき相関はないという. とおき, を X の標準得点行列という.標準化したものは,各変量の平均が 0 であり,相関係数行列は変わらない. 標準化したデータ行列の分散共分散行列は元のデータの標準化係数行列と一致している.
相関係数行列と分散共分散行列には次の関係式がある.
平均偏差行列,分散共分散行列,相関係数行列,標準得点行列の計算
% 平均偏差行列(mean deviation matrix)
% 分散共分散行列(variance-covariance matrix)
A = (1/size(M,1))*(M')*M;
% 相関係数行列(correleation matrix)
% MATLAB には corrcoef(X) がある.
A(j,k) = S(j,k)/(sqrt(S(j,j))*sqrt(S(k,k)));
Y = MDmatrix(X)*MD_CR(X);
コメント:このうち,相関係数行列に関しては MATLAB の corrcoef があるが,それと上記の CRmatrix は同じであることを確認する.
たとえば次のデータ行列 X を考える.
disp(char('CRmatrix(X) = ', num2str(CRmatrix(X))));
CRmatrix(X) =
1 0.90113
0.90113 1
disp(char('corrcoef(X) = ', num2str(corrcoef(X))));
corrcoef(X) =
1 0.90113
0.90113 1
データの標準化の具体例
データ行列としては前掲の X を考える.
disp(char('X の標準化 = ', num2str(stand(X))));
X の標準化 =
0.56195 1.069
0.84293 0.26726
-1.4049 -1.3363
disp(char('X の標準化の変量の平均 = ', num2str(mean(XS))));
標準化したデータ行列の分散共分散行列は元のデータの標準化係数行列と一致している
disp(char('X の標準化の分散共分散行列 = ', num2str(VCmatrix(XS))));
X の標準化の分散共分散行列 =
1 0.90113
0.90113 1
disp(char('X の相関係数行列 = ', num2str(CRmatrix(X))));
X の相関係数行列 =
1 0.90113
0.90113 1
特異値分解による主成分ベクトル
X を 行列で,N は個体数,p は変量の数とする.もしデータの単位などが不揃いの場合は,標準化したデータを考えていく.X の分散共分散行列( 標準化したデータの場合の分散共分散行列は元データの相関係数行列)の特異値分解をする. N 次ユニタリー行列 U と p 次ユニタリー行列 V により,その特異値標準形が により与えられる. の場合を考える. を の特異値とする., とする.このとき特異値分解は で与えられる.
を第 k 主成分(第 k 主成分ベクトル), を固体 n の第k主成分得点という. を第 k 主成分の寄与率, を第 k 主成分までの累積寄与率という.一般には累積寄与率が 80%を超えるような k までの主成分を考慮することが望ましいとされている.
具体例の計算
次の仮想的な成績のデータで試してみよう.
testkekka.xlsx (readtableで読み込んだものを下に表示する)
なおこれは数学的に作った架空の数値データで,実在の学校・個人とは一切関係ない.
データは,50人の架空の人たちの 架空の学生番号,数学,物理,アート,英語の点数からなっている.
filename = 'Score.xlsx'; % ここは自分の好きなデータを使う.
% その場合はこのセクションはデータの形態に合わせて変更
Score = readtable(filename,"TextType","string","VariableNamingRule","preserve")
Score = 50×5 table
| Student_ID | Mathematics | Physics | Art | English |
---|
1 | 1 | 44 | 93 | 79 | 100 |
---|
2 | 2 | 86 | 100 | 86 | 44 |
---|
3 | 3 | 89 | 100 | 70 | 77 |
---|
4 | 4 | 70 | 80 | 76 | 91 |
---|
5 | 5 | 30 | 100 | 84 | 53 |
---|
6 | 6 | 45 | 28 | 64 | 100 |
---|
7 | 7 | 21 | 40 | 64 | 58 |
---|
8 | 8 | 88 | 0 | 71 | 96 |
---|
9 | 9 | 65 | 45 | 62 | 81 |
---|
10 | 10 | 83 | 55 | 94 | 75 |
---|
11 | 11 | 42 | 47 | 86 | 17 |
---|
12 | 12 | 100 | 100 | 81 | 88 |
---|
13 | 13 | 100 | 43 | 90 | 53 |
---|
14 | 14 | 56 | 46 | 85 | 34 |
---|
15 | 15 | 27 | 72 | 70 | 6 |
---|
16 | 16 | 40 | 43 | 98 | 77 |
---|
17 | 17 | 61 | 86 | 80 | 81 |
---|
18 | 18 | 58 | 58 | 84 | 14 |
---|
19 | 19 | 40 | 100 | 89 | 72 |
---|
20 | 20 | 69 | 91 | 70 | 49 |
---|
21 | 21 | 48 | 47 | 70 | 77 |
---|
22 | 22 | 22 | 93 | 69 | 17 |
---|
23 | 23 | 52 | 98 | 78 | 86 |
---|
24 | 24 | 58 | 97 | 87 | 59 |
---|
25 | 25 | 90 | 1 | 70 | 100 |
---|
26 | 26 | 36 | 53 | 79 | 30 |
---|
27 | 27 | 63 | 9 | 76 | 51 |
---|
28 | 28 | 68 | 100 | 68 | 46 |
---|
29 | 29 | 0 | 79 | 70 | 100 |
---|
30 | 30 | 72 | 61 | 75 | 100 |
---|
31 | 31 | 31 | 34 | 87 | 55 |
---|
32 | 32 | 50 | 48 | 75 | 79 |
---|
33 | 33 | 100 | 49 | 79 | 100 |
---|
34 | 34 | 100 | 92 | 84 | 75 |
---|
35 | 35 | 85 | 78 | 77 | 72 |
---|
36 | 36 | 55 | 100 | 89 | 9 |
---|
37 | 37 | 34 | 66 | 89 | 0 |
---|
38 | 38 | 72 | 0 | 69 | 100 |
---|
39 | 39 | 53 | 98 | 79 | 100 |
---|
40 | 40 | 21 | 99 | 75 | 78 |
---|
41 | 41 | 60 | 73 | 62 | 59 |
---|
42 | 42 | 34 | 87 | 68 | 53 |
---|
43 | 43 | 93 | 68 | 86 | 100 |
---|
44 | 44 | 46 | 71 | 79 | 100 |
---|
45 | 45 | 80 | 65 | 74 | 100 |
---|
46 | 46 | 44 | 28 | 73 | 100 |
---|
47 | 47 | 61 | 45 | 93 | 90 |
---|
48 | 48 | 65 | 0 | 69 | 2 |
---|
49 | 49 | 51 | 81 | 68 | 27 |
---|
50 | 50 | 100 | 50 | 78 | 100 |
---|
各科目の平均点
mean(Score(:,["Mathematics" "Physics" "Art" "English"]))
ans = 1×4 table
| Mathematics | Physics | Art | English |
---|
1 | 59.1600 | 63.9400 | 77.5600 | 66.6200 |
---|
各教科の最低点(Min),中央値(Median),最高点(Max)
summary(Score(:,2:end))
Variables:
Mathematics: 50×1 double
Values:
Min 0
Median 58
Max 100
Physics: 50×1 double
Values:
Min 0
Median 67
Max 100
Art: 50×1 double
Values:
Min 62
Median 77.5
Max 98
English: 50×1 double
Values:
Min 0
Median 76
Max 100
個人の平均点を計算して表に付加
Score.Average = round(mean(Score{:,2:5},2),1) %小数点2桁目を四捨五入
Score = 50×6 table
| Student_ID | Mathematics | Physics | Art | English | Average |
---|
1 | 1 | 44 | 93 | 79 | 100 | 79 |
---|
2 | 2 | 86 | 100 | 86 | 44 | 79 |
---|
3 | 3 | 89 | 100 | 70 | 77 | 84 |
---|
4 | 4 | 70 | 80 | 76 | 91 | 79.3000 |
---|
5 | 5 | 30 | 100 | 84 | 53 | 66.8000 |
---|
6 | 6 | 45 | 28 | 64 | 100 | 59.3000 |
---|
7 | 7 | 21 | 40 | 64 | 58 | 45.8000 |
---|
8 | 8 | 88 | 0 | 71 | 96 | 63.8000 |
---|
9 | 9 | 65 | 45 | 62 | 81 | 63.3000 |
---|
10 | 10 | 83 | 55 | 94 | 75 | 76.8000 |
---|
11 | 11 | 42 | 47 | 86 | 17 | 48 |
---|
12 | 12 | 100 | 100 | 81 | 88 | 92.3000 |
---|
13 | 13 | 100 | 43 | 90 | 53 | 71.5000 |
---|
14 | 14 | 56 | 46 | 85 | 34 | 55.3000 |
---|
15 | 15 | 27 | 72 | 70 | 6 | 43.8000 |
---|
16 | 16 | 40 | 43 | 98 | 77 | 64.5000 |
---|
17 | 17 | 61 | 86 | 80 | 81 | 77 |
---|
18 | 18 | 58 | 58 | 84 | 14 | 53.5000 |
---|
19 | 19 | 40 | 100 | 89 | 72 | 75.3000 |
---|
20 | 20 | 69 | 91 | 70 | 49 | 69.8000 |
---|
21 | 21 | 48 | 47 | 70 | 77 | 60.5000 |
---|
22 | 22 | 22 | 93 | 69 | 17 | 50.3000 |
---|
23 | 23 | 52 | 98 | 78 | 86 | 78.5000 |
---|
24 | 24 | 58 | 97 | 87 | 59 | 75.3000 |
---|
25 | 25 | 90 | 1 | 70 | 100 | 65.3000 |
---|
26 | 26 | 36 | 53 | 79 | 30 | 49.5000 |
---|
27 | 27 | 63 | 9 | 76 | 51 | 49.8000 |
---|
28 | 28 | 68 | 100 | 68 | 46 | 70.5000 |
---|
29 | 29 | 0 | 79 | 70 | 100 | 62.3000 |
---|
30 | 30 | 72 | 61 | 75 | 100 | 77 |
---|
31 | 31 | 31 | 34 | 87 | 55 | 51.8000 |
---|
32 | 32 | 50 | 48 | 75 | 79 | 63 |
---|
33 | 33 | 100 | 49 | 79 | 100 | 82 |
---|
34 | 34 | 100 | 92 | 84 | 75 | 87.8000 |
---|
35 | 35 | 85 | 78 | 77 | 72 | 78 |
---|
36 | 36 | 55 | 100 | 89 | 9 | 63.3000 |
---|
37 | 37 | 34 | 66 | 89 | 0 | 47.3000 |
---|
38 | 38 | 72 | 0 | 69 | 100 | 60.3000 |
---|
39 | 39 | 53 | 98 | 79 | 100 | 82.5000 |
---|
40 | 40 | 21 | 99 | 75 | 78 | 68.3000 |
---|
41 | 41 | 60 | 73 | 62 | 59 | 63.5000 |
---|
42 | 42 | 34 | 87 | 68 | 53 | 60.5000 |
---|
43 | 43 | 93 | 68 | 86 | 100 | 86.8000 |
---|
44 | 44 | 46 | 71 | 79 | 100 | 74 |
---|
45 | 45 | 80 | 65 | 74 | 100 | 79.8000 |
---|
46 | 46 | 44 | 28 | 73 | 100 | 61.3000 |
---|
47 | 47 | 61 | 45 | 93 | 90 | 72.3000 |
---|
48 | 48 | 65 | 0 | 69 | 2 | 34 |
---|
49 | 49 | 51 | 81 | 68 | 27 | 56.8000 |
---|
50 | 50 | 100 | 50 | 78 | 100 | 82 |
---|
平均点のヒストグラム
histogram(Score.Average,10)
主成分分分析
X = table2array(Score(:,2:5));
[Sigma, U, V]=SingNormal(X); % 前回の特異値分解のレクチャーで作った特異値標準形を使う.
% もちろんMATLAB の svd を使っても良い.
主成分ベクトルの表示
disp(char(['第',num2str(j),'主成分ベクトル'], num2str(V(:,j))));
end
第1主成分ベクトル
0.41056
-0.48254
-0.028703
0.77316
第2主成分ベクトル
0.11919
0.86853
0.032773
0.47998
第3主成分ベクトル
0.9003
0.10029
0.099132
-0.4118
第4主成分ベクトル
-0.081852
-0.052566
0.99412
0.047564
寄与率と累積寄与率の計算
Kiyo = zeros(length(Sigma),1);
Ruiseki_Kiyo = zeros(length(Sigma),1);
Kiyo(j)=Sigma(j)^2/sum(Sigma.^2);
disp(['第',num2str(j),'主成分寄与率 =',num2str(Kiyo(j))]);
end
第1主成分寄与率 =0.44855
第2主成分寄与率 =0.33504
第3主成分寄与率 =0.18841
第4主成分寄与率 =0.028006
disp(['第',num2str(j),'累積寄与率 =',num2str(Ruiseki_Kiyo(j))]);
end
第1累積寄与率 =0.44855
第2累積寄与率 =0.78359
第3累積寄与率 =0.97199
第4累積寄与率 =1
平均値による順位(order_avg),第一主成分得点(fristPC),第二主成分得点(secondPC),第三主成分得点(thirdPC)を表に付加.
Score_avg = sortrows(Score,6,'descend');
a = table2array(Score_avg(:,1));
[~,p] = sort(a,'ascend');
Score.order_avg = p; %平均点による順位
Score.firstPC = PCAdata(:,1); %第1主成分得点
Score.secondPC = PCAdata(:,2); %第2主成分得点
Score.thirdPC = PCAdata(:,3); %第3主成分得点
Score_sub = Score(:,["Student_ID" "Average" "order_avg" "firstPC" "secondPC" "thirdPC"])
Score_sub = 50×6 table
| Student_ID | Average | order_avg | firstPC | secondPC | thirdPC |
---|
1 | 1 | 79 | 10 | 5.5202 | 39.5015 | -24.3372 |
---|
2 | 2 | 79 | 11 | -24.1119 | 23.9375 | 37.9320 |
---|
3 | 3 | 84 | 4 | 3.0933 | 39.6100 | 25.4574 |
---|
4 | 4 | 79.3000 | 9 | 15.5954 | 26.8913 | 1.1755 |
---|
5 | 5 | 66.8000 | 25 | -40.0874 | 21.5173 | -16.3891 |
---|
6 | 6 | 59.3000 | 38 | 37.7261 | -17.3252 | -31.4427 |
---|
7 | 7 | 45.8000 | 48 | -10.3905 | -29.9225 | -34.5508 |
---|
8 | 8 | 63.8000 | 28 | 65.5976 | -38.2094 | 6.8031 |
---|
9 | 9 | 63.3000 | 30 | 23.1016 | -9.3617 | -4.1059 |
---|
10 | 10 | 76.8000 | 16 | 20.1088 | -0.3622 | 18.7454 |
---|
11 | 11 | 48 | 46 | -37.4775 | -40.2981 | 4.1222 |
---|
12 | 12 | 92.3000 | 1 | 15.7985 | 46.5614 | 31.9213 |
---|
13 | 13 | 71.5000 | 21 | 15.9840 | -19.4490 | 41.5100 |
---|
14 | 14 | 55.3000 | 40 | -18.0747 | -31.3711 | 9.5263 |
---|
15 | 15 | 43.8000 | 49 | -63.7448 | -26.1769 | -3.9314 |
---|
16 | 16 | 64.5000 | 27 | 9.6767 | -14.8185 | -21.5980 |
---|
17 | 17 | 77 | 14 | 1.1587 | 26.3611 | -1.8109 |
---|
18 | 18 | 53.5000 | 41 | -38.4785 | -30.3428 | 20.6673 |
---|
19 | 19 | 75.3000 | 17 | -21.4353 | 31.9927 | -14.7147 |
---|
20 | 20 | 69.8000 | 23 | -22.4236 | 15.9701 | 18.0792 |
---|
21 | 21 | 60.5000 | 35 | 11.8347 | -11.3085 | -16.7701 |
---|
22 | 22 | 50.3000 | 43 | -67.3974 | -3.2868 | -10.9557 |
---|
23 | 23 | 78.5000 | 12 | -4.4035 | 38.0451 | -10.9673 |
---|
24 | 24 | 75.3000 | 18 | -22.5913 | 25.2272 | 6.3449 |
---|
25 | 25 | 65.3000 | 26 | 69.0575 | -35.2154 | 6.9576 |
---|
26 | 26 | 49.5000 | 45 | -32.5841 | -29.7918 | -6.7252 |
---|
27 | 27 | 49.8000 | 44 | 16.0550 | -54.8076 | 4.2249 |
---|
28 | 28 | 70.5000 | 22 | -29.4390 | 22.1622 | 19.1187 |
---|
29 | 29 | 62.3000 | 33 | -5.5306 | 21.8029 | -66.2466 |
---|
30 | 30 | 77 | 15 | 32.5718 | 14.9148 | -2.7347 |
---|
31 | 31 | 51.8000 | 42 | -6.3693 | -34.6280 | -22.6341 |
---|
32 | 32 | 63 | 32 | 13.5761 | -9.0778 | -15.1972 |
---|
33 | 33 | 82 | 6 | 49.7431 | 7.9607 | 21.6667 |
---|
34 | 34 | 87.8000 | 2 | 9.5216 | 33.4717 | 36.7698 |
---|
35 | 35 | 78 | 13 | 8.0001 | 17.8552 | 22.4028 |
---|
36 | 36 | 63.3000 | 31 | -63.9860 | 3.5417 | 24.7332 |
---|
37 | 37 | 47.3000 | 47 | -63.1600 | -32.8110 | 6.1233 |
---|
38 | 38 | 60.3000 | 37 | 62.1787 | -38.2620 | -9.4471 |
---|
39 | 39 | 82.5000 | 5 | 6.8026 | 44.9168 | -15.7331 |
---|
40 | 40 | 68.3000 | 24 | -23.7126 | 31.2807 | -35.7793 |
---|
41 | 41 | 63.5000 | 29 | -9.4718 | 3.8016 | 3.2603 |
---|
42 | 42 | 60.5000 | 36 | -31.7130 | 10.1788 | -15.6778 |
---|
43 | 43 | 86.8000 | 3 | 37.5001 | 23.8579 | 17.9640 |
---|
44 | 44 | 74 | 19 | 16.9571 | 20.6323 | -24.7430 |
---|
45 | 45 | 79.8000 | 8 | 33.9548 | 19.3096 | 4.7697 |
---|
46 | 46 | 61.3000 | 34 | 37.0572 | -17.1494 | -31.4508 |
---|
47 | 47 | 72.3000 | 20 | 27.5280 | -4.5026 | -8.3402 |
---|
48 | 48 | 34 | 50 | -16.4649 | -86.1345 | 24.6072 |
---|
49 | 49 | 56.8000 | 39 | -41.9404 | -5.4857 | 9.7323 |
---|
50 | 50 | 82 | 7 | 49.2893 | 8.7965 | 21.6679 |
---|
補足
以下は前回のレクチャー「特異値分解のアルゴリズムと次元圧縮」より必要なコマンド
Lemma. 足りない正規直交系を補完して正規直交基底にするアルゴリズム
% Q は Nxp 配列,ただし N>=p (行数 >= 列数)である必要がある.
% Q(:,1),...,Q(:,p) は正規直交系になるようにしておく.
% A は NxN 配列で,A(:,1),...,A(:,N)は正規直交基底であり,かつ A(:,k)=Q(:,k), 1<=k<=p
% Q は正規直交系でない場合,Q の部分も合わせて直交化される.
disp('入力配列の列数が行数を超えてます.')
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function Q = GramSchmidt(A)
v = v - (Q(:, j)' * A(:, i)) * Q(:, j);
特異値標準形を与えるアルゴリズム
以上の準備のもとに特異値標準系を与えるアルゴリズムを記す.このアルゴリズム自体は線形代数でよく知られたものである.(たとえば [1] 参照.)
function [Sigma, U, W]=SingNormal(A)
% Sigma は A の特異値 min(M,N)x1 配列
% U,W は U'*A*W が特異値標準形を与えるユニタリー行列
[Sigma,p] = sort(Sigma,'descend');
U1(:,k)=Sigma(k)^(-1)*A*VV(:,k);
参考文献
[1] 新井仁之,線形代数 基礎と応用,日本評論社,2006. Kindle版(2022年版)があります.
履歴
ベータ版 1.1 2024/7/19 公開
ベータ版 2.0 2024/7/20 不十分な箇所をいくつか修正及び補足の追加
ベータ版 3.0 2024/8/2 minor changes