因子分析 関連の補強キーワード。 クリックで該当箇所へ:
🍰 まずはやさしく
目に見えない共通点を探す道具です。
たくさんのデータから正体を突き止めます。
5科目の点数から学力を測るようなものです。
この章では分析の基本について読みます。
因子分析(Factor Analysis, FA)は、 観測された多変数の背後に潜む少数の潜在変数(=因子)を推定する手法。 「5科目の点数 ← 学力という1つの潜在因子」のように、 観測できない構成概念を抽出します。
古典的例:知能の因子構造。 1904年 Spearman が、 子供たちの様々な科目の点数が強く相関することから、 「一般知能 g」 という単一の潜在因子の存在を提唱。 これが因子分析の歴史的起源で、 現代の心理学・教育測定の基礎となりました。
身近な例:質問紙調査。 顧客満足度調査で「品質」「価格」「対応」「速度」「総合」など20問の点数があるとします。 これらは独立した質問に見えて、 実は「製品満足度」「サービス満足度」のような少数の潜在因子で説明できることが多い。 因子分析でその構造を発見できます。
🍰 まずはやさしく
データの裏に隠れた原因を探る手法です。
複雑な情報をシンプルにまとめるために使います。
アンケートの結果を分析するときに便利です。
ここでは専門的な用語の意味を確認します。
心理学・社会学・マーケティングで頻出。 「因子分析」「探索的因子分析(EFA)」「Varimax 回転」「因子負荷量」「共通性」と書かれているとき。 「観測される多変数の裏に潜む少数の潜在因子を見つける」手法。
因子分析 とは:観測変数の背後にある潜在的な少数の「因子」を推定する手法。PCAと似て非なる(仮定が異なる)。
🍰 まずはやさしく
バラバラな情報をグループに分けるイメージです。
データの正体をわかりやすく解釈するために使います。
性格診断テストで性格を分けるようなものです。
図を使って直感的な仕組みを学びます。

