アンケートの複数項目が似た動きをするとき、「背後に共通する少数の傾向があるのでは」と考えるのが因子分析の入口です。ただし、計算で二つの軸が出たことと、人の心理に二つの性質が実在することは同じではありません。
この記事では、質問項目の設計、因子数、回転、負荷量と得点の読み方までをつなげます。Pythonの例はすべて合成データです。小さな表で起きる問題を確かめた後、別の連続値データで推定を試します。
30秒で要点
- 最初に確かめるのは、行が誰を表すか、項目が何を測るか、同じ内容の重複や完全な依存がないか。
- 因子数は、モデルを推定できる情報量、乱数との比較、残差、項目内容を合わせて検討する。
- 因子同士の相関を許す回転では、負荷量の表だけでなく因子相関も読む。
- 因子得点は推定値。顧客の診断や施策効果に使うには、別の対象や外部指標で確かめる。
共通因子とは、似た変動を説明する仮定
例えば「操作が迷わない」「説明が理解しやすい」「目的の機能を見つけやすい」の回答が一緒に高くなるとします。因子分析では、その共通する動きを一つの潜在因子で表すモデルを考えます。潜在とは、各回答のように直接は観測していない、という意味です。
標準化した項目ベクトルを x = Lf + e と表します。fは因子、Lは項目と因子を結ぶ重みの行列、eはその項目に固有の変動です。固有の変動には測定誤差だけでなく、ほかの項目と共有しない内容も含まれます。「共通ではないから無価値」とは限りません。
基本的な共通因子モデルは、因子と固有部分が無相関で、固有部分同士も無相関と置きます。似た語尾や質問の順序による回答の癖が残るなら、この仮定が合わない可能性があります。scikit-learnの因子モデルとRの公式説明を読む際も、モデルの仮定とデータの性質を分けてください。
表が収まらない場合は、横にスクロールできます
| 問い | 向いている出発点 | 出力だけでは言えないこと |
|---|---|---|
| 多数の数値を少ない軸で要約したい | 主成分分析(PCA) | 軸が心理的特性である |
| 項目間の共通変動を潜在因子で説明したい | 探索的因子分析(EFA) | 因子の名前が実在や原因を証明する |
| 事前に決めた項目と因子の関係を検討したい | 制約を明示した確認的因子分析(CFA) | 同じ標本で都合よく修正した構造が再現する |
PCAとFAはともに軸を作りますが、最適化する問いが違います。PCAの分散・係数・スコアの区別を、そのまま因子の「説明力」に読み替えないことが大切です。
項目数と標本数は、別々に点検する
まず測定の内容を確認します。回答の向きが逆の項目、欠測の意味、全員が同じ回答をした列、ほかの列から計算した合計点などを、分析へ渡す前に整理します。合計点とその内訳を一緒に入れると、独立した情報が増えたように見えても完全な依存ができます。
次に、自由に推定したい量に対して情報が足りるかを考えます。p項目の共分散にはp(p+1)/2個の異なる値があります。制約のないm共通因子モデルでは、回転による重複を差し引いたパラメータ数をpm + p - m(m - 1)/2と数えます。その差が情報数に基づく自由度です。factor_analyzerの実装にも同じ自由度の式があります。
表が収まらない場合は、横にスクロールできます
| 項目数p | 因子数m | 情報数による自由度 | 読み方 |
|---|---|---|---|
| 4 | 2 | -1 | 自由なモデルのままでは情報が足りない |
| 4 | 1 | 2 | 必要条件を通るが、適切なモデルとは限らない |
| 6 | 2 | 4 | 同じく必要条件。負荷の配置や残差も調べる |
自由度が非負なのは必要条件であり、識別の十分条件ではありません。 識別とは、観測からモデルの量を区別して推定できることです。回答者を増やしても、4項目2因子という情報数の不足は解消しません。因子数を減らす、内容に沿って測定項目を追加する、理論的な制約を置くなど、モデル自体の見直しが要ります。
標本数はそれとは別です。情報数の条件を通っても、少数の回答者から推定した相関は不安定になり得ます。「項目の何倍なら十分」と一つの数で保証せず、負荷量、欠測、分布、因子ごとの項目構成、推定のばらつきを見ます。
例1:8行の表を点検し、別の教材を作る
実行環境は2026年10月4日に確認したPython 3.12.10、NumPy 2.1.3、pandas 2.2.3、SciPy 1.14.1、scikit-learn 1.5.2、factor-analyzer 0.5.1、Matplotlib 3.9.2です。再現用の固定環境であり、最新版の推奨ではありません。以下の3例は同じPythonセッションで順に実行できます。例2と例3は、いずれも例1のdfを使います。
import numpy as np
import pandas as pd
small = pd.DataFrame({
"price_sensitivity": [4, 5, 3, 4, 5, 2, 3, 4],
"design_preference": [2, 3, 4, 2, 3, 5, 4, 5],
"usability_ease": [3, 4, 5, 3, 4, 5, 3, 4],
"functionality_need": [5, 4, 3, 5, 4, 3, 5, 4],
})
def information_df(p, m):
return p * (p + 1) // 2 - (p * m + p - m * (m - 1) // 2)
print("Old example shape:", small.shape)
print("Ease + function:", (small.usability_ease + small.functionality_need).tolist())
print("Centered rank:", np.linalg.matrix_rank(small - small.mean()))
for p, m in [(4, 2), (4, 1), (6, 2)]:
print("items, factors, df:", p, m, information_df(p, m))
# Separate continuous synthetic data: not eight real survey responses.
rng = np.random.default_rng(20261004)
latent = rng.multivariate_normal([0, 0], [[1, .35], [.35, 1]], size=400)
true_loadings = np.array([[.8, 0], [.7, .1], [.75, 0],
[0, .8], [.1, .7], [0, .75]])
errors = rng.normal(0, .55, size=(400, 6))
df = pd.DataFrame(latent @ true_loadings.T + errors,
columns=["Q1", "Q2", "Q3", "Q4", "Q5", "Q6"])
print("New synthetic shape:", df.shape)
最初の表は8行4項目です。usability_easeとfunctionality_needの和はすべて8で、中心化した行列の階数は3になります。片方を知るともう片方が完全に決まり、相関行列を逆行列にできません。この入力で通常の初期推定を進めると、固定環境ではSingular matrixとなりました。
ここには、完全な列の依存、4項目2因子の情報不足、標本8件という三つの問題があります。一列を削除したり乱数を少し足したりしてエラーだけを消しても、測定設計が妥当になったとは言えません。
後半は別の400行6項目の連続値教材です。二つの相関する因子と固有の乱数から、計算のために作りました。6項目で2因子を調べる目的を満たすための変更であり、元の8人に架空の回答を追加したものではありません。400件はこの例の設定で、必要標本数の基準ではありません。
KMO・Bartlettは「先へ進める保証」ではない
KMOは、項目間の通常の相関に比べ、ほかの項目を考慮した偏相関がどの程度残るかを見る指標です。全体値だけでなく項目別の値や相関行列も確認します。数値が一つの閾値を超えたことだけで、質問の意味や尺度の妥当性は決まりません。
Bartlettの球面性検定は、母相関行列が単位行列、つまり項目同士の相関がすべてゼロという帰無仮説を検討します。p値が小さくても「2因子が正しい」「心理特性が実証された」とは言えません。標本数や分布の条件にも依存します。両指標の計算は公開実装で確認できます。
実データで欠測を中央値に置き換える場合も、相関が変わることを考えます。段階評価の項目にPearson相関を使うか、順序データ向けの相関を検討するかは、回答分布と測定の条件次第です。以下の教材は連続値で欠測がなく、そのまま実アンケートへ転用する前提ではありません。
因子数は、乱数に比べて残る構造を見る
固有値が1を超えるか、スクリープロットがどこで折れるかは手掛かりですが、固定的な答えではありません。並行分析は、同じ行数・列数の無関連な乱数にも現れる固有値と、観測データの固有値を比べます。
ここでは、相関行列の対角を各項目の重相関係数の平方(SMC)へ置き換える変種を使います。SMCは、その項目をほかの項目で線形に説明できる割合です。乱数にも同じ手順を適用し、各順位の95百分位と比較します。通常の相関行列の対角を1のまま使うPCAの並行分析とは異なります。
psych作者の説明は、共通性の求め方や乱数の比較基準によって候補数が変わり、SMCを使うと小さい因子まで拾うことがあると注意しています。リンク先には旧版の表記もあるため、以下を現在のpsychの既定動作の再現とは呼びません。条件を明示したPython教材です。例2:適性の点検と、実際の並行比較
# Run example 1 first: df, np and pd are required.
import matplotlib.pyplot as plt
from factor_analyzer.factor_analyzer import calculate_kmo, calculate_bartlett_sphericity
kmo_items, kmo_total = calculate_kmo(df)
chi2, p_value = calculate_bartlett_sphericity(df)
print("KMO:", round(kmo_total, 3))
print("Bartlett chi2, p:", round(chi2, 3), f"{p_value:.3g}")
def smc_eigenvalues(values):
r = np.corrcoef(values, rowvar=False)
if np.linalg.eigvalsh(r).min() <= 1e-10:
raise ValueError("Correlation matrix must be positive definite")
reduced = r.copy()
np.fill_diagonal(reduced, 1 - 1 / np.diag(np.linalg.inv(r)))
return np.linalg.eigvalsh(reduced)[::-1]
observed = smc_eigenvalues(df.to_numpy())
random_rng = np.random.default_rng(812)
random_eigs = np.array([smc_eigenvalues(random_rng.normal(size=df.shape))
for _ in range(500)])
reference = np.quantile(random_eigs, .95, axis=0)
print("Observed:", np.round(observed, 3))
print("Random 95th:", np.round(reference, 3))
# Retain consecutive leading eigenvalues above the reference; no later re-entry.
suggested = int(np.cumprod(observed > reference).sum())
print("SMC parallel-analysis candidate:", suggested)
ranks = np.arange(1, df.shape[1] + 1)
plt.plot(ranks, observed, "o-", label="Observed, SMC diagonal")
plt.plot(ranks, reference, "s--", label="Random 95th percentile")
plt.axhline(0, color="gray", linewidth=.8)
plt.xticks(ranks)
plt.xlabel("Ordered eigenvalue")
plt.ylabel("Reduced-correlation eigenvalue")
plt.legend()
plt.tight_layout()
plt.savefig("fa-parallel.png", dpi=150)
plt.close()
この固定教材のKMOは0.792、Bartlettの統計量は約1113.917、p値は約4.97×10の-228乗です。観測側の先頭固有値は2.752、0.958、3番目は-0.103。乱数95百分位は順に0.262、0.160、0.075で、先頭から連続して基準を上回るのは2個でした。
対角を変えた縮約相関行列は、通常の相関行列とは違い、負の固有値を持つことがあります。これらをPCAの寄与率として足し合わせないでください。2因子はこの条件での候補です。乱数回数、相関の種類、項目の選び方を変えた検討や、残差の点検を省略する理由にはなりません。
推定と回転は、別の選択
因子の推定には、共通性を更新しながら求める主軸法、モデルの下で尤度を最大化する最尤法、相関の残差を小さくするMINRESなどがあります。最尤法では正規性などの条件が推論に関わります。以下はfactor_analyzerのAPIで方法を明示してMINRESを使います。名称の似たPCAを抽出法として置き換えてはいません。
回転は、推定された共通構造を読みやすい座標で表す操作です。バリマックスは因子の直交、プロマックスは因子間の相関を許す斜交回転です。直交だから一般に統計的に独立、斜交だから優秀、という関係ではありません。想定する内容と因子相関を併せて選びます。
例えば操作の分かりやすさと機能への評価が関連すると考えるなら、無相関を固定する理由を検討します。反対に、斜交の結果で因子相関が非常に大きければ、因子を分ける意味や項目の重複を見直す余地があります。見栄えのよい表になるまで回転を選び続けるのは避けます。
例3:負荷量、因子相関、共通性を分けて読む
# Run example 1 first: df, np and pd are required.
import matplotlib.pyplot as plt
from factor_analyzer import FactorAnalyzer
fa = FactorAnalyzer(n_factors=2, method="minres", rotation="promax")
fa.fit(df)
pattern = fa.loadings_
phi = fa.phi_
structure = pattern @ phi
common = np.diag(pattern @ phi @ pattern.T)
unique = 1 - common
scores = fa.transform(df)
print("Pattern:\n", pd.DataFrame(pattern, index=df.columns,
columns=["F1", "F2"]).round(3))
print("Factor correlation:\n", np.round(phi, 3))
print("Structure:\n", np.round(structure, 3))
print("Common variance:", np.round(common, 3))
print("Unique variance:", np.round(unique, 3))
print("Score shape:", scores.shape)
pd.DataFrame(pattern, index=df.columns, columns=["F1", "F2"]).plot.bar()
plt.ylabel("Pattern loading")
plt.axhline(0, color="gray", linewidth=.8)
plt.tight_layout()
plt.savefig("fa-pattern.png", dpi=150)
plt.close()
この実行では、Q1〜Q3が主にF2、Q4〜Q6が主にF1に対応し、因子相関は約0.449でした。生成時の因子相関0.35そのものが再現されるわけではありません。標本、推定、回転が介在します。また、軸の順序や符号が変わっても同じ構造を表す場合があるため、F1という番号だけで実行間の意味を固定しません。
表が収まらない場合は、横にスクロールできます
| 出力 | 読む対象 | 混同しやすいもの |
|---|---|---|
| Pattern(L) | 各因子から項目への係数 | 項目と因子の単純な相関 |
| Phi(Φ) | 因子同士の相関 | 因子得点同士の標本相関 |
| Structure(LΦ) | モデル上の項目と因子の相関 | Patternと常に同じ表 |
| 共通性 | LΦLᵀの対角成分 | 斜交時のPatternの単純な平方和 |
| 因子得点 | 各行の潜在因子の推定値 | 直接観測した性格や能力 |
数式で共通性は diag(LΦLᵀ) です。因子分散を1とするこの規約では、標準化した項目の固有分散は1から共通性を引きます。例の共通性は約0.625〜0.699でした。単純に各行の負荷量を二乗して足す関数と、相関する因子を含めた再構成とは区別してください。1を超える共通性や不適切な固有分散が出たら、丸めて隠さずモデル・推定・入力を点検します。
因子へ名前を付ける前に、項目へ戻る
因子の名前は、負荷量の大きい項目の内容をまとめる解釈です。「合理性」「感性」のような広い名前を先に決めると、違う意味の項目まで同じ性質として扱いやすくなります。項目文、回答の向き、複数因子への負荷、残差を示し、他の読み方がないかを検討してください。
因子得点を顧客の配置図やクラスタリングの入力に使うことはできます。ただし、得点には推定誤差があり、因子を変えると配置も変わります。Rの得点推定の説明が扱うように、得点化にも方法があります。一つの得点を性格診断として返したり、低得点の人に施策が効くと決めたりする根拠にはなりません。
例えば仮想のサービス調査なら、操作に関する因子と、後日の操作完了率がどう関連するかを別途確かめます。同じ回答者の同じ質問から作った軸を、同じ質問との相関だけで評価しても外部での有用性は分かりません。関係が見つかっても、説明画面を変えれば完了率が上がるという因果効果は別の検証です。
最小検証:項目を減らす前に、残る意味を確認する
初回は一つの判断に絞ります。例えば「似た項目を減らして回答負担を下げられるか」であれば、負荷量の小さい項目を自動削除するのではなく、その項目だけが測っている内容を確認します。
- 対象者、測定したい内容、項目文、欠測の扱いを記録する。
- 重複列・完全依存・分布を確認し、因子数の候補と識別の条件を点検する。
- 推定法・回転・並行分析の条件を固定し、負荷量と因子相関、再構成の残差を併読する。
- 因子名を変えても判断が変わらないか、別の標本や時期で構造を確かめられるかを検討する。
- 項目削除や施策を決める前に、内容の網羅性と外部での有用性を確認する。
練習として、この教材で因子数を1に変える、回転をバリマックスに変える、Q2を外す、の三つを別々に試してください。比較するのは見やすさだけでなく、残差、項目内容、因子相関です。生成時に2因子と分かっている教材と、答えが観測できない実調査との違いも残してください。
対象を似た集団に分けたい場合はクラスター分析、目的から手法を選び直す場合はデータサイエンス手法の一覧へ進めます。