- 技術 💻
主成分分析(PCA)とは|手順・寄与率・負荷量の読み方をPythonで実演
結論
主成分分析(PCA)とは、たくさんの変数を、情報をなるべく残したまま少ない数の新しい軸にまとめる方法です。軸は分散が最大になる向きに順に取ります。
この記事でわかること
- 手順4つの手計算と、scikit-learnとの一致確認
- 寄与率・負荷量・得点の読み方と5科目の実例
- 標準化なしで第1主成分が変わる実測と決め方4種
主成分分析は「そろえる → 関係を表にする → 軸を求める → 何本使うか決める → 新しい軸で表す」の順に進みます。この記事では、10人の5科目のテストの点を例に、全部の手順を実際に計算します。
flowchart TD
A[元のデータ<br>10人 × 5科目] --> B[標準化<br>平均0・標準偏差1]
B --> C[相関行列<br>5 × 5]
C --> D[固有値分解<br>固有値と固有ベクトル]
D --> E[寄与率を見て<br>主成分の数を決める]
E --> F[主成分得点<br>10人 × 2]
急いでいる人向けに、よく調べられることの答えを先にまとめます。
| 知りたいこと | 答え | 詳しい節 |
|---|---|---|
| 主成分分析とは | 多くの変数を少ない軸に要約する次元削減 | 主成分分析とは |
| 寄与率 | その主成分が持つ情報(分散)の割合 | 読み方 |
| 累積寄与率の目安 | 70〜80%がよく使われる。例は2本で84.7% | 主成分の数 |
| 主成分負荷量 | 変数と主成分得点の相関。名前付けに使う | 読み方 |
| 標準化は必要? | 単位やばらつきが違うなら必要 | 標準化 |
| Python で1行 | PCA().fit_transform(StandardScaler().fit_transform(X)) |
Python |
| 因子分析との違い | PCAは要約、因子分析は背後の要因を推定 | 違い |
| t-SNE・UMAPとの違い | PCAは線形で軸に意味がある。新データにも使える | 違い |
確認環境:Ubuntu 24.04・Python 3.11.15・NumPy 2.4.6・scikit-learn 1.9.1(UMAP の実行のみ umap-learn 0.5.12・scikit-learn 1.8.0・NumPy 2.4.4)。10人×5科目のデータで、標準化から主成分得点までを NumPy で手順どおりに計算し、scikit-learn の PCA と一致することを確かめました。標準化の有無、外れ値、主成分の数の決め方(平行分析は乱数5000回)、因子分析・t-SNE・UMAP との比較(手書き数字 1797件×64次元)も実行し、出力をそのまま載せています。関数の仕様は scikit-learn 1.9.1・umap-learn の公式ドキュメント、R の prcomp のマニュアル、IBM SPSS Statistics の FACTOR コマンドのリファレンスで、歴史は Wikipedia「主成分分析」で確かめました(確認日 2026年10月22日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「主成分分析(PCA)とは|手順・寄与率・負荷量の読み方をPythonで実演」
主成分分析(PCA)とは(考え方を図で)
この節では、主成分分析が「何を、どうまとめているのか」が分かります。
主成分分析(しゅせいぶんぶんせき、英語 Principal Component Analysis、略して PCA)は、たくさんの変数を、それらを組み合わせた少数の新しい変数(主成分)に置きかえて、データを要約する方法です。 変数の数を減らすので、次元削減(じげんさくげん)の代表的な方法として使われます。
この記事では、次の10人の5科目のテストの点(100点満点)を例に使います。
| 生徒 | 国語・社会・英語 | 数学・理科 |
|---|---|---|
| A | 62・61・67 | 70・51 |
| B | 57・62・64 | 77・75 |
| C | 72・63・64 | 68・61 |
| D | 54・50・45 | 42・44 |
| E | 65・67・68 | 63・67 |
| F | 60・60・60 | 74・75 |
| G | 57・54・58 | 51・58 |
| H | 62・68・65 | 59・63 |
| I | 67・67・62 | 52・59 |
| J | 62・64・65 | 53・63 |
5科目を並べただけでは、10人の違いをひと目でつかめません。主成分分析をすると、5つの点数が次の2つの軸にまとまりました(計算の中身は後の節で全部見せます)。
flowchart TD
IN[国語・社会・英語・数学・理科<br>5つの点数] --> P1[第1主成分<br>総合力 62.2%]
IN --> P2[第2主成分<br>理系か文系か 22.5%]
P1 --> OUT[2本の軸で<br>情報の84.7%]
P2 --> OUT
- 第1主成分:5科目すべてに同じ向きの重みがかかった軸で、「総合力」と読めます。5科目の情報(分散)の62.2%を持っています。
- 第2主成分:数学・理科がプラス、国語・社会がマイナスの軸で、「理系寄りか文系寄りか」と読めます。情報の22.5%を持っています。
2つの軸だけで、5科目の情報の84.7%を表せました。5次元のデータを2次元に減らしても、情報の8割以上が残ったことになります。
「分散が最大になる向き」とは
主成分分析の軸は、データを投影(まっすぐ下ろす)したときに、点のばらつき(分散)がいちばん大きくなる向きに取ります。ばらつきが大きい向きほど、人と人の違いがよく表れるためです。
- 第1主成分:分散が最大になる向き。
- 第2主成分:第1主成分と直交する(直角に交わる)向きの中で、分散が最大になる向き。
- 第3主成分以降も同じで、変数の数だけ主成分が取れます。
主成分どうしは直交しているので、主成分得点どうしの相関は0になります(後の計算でも 0 になりました)。同じ情報を二重に数えない軸の組み、ということです。
主成分分析が使われる場面
1データを2次元で見る
変数が多いデータを第1・第2主成分の散布図にして、似たものの集まりや外れたものを目で探す。顧客・商品・アンケートの分類によく使う。
2指標を1つにまとめる
5科目から「総合力」、複数の満足度の質問から「総合満足度」のように、重み付きの合計を1本作る。重みはデータから決まる。
3機械学習の前処理
特徴量を減らして学習を軽くする、互いに相関の強い変数(多重共線性)をまとめる。主成分を説明変数に使う回帰は主成分回帰(PCR)と呼ぶ。
4画像・センサー・異常検知
画素やセンサーの値を少数の主成分で表し、ノイズを減らす。主成分で復元できない残りが大きいデータを異常として見つける。
Wikipedia によると、主成分分析は1901年にピアソンが導入し、1930年代にホテリングが独立に導入して「主成分分析」と名付けました。分野によって、カルーネン・レーベ変換(KL 変換)、ホテリング変換、固有直交分解(POD)とも呼ばれます。
主成分分析でわかること(固有値・寄与率・主成分負荷量・主成分得点)
この節では、主成分分析の結果に出てくる言葉の意味と、それぞれが何を答えてくれるのかが分かります。
主成分分析の結果は「固有値・寄与率」「固有ベクトル・主成分負荷量」「主成分得点」の3組で読みます。 それぞれ「その軸はどれくらい大事か」「その軸は何を表すか」「各データはその軸のどこにいるか」に答えます。
| 言葉 | 意味 | 答えてくれる疑問 |
|---|---|---|
| 固有値(λ、ラムダ) | その主成分の分散の大きさ | 何本目まで大事か |
| 寄与率 | 固有値 ÷ 固有値の合計 | 全体の何%を表すか |
| 累積寄与率 | 第1主成分からの寄与率の合計 | 何本でどれだけ残るか |
| 固有ベクトル(主成分の係数) | 各変数にかける重み。長さ1 | 得点をどう計算するか |
| 主成分負荷量 | 変数と主成分得点の相関係数 | その軸は何を表すか |
| 主成分得点 | 各データの新しい軸での位置 | 誰がどこにいるか |
| 共通性 | 使う主成分での負荷量の二乗和 | その変数はどれだけ表せたか |
固有ベクトルと主成分負荷量は似ていますが、別のものです。主成分負荷量 = 固有ベクトル × √固有値 の関係があり、負荷量は −1〜1 の相関係数として読めるので、軸の意味を考えるときは負荷量を使うのが一般的です。ライブラリによっては固有ベクトルを「loadings」と呼ぶことがあるので、どちらが出ているかを確かめます。
主成分分析の手順(標準化→共分散行列→固有値分解→主成分得点)
この節では、主成分分析の計算を4つの手順に分けて、それぞれ何をしているのかが分かります。
標準化する
変数ごとに「(値 − 平均) ÷ 標準偏差」を計算し、平均0・標準偏差1にそろえる。単位やばらつきの違いを消すため。
共分散行列を作る
標準化したデータの共分散行列を作る。標準化した後なので、これは相関行列と同じになる(5変数なら5×5)。
固有値分解する
R v = λ v を満たす固有値 λ と固有ベクトル v を求め、λ の大きい順に並べる。順に第1・第2…主成分。
主成分得点を出す
標準化したデータに固有ベクトルを掛けて、各データの新しい軸での位置を出す。使う本数は寄与率などで決める。
式を文字で書くと次のとおりです(n はデータの数、p は変数の数)。
① 標準化 zij = ( xij − 変数jの平均 ) ÷ 変数jの標準偏差
② 相関行列 R = Zᵀ Z ÷ (n − 1) … p × p の行列
③ 固有値分解 R vk = λk vk … λ1 ≥ λ2 ≥ … ≥ λp
寄与率k = λk ÷ (λ1 + … + λp) … 標準化した場合、合計は p
④ 主成分得点 tik = zi1·v1k + zi2·v2k + … + zip·vpk
主成分負荷量 ljk = vjk × √λk
「なぜ固有ベクトルが分散最大の向きなのか」を一言でいうと、向き v(長さ1)に投影した得点の分散は vᵀ R v で、これを最大にする v が R の最大の固有値の固有ベクトル、最大値がその固有値になるためです。だから「固有値 = その主成分得点の分散」になります。
2変数で手計算する(数学と理科)
この節では、変数が2つのときの主成分分析を、手で最後まで計算する方法が分かります。
変数が2つで標準化した場合、相関係数を r とすると、固有値は 1 + r と 1 − r、固有ベクトルは (1/√2, 1/√2) と (1/√2, −1/√2) になります。 10人の数学と理科で確かめます。
平均と偏差
数学の平均 60.9、理科の平均 61.6。偏差(値 − 平均)は、数学が 9.1・16.1・7.1・−18.9…、理科が −10.6・13.4・−0.6・−17.6…。
相関係数 r
偏差の積の和 679.6、数学の偏差の二乗和 1168.9、理科の偏差の二乗和 834.4。r = 679.6 ÷ √(1168.9 × 834.4) = 0.6881。
固有値を解く
相関行列は [[1, r], [r, 1]]。(1 − λ)² − r² = 0 を解くと λ = 1 ± r で、1.6881 と 0.3119。
寄与率と得点
寄与率は 1.6881 ÷ 2 = 84.4% と 15.6%。B さんの z は (1.413, 1.392) で、第1主成分得点は (1.413 + 1.392) ÷ √2 = 1.983。
NumPy で同じ計算をすると、手計算と同じ値になりました。
Σ偏差積 679.6 Sm 1168.9 Ss 834.4 r 0.688141172608958
固有値 [1.68814117 0.31185883]
固有ベクトル [[ 0.70710678 -0.70710678]
[ 0.70710678 0.70710678]]
B さんの z [1.41272767 1.39167846] 第1主成分得点 1.9830145916574011 得点の分散 1.6881411726089581
第1主成分は「数学と理科を同じ重みで足した値」、第2主成分は「数学と理科の差」です。 得点の分散 1.6881 が固有値と一致していることも確かめられます。相関が強いほど(r が1に近いほど)第1主成分の寄与率が上がり、2つの変数を1本にまとめやすくなります。
5科目のデータで主成分分析をNumPyで計算する
この節では、5変数の主成分分析を、前の4つの手順どおりに NumPy で計算したコードと、その全出力が分かります。
変数が3つ以上になると、固有値を手で解くのは大変なので、固有値分解だけを np.linalg.eigh(対称行列用)に任せます。それ以外は手順どおりです。
import numpy as np
cols = ["国語", "社会", "英語", "数学", "理科"]
X = np.array([
[62, 61, 67, 70, 51], [57, 62, 64, 77, 75], [72, 63, 64, 68, 61],
[54, 50, 45, 42, 44], [65, 67, 68, 63, 67], [60, 60, 60, 74, 75],
[57, 54, 58, 51, 58], [62, 68, 65, 59, 63], [67, 67, 62, 52, 59],
[62, 64, 65, 53, 63],
], dtype=float)
n, p = X.shape
# ① 標準化(標準偏差は n-1 で割る不偏標準偏差)
mean, sd = X.mean(axis=0), X.std(axis=0, ddof=1)
Z = (X - mean) / sd
# ② 共分散行列(標準化したので相関行列と同じ)
R = Z.T @ Z / (n - 1)
# ③ 固有値分解して、固有値の大きい順に並べる
lam, V = np.linalg.eigh(R)
idx = lam.argsort()[::-1]
lam, V = lam[idx], V[:, idx]
V = V * np.sign(V.sum(axis=0)) # 符号をそろえる(各列の合計を正に)
ratio = lam / lam.sum() # 寄与率
# ④ 主成分得点と主成分負荷量
T = Z @ V # 主成分得点
L = V * np.sqrt(lam) # 主成分負荷量
実行した結果です。
平均 [61.8 61.6 61.8 60.9 61.6]
標準偏差 [ 5.287 5.797 6.63 11.396 9.629]
相関行列 R =
[[1. 0.686 0.595 0.234 0.136]
[0.686 1. 0.839 0.364 0.495]
[0.595 0.839 1. 0.603 0.523]
[0.234 0.364 0.603 1. 0.688]
[0.136 0.495 0.523 0.688 1. ]]
np.corrcoef と一致: True
固有値 λ [3.108 1.126 0.402 0.281 0.083] 合計 5.0
寄与率 [62.2 22.5 8. 5.6 1.7]
累積寄与率 [ 62.2 84.7 92.7 98.3 100. ]
固有ベクトル(列が第1〜第5主成分)
[[ 0.381 -0.59 0.406 0.558 -0.173]
[ 0.498 -0.3 -0.467 -0.114 0.656]
[ 0.523 -0.102 -0.026 -0.623 -0.571]
[ 0.41 0.508 0.653 -0.104 0.368]
[ 0.405 0.542 -0.435 0.525 -0.279]]
V^T V = I: True
R v1 = λ1 v1: True
得点の分散 [3.108 1.126 0.402 0.281 0.083] 得点どうしの相関(PC1,PC2) -0.0
負荷量 = 変数と得点の相関: True
PC1の負荷量の二乗和 = 3.1083
出力から、手順の式が成り立っていることを5つ確かめられます。
- 標準化した後の共分散行列は相関行列と同じ(
np.corrcoefと一致: True)。 - 固有値の合計は変数の数と同じ 5.0。標準化すると各変数の分散が1になり、全体の分散が5になるためです。
- 固有ベクトルは互いに直交し長さ1(VᵀV = I)、R v1 = λ1 v1 を満たす。
- 主成分得点の分散は固有値と同じで、第1・第2主成分得点の相関は0。
- 主成分負荷量は、変数と主成分得点の相関係数と同じ。第1主成分の負荷量の二乗和は固有値 3.108 と同じ。
主成分得点の計算も、A さんで手で確かめました。A さんの標準化した点(z)に、第1主成分の固有ベクトルを掛けて足します。
A さんの z = [ 0.038 -0.103 0.784 0.798 -1.101]
v1 = [ 0.381 0.498 0.523 0.410 0.405]
得点 = 0.038×0.381 + (−0.103)×0.498 + 0.784×0.523 + 0.798×0.410 + (−1.101)×0.405
= 0.2551
行列の作り方や @(行列の積)の書き方は、関連記事「NumPyの使い方 基本一覧|配列の作成・演算・形状変更」で扱っています。
寄与率・累積寄与率・主成分負荷量の読み方
この節では、主成分分析の出力から「何本使うか」「各主成分は何を表すか」「誰がどこにいるか」を読み取る方法が分かります。
寄与率と累積寄与率
寄与率は「その主成分1本で、元のデータの情報(分散)の何%を表せるか」、累積寄与率は「第1主成分から何本か使ったとき、合わせて何%を表せるか」です。 5科目の例では、第1主成分で62.2%、第2主成分までで84.7%、第3主成分までで92.7%でした。
主成分負荷量で、主成分に名前を付ける
主成分そのものには名前が付いていません。負荷量の大きさと符号のパターンを見て、人が意味を読み取ります。
| 科目 | 第1主成分の負荷量 | 第2主成分の負荷量 | 共通性(2本で表せた割合) |
|---|---|---|---|
| 国語 | 0.672 | −0.626 | 0.844 |
| 社会 | 0.878 | −0.318 | 0.873 |
| 英語 | 0.923 | −0.109 | 0.864 |
| 数学 | 0.723 | 0.539 | 0.814 |
| 理科 | 0.714 | 0.575 | 0.840 |
- 第1主成分は、5科目すべてが 0.67〜0.92 のプラスなので、「どの科目も高い人ほど得点が高い」軸、つまり総合力と読めます。
- 第2主成分は、数学・理科がプラス、国語・社会がマイナスなので、「理系科目が文系科目より得意な人ほど得点が高い」軸と読めます。英語は −0.109 で、どちらにもあまり寄っていません。
- 共通性は5科目とも 0.81〜0.87 で、2本の主成分で各科目のばらつきの8割以上を表せています。
負荷量の点を図にすると、文系3科目と理系2科目が上下に分かれる様子が分かります(横が第1主成分、縦が第2主成分の負荷量。図の座標は 0.5 + 負荷量 ÷ 2 に置きかえています)。
---
config:
quadrantChart:
chartWidth: 460
chartHeight: 380
---
quadrantChart
title 主成分負荷量(横 第1主成分・縦 第2主成分)
x-axis 負荷量 マイナス --> 負荷量 プラス
y-axis 文系寄り --> 理系寄り
quadrant-1 総合 プラス・理系寄り
quadrant-2 総合 マイナス・理系寄り
quadrant-3 総合 マイナス・文系寄り
quadrant-4 総合 プラス・文系寄り
国語: [0.836, 0.187]
社会: [0.939, 0.341]
英語: [0.962, 0.446]
数学: [0.862, 0.770]
理科: [0.857, 0.788]
主成分得点で、各データの位置を見る
10人の第1・第2主成分得点です。
| 生徒 | 第1主成分(総合力) | 第2主成分(理系寄り) | 読み取れること |
|---|---|---|---|
| E | 1.487 | −0.335 | 総合力がいちばん高い |
| C | 1.260 | −0.961 | 総合力が高く、文系寄り |
| B | 1.005 | 1.953 | 理系寄りがいちばん強い |
| H | 0.808 | −0.409 | 総合力がやや高い |
| F | 0.626 | 1.649 | 理系寄りが強い |
| I | 0.425 | −1.406 | 文系寄りがいちばん強い |
| A | 0.255 | −0.262 | ほぼ平均 |
| J | 0.248 | −0.469 | ほぼ平均 |
| G | −1.807 | 0.343 | 総合力が低め |
| D | −4.307 | −0.103 | 総合力がいちばん低い |
得点を散布図にしたのが次の図です(スコアプロット。図の座標は、横 0.5 + 得点 ÷ 9、縦 0.5 + 得点 ÷ 4.5 に置きかえています。中央の線が得点0)。
---
config:
quadrantChart:
chartWidth: 460
chartHeight: 380
---
quadrantChart
title 主成分得点(10人)
x-axis 総合力 低い --> 総合力 高い
y-axis 文系寄り --> 理系寄り
quadrant-1 総合力が高く理系寄り
quadrant-2 総合力が低く理系寄り
quadrant-3 総合力が低く文系寄り
quadrant-4 総合力が高く文系寄り
A: [0.528, 0.442]
B: [0.612, 0.934]
C: [0.640, 0.286]
D: [0.021, 0.477]
E: [0.665, 0.426]
F: [0.570, 0.866]
G: [0.299, 0.576]
H: [0.590, 0.409]
I: [0.547, 0.188]
J: [0.528, 0.396]
B と F は右上(総合力が高く理系寄り)、I と C は右下(総合力が高く文系寄り)、D は左端に離れています。 5科目の表からは読み取りにくかった「タイプ」と「外れたデータ」が、2次元の図で見えるようになりました。得点と負荷量の矢印を1枚に重ねた図をバイプロットと呼びます。
得点は平均が0になるので、「0より大きい = 10人の平均より上」 という相対的な位置です。100点満点のような絶対的な意味はありません。
scikit-learnの結果と手計算が一致するか確かめる
この節では、scikit-learn の PCA が手計算と同じものを計算していること、そして数値が少しずれて見える2つの理由が分かります。
from sklearn.decomposition import PCA
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
pipe = make_pipeline(StandardScaler(), PCA())
T_s = pipe.fit_transform(X) # 主成分得点
pca = pipe.named_steps["pca"]
print(pca.explained_variance_) # 固有値
print(pca.explained_variance_ratio_) # 寄与率
print(pca.components_) # 固有ベクトル(行が主成分)
scikit-learn 1.9.1 numpy 2.4.6
explained_variance_ [3.4537 1.2506 0.4471 0.3119 0.0922]
explained_variance_ratio_ [0.6217 0.2251 0.0805 0.0561 0.0166]
components_[0] [0.3813 0.4983 0.5235 0.4102 0.405 ] components_[1] [ 0.5899 0.2996 0.1025 -0.5083 -0.5416]
手計算との符号 [ 1. -1. 1. -1. 1.]
寄与率が一致 : True
固有ベクトルが一致(符号をそろえて): True
固有値の比 sklearn/手計算: [1.1111 1.1111 1.1111 1.1111 1.1111] n/(n-1) = 1.111111
得点の比 sklearn/手計算: [1.0541 1.0541] sqrt(n/(n-1)) = 1.054093
StandardScaler の scale_: [ 5.016 5.4991 6.2897 10.8116 9.1345] (ddof=0)
ddof=0で標準化した手計算と比べた最大差: 固有値 1.3322676295501878e-15 得点 2.6645352591003757e-15
SVD: s**2/(n-1) = [3.4537 1.2506 0.4471 0.3119 0.0922] singular_values_ = [5.5752 3.355 2.006 1.6754 0.9109]
寄与率と固有ベクトルの向きは、手計算と完全に一致しました。 ずれて見えたのは次の2つで、どちらも計算の誤りではありません。
| ずれて見えたもの | 理由 | そろえ方 |
|---|---|---|
| 第2・第4主成分の符号が逆 | 固有ベクトルは −1 を掛けても固有ベクトル。どちらの向きが出るかは計算方法しだい | 負荷量の合計が正になる向きなど、自分で決めてそろえる |
| 固有値が 1.1111 倍(合計が 5 にならず 5.556) | StandardScaler は標準偏差を n で割り(ddof=0)、PCA は分散を n − 1 で割る |
寄与率で比べる。固有値が要るなら explained_variance_ratio_ × 変数の数 |
| 得点が 1.0541 倍 | 上と同じ理由で z が √(n/(n−1)) 倍になる | 同じ標準化をした値どうしで比べる |
標準化を n で割る形(ddof=0)に変えて手計算すると、固有値も得点も差が 1e-15 程度(計算機の丸め誤差)まで一致しました。scikit-learn 1.9.1 のドキュメントは、explained_variance_ は「n_samples − 1 の自由度」を使う、と書いています。固有値1以上で主成分の数を決めるときに explained_variance_ をそのまま見ると、データが少ないほど大きめに出るので注意します。
singular_values_(特異値)の二乗を n − 1 で割ると、explained_variance_ と同じになりました。主成分分析は、相関行列の固有値分解の代わりに、データ行列の特異値分解(SVD)でも計算できます。scikit-learn 1.9.1 の svd_solver='auto' は、ドキュメントによると「変数が1000未満で、データ数が変数の10倍より多い」と covariance_eigh(共分散行列の固有値分解)、500×500 より大きく取り出す数が少ないと randomized、それ以外は full(SVD)を選びます。この例(10件×5変数)は full が選ばれていました。
標準化しないと結果が変わる(共分散行列と相関行列)
この節では、標準化(相関行列)と、標準化なし(共分散行列)で主成分分析の結果がどれくらい変わるかが、実測で分かります。
主成分分析は分散の大きい向きを探すので、標準化しないと、ばらつきの大きい変数に第1主成分が引っぱられます。 5科目の分散は、国語 28.0・社会 33.6・英語 44.0・数学 129.9・理科 92.7 で、数学と理科だけで全体の 328.1 の約7割を占めています。
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
PCA().fit(X - X.mean(axis=0)) # 標準化なし(共分散行列)
PCA().fit(StandardScaler().fit_transform(X)) # 標準化あり(相関行列)
X2 = X.copy(); X2[:, 3] *= 2 # 数学を200点満点に換算
[標準化なし(共分散行列)] 寄与率 [67.9 17. 10.8 3.2 1.1] PC1 [0.134 0.244 0.343 0.704 0.556] PC2 [ 0.541 0.552 0.478 -0.358 -0.214]
[標準化あり(相関行列) ] 寄与率 [62.2 22.5 8. 5.6 1.7] PC1 [0.381 0.498 0.523 0.41 0.405] PC2 [-0.59 -0.3 -0.102 0.508 0.542]
--- 数学を200点満点に換算(×2)
[標準化なし(共分散行列)] 寄与率 [82.7 9.3 6.1 1.5 0.5] PC1 [0.061 0.107 0.181 0.929 0.299] PC2 [ 0.441 0.602 0.515 -0.296 0.302]
[標準化あり(相関行列) ] 寄与率 [62.2 22.5 8. 5.6 1.7] PC1 [0.381 0.498 0.523 0.41 0.405] PC2 [-0.59 -0.3 -0.102 0.508 0.542]
数学の点を2倍(200点満点)にしたとき
標準化なしの結果は、点数の単位(満点の決め方)しだいで変わる
標準化なしでは、第1主成分の重みが数学 0.704・理科 0.556 に偏り、国語は 0.134 しかありませんでした。 「総合力」ではなく「理系科目の点」に近い軸です。さらに数学を200点満点に換算しただけで、数学の重みは 0.929 になりました。標準化した結果は、換算の前後で同じでした。
| 状況 | 使う行列 | 理由 |
|---|---|---|
| 単位が違う(円・人・秒・%) | 相関行列(標準化する) | 単位の大きい変数が勝ってしまう |
| 単位は同じでもばらつきが大きく違う | 相関行列(標準化する) | ばらつきの大きい変数に引っぱられる |
| 同じ単位で、ばらつきの大きさに意味がある(画素の明るさ、同じ通貨の価格など) | 共分散行列(中心化だけ) | ばらつきの違い自体が情報 |
| 迷ったとき | 両方計算して負荷量を比べる | 1つの変数が支配していれば標準化を選ぶ |
ツールの初期設定はまちまちです。 R の prcomp の初期値は center = TRUE, scale. = FALSE(中心化だけで標準化しない)で、マニュアルは一般には標準化が望ましいと書いています。scikit-learn の PCA も中心化だけなので、標準化するなら StandardScaler を前に置きます。
主成分の数の決め方(累積寄与率・固有値1以上・スクリープロット・平行分析)
この節では、主成分を何本使うかを決める4つの基準と、それぞれで結果が違ったときの考え方が分かります。
よく使う基準は「累積寄与率が70〜80%に届くまで」「固有値1以上(カイザー基準)」「スクリープロットの肘」「平行分析」の4つです。 どれも目安で、決まった正解はありません。
---
config:
xyChart:
width: 480
height: 300
---
xychart-beta
title "固有値(棒)・1の線・乱数の95%点(線)"
x-axis "主成分" [PC1, PC2, PC3, PC4, PC5]
y-axis "固有値" 0 --> 3.5
bar [3.108, 1.126, 0.402, 0.281, 0.083]
line [1, 1, 1, 1, 1]
line [2.542, 1.652, 1.139, 0.773, 0.421]
固有値を大きい順に並べた図をスクリープロットと呼びます。5科目では、PC1 から PC2 で大きく下がり、PC3 以降はなだらかです。下がり方が急に緩くなる点(肘)の手前までを使う、というのがスクリープロットの読み方です。
平行分析は、同じ大きさ(10件×5変数)の乱数データで主成分分析を何度も行い、乱数でも出てしまう固有値より大きいものだけを残す方法です。乱数で5000回計算しました。
rng = np.random.default_rng(0)
sims = np.array([np.sort(np.linalg.eigvalsh(np.corrcoef(rng.normal(size=(n, p)), rowvar=False)))[::-1]
for _ in range(5000)])
np.percentile(sims, 95, axis=0) # 乱数の固有値の95%点
実データの固有値 [3.108 1.126 0.402 0.281 0.083]
乱数の固有値 平均 [2.02 1.356 0.897 0.513 0.214]
乱数の固有値 95%点 [2.542 1.652 1.139 0.773 0.421]
平行分析で残す数: 1
カイザー基準(λ≥1)で残す数: 2
累積70%/80%に届く数: 2 2
| 基準 | 決め方 | 5科目の結果 | 注意 |
|---|---|---|---|
| 累積寄与率 | 70〜80%に届くまで | 2本(84.7%) | 目的で変える。前処理なら90〜95%も使う |
| カイザー基準 | 固有値1以上 | 2本(3.108・1.126) | 標準化した場合だけ使える |
| スクリープロット | 肘の手前まで | 2本 | 肘がはっきりしないことがある |
| 平行分析 | 乱数の95%点より大きいもの | 1本 | データが少ないと厳しめになる |
| 解釈できるか | 名前が付けられる本数まで | 2本 | 分析の目的に合うかで決める |
データが10件と少ないので、乱数でも第1固有値の平均が 2.02 になりました。 第2主成分の 1.126 は乱数の平均 1.356 より小さく、「偶然でも出る程度」とも言えます。件数が少ないときは、第2主成分以降の解釈を控えめにします。
scikit-learn では、n_components に 0〜1 の小数を入れると、累積寄与率がその値を超える最小の本数を自動で選びます(svd_solver='full' のとき)。
n_components=2: n_components_=2 累積=0.8468
n_components=0.8: n_components_=2 累積=0.8468
n_components=0.9: n_components_=3 累積=0.9273
n_components='mle': n_components_ = 1
'mle' は、ドキュメントによると Minka の方法で次元を推定する指定で、この例では1本になりました。
Pythonで主成分分析をする(コピペで使える完成版)
この節では、CSV を読んで、寄与率・負荷量・得点を表で出す完成版のスクリプトと、機械学習の前処理に使う書き方が分かります。
CSV から結果の表を出すスクリプト
1列目が名前、2列目以降が数値の CSV を読みます。使うライブラリは NumPy と scikit-learn だけです。
"""CSV(1列目が名前、2列目以降が数値)を主成分分析して、結果を表で出す。
使い方: python pca_report.py scores.csv [累積寄与率のしきい値 0〜1]"""
import csv, sys
import numpy as np
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
path = sys.argv[1]
threshold = float(sys.argv[2]) if len(sys.argv) > 2 else 0.8
with open(path, encoding="utf-8") as f:
rows = list(csv.reader(f))
cols = rows[0][1:]
names = [r[0] for r in rows[1:]]
X = np.array([[float(v) for v in r[1:]] for r in rows[1:]])
Z = StandardScaler().fit_transform(X) # 標準化(平均0・標準偏差1。分母は n)
pca = PCA().fit(Z)
ratio = pca.explained_variance_ratio_
k = int(np.argmax(ratio.cumsum() >= threshold)) + 1 # しきい値に届く主成分の数
# 符号をそろえる(各主成分で、負荷量の合計が正になる向き)
sign = np.sign(pca.components_.sum(axis=1)); sign[sign == 0] = 1
V = pca.components_.T * sign # 列が主成分(固有ベクトル)
lam = ratio * len(cols) # 相関行列の固有値(合計=変数の数)
L = V * np.sqrt(lam) # 主成分負荷量(変数と得点の相関)
T = Z @ V # 主成分得点
print(f"{'':6}" + "".join(f"{'PC'+str(i+1):>8}" for i in range(len(cols))))
print(f"{'固有値':5}" + "".join(f"{v:8.3f}" for v in lam))
print(f"{'寄与率':5}" + "".join(f"{v:8.1%}" for v in ratio))
print(f"{'累積':6}" + "".join(f"{v:8.1%}" for v in ratio.cumsum()))
print(f"\n累積寄与率 {threshold:.0%} 以上になる主成分の数: {k}(固有値1以上: {(lam >= 1).sum()})")
print("\n主成分負荷量")
for c, l in zip(cols, L[:, :k]):
print(f" {c:4}" + "".join(f"{v:8.3f}" for v in l))
print("\n主成分得点(PC1 の高い順)")
for i in np.argsort(-T[:, 0]):
print(f" {names[i]:4}" + "".join(f"{v:8.3f}" for v in T[i, :k]))
scores.csv は、先頭行が 生徒,国語,社会,英語,数学,理科、2行目以降が A,62,61,67,70,51 のような形です。python pca_report.py scores.csv 0.8 の出力です。
PC1 PC2 PC3 PC4 PC5
固有値 3.108 1.126 0.402 0.281 0.083
寄与率 62.2% 22.5% 8.0% 5.6% 1.7%
累積 62.2% 84.7% 92.7% 98.3% 100.0%
累積寄与率 80% 以上になる主成分の数: 2(固有値1以上: 2)
主成分負荷量
国語 0.672 -0.626
社会 0.878 -0.318
英語 0.923 -0.109
数学 0.723 0.539
理科 0.714 0.575
主成分得点(PC1 の高い順)
E 1.568 -0.353
C 1.328 -1.014
B 1.059 2.058
H 0.851 -0.431
F 0.660 1.739
I 0.448 -1.482
A 0.269 -0.276
J 0.261 -0.495
G -1.905 0.362
D -4.540 -0.109
固有値は寄与率 × 変数の数で出しているので、手計算と同じ 3.108 になります。得点は StandardScaler(n で割る標準化)を使っているため、手計算の値の 1.054 倍です(前の節の理由)。並び順や符号の読み方は変わりません。CSV を pandas で読み込む方法は、関連記事「pandasの使い方 逆引き81選|pandas 3.0の実行結果つき」で扱っています。ブラウザで試すなら、関連記事「Google Colabとは|使い方・GPU・料金・制限とエラーの直し方」で扱っています。
2本の主成分から元のデータを復元する
inverse_transform で、2本の主成分から元の5科目の点を戻せます。戻した値と元の値の差が、2本に入りきらなかった情報です。
p2 = make_pipeline(StandardScaler(), PCA(n_components=2)).fit(X)
Xr = p2.inverse_transform(p2.transform(X))
2成分で復元したAさん: [63.1 62.8 62.9 60.6 61.2] 元: [62. 61. 67. 70. 51.]
復元誤差(RMSE, 点): [1.98 1.96 2.32 4.66 3.65]
A さんは「英語と数学が高く、理科だけ低い」という2本の軸では表せない形なので、復元すると平均に近い値になりました。 科目ごとの誤差は国語・社会が約2点、数学が4.66点でした。この「復元できない残り」が大きいデータを探すと、主成分分析を異常検知に使えます。
機械学習の前処理に使う(Pipeline)
scikit-learn に入っている手書き数字のデータ(1797件×64画素)で、標準化 → PCA → ロジスティック回帰をつなぎました。
from sklearn.datasets import load_digits
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
X, y = load_digits(return_X_y=True)
Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.25, random_state=0, stratify=y)
pipe = make_pipeline(StandardScaler(), PCA(n_components=0.95), LogisticRegression(max_iter=5000))
pipe.fit(Xtr, ytr) # 標準化も PCA も学習データだけで fit される
pipe.score(Xte, yte)
PCAなし(64次元) 次元 64 テスト正解率 0.9689 学習 0.03秒
PCA 累積95% 次元 39 テスト正解率 0.9689 学習 0.05秒
PCA 10成分 次元 10 テスト正解率 0.8667 学習 0.08秒
累積95%の39次元では正解率が変わらず、10次元まで減らすと 0.9689 → 0.8667 に下がりました。 主成分分析は正解ラベルを見ずに軸を作るので、分散の小さい方向に分類に必要な情報があると、減らしすぎで失われます。本数は、検証データでの性能を見て決めます。
Pipeline に入れると、fit は学習データだけで標準化と主成分を決め、テストデータは transform だけを通ります。テストデータも含めて先に標準化や PCA をすると、テストの情報が学習に混ざります。
主成分分析のメリット・デメリット(注意点)
この節では、主成分分析の長所と弱点、そして外れ値1つで結果がどれくらい変わるかが分かります。
メリット
変数を減らしても情報の多くが残る(例は2本で84.7%)
2次元・3次元の図にでき、タイプや外れ値が見える
主成分どうしは相関0で、多重共線性を避けられる
計算が速く、答えが(符号を除いて)1つに決まる。新しいデータにも同じ変換を使える
デメリット
捨てた主成分の情報は失われる
主成分の意味は人が読み取る。名前が付かないこともある
直線的(線形)な関係しかとらえられない
標準化の有無・外れ値で結果が大きく変わる
外れ値1つで主成分が変わる
E さんの数学 63 点を、6 点と打ち間違えた場合を計算しました。
[元のデータ] 寄与率 [62.2 22.5 8. ] PC1 [0.381 0.498 0.523 0.41 0.405] PC2 [-0.59 -0.3 -0.102 0.508 0.542]
[Eの数学を6と打ち間違い] 寄与率 [53.9 23.2 14.6] PC1 [0.459 0.574 0.562 0.018 0.379] PC2 [-0.309 -0.123 0.024 0.808 0.485]
1つの打ち間違いで、第1主成分の数学の重みが 0.41 から 0.018 になり、「総合力」の軸から数学が抜け落ちました。 主成分分析は分散(二乗した距離)を使うので、遠く離れた1点の影響を強く受けます。分析の前に、各変数の最小値・最大値と散布図で外れ値を確かめます。
計算の量
主成分分析の計算は、データが n 件・変数が p 個のとき、相関行列(p×p)の固有値分解か、データ行列の SVD です。手書き数字(1797件×64変数)の2成分の計算は 0.0035秒でした。変数がとても多い(画像の全画素、文章の単語数など)ときは、scikit-learn の randomized(乱択 SVD)、IncrementalPCA(少しずつ読み込む)、TruncatedSVD(疎行列)が使えます。
因子分析・t-SNE・UMAPとの違い
この節では、主成分分析とよく比べられる3つの方法の違いが、事実の表と実測で分かります。
| 項目 | 主成分分析(PCA) | 因子分析 | t-SNE | UMAP |
|---|---|---|---|---|
| 目的 | 変数を少ない軸に要約する | 変数の背後の共通の要因を推定する | 似た点を近くに置いて図にする | 似た点を近くに置いて図にする |
| 関係の形 | 線形 | 線形+変数ごとの誤差 | 非線形 | 非線形 |
| 軸の意味 | 負荷量で読める | 回転して読みやすくする | 軸に意味はない | 軸に意味はない |
| 新しいデータ | transform できる |
transform できる |
できない(transform が無い) |
transform できる |
| 結果の再現 | 1つに決まる | 初期値・回転で変わる | 乱数で変わる | 乱数で変わる |
因子分析との違い(5科目で比べる)
主成分分析は「データを要約する軸」を作り、因子分析は「点数の背後にある、目に見えない能力(因子)」を推定します。 scikit-learn のドキュメントは、因子分析のモデルで、変数ごとの誤差の分散をすべて同じと仮定すると(確率的な)主成分分析になる、と説明しています。
同じ5科目で、因子分析(2因子・varimax 回転)を実行しました。
from sklearn.decomposition import FactorAnalysis
fa = FactorAnalysis(n_components=2, rotation="varimax", random_state=0).fit(Z)
因子分析(varimax) 負荷量
国語 [0.702 0.085] 独自分散 0.5
社会 [0.948 0.204] 独自分散 0.061
英語 [0.78 0.479] 独自分散 0.161
数学 [0.189 0.932] 独自分散 0.099
理科 [0.346 0.657] 独自分散 0.449
| 科目 | PCA 第1(総合力) | PCA 第2(理系寄り) | 因子1(文系の力) | 因子2(理系の力) |
|---|---|---|---|---|
| 国語 | 0.672 | −0.626 | 0.702 | 0.085 |
| 社会 | 0.878 | −0.318 | 0.948 | 0.204 |
| 英語 | 0.923 | −0.109 | 0.780 | 0.479 |
| 数学 | 0.723 | 0.539 | 0.189 | 0.932 |
| 理科 | 0.714 | 0.575 | 0.346 | 0.657 |
主成分分析は「総合力」と「理系か文系か」、因子分析(回転あり)は「文系の力」と「理系の力」という分け方になりました。 因子分析には、どの因子でも説明できない「独自分散」(国語は 0.5)が科目ごとに出ます。データを短くまとめたいなら主成分分析、アンケートやテストの背後の要因を探したいなら因子分析、が一般的な使い分けです。IBM SPSS Statistics では、主成分分析は因子分析と同じ FACTOR コマンドで行い、抽出法の既定値が主成分(PC)です(SPSS 23 のリファレンス)。
2組の変数の関係を調べる正準相関分析とも名前が似ています。主成分分析は1組の変数の中で軸を作り、正準相関分析は2組の変数(例:テストの点と生活習慣)の間で相関が最大になる組み合わせを探します。
t-SNE・UMAP との違い(手書き数字で比べる)
手書き数字(1797件×64次元)を2次元にして、4つの方法を比べました。trustworthiness は「2次元で近くにある点が、元の64次元でも近いか」(1が最高、近い5点で計算)、5-NN 正解率は「2次元の座標だけで、近い5点の多数決で数字を当てた割合」です。
digits (1797, 64)
累積50%に必要な主成分の数: 5
累積80%に必要な主成分の数: 13
累積90%に必要な主成分の数: 21
累積95%に必要な主成分の数: 29
2成分の累積寄与率: 0.2851
PCA 時間 0.00秒 trustworthiness 0.830 2次元での5-NN正解率 0.603
FA 時間 1.32秒 trustworthiness 0.799 2次元での5-NN正解率 0.441
t-SNE 時間 6.59秒 trustworthiness 0.995 2次元での5-NN正解率 0.976
元の64次元での5-NN正解率 0.963
UMAP は umap-learn 0.5.12(scikit-learn 1.8.0)で、同じデータ・同じ指標で測りました。
UMAP 時間 4.94秒 trustworthiness 0.990 5-NN 0.976
UMAP transform 新データ: (297, 2)
PCA の時間は表示の桁が足りず 0.00秒になったので、別に測り直すと 0.0035秒でした。
| 方法 | 計算時間 | trustworthiness | 2次元での5-NN 正解率 |
|---|---|---|---|
| PCA | 0.0035秒 | 0.830 | 0.603 |
| 因子分析 | 1.32秒 | 0.799 | 0.441 |
| t-SNE | 6.59秒 | 0.995 | 0.976 |
| UMAP | 4.94秒(初回の JIT コンパイルを除く) | 0.990 | 0.976 |
2次元の図で数字の種類を分けて見せる力は、t-SNE と UMAP が高く、PCA の2成分は累積寄与率が28.5%しかないため 0.603 にとどまりました。 一方で PCA は計算が千倍以上速く、軸に意味があり、新しいデータにも同じ変換を使えます。t-SNE と UMAP は全データで座標を作った後に5-NN を測っているので、正解率は甘めに出ています。
scikit-learn の TSNE には transform が無く、呼ぶと AttributeError: 'TSNE' object has no attribute 'transform' になりました。UMAP は、学習済みのモデルで新しいデータを transform でき、1500件で学習して残り297件を変換すると (297, 2) の座標が返りました。scikit-learn のドキュメントは、変数がとても多いときは t-SNE の前に PCA などで50次元程度に減らすことを強く勧めています。
| やりたいこと | 選ぶ方法 |
|---|---|
| 変数を減らして、各軸の意味も知りたい | 主成分分析 |
| 機械学習の前処理で次元を減らす | 主成分分析(寄与率90〜95%など) |
| アンケートの背後の要因を探したい | 因子分析 |
| 似たデータの集まりを2次元の図で見たい | t-SNE・UMAP(前に PCA で50次元程度に) |
| 図を作った後に新しいデータも同じ図に載せたい | 主成分分析・UMAP |
| 曲がった関係を主成分分析の形で扱いたい | カーネル主成分分析(KernelPCA) |
文章やコードを数値のベクトルにした埋め込みを2次元で見るときにも、主成分分析がよく使われます。埋め込みとベクトルの考え方は、関連記事「エンベディングとは?ベクトル検索とコサイン類似度を計算例で解説」で扱っています。
主成分分析と最小二乗法(回帰)の違い
この節では、主成分分析の第1主成分と、最小二乗法の回帰直線がどう違うのかが分かります。
最小二乗法は「y の縦のずれ」の二乗和を最小にし、主成分分析の第1主成分は「点から直線への垂直な距離」の二乗和を最小にします。 第1主成分の向きは、分散が最大になる向きであり、同時に垂直な距離の二乗和が最小になる向きでもあるためです。
最小二乗法の記事で使った5点 (1, 2)・(2, 3)・(3, 5)・(4, 4)・(5, 6) に、標準化せずに主成分分析をしました。
PC1の向き [0.7071 0.7071] 傾き 1.0 平均 [3. 4.]
寄与率 [0.95 0.05]
第1主成分は傾き 1.0 で平均の点 (3, 4) を通る直線 y = x + 1 になりました。 最小二乗法の直線は y = 0.9x + 1.3 で、別の直線です。y = x + 1 は、最小二乗法の記事で直交回帰(全最小二乗法)として求めた直線と同じです。
| 項目 | 最小二乗法(回帰) | 主成分分析 |
|---|---|---|
| 変数の役割 | 予測したい y と、説明する x を分ける | すべての変数を対等に扱う |
| 最小にするもの | y の縦のずれの二乗和 | 直線への垂直な距離の二乗和 |
| 使う場面 | x から y を予測する | 変数をまとめる・図にする |
最小二乗法の公式と計算例は、関連記事「最小二乗法とは|公式・手計算の例とPythonでの求め方を実例で解説」で扱っています。主成分分析は正解ラベルを使わない「教師なし学習」の代表で、教師あり学習のニューラルネットワークとの違いは、関連記事「ニューラルネットワークとは|仕組み・学習・AttentionをNumPyで実演」で扱っています。
主成分分析のよくある間違いとエラーの直し方
この節では、主成分分析で起こりやすい考え違いと、Python で出るエラーの原文と直し方が分かります。
- 1単位が違う変数を、標準化せずに入れていないか数学を200点満点にしただけで、第1主成分の数学の重みが 0.704 → 0.929 になった
- 2符号の向きで意味を決めつけていないか固有ベクトルは −1 倍しても同じ。scikit-learn では第2・第4主成分の符号が手計算と逆だった
- 3固有ベクトルを負荷量として読んでいないか負荷量 = 固有ベクトル × √固有値。ライブラリの「loadings」がどちらかを確かめる
- 4外れ値・打ち間違いを確かめたか1件の打ち間違いで数学の重みが 0.41 → 0.018 になった
- 5テストデータも含めて fit していないかPipeline に入れて、学習データだけで標準化と主成分を決める
- 6主成分を原因と読んでいないか主成分は相関の要約で、「総合力が点数を決める」という因果は示さない
エラーの原文と直し方
どれも scikit-learn 1.9.1 で実際に出たものです。
| エラー | 原因 | 直し方 |
|---|---|---|
ValueError: n_components=6 must be between 0 and min(n_samples, n_features)=5 with svd_solver='full' |
変数の数(またはデータ数)より多い主成分を指定 | n_components を min(データ数, 変数の数) 以下にする |
ValueError: Input X contains NaN. |
欠損値が入っている | 欠損のある行を除くか、SimpleImputer で埋めてから PCA |
ValueError: could not convert string to float: 'A' |
名前などの文字列の列が入っている | 数値の列だけを渡す。カテゴリはダミー変数にするか別の方法を使う |
ValueError: Expected 2D array, got 1D array instead: |
1列だけを1次元の配列で渡した | reshape(-1, 1) で2次元にする(1変数では主成分分析の意味がない) |
ValueError: n_components=0.8 must be between 1 and min(n_samples, n_features)=5 with svd_solver='arpack' |
小数の指定は arpack で使えない |
svd_solver="full" にする |
AttributeError: 'TSNE' object has no attribute 'transform' |
t-SNE は新しいデータを変換できない | 全データで fit_transform するか、PCA・UMAP を使う |
ValueError: perplexity (30.0) must be less than n_samples (10) |
t-SNE の perplexity(既定 30)がデータ数以上 | データを増やすか perplexity を小さくする(ドキュメントの目安は5〜50) |
欠損値のエラーは、続けて「PCA は NaN で表した欠損値をそのままでは受け付けない。前処理で埋めるか、欠損のある行を除く」という説明と、欠損値の扱い方のページの URL を表示しました。
よくある質問
Q. 主成分分析とは簡単に言うと何ですか? A. たくさんの変数を、情報(分散)をなるべく残したまま、少ない数の新しい軸にまとめる方法です。5科目の点数なら「総合力」と「理系か文系か」の2本で、情報の84.7%を表せました。
Q. 累積寄与率は何%あればよいですか? A. 70〜80%がよく使われる目安です。決まった基準ではなく、図にして見るだけなら低くてもよく、機械学習の前処理では90〜95%を使うこともあります。手書き数字(64次元)では、95%に届くのに標準化なしで29本、標準化ありで39本が必要でした。
Q. 「固有値1以上」とはどういう意味ですか? A. 標準化した場合、元の変数1つの分散が1なので、固有値1以上の主成分は「元の変数1つ分以上の情報を持つ」という意味です。カイザー基準と呼ばれ、標準化しない主成分分析には使えません。
Q. 主成分負荷量と固有ベクトルの違いは? A. 主成分負荷量 = 固有ベクトル × √固有値 で、変数と主成分得点の相関係数になります。−1〜1 で読めるので、主成分の意味を考えるときは負荷量を見ます。
Q. 主成分分析の前に標準化は必要ですか? A. 単位やばらつきが違う変数を使うなら必要です。標準化しないと、ばらつきの大きい変数に第1主成分が引っぱられ、単位を変えるだけで結果が変わりました。同じ単位でばらつきの違いに意味があるときは、標準化しないこともあります。
Q. 主成分分析と因子分析の違いは? A. 主成分分析はデータを要約する軸を作り、因子分析は変数の背後の共通の要因を推定します。5科目では、主成分分析が「総合力・理系か文系か」、因子分析が「文系の力・理系の力」に分かれました。
Q. Pythonで主成分分析をするには?
A. PCA().fit_transform(StandardScaler().fit_transform(X)) で主成分得点、explained_variance_ratio_ で寄与率、components_ で固有ベクトルが得られます。負荷量は components_.T × √固有値 で計算します。
Q. R ではどうしますか?
A. prcomp(x, scale. = TRUE) です。prcomp の初期値は scale. = FALSE(標準化しない)なので、標準化するときは指定します。分散は n − 1 で割り、sdev は主成分の標準偏差、rotation は固有ベクトルの行列です。
Q. SPSS ではどうしますか? A. IBM SPSS Statistics では、因子分析と同じ FACTOR コマンドで行い、抽出法の既定値が主成分(PC)です。
Q. 主成分得点の符号が、ほかの結果と逆になるのはなぜですか? A. 固有ベクトルは −1 を掛けても同じ固有ベクトルなので、どちらの向きが出るかはツールや計算方法で変わります。scikit-learn では第2・第4主成分が手計算と逆でした。意味は変わらないので、負荷量の合計が正になる向きなど、自分で決めてそろえます。
Q. データは何件あればよいですか? A. 決まった件数はありませんが、少ないと固有値が偶然で大きく出ます。10件×5変数の乱数データでも、第1固有値の平均は 2.02 になりました。件数が少ないときは平行分析で確かめ、第2主成分以降の解釈を控えめにします。
Q. カテゴリ(文字)のデータにも使えますか? A. 主成分分析は数値(量的変数)のための方法です。カテゴリはダミー変数(0と1)にして入れる方法がありますが、カテゴリのデータには多重対応分析など専用の方法もあります。
まとめ
- 主成分分析(PCA)は、多くの変数を、分散が最大になる向きの新しい軸(主成分)にまとめる次元削減の方法。
- 手順は 標準化 → 相関行列 → 固有値分解 → 主成分得点。固有値は主成分得点の分散、寄与率は 固有値 ÷ 固有値の合計。
- 5科目×10人では、第1主成分「総合力」62.2%、第2主成分「理系か文系か」22.5%、2本で84.7%。手計算と scikit-learn の寄与率・固有ベクトルは一致した。
- scikit-learn の固有値は n/(n−1) 倍、符号は逆のことがある。寄与率と負荷量で比べる。
- 標準化しないと、ばらつきの大きい変数に引っぱられ、単位を変えるだけで結果が変わった。
- 主成分の数は、累積寄与率70〜80%・固有値1以上・スクリープロット・平行分析を組み合わせ、解釈できるかで決める。
- 背後の要因を探すなら因子分析、図で集まりを見るなら t-SNE・UMAP。PCA は速く、軸に意味があり、新しいデータにも使える。
参考・出典
確認日はいずれも 2026年10月22日です。
- Wikipedia「主成分分析」:https://ja.wikipedia.org/wiki/主成分分析
- scikit-learn「sklearn.decomposition.PCA」:https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html
- scikit-learn「sklearn.decomposition.FactorAnalysis」:https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.FactorAnalysis.html
- scikit-learn「sklearn.manifold.TSNE」:https://scikit-learn.org/stable/modules/generated/sklearn.manifold.TSNE.html
- umap-learn「Transforming New Data with UMAP」:https://umap-learn.readthedocs.io/en/latest/transform.html
- R Documentation「prcomp: Principal Components Analysis」:https://stat.ethz.ch/R-manual/R-devel/library/stats/html/prcomp.html
- IBM SPSS Statistics 23「EXTRACTION Subcommand (FACTOR command)」:https://www.ibm.com/docs/en/SSLVMB_23.0.0/spss/base/syn_factor_extraction.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「主成分分析(PCA)とは|手順・寄与率・負荷量の読み方をPythonで実演」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。