図は2因子に圧縮した47都道府県の散布図のイメージ。 因子分析の真価はローディング行列の解釈にあります。
例えば6つの観測変数(死亡率、 高齢化率、 出生率、 転入率、 保健医療費、 消費支出)を2因子で分析すると:
こうして「6次元のデータが、 実は2つの潜在的な軸で大部分説明できる」と分かります。 各県に「高齢化スコア」「経済スコア」を割り当てて、 1次元の指標として扱えるようになる。
因子分析の発想は性格診断テスト(ビッグファイブ等)と同じ。 50問の質問への回答(観測変数)は、 実は「外向性」「協調性」「誠実性」「神経症傾向」「開放性」という 5 つの潜在因子(共通因子)で大半が説明できる、 という仮説に基づいている。 「人前で話すのが好き」「パーティーに行きたい」「初対面の人と話せる」といった項目はどれも「外向性」因子に高くロードする。 PCA との違いは「観測値の背後に意味ある潜在変数がある」という因果的世界観を持つこと。
| 観測変数の例 | 因子1(高齢化軸)への負荷 | 因子2(経済活力軸)への負荷 |
|---|---|---|
| 65歳以上人口比率 | 0.92(強く正) | -0.18 |
| 合計特殊出生率 | -0.61 | 0.34 |
| 消費支出(二人以上の世帯) | -0.22 | 0.85(強く正) |
| 転入超過率(A5101−A5102) | -0.45 | 0.78 |
| 保健医療費(二人以上の世帯) | 0.31 | 0.62 |
もし君が地方創生の担当者で「47 都道府県を 2 軸で位置づけて施策を決めたい」と思ったら、 まず因子分析で軸を抽出し、 各県を「高齢化軸」と「経済活力軸」で配置する。 秋田・高知は高齢化軸が大きく経済活力軸が小さい象限へ、 東京・神奈川は経済活力軸が大きく高齢化軸が小さい象限へ、 と整理される。 6 変数を眺めるより 2 軸でマップにする方が直感的に課題が見える。
PCA は「分散を最大化する軸」を機械的に探す。 因子分析は「共通因子 + 独自因子(誤差)」という生成モデルを仮定し、 観測の背後にある潜在因子を推定する。 PCA は要約、 因子分析は潜在変数の発見と覚えるとよい。
🍰 まずはやさしく
数式を使って正体を計算する方法です。
データがどう作られているかをモデルにします。
テストの点数と誤差の関係を式にします。
計算式や他の手法との違いについて読みます。
$$ \mathbf{x} = \Lambda \mathbf{f} + \boldsymbol{\varepsilon} $$
各観測変数の分散 = 共通性(因子で説明)+ 独自性(誤差)
$$ \text{Var}(x_j) = h_j^2 + u_j^2 $$
| 項目 | PCA | 因子分析 |
|---|---|---|
| 目的 | 分散最大化、 次元削減 | 潜在変数の発見 |
| モデル | 線形変換 | 潜在変数モデル |
| 誤差項 | なし | あり(独自因子) |
| 解釈性 | 主成分は直交 | 回転で解釈性向上 |
| 推定法 | 固有値分解 | 最尤法、 主因子法 |
因子分析の結果は回転不変。 解釈しやすい形に回転させるのが標準:
因子間の直交性を保ちつつ、 「各変数が1つの因子のみに強く依存」する解を探す。 最も一般的。
因子間の相関を許容。 心理学的因子(外向性と神経症傾向は相関するなど)に自然。
因子分析の核心は「見えない共通因子 $f$ が、 負荷量 $\Lambda$ を通じて観測変数 $x$ を駆動し、 説明しきれない残りは独自因子 $\varepsilon$ が受け持つ」という生成モデルです。 PCA が「与えられたデータの分散を最大限保つ要約軸」を機械的に探す記述的変換であるのに対し、 因子分析は「データがどう生まれたか」という確率モデル(誤差構造つき)を立てて逆向きに推定します。 以下の 3 つのデモはすべて架空のテスト得点(国語・英語・数学・理科の標準化得点。 実データではありません)を例にしています。
「文系因子 $f_1$」「理系因子 $f_2$」の 2 本のスライダーを動かすと、 固定した負荷量行列 Λ(下表)を通じて 4 科目の得点バーが連動して動きます。 スライダー 1 本で複数科目が同時に動く——「観測変数間の相関は共通因子が作る」というモデルの直感です。 「誤差 ε を加える」を ON にすると、 独自性 $\psi_i = 1 - h_i^2$ の大きさに応じたノイズが各科目に乗ります(理論値 $x_i = \lambda_{i1}f_1 + \lambda_{i2}f_2$ からのズレ)。
| 科目(架空) | λ (文系 f₁) | λ (理系 f₂) | 共通性 h² | 独自性 ψ |
|---|---|---|---|---|
| 国語 | 0.80 | 0.10 | 0.65 | 0.35 |
| 英語 | 0.70 | 0.20 | 0.53 | 0.47 |
| 数学 | 0.10 | 0.80 | 0.65 | 0.35 |
| 理科 | 0.20 | 0.70 | 0.53 | 0.47 |
💬 読み方:f₁ だけ上げると国語・英語が大きく、 数学・理科がわずかに動く(λ の比のとおり)。 これを逆から見るのが因子分析——「国語と英語が一緒に動く」という相関パタンから、 見えない f と Λ を復元する。 ε を ON にすると独自性の大きい英語・理科(ψ=0.47)ほど理論値から大きくブレることも確認できます。
因子分析の推定とは「モデルが作る相関 $\hat{R} = \Lambda\Lambda^\top + \Psi$ が実相関 $R$ に近づくように Λ を選ぶ」こと。 ここでは実相関として上の真の Λ から作った相関行列(例:国語×英語 = 0.8×0.7 + 0.1×0.2 = 0.58)を固定し、 君が 8 個の負荷量スライダーを動かして再現に挑戦します。 対角は独自性 $\Psi$ が埋めるので常に 1。 残差 = 実相関 − モデル相関 が全部白(≈0)になれば再現成功です。
各変数の独自性(スライダー連動):
💬 読み方:h² = λ₁² + λ₂² が 1 を超えると独自性 ψ が負になるHeywood ケース(不適解)で警告が出ます。 また「正解」以外にも残差をほぼ 0 にできる Λ が無数にあること(例:正解をセットした後、 ③の要領で回転した値)に気づけば、 回転の不定性を体感したことになります。
回転前の初期解では、 第 1 因子が全科目に正に負荷する「総合学力」風の一般因子、 第 2 因子が文系と理系の対比、 という解釈しにくい形になりがちです。 負荷量平面(横軸 F1・縦軸 F2 に 4 科目をプロット)で軸を回転させると、 点は動かないまま座標の読み方だけが変わり、 ある角度で各科目が片方の軸だけに強く負荷する「単純構造」が現れます。 スライダーまたは図の上をドラッグして回してください(バリマックス基準 Q が最大になるのは θ = 35°)。
| 科目 | F1'(回転後) | F2'(回転後) |
|---|
|負荷量| > 0.4 を太字表示。 θ=0° では 4 科目とも F1' に 0.4 超で「何の因子か」不明瞭。 θ=35° で国語・英語→F1'(文系)、 数学・理科→F2'(理系)にくっきり分離。
💬 重要:どの角度でも共通性 h²(原点からの距離²)とモデル相関 ΛΛ'+Ψ は一切変わりません。 つまり回転はデータへの当てはまりを変えず、 解釈だけを変える操作——数学的に等価な解が無限にある(回転の不定性)からこそ、 バリマックスのような「解釈しやすさの基準」で 1 つを選ぶのです。
簡略化した例で因子分析の出力を読み解きます。 SSDSE-B-2026 の家計 4 変数(教育費・教養娯楽費・食料費・保健医療費、 いずれも二人以上の世帯)を1因子に圧縮すると仮定。
観測変数間の相関行列が、 因子分析の入力:
| 教育費 | 教養娯楽費 | 食料費 | 保健医療費 | |
|---|---|---|---|---|
| 教育費 | 1.00 | 0.75 | 0.68 | 0.42 |
| 教養娯楽費 | 0.75 | 1.00 | 0.70 | 0.45 |
| 食料費 | 0.68 | 0.70 | 1.00 | 0.55 |
| 保健医療費 | 0.42 | 0.45 | 0.55 | 1.00 |
すべて正相関 → 共通因子が1つ存在する可能性が高い
1因子モデルで推定すると:
| 変数 | 因子負荷量 λ | 共通性 h² | 独自性 |
|---|---|---|---|
| 教育費 | 0.87 | 0.76 | 0.24 |
| 教養娯楽費 | 0.89 | 0.79 | 0.21 |
| 食料費 | 0.84 | 0.71 | 0.29 |
| 保健医療費 | 0.62 | 0.38 | 0.62 |
解釈:教育費、 教養娯楽費、 食料費は強くこの因子にロード(λ > 0.8)。 保健医療費は中程度(λ = 0.62)。 共通性が高い変数ほど、 因子の影響を強く受ける。 この因子は「世帯消費水準」と命名できそう。
各サンプル(都道府県)の「世帯消費水準因子スコア」を計算。 推定式の1つは:
$\hat{f} = w_1 z_{教育費} + w_2 z_{教養娯楽費} + w_3 z_{食料費} + w_4 z_{保健医療費}$
$z$ は標準化済みの値、 $w$ は推定された重み。 結果:
| 都道府県 | 世帯消費水準スコア |
|---|---|
| 東京 | +2.1 |
| 神奈川 | +1.5 |
| 愛知 | +1.2 |
| 秋田 | -1.4 |
| 島根 | -1.3 |
スコアが高いほど世帯消費水準が高い、 という1次元の指標が得られました。
得られた知見:4変数を1次元に圧縮しても「世帯消費水準」という解釈可能な軸として表現できた。 これを使って:
注意:共通性 0.76, 0.79, 0.71 は十分高いが、 保健医療費の共通性 0.38 は低め。 「保健医療費は世帯消費水準以外の要因(高齢化率、 地域医療体制)に強く影響される」と解釈。 必要なら保健医療費を別の因子で扱う2因子モデルへ。
表面的には似ていますが、 数学的なモデルが違います:
PCA の分解:相関行列をそのまま固有値分解。 すべての分散(共通+独自)を主成分で説明しようとする。
$\Sigma = V \Lambda V^\top$
因子分析の分解:相関行列の対角を共通性で置き換えてから分解。 独自分散は除外する。
$\Sigma = \Lambda \Phi \Lambda^\top + \Psi$
$\Psi$ は独自分散の対角行列。 PCA は $\Psi = 0$(独自分散なし)と仮定した特殊例とも言えます。
結論:使い分け
因子分析の解には本質的な不定性があります。 因子軸を回転させても、 観測変数の分散・共分散構造は変わらない。 数学的に正しい解が複数あるので、 解釈しやすい解を選びます。
Varimax 回転(直交):因子間の相関を 0 に保つ。 各観測変数が「1つの因子に強く、 他の因子にはほとんどロードしない」シンプル構造を目指す。 最も使われる。
Promax 回転(斜交):因子間に相関を許す。 心理学的構成概念は相関するのが普通(「外向性」と「協調性」は無関係ではない)なので、 より現実的。
回転前の解は機械的に得られるが、 第1因子が「あらゆる変数とそこそこ相関」する一般因子になりがちで、 解釈しにくい。 回転で「各観測変数がどの因子に属するか」をくっきりさせます。
「何個の因子を仮定するか」は分析の核心。 客観的方法:
R の psych::fa.parallel() で平行分析が簡単に実行できる。 Python でも factor_analyzer パッケージで対応。
SSDSE-B の経済・人口関連 5 変数から潜在因子を抽出する完全例。 因子数決定・回転・スコア計算まで。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | import pandas as pd import numpy as np from factor_analyzer import calculate_bartlett_sphericity, calculate_kmo from sklearn.decomposition import FactorAnalysis from sklearn.preprocessing import StandardScaler df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] # 2023 年の 47 都道府県のみ (n=47) # 実在列コード: A1101総人口 A1303高齢人口 A4101出生数 A4103合計特殊出生率 L3221消費支出 L322106保健医療費 features = ['A1101','A1303','A4101','A4103','L3221','L322106'] X = pd.DataFrame(StandardScaler().fit_transform(df[features]), columns=features) # 適切性のチェック chi2, p = calculate_bartlett_sphericity(X) print(f'Bartlett: χ²={chi2:.2f}, p={p:.4g}') kmo_per_var, kmo_total = calculate_kmo(X) print(f'KMO total = {kmo_total:.3f} (> 0.6 で適切)') # 注意: factor_analyzer 0.5 は scikit-learn 1.9 で削除された引数 # (force_all_finite) を使うため FactorAnalyzer.fit が動かない。 # ここでは同じことができる scikit-learn の FactorAnalysis を使う。 # 因子数の決定(相関行列の固有値・Kaiser 基準) eigenvalues = np.linalg.eigvalsh(np.corrcoef(X.T))[::-1] print('固有値:', eigenvalues.round(3)) print('Kaiser 基準(λ>1):', int((eigenvalues > 1).sum())) # 2 因子で Varimax 回転 fa = FactorAnalysis(n_components=2, rotation='varimax', random_state=0) fa.fit(X) loadings = pd.DataFrame(fa.components_.T, index=features, columns=['F1', 'F2']) print('\n負荷量行列(Varimax):') print(loadings.round(3)) |
| 項目 | 値 | 参考 | 解釈 |
|---|---|---|---|
| 変数 | F1 (人口規模) | F2 (少子・生活) | 共通性 |
| 総人口 | 0.85 | -0.12 | 0.74 |
| 出生数 | 0.92 | -0.21 | 0.89 |
| 合計特殊出生率 | -0.35 | 0.78 | 0.73 |
| 65歳以上人口 | -0.41 | 0.62 | 0.55 |
| 保健医療費 | 0.18 | 0.51 | 0.29 |
| 解釈 | F1=人口規模 | F2=少子・生活 | 2因子で74%説明 |
👉 値は SSDSE-B-2026 の典型値。 同じ手順で他都道府県・他変数にも適用可能。
SSDSE-B-2026 (47 都道府県) の A1101 総人口・A1303 65歳以上人口・A4103 合計特殊出生率 の 3 変数から 2 因子 (規模因子 F1・出生因子 F2) を取り出した負荷量行列で、 各変数の共通性 h² = 負荷量² の和 を計算する。 ここで示す負荷量は「規模因子 F1・出生因子 F2」の典型的なパタンを表す解説用の丸め例であり(共通性 h² の計算手順を追うための値)、 実データでの正確な負荷量は下の「🐍 Python での実装」①〜③で 2023 年 47 都道府県から再計算できる。
| 変数 (SSDSE 列) | F1 (規模) | F2 (出生) | 共通性 h² |
|---|---|---|---|
| A1101 総人口 | 0.80 | 0.30 | 0.73 |
| A1303 65歳以上人口 | 0.70 | 0.20 | 0.53 |
| A4103 合計特殊出生率 | 0.30 | 0.90 | 0.90 |
💬 読み方: A1101・A1303 は F1 (規模) で大半が説明される (負荷量 0.8・0.7)。 A4103 は F2 (出生) に強く寄り (0.9)、 規模因子からは独立に動く。 h² が大きいほど 2 因子モデルで再現性が高い。
1 2 3 4 5 | import numpy as np loadings = np.array([[0.8, 0.3],[0.7, 0.2],[0.3, 0.9]]) h2 = (loadings**2).sum(axis=1) print(f"共通性: {h2}") print(f"独自性: {1 - h2}") |
💬 手計算 (Step 2) と Python 出力が完全一致。
このコードでやること:SSDSE-B-2026 の人口・出生・世帯生活の 6 指標を factor_analyzer.FactorAnalyzer で 2 因子解を抽出し、 Varimax 回転で「人口規模」「世帯生活・出生」の潜在因子を解釈する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | import pandas as pd import numpy as np from sklearn.preprocessing import StandardScaler from sklearn.decomposition import FactorAnalysis df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] # 2023 年の 47 都道府県のみ (n=47) features = ['A1101', 'A4101', 'A4103', # 総人口 出生数 合計特殊出生率 'L322106', 'L3221', 'A1303'] # 保健医療費 消費支出 65歳以上人口 X = StandardScaler().fit_transform(df[features]) # 注意: factor_analyzer 0.5 は scikit-learn 1.9 で削除された引数 # (force_all_finite) を使うため FactorAnalyzer.fit が動かない。 # ここでは同じことができる scikit-learn の FactorAnalysis を使う。 # 2 因子モデル + Varimax 回転 fa = FactorAnalysis(n_components=2, rotation='varimax', random_state=0) fa.fit(X) loadings = pd.DataFrame(fa.components_.T, index=features, columns=['F1', 'F2']) print('因子負荷量 (Varimax 回転後):') print(loadings.round(3)) # 共通性 h² = 各変数の負荷量の二乗和 comm = (fa.components_ ** 2).sum(axis=0) print('共通性 (h²):', dict(zip(features, comm.round(3)))) # 寄与率 = 各因子の負荷量二乗和 ÷ 変数の数 var = (fa.components_ ** 2).sum(axis=1) prop = var / len(features) print(f'累積寄与率: {prop.sum():.3f}') |
📤 実行例:
💬 読み方:F1 は A1101 総人口 (0.975)・A4101 出生数 (0.990)・A1303 65歳以上人口 (0.951) に高く負荷 → 「人口規模」因子。 F2 は A4103 合計特殊出生率が強く負に負荷し (−0.712)、 L3221 消費支出・L322106 保健医療費も中程度に負荷 → 「世帯生活・出生」因子(因子の符号は反転可能)。 累積寄与率 69.2% は 6 変数を 2 軸でかなり説明できることを示す。 共通性 h² を見ると A1101 が 1.000、 A4101 が 0.999 とほぼ完全に 2 因子で説明できる一方、 L3221 消費支出は 0.192 しかない ── この変数はどちらの因子にもほとんど乗っておらず、 累積寄与率が 7 割止まりなのは主にこの 1 変数のせいである。 全体の寄与率だけを見て「まあまあ」と流さず、 変数ごとの h² で「取りこぼしている変数」を特定するのが実務の読み方。
このコードでやること:因子分析を実行する前に「変数間に十分な相関構造が存在するか」を Bartlett 検定 (相関行列 = 単位行列の帰無仮説) と KMO (Kaiser-Meyer-Olkin) 指標で診断する。
1 2 3 4 5 6 7 8 9 10 11 12 | from factor_analyzer.factor_analyzer import ( calculate_bartlett_sphericity, calculate_kmo ) # Bartlett 球面性検定 chi2, p_bartlett = calculate_bartlett_sphericity(X) print(f'Bartlett: χ² = {chi2:.2f}, p = {p_bartlett:.4f}') # KMO 指標 (0.6 以上で適合可) kmo_per_var, kmo_total = calculate_kmo(X) print(f'KMO 全体: {kmo_total:.3f} (≥0.6 で適合可、 ≥0.8 で良好)') print('変数別 KMO:', dict(zip(features, kmo_per_var.round(3)))) |
📤 実行例:
💬 読み方:Bartlett p < 0.001 → 「相関なし」を棄却、 因子分析する意味あり。 KMO = 0.681 → 0.6 以上で適合、 因子分析を実行してよい。 SSDSE-B-2026 都道府県データ (2023 年 n=47) は因子分析に向いている。
このコードでやること:固有値の減衰パタン (スクリープロット) とランダム相関行列を比較する平行分析 (Horn 1965) で、 SSDSE-B-2026 の 6 変数を何因子で説明するのが妥当かを客観的に判定する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import numpy as np import matplotlib.pyplot as plt np.random.seed(0) # 実行のたびに同じ結果が出るようにする # 観測データの固有値 R = np.corrcoef(X.T) obs_eigs = np.sort(np.linalg.eigvalsh(R))[::-1] # 平行分析 (ランダム相関行列 100 回の 95 パーセンタイル) n, p = X.shape rand_eigs = np.array([np.sort(np.linalg.eigvalsh( np.corrcoef(np.random.randn(n, p).T)))[::-1] for _ in range(100)]) ref = np.percentile(rand_eigs, 95, axis=0) print('観測固有値 :', obs_eigs.round(3)) print('ランダム95%:', ref.round(3)) n_factors = int(np.sum(obs_eigs > ref)) print(f'推奨因子数: {n_factors}') |
📤 実行例:
💬 読み方:λ₁ = 3.975 はランダム上限 1.656 を大きく超える → 第 1 因子は明確に有意。 λ₂ = 1.089 はランダム上限 1.392 を下回るため、 平行分析では第 2 因子を採用せず「1 因子」を推奨する。 一方 Kaiser 基準 (λ>1) では λ₂=1.089>1 で 2 因子となり、 判定が割れる(ランダム上限は乱数依存でやや変動する)。
📝 より正確な分析:2023 年の 47 都道府県 (n=47) で厳密に再計算すると、 平行分析は 1 因子を、 Kaiser 基準は 2 因子を示唆し結論が分かれる。 λ₂=1.089 は境界ぎりぎりで、 n=47 と小標本のため固有値・ランダム上限とも不安定。 本ページは解釈可能性(「人口規模」「世帯生活・出生」の 2 軸)と Kaiser 基準を優先して 2 因子解を提示するが、 平行分析基準では 1 因子が保守的に妥当であり、 2 因子目は探索的な位置づけであることに留意する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | from sklearn.decomposition import FactorAnalysis, PCA # sklearn の FA(回転なし) fa = FactorAnalysis(n_components=2, random_state=42) fa.fit(X) print('sklearn FA loadings:') print(pd.DataFrame(fa.components_.T, index=features, columns=['F1', 'F2']).round(3)) # 比較:PCA pca = PCA(n_components=2) pca.fit(X) print('\nPCA loadings:') print(pd.DataFrame(pca.components_.T, index=features, columns=['PC1', 'PC2']).round(3)) print('PCA 寄与率:', pca.explained_variance_ratio_) # 因子スコアの計算 scores = fa.transform(X) print('\n上位 5 県のスコア:') print(pd.DataFrame(scores, columns=['F1', 'F2'], index=df['Prefecture']).head()) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | from scipy.stats import chi2 as chi2_dist import numpy as np np.random.seed(0) # 実行のたびに同じ結果が出るようにする # Bartlett 球面性検定(自前実装) R = np.corrcoef(X.T) n, p = X.shape chi2_stat = -((n - 1) - (2*p + 5)/6) * np.log(np.linalg.det(R)) df_chi = p * (p - 1) / 2 pval = 1 - chi2_dist.cdf(chi2_stat, df_chi) print(f'Bartlett χ² = {chi2_stat:.2f}, df = {df_chi:.0f}, p = {pval:.4f}') # 平行分析(Horn 1965):ランダム相関行列の固有値と比較 n_iter = 100 random_eigs = np.zeros((n_iter, p)) for i in range(n_iter): Xr = np.random.randn(*X.shape) Rr = np.corrcoef(Xr.T) random_eigs[i] = np.sort(np.linalg.eigvalsh(Rr))[::-1] obs_eigs = np.sort(np.linalg.eigvalsh(R))[::-1] ref_95 = np.percentile(random_eigs, 95, axis=0) print('\n平行分析:') for i, (obs, ref) in enumerate(zip(obs_eigs, ref_95)): print(f' λ{i+1}: 観測 {obs:.3f}, ランダム 95th = {ref:.3f} {"✓" if obs > ref else "✗"}') |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | import numpy as np import optuna from sklearn.decomposition import FactorAnalysis optuna.logging.set_verbosity(optuna.logging.WARNING) n, p = X.shape # 因子数を BIC で選ぶ。BIC = -2·対数尤度 + log(n)·パラメータ数 def objective(trial): k = trial.suggest_int('n_factors', 1, 5) fa = FactorAnalysis(n_components=k, random_state=0).fit(X) ll = fa.score(X) * n # 対数尤度の合計 n_par = p * k - k * (k - 1) // 2 + p # 負荷量 + 回転の自由度を引く + 独自分散 return -2 * ll + np.log(n) * n_par study = optuna.create_study(direction='minimize', sampler=optuna.samplers.TPESampler(seed=0)) study.optimize(objective, n_trials=30, show_progress_bar=False) print('最良の因子数:', study.best_params['n_factors']) print(f'そのときの BIC: {study.best_value:.2f}') # 因子数ごとの BIC を並べて確認する for k in range(1, 6): fa = FactorAnalysis(n_components=k, random_state=0).fit(X) n_par = p * k - k * (k - 1) // 2 + p print(f' k={k}: BIC = {-2 * fa.score(X) * n + np.log(n) * n_par:7.2f}') # 回転は当てはまりを変えないので BIC では選べない(解釈しやすさで選ぶ) for rot in (None, 'varimax', 'quartimax'): fa = FactorAnalysis(n_components=3, rotation=rot, random_state=0).fit(X) print(f' 回転 {str(rot):10s}: 対数尤度 = {fa.score(X) * n:.4f}') |
| ライブラリ / 関数 | 用途 |
|---|---|
factor_analyzer.FactorAnalyzer | 因子分析専門ライブラリ |
sklearn.decomposition.FactorAnalysis | 簡易な FA(回転なし) |
statsmodels.multivariate.factor.Factor | 詳細な FA |
semopy | 構造方程式モデリング(CFA 含む) |
psynthesizer | 心理測定特化 |
因子分析(Factor Analysis)は、 多数の観測変数の背後にある少数の潜在因子(latent factors)を推定する手法。 PCA と似ているが、 「共通因子」と「独自因子(誤差)」を区別する明確な確率モデルを持つ。
因子分析 がデータサイエンスの体系の中でどこに位置するかを、 3つの異なる視点で可視化します。 同じ情報でも見方を変えると気付きが変わります。
🌐 統計・データサイエンス › 教師なし学習 › 次元削減 › 因子分析
中心に 因子分析 を置き、 そこから PCA・相関係数・標準化・前処理・共分散・Spearman相関 など 計 9 個の用語へ、 前提・兄弟・発展形といった関係を矢印で結んでいます。 線がどちら向きかを見れば、 先に読むべき用語とあとから読む用語が分かります。 ノードはドラッグで動かせ、 ホイールでズーム、 クリックでその用語のページへ遷移します。
大きな円が小さな円を包含する Circle Packing 図。 「因子分析」は緑色でハイライト。
長方形を入れ子に分割した Treemap 図。 各分野の規模感を面積で比較。 「因子分析」は緑色でハイライト。
| マップ | 分かること | こんな時に見る |
|---|---|---|
| 🔗 関係マップ | 手法間の横の関係(前提→発展→応用) | 「次に何を学べばよい?」 学習順序の判断 |
| ⭕ 包含マップ | 分類体系の入れ子構造(上位⊃下位) | 「この手法はどんなジャンルに属する?」 |
| 🌳 ツリーマップ | 分野の規模比較(面積=ボリューム) | 「データサイエンス全体の俯瞰像」 |
💡 3 つの図は同じ位置関係を別の角度から描いています。 関係マップは 因子分析 の隣に何が並ぶかを、 包含マップとツリーマップは 統計・データサイエンス → 次元削減 → 因子分析 という入れ子の位置を示します。 「次元削減には他に何があったか」を思い出したいときは包含マップを、 「次に何を読むか」を決めたいときは関係マップを開いてください。
「因子分析」は単独で完結せず、 隣接する手法と接続することで分析パイプラインの一部として機能する。 以下に具体的な接続関係を示す。
因子分析は (1) KMO > 0.6 で標本妥当性確認 → (2) 平行分析 / MAP 基準で因子数決定 → (3) 主因子法 or 最尤法で抽出 → (4) varimax (直交) or promax (斜交) 回転で解釈性向上 → (5) Cronbach's α で内的整合性 → (6) 因子得点で後続分析、 という 6 段の手順が心理計量学 (Brown 2015) の標準。 PCA とは「観測 = 因子の線形結合 + 誤差」の構造で異なる。
「factor analysis」を含む手法選択は、 データの性質・分析目的・運用制約の 3 軸で決まる。 以下に典型シナリオと対応する手法の組合せを示す。
| シナリオ | 重視する観点 | 候補手法 |
|---|---|---|
| 背後の潜在因子を探索したい | 共通因子 + 独自因子 | 探索的因子分析 EFA (Spearman 1904) |
| 理論モデルを検証したい | 仮説検定 / 適合度指標 | 確認的因子分析 CFA (Jöreskog 1969) / SEM |
| 次元削減・要約が目的 | 分散最大化 | PCA (Pearson 1901) |
| 因子の解釈性を高めたい | 単純構造 / 因子負荷量明確化 | Varimax (Kaiser 1958) / Promax 回転 |
| 因子数を決めたい | 固有値 / 並行分析 | スクリープロット (Cattell 1966) / 平行分析 (Horn 1965) |
| 尺度の信頼性確認 | 内部一貫性 | Cronbach α (Cronbach 1951) |
ここは既存の解説を壊さずに追記したまとめです。 因子分析を「データがどう生まれたかを説明する測定モデル」として捉え直し、 直感・落とし穴・発展を 1 か所に凝縮します。 数値はすべて SSDSE-B-2026.csv(cp932・skiprows=[1]・2023 年 47 都道府県)からの実測で、 合成データを使う箇所は「架空」と明記します。
因子分析の世界観は矢印の向きに集約されます。 潜在因子 f → 観測変数 x(因子が観測を生成する)。 一方 PCA は 観測変数 x → 主成分 PC(観測を機械的に合成し直す)。 この向きの違いが「測定モデル vs 次元圧縮」という性格の違いを生みます。
| 観点 | 因子分析(測定モデル) | PCA(次元圧縮) |
|---|---|---|
| 矢印の向き | 因子 → 観測(生成) | 観測 → 成分(合成) |
| 各変数の分散 | 共通性 h² + 独自性 ψ に分解 | 全分散をそのまま配分 |
| 誤差 ε | 明示的にモデル化(独自因子) | 概念として持たない |
| 問いの形 | 「背後に何があるか?」 | 「どう要約するか?」 |
| 解の一意性 | 回転で無限個(不定) | 分散最大で基本的に一意 |
各観測変数は x = 共通因子成分(Λf)+ 独自因子成分(ε) に分かれます。 共通因子成分は「複数の変数が一緒に動く部分」、 独自因子成分は「その変数だけに固有の変動+測定誤差」。 だから因子分析は変数間の相関の共通源を推定する作業に他なりません。
相関が高い変数群は同じ因子から駆動されている、 というのが読みの起点です。 下は実測の相関係数(標準化後)です。
| 変数ペア(SSDSE 列) | 相関係数 r(実測) | 読み |
|---|---|---|
| A1101 総人口 × A4101 出生数 | +0.995 | ほぼ一体 → 同一の「人口規模」因子 |
| A1101 総人口 × A1303 65歳以上人口 | +0.991 | 同上(規模が大きいほど高齢人口も多い) |
| A4103 合計特殊出生率 × A1303 65歳以上人口 | −0.587 | 別方向の軸(少子高齢の対比) |
| L3221 消費支出 × L322106 保健医療費 | +0.603 | 「世帯生活水準」寄りの共通変動 |
💬 A1101・A4101・A1303 は r≈0.99 でほぼ同じ動きをするため、 1 本の共通因子(人口規模)で束ねられます。 一方 A4103 は規模系と負の相関しか持たず、 別の軸に載ります。 「強く相関する塊」を探すことが、 そのまま因子の発見に直結する——これが測定モデルの直感です。
semopy が代表的)📝 補足:構造方程式モデリング(SEM)・潜在変数モデルの単独解説ページは本用語集に未収録のため、 上記リンクには含めていません(リンク切れ防止)。 実装で確認する場合は semopy(SEM/CFA)・factor_analyzer(EFA・回転・KMO・Bartlett)が標準です。