本ページでは、 次元削減を統合的に解説します。 PCA・FA(因子分析)・MDS・t-SNE・UMAP・LDA・Kernel PCAを一気通貫で扱います。
次元削減は「本質的な情報を残しつつ、 変数を減らす」技術。 可視化・前処理・ノイズ除去・解釈支援に不可欠です。 SSDSE-B のように 30+ 変数があるデータでは、 PCA で 2-3 次元に可視化することから分析が始まります。
論文記事から各用語のリンクをクリックすると、 該当箇所が開きます:
| 章 | 内容 |
|---|---|
| 1. なぜ次元削減 | 高次元データの問題 |
| 2. PCA | 線形・最大分散 |
| 3. 因子分析 | 潜在因子モデル |
| 4. MDS | 距離保存 |
| 5. t-SNE | 局所構造保存・可視化 |
| 6. UMAP | 高速・スケーラブル |
| 7. LDA | 教師あり次元削減 |
| 8. オートエンコーダ | NN による非線形削減 |
分散を最大化する直交方向(主成分)を順に見つける。 第1主成分が最大分散、 第2は次に大きく、 第1と直交。
標準化済みデータ $\mathbf{X} \in \mathbb{R}^{n \times p}$ の共分散行列 $\mathbf{S} = \mathbf{X}^\top \mathbf{X}/(n-1)$ の固有分解:
$$\mathbf{S} = \mathbf{V} \boldsymbol{\Lambda} \mathbf{V}^\top$$
固有値 $\lambda_1 \geq \lambda_2 \geq \cdots$ に対応する固有ベクトル $\mathbf{v}_1, \mathbf{v}_2, \dots$ が主成分軸。 主成分得点:$\mathbf{Z} = \mathbf{X}\mathbf{V}$。
$$\text{寄与率}_k = \frac{\lambda_k}{\sum_j \lambda_j}, \quad \text{累積寄与率}_K = \sum_{k=1}^{K} \text{寄与率}_k$$
慣例 80–90% を満たす K を採用。
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 | import pandas as pd import numpy as np import matplotlib.pyplot as plt from sklearn.decomposition import PCA from sklearn.preprocessing import StandardScaler df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1) num = df.select_dtypes(include='number') X = StandardScaler().fit_transform(num) pca = PCA() Z = pca.fit_transform(X) # 寄与率 print(pca.explained_variance_ratio_[:5].round(3)) print('累積:', np.cumsum(pca.explained_variance_ratio_)[:5].round(3)) # 第1・第2主成分で可視化 plt.figure(figsize=(10, 6)) plt.scatter(Z[:,0], Z[:,1]) for i, name in enumerate(df['都道府県']): plt.annotate(name, (Z[i,0], Z[i,1]), fontsize=8) plt.xlabel('PC1'); plt.ylabel('PC2') plt.title('SSDSE-B 主成分得点') plt.show() |
固有値の大きい順プロット。 「肘」より上の主成分を採用。
各元変数の主成分への寄与。 主成分の解釈に使う。
1 2 3 4 5 6 | loadings = pd.DataFrame( pca.components_[:3].T, columns=['PC1', 'PC2', 'PC3'], index=num.columns, ) print(loadings.round(2)) |
観測変数を、 少数の共通因子と独自因子(誤差)の線形結合で表現するモデル:
$$\mathbf{x} = \boldsymbol{\Lambda} \mathbf{f} + \boldsymbol{\varepsilon}, \quad \mathbf{f} \sim N(0, \mathbf{I}),\ \boldsymbol{\varepsilon} \sim N(0, \boldsymbol{\Psi})$$
記号読み:$\mathbf{f}$ は「エフ・太字」共通因子、 $\boldsymbol{\Lambda}$ は「ラムダ・大文字」因子負荷行列、 $\boldsymbol{\Psi}$ は「プサイ・大文字」独自分散の対角行列。
| 項目 | PCA | 因子分析 |
|---|---|---|
| モデル | 射影 | 潜在変数モデル |
| 誤差項 | なし | あり |
| 説明対象 | 全分散 | 共通分散 |
| 用途 | 圧縮・前処理 | 理論的構造の検証 |
1 2 3 4 5 | from factor_analyzer import FactorAnalyzer fa = FactorAnalyzer(n_factors=3, rotation='varimax') fa.fit(X) print(pd.DataFrame(fa.loadings_, index=num.columns, columns=['F1','F2','F3']).round(2)) |
個体間の距離を可能な限り保存する低次元配置を求める。 距離行列が出発点。
1 2 3 | from sklearn.manifold import MDS mds = MDS(n_components=2, dissimilarity='euclidean', random_state=42) Z_mds = mds.fit_transform(X) |
古典的 MDS は PCA と等価(距離 = ユークリッドのとき)。 非計量 MDS は順序のみ保存。
高次元の局所構造を低次元で再現。 距離をガウス → 低次元では t分布(重い裾)として確率に変換し、 KL divergence を最小化。
1 2 3 | from sklearn.manifold import TSNE tsne = TSNE(n_components=2, perplexity=10, random_state=42, init='pca') Z_tsne = tsne.fit_transform(X) |
2018 年 McInnes ら。 t-SNE より高速・スケーラブル、 大局構造もある程度保存。 現代の可視化標準。
1 2 3 | import umap reducer = umap.UMAP(n_neighbors=15, min_dist=0.1, n_components=2, random_state=42) Z_umap = reducer.fit_transform(X) |
クラスラベルを使って、 クラス間分離を最大化、 クラス内分散を最小化する軸を求める。 次元削減と分類の両方に使える。
$$J(\mathbf{w}) = \frac{\mathbf{w}^\top \mathbf{S}_B \mathbf{w}}{\mathbf{w}^\top \mathbf{S}_W \mathbf{w}} \to \max$$
$\mathbf{S}_B$ がクラス間分散、 $\mathbf{S}_W$ がクラス内分散。 K クラスなら K-1 次元まで削減可能。
1 2 3 4 | from sklearn.discriminant_analysis import LinearDiscriminantAnalysis df['region'] = pd.qcut(df['人口密度'], q=3, labels=['農村','中規模','都市']) lda = LinearDiscriminantAnalysis(n_components=2) Z_lda = lda.fit_transform(X, df['region']) |
入力を低次元に圧縮(encoder)→ 復元(decoder)する NN。 ボトルネック層が次元削減された潜在表現。
1 2 3 4 5 6 7 8 9 10 11 12 | import torch import torch.nn as nn class Autoencoder(nn.Module): def __init__(self, in_dim, latent_dim=2): super().__init__() self.enc = nn.Sequential(nn.Linear(in_dim, 16), nn.ReLU(), nn.Linear(16, latent_dim)) self.dec = nn.Sequential(nn.Linear(latent_dim, 16), nn.ReLU(), nn.Linear(16, in_dim)) def forward(self, x): z = self.enc(x) return self.dec(z), z |
派生形:VAE(変分オートエンコーダ)、 Sparse AE、 Denoising AE、 Contractive AE。
カーネル法で非線形 PCA。 元データ → カーネル特徴空間 → 線形 PCA。 RBF / Polynomial / Sigmoid カーネルがよく使われる。
1 2 3 | from sklearn.decomposition import KernelPCA kpca = KernelPCA(n_components=2, kernel='rbf', gamma=0.5) Z_kpca = kpca.fit_transform(X) |
近傍グラフ上の測地距離を MDS で配置。 多様体の形状を保つ。
1 2 3 | from sklearn.manifold import Isomap iso = Isomap(n_neighbors=5, n_components=2) Z_iso = iso.fit_transform(X) |
| 手法 | 線形/非線形 | 教師 | 速度 | 用途 |
|---|---|---|---|---|
| PCA | 線形 | なし | 速 | 圧縮・前処理 |
| FA | 線形 | なし | 中 | 潜在構造 |
| MDS | 線形/非線形 | なし | 遅 | 距離保存 |
| t-SNE | 非線形 | なし | 遅 | 可視化 |
| UMAP | 非線形 | なし | 中 | 可視化(標準) |
| LDA | 線形 | あり | 速 | 分類前処理 |
| Autoencoder | 非線形 | なし | 遅 | 表現学習 |
| Kernel PCA | 非線形 | なし | 遅 | 非線形圧縮 |
| 落とし穴 | 対処 |
|---|---|
| 標準化せずに PCA | 大スケール変数だけが第1主成分に。 必ず StandardScaler。 |
| t-SNE の大局構造を信用 | クラスタ間の距離・大きさは意味なし。 局所構造のみ。 |
| PCA と FA を混同 | FA は潜在変数モデル、 PCA は射影。 目的に応じて使い分け。 |
| 主成分を符号付きで解釈 | 主成分の符号は任意。 解釈には絶対値の大小と方向を見る。 |
| 寄与率の低い PC で結論 | 第3主成分以降は寄与率が低いと解釈価値も低い。 |
| t-SNE / UMAP で外挿 | 新データに transform できない(UMAP は parametric なら可)。 |
| LDA でクラスが少ない | K クラスなら K-1 次元まで。 多クラス分類前段で。 |
1 2 3 4 5 6 7 8 9 10 | import pandas as pd, numpy as np from sklearn.decomposition import PCA from sklearn.preprocessing import StandardScaler df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1) num = df.select_dtypes(include='number') X = StandardScaler().fit_transform(num) pca = PCA().fit(X) cum = np.cumsum(pca.explained_variance_ratio_) print('80%%超え K =', np.argmax(cum >= 0.8) + 1) print(pd.DataFrame(pca.components_[:3].T, columns=['PC1','PC2','PC3'], index=num.columns).round(2)) |
1 2 3 4 5 | from sklearn.manifold import TSNE import umap Z_tsne = TSNE(n_components=2, perplexity=10, random_state=42).fit_transform(X) Z_umap = umap.UMAP(n_neighbors=10, random_state=42).fit_transform(X) # プロット比較 |
1 2 3 4 | from sklearn.discriminant_analysis import LinearDiscriminantAnalysis df['region'] = pd.qcut(df['人口密度'], q=3, labels=['農村','中規模','都市']) lda = LinearDiscriminantAnalysis(n_components=2) Z_lda = lda.fit_transform(X, df['region']) |
「PCA で 2 次元にして可視化しました。」
「30 変数を標準化後 PCA に投入。 第1主成分の寄与率 31%、 第2主成分 22%(累積 53%)。 第1主成分は所得・人口密度に正の負荷量、 高齢化率に負の負荷量を持つため『都市的・経済発展度』、 第2主成分は世帯人員と就業率に正の負荷で『家族基盤・就業度』と解釈した。 上位 5 主成分で累積 82%、 これらを後続のクラスタリングの入力に使用。」
| 手法 | クラス・関数 |
|---|---|
| PCA | sklearn.decomposition.PCA / TruncatedSVD / IncrementalPCA |
| Kernel PCA | sklearn.decomposition.KernelPCA |
| FA | sklearn.decomposition.FactorAnalysis / factor_analyzer.FactorAnalyzer |
| MDS | sklearn.manifold.MDS |
| t-SNE | sklearn.manifold.TSNE / openTSNE |
| UMAP | umap-learn (import umap) |
| Isomap | sklearn.manifold.Isomap |
| LLE | sklearn.manifold.LocallyLinearEmbedding |
| LDA | sklearn.discriminant_analysis.LinearDiscriminantAnalysis |
| Autoencoder | torch.nn / keras.layers |
| NMF | sklearn.decomposition.NMF |
| ICA | sklearn.decomposition.FastICA |
論文・記事に登場する用語のリンクで該当箇所へジャンプ:
SSDSE-B-2026 2023年データから家計支出15項目(食品・住居・光熱・教育等)を取り、 PCA・t-SNE・UMAP の 3 手法で2次元に圧縮します。
| 主成分 | 寄与率 | 累積寄与率 | 意味(仮想) |
|---|---|---|---|
| PC1 | 42.3% | 42.3% | 「総支出規模」軸 |
| PC2 | 18.7% | 61.0% | 「都市型 vs 郊外型消費」軸 |
| PC3 | 9.4% | 70.4% | 「教育投資度」軸 |
| PC4 | 6.8% | 77.2% | 「光熱費比重」軸 |
| PC5 | 5.2% | 82.4% | 「住居費比重」軸 |
第2主成分まで61%の情報、 第5主成分まで82%の情報。 「カイザー基準(固有値 > 1)」と「スクリープロットの肘」から PC を選ぶのが慣行。
| 手法 | 原理 | SSDSE 47県でのプロット | 計算時間 |
|---|---|---|---|
| PCA | 線形・分散最大化 | 東京・大阪が右上、 地方は左下に並ぶ単調な配置 | < 0.1秒 |
| t-SNE | 局所近傍を保つ非線形 | 3-4のクラスタが見える、 県の地理的近接が反映 | 2-5秒 |
| UMAP | 位相幾何学的保存 | t-SNEと類似、 大域構造をより保つ | 1-3秒 |
「家計支出(数万円単位)」と「世帯人数(小数の単位)」を混在させて PCA をかけると、 単位が大きい変数(家計支出)が PC1 を完全に支配し、 他の情報が埋もれる。 必ず StandardScaler で各変数を平均 0・分散 1 に標準化してから PCA を行う。 ただし「自然に同単位」の場合(同種計測値の集合)は標準化しない方が良いこともあるので、 ケースごとに判断。
t-SNE の出力は「局所構造を保つ」ものの、 クラスタ間の距離やサイズには意味がない。 グラフで離れていても「全く違う」とは限らないし、 大きいクラスタが「種類が多い」わけでもない。 t-SNE の図を見るときは「同じ色は同じグループ」だけを情報として受け取り、 「距離が遠い = 違う」と即断しないこと。 大域構造を見たいなら UMAP か PCA を併用。
「PC1 は所得、 PC2 は都市性」のように強引な意味付けをすると、 後の議論が脆くなる。 主成分は変数の線形結合であり、 必ずしも単純な概念に対応しない。 ローディング(負荷量)を確認し、 0.4 以上の絶対値を持つ変数だけで解釈する。 「解釈可能性」を高めたいなら主成分回転(Varimax)や因子分析を検討。
機械学習で「全データで PCA を計算してから訓練/テスト分割」するのは、 テストデータの情報が前処理に漏れるデータリーク。 必ず train で fit、 test には transform のみ。 scikit-learn の Pipeline なら自動的に正しい順序で実行される。 これは StandardScaler でも同じ問題が発生します。
PCA は応答変数 y を見ないので、 「圧縮した結果 y の予測に重要な情報が失われる」ことがあります。 教師あり学習の特徴量削減なら、 PCA より Partial Least Squares (PLS)、 LDA、 RFE 等を検討。 PCA を盲信せず、 圧縮後と圧縮前で CV スコアを比較する。
t-SNE の perplexity、 UMAP の n_neighbors / min_dist を変えると、 全く違う図が出ることが普通。 デフォルト値で 1回だけ実行して結論を出すのは危険。 複数の設定で実行し、 安定して見えるパターンだけを信用する。 また乱数シードでも結果が変わるので、 複数 seed で繰り返すと安心。
1 2 3 4 5 6 | from sklearn.decomposition import PCA from sklearn.preprocessing import StandardScaler X_std = StandardScaler().fit_transform(X) pca = PCA(n_components=2).fit(X_std) Z = pca.transform(X_std) print(pca.explained_variance_ratio_) |
1 2 3 | from sklearn.manifold import TSNE tsne = TSNE(n_components=2, perplexity=5, random_state=42) Z_tsne = tsne.fit_transform(X_std) |
注意:47サンプルなら perplexity は 5-10 程度に下げる。 デフォルト30 はサンプル数より大きいと警告が出る。
pip install umap-learn)1 2 3 | import umap reducer = umap.UMAP(n_neighbors=10, min_dist=0.3, random_state=42) Z_umap = reducer.fit_transform(X_std) |
1 2 3 4 | from sklearn.decomposition import KernelPCA, NMF, SparsePCA kpca = KernelPCA(n_components=2, kernel='rbf', gamma=0.1) nmf = NMF(n_components=3) # 非負データ専用 spca = SparsePCA(n_components=3, alpha=1) # L1 ペナルティで解釈性向上 |
1 2 3 4 5 | from scipy.linalg import svd X_c = X_std - X_std.mean(0) U, S, Vt = svd(X_c, full_matrices=False) Z = U @ np.diag(S) # PCA スコアと同じ print(S**2 / (len(X_c)-1)) # 固有値 |
$$ \max_{w} w^\top \Sigma w \quad \text{subject to} \quad \| w \| = 1 $$
$$ \Sigma = \frac{1}{n-1} \sum_{i=1}^{n} (x_i - \bar{x})(x_i - \bar{x})^\top $$
次元削減は、 高次元データを情報損失を最小化しながら低次元に圧縮する手法。 PCA(主成分分析)、 t-SNE、 UMAP、 オートエンコーダなど。 SSDSE-B-2026 の 100 超の列を 2-3 次元に圧縮して可視化する典型応用。
次元削減 (Dimension Reduction) は、 統計・データ解析の文脈で頻繁に登場する概念です。 ここでは初学者向けの直感と、 上級者向けの形式定義を併記します。
SSDSE-B-2026 の 100 超の列を PCA で 2 次元に圧縮し、 47 都道府県を散布図に。 PC1 軸は「人口規模」、 PC2 軸は「高齢化度」 などと解釈できる。 t-SNE や UMAP は非線形でクラスタ構造をより明確に表示。
SSDSE-B-2026 は 都道府県別社会経済データ集 2026 年版で、 47 都道府県 × 約 10 年度 × 100 超の指標を含む公的データです。 次元削減の概念を SSDSE-B-2026 で実証することで、 「数値の動きが地理的・社会的直感と整合するか」を検証できます。
| 列コード | 意味 | 本ページでの用途 |
|---|---|---|
A1101 | 総人口 | PCA の主要寄与因子 |
A1303 | 65 歳以上人口 | 高齢化軸 |
E1101 | 小学校数 | 教育リソース次元 |
F3101 | 新規求人数 | 雇用機会次元 |
J2503 | 住宅ストック | 住宅次元 |
以下は SSDSE-B-2026 を題材にした実コード例集です。 すべて data/raw/SSDSE-B-2026.csv を読み込み、 実値で動作確認しています。
import pandas as pd
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='shift_jis', skiprows=[1])
d23 = df[df['SSDSE-B-2026']==2023].reset_index(drop=True)
d23['aging'] = d23['A1303'].astype(float)/d23['A1101'].astype(float)
d23['birth_rate'] = d23['A4101'].astype(float)/d23['A1101'].astype(float)*1000
print(d23[['Prefecture','aging','birth_rate']].describe().round(3))
print('最高齢化:', d23.nlargest(3,'aging')[['Prefecture','aging']].values)
print('最低高齢化:', d23.nsmallest(3,'aging')[['Prefecture','aging']].values)
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='shift_jis', skiprows=[1])
d23 = df[df['SSDSE-B-2026']==2023].reset_index(drop=True)
d23['aging'] = d23['A1303'].astype(float)/d23['A1101'].astype(float)
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
axes[0].hist(d23['aging'], bins=15, edgecolor='black')
axes[0].set_xlabel('高齢化率'); axes[0].set_ylabel('県数')
axes[1].boxplot(d23['aging'])
axes[1].set_ylabel('高齢化率')
plt.savefig('aging_dist.png', dpi=100)
import pandas as pd
from scipy import stats
import numpy as np
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='shift_jis', skiprows=[1])
d23 = df[df['SSDSE-B-2026']==2023].copy()
d23['aging'] = d23['A1303'].astype(float)/d23['A1101'].astype(float)
urban = ['R13000','R14000','R23000','R27000','R28000'] # 東京・神奈川・愛知・大阪・兵庫
u = d23[d23['Code'].isin(urban)]['aging']
r = d23[~d23['Code'].isin(urban)]['aging']
t, p = stats.ttest_ind(u, r, equal_var=False)
d_cohen = (u.mean() - r.mean()) / np.sqrt((u.var() + r.var())/2)
print(f't = {t:.2f}, p = {p:.4f}, Cohen d = {d_cohen:.2f}')
import pandas as pd
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='shift_jis', skiprows=[1])
df['aging'] = df['A1303'].astype(float)/df['A1101'].astype(float)
trend = df.groupby('SSDSE-B-2026')['aging'].agg(['mean','std','min','max']).round(3)
print(trend)
次元削減は前提条件次第で意味が変わります。 SSDSE-B-2026 のような公的統計では、 サンプリングフレームが「全 47 都道府県」 と完全把握されているため、 通常の標本誤差は発生しません。 しかし「2023 年の 1 時点を全体集団とみなすか、 もっと長期の集団からの 1 サンプルとみなすか」で解釈が変わります。
SSDSE-B-2026 のような 100 超の列を扱うと、 多重比較(同じデータで多数の検定を行う)の罠が発生します。 Bonferroni 補正、 Benjamini-Hochberg などで補正してから 次元削減に関連する統計量を解釈すべきです。
都道府県の中に市区町村があり、 階層構造を持つ場合、 階層線形モデル(HLM)で 次元削減を扱うことを検討します。 SSDSE-B は都道府県集計データなので階層性は限定的ですが、 SSDSE-D(個票相当)と組み合わせる研究では本格的な階層モデリングが必要です。
SSDSE-B-2026 は 2014〜2023 年の 10 年間のパネル構造を持ちます。 次元削減を時間軸込みで扱うときは、 固定効果モデル・ランダム効果モデルなどパネルデータ手法を併用します。
SSDSE-B-2026 の県別データから「次元削減に関わる関係」を抽出できても、 それは多くの場合「相関」であり、 「因果」を主張するには無作為化試験・自然実験・操作変数などの追加設計が必須です。
SSDSE-B-2026 で「人口」「出生数」「死亡数」を比較。 次元削減を使って自然増減のパターンを定量化。 東京・神奈川・愛知の都市集中、 秋田・高知の過疎化。
「学校数」「教員数」「進学率」を 次元削減で分析。 県別の教育リソース配分の効率性を評価。 都市と地方の格差を可視化。
「病院数」「医師数」「平均寿命」 を組み合わせ。 次元削減で医療資源の不均衡と健康成果の関係を推定。 北海道の医師偏在問題。
「就業者数」「県内総生産」「1 人当たり所得」を 次元削減で関連付け。 製造業県と観光業県のパターン差。
「高齢化率」「税収」「社会保障費」を 次元削減で評価。 高齢化が進む県の財政負担の重さを定量化。 県政策への含意。
研究結果を 次元削減を使って報告するときに守るべきチェックリスト:
次元削減は学術研究だけでなく、 政策・ビジネスの意思決定に直接活用されています。
計量経済学・教育測定・心理測定・疫学などで 次元削減は基礎ツール。 近年は機械学習との融合で新しい応用が広がっています。
次元削減 の概念は、 統計学の発展史と並行して洗練されてきました。
日本では、 1947 年の統計法制定以降、 SSDSE-B のような公的統計の整備が進み、 次元削減を学ぶ実データ環境が充実してきました。