論文一覧に戻る 📚 用語集トップ 🗺 概念マップ
📚 用語解説(ジャストインタイム型データサイエンス教育)
次元削減
Dimensionality Reduction
高次元データを少ない次元で表現する — 可視化・前処理の必須技術
教師なし/教師あり可視化前処理解釈支援

🔖 キーワード索引

「dimension reduction」は統計データ分析の文脈で扱う重要概念のひとつ。 本ページでは「dimension reduction」を取り巻く中核キーワードを以下にチップで一覧化する。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になる。

dimension reduction統計分析SSDSE-B-2026前提条件適用範囲落とし穴関連手法Python 実装検証方法

これらのキーワードは「dimension reduction の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。

💡 30秒で分かる結論

🍰 まずはやさしく

情報の要約のような技術です。

大事なところだけを残して、扱いやすくします。

スマホの写真の容量を減らす感覚に似ています。

代表的な手法と使い分けについて読みましょう。

📍 あなたが今見ているもの

🍰 まずはやさしく

データの項目を絞り込む方法です。

複雑なデータを分かりやすくするために使います。

部活の成績表から重要な項目だけを選ぶイメージです。

次元削減の全体像と、具体的な種類を学びます。

本ページでは、 次元削減を統合的に解説します。 PCA・FA(因子分析)・MDS・t-SNE・UMAP・LDA・Kernel PCAを一気通貫で扱います。

次元削減は「本質的な情報を残しつつ、 変数を減らす」技術。 可視化・前処理・ノイズ除去・解釈支援に不可欠です。 SSDSE-B のように 30+ 変数があるデータでは、 PCA で 2-3 次元に可視化することから分析が始まります。

🎨 5. t-SNE

🍰 まずはやさしく

似たもの同士を近くに集める地図のようなものです。

データのグループを絵にして、目で見て分かるようにします。

似た趣味を持つ友達をグループ分けする感覚です。

t-SNEという手法で、データを可視化する方法を読みます。

高次元の局所構造を低次元で再現。 距離をガウス → 低次元では t分布(重い裾)として確率に変換し、 KL divergence を最小化。

🎯 解説: t-SNE で、 SSDSE-B-2026 の 47 都道府県を高次元の指標空間から 2 次元へ埋め込み、 似た県どうしの局所的な近傍構造を保ったままクラスタを可視化する。
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1301(15歳未満人口) A1303(65歳以上人口) A4101(出生数) L3221(消費支出(二人以上の世帯)) 北海道 5,092,000 514,000 1,681,000 24,430 296,888 東京都 14,086,000 1,513,000 3,205,000 86,348 341,320 沖縄県 1,468,000 236,000 350,000 12,549 251,222 …(全 47 行)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import pandas as pd
from sklearn.preprocessing import StandardScaler

# ── この抜粋だけで動くように、47 都道府県の特徴量を用意する ──
# 英字の項目コードを使うので、2 行目の日本語名は読み飛ばす
_d = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
_d = _d[_d['SSDSE-B-2026'] == 2023]          # 最新年度の 47 行
_cols = ['A1101', 'A1301', 'A1303', 'A4101', 'L3221']  # 総人口・15歳未満・65歳以上・出生数・消費支出
# この後のブロックでも使うので df / X という名前で置いておく
df = _d
X = StandardScaler().fit_transform(_d[_cols].astype(float).values)   # 列ごとに平均 0・分散 1

from sklearn.manifold import TSNE
# perplexity は標本数(47)より小さくすること。
# 標本が数千未満なら method='exact' のほうが正確で、しかも速い
tsne = TSNE(n_components=2, perplexity=10, random_state=42,
            init='pca', method='exact')
Z_tsne = tsne.fit_transform(X)
print(Z_tsne.shape)
print('KL divergence:', round(tsne.kl_divergence_, 3))
📥 入力例: data/raw/SSDSE-B-2026.csv(2023 年度の 47 行) X = 標準化済み (47 都道府県 × 5 指標: A1101 総人口, A1301 15歳未満人口, A1303 65歳以上人口, A4101 出生数, L3221 消費支出)
📤 実行例(実測) (47, 2) KL divergence: 0.125
💬 読み方: 47 県が 2 次元の座標 (47, 2) に置き換わり、最適化後の KL divergence は 0.125 だった。KL は高次元での近所の確率と 2 次元での近所の確率のずれで、0 に近いほど近所関係がよく写せている。perplexity や乱数を変えると値も配置も変わるので、0.125 を比べるのは同じデータ・同じ perplexity の範囲に限る。クラスタ間の距離や大きさには意味がないため「離れている=無関係」と即断しない。

🚀 6. UMAP

2018 年 McInnes ら。 t-SNE より高速・スケーラブル、 大局構造もある程度保存。 現代の可視化標準。

🎯 解説: UMAP で、 SSDSE-B-2026 の 47 都道府県を 2 次元へ埋め込む。 t-SNE より高速で、 局所構造に加えて大局構造もある程度保ったクラスタ配置が得られる。
1
2
3
4
5
6
7
8
9
import umap
reducer = umap.UMAP(n_neighbors=15, min_dist=0.1, n_components=2, random_state=42)
Z_umap = reducer.fit_transform(X)
import numpy as np
names = df['Prefecture'].values
tokyo = np.where(names == '東京都')[0][0]
dist = np.linalg.norm(Z_umap - Z_umap[tokyo], axis=1)
print(Z_umap.shape)
print('UMAP 上で東京に近い 3 県:', list(names[np.argsort(dist)[1:4]]))
📥 入力例: X = 上の t-SNE で作った標準化済みデータ (47 都道府県 × 5 指標)
📤 実行例(実測) (47, 2) UMAP 上で東京に近い 3 県: ['神奈川県', '大阪府', '愛知県']
💬 読み方: UMAP の 2 次元配置で東京に最も近いのは神奈川県・大阪府・愛知県で、人口・出生数・高齢人口がそろって大きい大都市圏どうしが近所に集まった。5 指標のうち 4 つが人口規模の列なので、この近さはほぼ「県の大きさが似ている」ことを表している。n_neighbors を変えると近所の顔ぶれが入れ替わることがあるので、複数の設定で確かめる。

🎯 7. LDA(線形判別分析、 教師あり)

クラスラベルを使って、 クラス間分離を最大化、 クラス内分散を最小化する軸を求める。 次元削減と分類の両方に使える。

$$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 次元まで削減可能。

🎯 解説: LDA(線形判別分析)で、 都道府県を総人口(A1101)により「農村/中規模/都市」の 3 群に分け、 群を最もよく分離する低次元軸(判別軸)を構築する。
1
2
3
4
5
6
7
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
df['region'] = pd.qcut(df['A1101'], q=3, labels=['農村','中規模','都市'])
lda = LinearDiscriminantAnalysis(n_components=2)
Z_lda = lda.fit_transform(X, df['region'])
print(df['region'].value_counts().sort_index().to_dict())
print('判別軸の寄与率:', lda.explained_variance_ratio_.round(3))
print(pd.DataFrame(Z_lda, columns=['LD1', 'LD2']).groupby(df['region'].values, observed=True).mean().round(2))
📥 入力例: X = 上の t-SNE で作った標準化済みデータ (47 都道府県 × 5 指標) y = 総人口 A1101 の 3 分位ラベル(農村 / 中規模 / 都市)
📤 実行例(実測) {'農村': 16, '中規模': 15, '都市': 16} 判別軸の寄与率: [0.988 0.012] LD1 LD2 農村 -1.48 -0.18 中規模 -0.69 0.24 都市 2.13 -0.05
💬 読み方: 総人口の 3 分位で 16・15・16 県に分けると、判別軸の寄与率は LD1 が 0.988 でほぼすべてを担い、LD2 は 0.012 しかない。群平均は LD1 上で 農村 -1.48、中規模 -0.69、都市 2.13 と一直線に並び、LD2 はどの群も ±0.24 以内なので、3 群を分けているのは実質 1 本の規模軸である。ラベルを作った総人口そのものが X に入っているので分離が良いのは当然で、X から A1101 を抜いても分かれるかを確かめると判別軸の意味がはっきりする。

🧠 8. オートエンコーダ(NN による非線形次元削減)

入力を低次元に圧縮(encoder)→ 復元(decoder)する NN。 ボトルネック層が次元削減された潜在表現。

🎯 解説: オートエンコーダで、 都道府県の多変量指標を encoder で 2 次元の潜在変数 z に圧縮し、 decoder で元の次元へ復元する非線形次元削減を学習する。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import torch
import torch.nn as nn
torch.manual_seed(0)   # 実行のたびに同じ結果が出るようにする
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
# 47 県 × 5 指標(標準化済みの X)で学習する
Xt = torch.tensor(X, dtype=torch.float32)
ae = Autoencoder(in_dim=Xt.shape[1])
opt = torch.optim.Adam(ae.parameters(), lr=1e-2)
for epoch in range(500):
    recon, z = ae(Xt)
    loss = ((recon - Xt) ** 2).mean()          # 再構成誤差(MSE)
    opt.zero_grad(); loss.backward(); opt.step()
    if epoch % 100 == 0 or epoch == 499:
        print(f'epoch {epoch:3d}: 再構成 MSE = {loss.item():.4f}')
print('潜在変数 z の形:', tuple(z.shape))
📥 入力例: X = 上の t-SNE で作った標準化済みデータ (47 都道府県 × 5 指標)
📤 実行例(実測) epoch 0: 再構成 MSE = 1.0591 epoch 100: 再構成 MSE = 0.0055 epoch 200: 再構成 MSE = 0.0032 epoch 300: 再構成 MSE = 0.0029 epoch 400: 再構成 MSE = 0.0028 epoch 499: 再構成 MSE = 0.0027 潜在変数 z の形: (47, 2)
💬 読み方: 再構成 MSE は学習前の 1.0591 から 500 epoch で 0.0027 まで下がった。同じ 5 指標を線形 PCA の 2 成分で復元したときに失われる分散は約 0.005(寄与率 0.821+0.174 の残り)なので、AE はそれより少し小さい誤差で復元している。ただし 47 件に対して重みは 263 個あり、学習データに合わせ込んだ結果なので、新しい県をうまく復元できるかはこの数字からは分からない。

派生形:VAE(変分オートエンコーダ)、 Sparse AE、 Denoising AE、 Contractive AE。

🌀 9. 非線形 PCA・Isomap

9.1 Kernel PCA

カーネル法で非線形 PCA。 元データ → カーネル特徴空間 → 線形 PCA。 RBF / Polynomial / Sigmoid カーネルがよく使われる。

🎯 解説: Kernel PCA(カーネル主成分分析)で、 SSDSE-B-2026 を非線形変換して、 通常の線形 PCA では捉えられない曲面状の構造を 2 次元で可視化する。
1
2
3
4
5
6
7
from sklearn.decomposition import KernelPCA
kpca = KernelPCA(n_components=2, kernel='rbf', gamma=0.5)
Z_kpca = kpca.fit_transform(X)
print(Z_kpca.shape)
print('上位 2 固有値:', kpca.eigenvalues_.round(3))
tokyo = list(df['Prefecture']).index('東京都')
print('東京の座標:', Z_kpca[tokyo].round(3))
📥 入力例: X = 上の t-SNE で作った標準化済みデータ (47 都道府県 × 5 指標)
📤 実行例(実測) (47, 2) 上位 2 固有値: [8.506 6.764] 東京の座標: [0.159 0.428]
💬 読み方: gamma=0.5 の RBF カーネルでは上位 2 固有値が 8.506 と 6.764 で差が小さく、線形 PCA で PC1 が 8 割を持つのとは様子が違う。東京の座標 (0.159, 0.428) は他県の範囲(第 1 軸 -0.60〜0.74)の内側にあり、線形 PCA のように端へ飛び出さない。標準化後に他県から大きく離れた東京は、カーネル値 exp(-0.5×距離²) がどの県ともほぼ 0 になり、「どの県とも似ていない」という情報しか残らないためで、gamma の選び方で外れ値の見え方が大きく変わる。

9.2 Isomap

近傍グラフ上の測地距離を MDS で配置。 多様体の形状を保つ。

🎯 解説: Isomap で、 都道府県データの多様体上での距離(近傍グラフ上の測地距離)に基づいて 2 次元へ埋め込み、 連続的な変化軸を抽出する。
1
2
3
4
5
6
7
8
9
from sklearn.manifold import Isomap
iso = Isomap(n_neighbors=5, n_components=2)
Z_iso = iso.fit_transform(X)
print(Z_iso.shape)
print('再構成誤差:', round(iso.reconstruction_error(), 3))
names = df['Prefecture'].values
tokyo = list(names).index('東京都')
d_iso = np.linalg.norm(Z_iso - Z_iso[tokyo], axis=1)
print('Isomap 上で東京に近い 3 県:', list(names[np.argsort(d_iso)[1:4]]))
📥 入力例: X = 上の t-SNE で作った標準化済みデータ (47 都道府県 × 5 指標)
📤 実行例(実測) (47, 2) 再構成誤差: 0.227 Isomap 上で東京に近い 3 県: ['神奈川県', '大阪府', '埼玉県']
💬 読み方: 近傍 5 県のグラフで測地距離を取った Isomap でも、東京に近いのは神奈川県・大阪府・埼玉県で、UMAP の結果(神奈川・大阪・愛知)とほぼ同じ顔ぶれになった。再構成誤差 0.227 は測地距離を 2 次元で表しきれなかった分の目安で、n_neighbors を変えて比べるときの物差しに使える。近傍数が小さすぎるとグラフが分断し、大きすぎると PCA に近づく。

📊 10. 手法比較

手法 線形/非線形 教師 速度 用途
PCA線形なし速圧縮・前処理
FA線形なし中潜在構造
MDS線形/非線形なし遅距離保存
t-SNE非線形なし遅可視化
UMAP非線形なし中可視化(標準)
LDA線形あり速分類前処理
Autoencoder非線形なし遅表現学習
Kernel PCA非線形なし遅非線形圧縮

📐 数式 — PCA の最適化問題

🍰 まずはやさしく

データの散らばりを計算するルールです。

一番特徴が出ている方向を見つけるために使います。

テストの点数から、得意分野を分析するイメージです。

PCAという手法で、計算をどう行うかを読みます。

$$ \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 における具体例

SSDSE-B-2026 の 100 超の列を PCA で 2 次元に圧縮し、 47 都道府県を散布図に。 PC1 軸は「人口規模」、 PC2 軸は「高齢化度」 などと解釈できる。 t-SNE や UMAP は非線形でクラスタ構造をより明確に表示。

SSDSE-B-2026 は 都道府県別社会経済データ集 2026 年版で、 47 都道府県 × 約 10 年度 × 100 超の指標を含む公的データです。 次元削減の概念を SSDSE-B-2026 で実証することで、 「数値の動きが地理的・社会的直感と整合するか」を検証できます。

使用する主要な SSDSE-B-2026 列

列コード意味本ページでの用途
A1101総人口PCA の主要寄与因子
A130365 歳以上人口高齢化軸
E1101小学校数教育リソース次元
F3101新規求人数雇用機会次元
J2503住宅ストック住宅次元

🧮 SSDSE-B 実値計算例:家計10項目を 2 次元に圧縮

SSDSE-B-2026 2023年データから家計支出10項目(食料費・住居費・光熱・水道費・家具・家事用品費・被服及び履物費・保健医療費・交通・通信費・教育費・教養娯楽費・その他の消費支出、 列コード L322101〜L322110)を取り、 PCA・t-SNE・UMAP の 3 手法で2次元に圧縮します。

📝 補足(実測ベースであることの明示):下の寄与率表は、 SSDSE-B-2026 の 2023 年・47 都道府県について、 家計支出 10 項目(L322101〜L322110)を標準化(相関行列)した PCA の実測値です。 SSDSE-B に家計支出の細目は 10 項目しか存在しないため(旧記述の「15 項目」は誤り)、 本例も 10 項目で構成しています。 「意味」列の軸解釈のみ理解を助けるための仮想ラベルです。

📊 ステップ1:PCA の寄与率と累積寄与率

主成分 寄与率 累積寄与率 意味(仮想)
PC142.8%42.8%「総支出規模」軸
PC216.0%58.8%「都市型 vs 郊外型消費」軸
PC310.6%69.5%「教育投資度」軸
PC48.7%78.2%「光熱費比重」軸
PC57.0%85.2%「住居費比重」軸

第2主成分まで58.8%の情報、 第5主成分まで85.2%の情報。 「カイザー基準(固有値 > 1)」と「スクリープロットの肘」から PC を選ぶのが慣行。

📊 ステップ2:手法ごとの特徴

手法 原理 SSDSE 47県でのプロット 計算時間
PCA線形・分散最大化東京・大阪が右上、 地方は左下に並ぶ単調な配置< 0.1秒
t-SNE局所近傍を保つ非線形3-4のクラスタが見える、 県の地理的近接が反映2-5秒
UMAP位相幾何学的保存t-SNEと類似、 大域構造をより保つ1-3秒

🧮 数式に値を入れて手で計算する — PCA の共分散行列と固有値

PCA の心臓部である 共分散行列 → 固有値分解 に、 2 次元 5 点の合成データを代入して計算過程を Step 1〜5 で展開する。 同じ計算を Python (numpy) で再現し、 結果が一致することを確認する。

📐 用語の主要数式 (再掲)

$$ \Sigma = \frac{1}{n-1}(X - \bar X)^\top (X - \bar X), \qquad \Sigma v = \lambda v $$

$\Sigma$ は標本共分散行列、 $\lambda$ は固有値 (主成分の分散)、 $v$ は固有ベクトル (主成分軸)。

Step 1: データ準備 (合成、 2 次元 5 点)

サンプル$x_1$$x_2$
A23
B47
C712
D59
E34

Step 2: 平均と中心化

項目計算結果
$\bar x_1$$(2+4+7+5+3)/5$4.2
$\bar x_2$$(3+7+12+9+4)/5$7.0

Step 3: 共分散行列 $\Sigma$ ($n-1$ で割る)

項目計算結果
$\sum (x_{1i}-\bar x_1)^2$$4.84+0.04+7.84+0.64+1.44$14.8
$\sum (x_{2i}-\bar x_2)^2$$16+0+25+4+9$54
$\sum (x_{1i}-\bar x_1)(x_{2i}-\bar x_2)$$8.8+0+14+1.6+3.6$28
$\Sigma_{11}$$14.8/4$3.7
$\Sigma_{22}$$54/4$13.5
$\Sigma_{12}=\Sigma_{21}$$28/4$7.0

よって $\Sigma = \begin{pmatrix} 3.7 & 7.0 \\ 7.0 & 13.5 \end{pmatrix}$。

Step 4: 固有値 (特性方程式 $\det(\Sigma - \lambda I)=0$)

項目計算結果
トレース $\Sigma_{11}+\Sigma_{22}$$3.7+13.5$17.2
行列式 $\Sigma_{11}\Sigma_{22}-\Sigma_{12}^2$$3.7 \times 13.5 - 49$0.95
2 次方程式 $\lambda^2 - 17.2\lambda + 0.95 = 0$$\lambda = (17.2 \pm \sqrt{17.2^2 - 3.8})/2$—
判別式 $\sqrt{}$$\sqrt{295.84 - 3.8} = \sqrt{292.04}$17.0892
$\lambda_1$ (大)$(17.2+17.0892)/2$17.1446
$\lambda_2$ (小)$(17.2-17.0892)/2$0.0554

Step 5: 寄与率 (第 1 主成分が説明する分散割合)

項目計算結果
$\lambda_1 / (\lambda_1+\lambda_2)$$17.1446 / 17.2$0.9968 (99.68%)

🐍 同じ計算を Python で再現

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import numpy as np

X = np.array([
    [2, 3],
    [4, 7],
    [7, 12],
    [5, 9],
    [3, 4],
], dtype=float)

Xc = X - X.mean(axis=0)
Sigma = Xc.T @ Xc / (len(X) - 1)
eigvals, eigvecs = np.linalg.eigh(Sigma)

# eigh は昇順なので降順に並べ替え
order = eigvals.argsort()[::-1]
eigvals = eigvals[order]
eigvecs = eigvecs[:, order]

print("Sigma =")
print(Sigma)
print(f"lambda_1 = {eigvals[0]:.4f}")
print(f"lambda_2 = {eigvals[1]:.4f}")
print(f"PC1 寄与率 = {eigvals[0] / eigvals.sum():.4f}")

📤 実行結果

Sigma = [[ 3.7 7. ] [ 7. 13.5]] lambda_1 = 17.1446 lambda_2 = 0.0554 PC1 寄与率 = 0.9968

💬 手計算 Step 3-5 ($\Sigma$, $\lambda_1=17.1446$, $\lambda_2=0.0554$, 寄与率 99.68%) と Python の出力が一致。 判別式は $17.2^2 = 295.84$ から $4 \times 0.95 = 3.8$ を引いた 292.04 で、 ここを取り違えると $\lambda_2$ が 0.058 のようにずれる。 元の 2 変数 $x_1, x_2$ がほぼ完全に相関 (相関係数 $\approx +0.99$) しているため、 第 1 主成分だけで分散の 99.68% を説明でき、 「2 次元 → 1 次元」の次元削減でほとんど情報を失わないことが裏付けられる。

🧮 数式に値を入れて手で計算する: PCA 寄与率

合成 5 主成分の固有値から累積寄与率を計算する。

Step 1: 固有値

PC固有値 λ寄与率累積
PC15.00.5000.500
PC23.00.3000.800
PC31.20.1200.920
PC40.50.0500.970
PC50.30.0301.000

Step 2: 80% 達成の主成分数

合計 = 5+3+1.2+0.5+0.3 = 10.0 累積 80% 達成: PC2 で 0.800 → 2 成分で十分 累積 90% 達成: PC3 で 0.920 → 3 成分

🐍 Python で再現

1
2
3
4
5
6
7
import numpy as np
lam = np.array([5.0, 3.0, 1.2, 0.5, 0.3])
ratio = lam / lam.sum()
cum = ratio.cumsum()
print(f"寄与率: {ratio}")
print(f"累積: {cum}")
print(f"80% 達成 PC 数: {(cum >= 0.8).argmax()+1}")

📤 実行結果

寄与率: [0.5 0.3 0.12 0.05 0.03] 累積: [0.5 0.8 0.92 0.97 1. ] 80% 達成 PC 数: 2

💬 手計算 (Step 2) 2 成分と Python 出力が完全一致。

🐍 14. ライブラリ早見表

🐍 14. ライブラリ早見表

手法 クラス・関数
PCAsklearn.decomposition.PCA / TruncatedSVD / IncrementalPCA
Kernel PCAsklearn.decomposition.KernelPCA
FAsklearn.decomposition.FactorAnalysis / factor_analyzer.FactorAnalyzer
MDSsklearn.manifold.MDS
t-SNEsklearn.manifold.TSNE / openTSNE
UMAPumap-learn (import umap)
Isomapsklearn.manifold.Isomap
LLEsklearn.manifold.LocallyLinearEmbedding
LDAsklearn.discriminant_analysis.LinearDiscriminantAnalysis
Autoencodertorch.nn / keras.layers
NMFsklearn.decomposition.NMF
ICAsklearn.decomposition.FastICA

📜 15. 次元削減の歴史

💼 16. 次元削減の実務応用

① scikit-learn PCA

🎯 解説: PCA の主成分負荷量を 47 都道府県 × 上位 5 成分について計算し、 各成分がどの元の変数の合成かを解釈する。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np
import pandas as pd
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

# 2023 年度の 47 都道府県、5 指標(総人口・15歳未満・65歳以上・出生数・消費支出)
_d = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
_d = _d[_d['SSDSE-B-2026'] == 2023]
cols = ['A1101', 'A1301', 'A1303', 'A4101', 'L3221']
X_std = StandardScaler().fit_transform(_d[cols].astype(float))
pca = PCA(n_components=5).fit(X_std)
Z = pca.transform(X_std)
print(pca.explained_variance_ratio_.round(3))
# 負荷量 = 固有ベクトル × √固有値(標準化データでは変数と主成分の相関にほぼ等しい)
loadings = pca.components_.T * np.sqrt(pca.explained_variance_)
print(pd.DataFrame(loadings, index=cols,
                   columns=[f'PC{i}' for i in range(1, 6)]).round(2))
📥 入力例: data/raw/SSDSE-B-2026.csv(2023 年度の 47 行) X_std = 5 指標 (A1101, A1301, A1303, A4101, L3221) を標準化
📤 実行例(実測) [0.821 0.174 0.004 0.001 0. ] PC1 PC2 PC3 PC4 PC5 A1101 1.01 -0.08 -0.00 0.04 -0.01 A1301 1.00 -0.10 -0.03 -0.03 -0.02 A1303 1.00 -0.09 0.12 -0.01 0.01 A4101 1.00 -0.11 -0.08 -0.00 0.02 L3221 0.41 0.92 -0.00 -0.00 0.00
💬 読み方: PC1 が 82.1%、PC2 が 17.4% で、2 成分で 99.5% になる。PC1 の負荷量は総人口・15歳未満・65歳以上・出生数がそろって 1.00 前後なので「人口規模軸」、PC2 は消費支出 L3221 だけが 0.92 と大きいので「家計の消費水準軸」と読める。負荷量が 1.01 と 1 をわずかに超えるのは、StandardScaler が n で割り、PCA の分散が n−1 で割るためのずれ。軸の符号は任意(PCA の解は符号不定)。

② scikit-learn t-SNE

🎯 解説: 標準化済みの都道府県データを t-SNE で 2 次元に埋め込み、 局所的な近傍構造を保ったクラスタを可視化する。 サンプルが 47 件と少ないため perplexity を小さめに設定する。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import pandas as pd
from sklearn.manifold import TSNE
from sklearn.preprocessing import StandardScaler

# perplexity は標本数より小さくないといけない。
# この抜粋だけで動くよう、47 都道府県のデータを用意してから t-SNE にかける
_d = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
_d = _d[_d['SSDSE-B-2026'] == 2023]
X_std = StandardScaler().fit_transform(
    _d[['A1101', 'A1303', 'A4101', 'L3221']].astype(float))

tsne = TSNE(n_components=2, perplexity=5, random_state=42)
Z_tsne = tsne.fit_transform(X_std)
print(Z_tsne.shape)
📥 入力例: X_std = 標準化済み (47 都道府県 × 4 指標: A1101, A1303, A4101, L3221)
📤 実行例(実測) (47, 2)
💬 読み方: 出力 (47, 2) は 47 県それぞれに 2 次元の座標が 1 組ずつ付いたことだけを示し、どの県がどこに来たかはこの表示からは分からない。perplexity=5 は 1 県あたり実効的に約 5 県を近所とみなす設定。図の上でのクラスタ間の距離やクラスタの大きさに意味はなく、「同じかたまり = 似ている」だけを読み取る。

注意:47サンプルなら perplexity は 5-10 程度に下げる。 デフォルト30 はサンプル数より大きいと警告が出る。

③ UMAP(要 pip install umap-learn)

🎯 解説: 標準化済みの都道府県データを UMAP で 2 次元に埋め込む。 t-SNE より高速で大局構造も保たれ、 n_neighbors と min_dist でクラスタの見え方を調整する。
1
2
3
4
5
6
7
8
9
import umap
reducer = umap.UMAP(n_neighbors=10, min_dist=0.3, random_state=42)
Z_umap = reducer.fit_transform(X_std)
import numpy as np
names = _d['Prefecture'].values
tokyo = list(names).index('東京都')
dist = np.linalg.norm(Z_umap - Z_umap[tokyo], axis=1)
print(Z_umap.shape)
print('UMAP 上で東京に近い 3 県:', list(names[np.argsort(dist)[1:4]]))
📥 入力例: X_std = 上の t-SNE と同じ標準化済みデータ (47 都道府県 × 4 指標)
📤 実行例(実測) (47, 2) UMAP 上で東京に近い 3 県: ['大阪府', '神奈川県', '愛知県']
💬 読み方: 4 指標の X_std による UMAP では、東京に近い 3 県は大阪府・神奈川県・愛知県で、5 指標版(神奈川・大阪・愛知)と順番だけが入れ替わった。min_dist=0.3 は点どうしを詰めすぎない設定で、近所の順位は変わっても顔ぶれは安定している。UMAP は t-SNE と違い、学習済みの reducer で新しいデータを transform できる。

④ scikit-learn Kernel PCA / NMF / Sparse PCA

🎯 解説: 通常の PCA の代わりに、 非線形の Kernel PCA、 非負データ用の NMF、 解釈しやすい Sparse PCA(L1 ペナルティ)を切り替えて、 目的に応じた次元削減を行う。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from sklearn.decomposition import KernelPCA, NMF, SparsePCA
from sklearn.preprocessing import MinMaxScaler
kpca = KernelPCA(n_components=2, kernel='rbf', gamma=0.1, random_state=0)
nmf = NMF(n_components=3, random_state=0, max_iter=2000)  # 非負データ専用
spca = SparsePCA(n_components=3, alpha=1, random_state=0)  # L1 ペナルティで解釈性向上

cols4 = ['A1101', 'A1303', 'A4101', 'L3221']
Z_kpca = kpca.fit_transform(X_std)
# NMF は負の値を受け付けないので、標準化ではなく 0〜1 に縮めたデータを渡す
X_pos = MinMaxScaler().fit_transform(_d[cols4].astype(float))
W = nmf.fit_transform(X_pos)
Z_spca = spca.fit_transform(X_std)
print('Kernel PCA:', Z_kpca.shape)
print('NMF の基底 H(行 = 成分, 列 =', cols4, ')')
print(nmf.components_.round(2))
print('Sparse PCA の負荷(0 は L1 で落とされた変数)')
print(spca.components_.round(2))
📥 入力例: X_std = 標準化済み (47 都道府県 × 4 指標)。 NMF には負の値を入れられないので、同じ 4 列を MinMaxScaler で 0〜1 に縮めて渡す
📤 実行例(実測) Kernel PCA: (47, 2) NMF の基底 H(行 = 成分, 列 = ['A1101', 'A1303', 'A4101', 'L3221'] ) [[0.15 0.51 0. 1.28] [0.91 0.93 0.95 0. ] [0.01 0. 0.02 1.49]] Sparse PCA の負荷(0 は L1 で落とされた変数) [[0.3 0.95 0. 0. ] [0. 0. 0. 1. ] [0.56 0. 0.83 0. ]]
💬 読み方: NMF の基底は、第 2 成分が総人口・65歳以上・出生数に 0.91〜0.95 で乗る「人口規模」、第 1・第 3 成分は消費支出 L3221 に 1.28・1.49 と大きく乗る「家計」側に分かれ、すべて 0 以上なので足し算で読める。Sparse PCA は L1 ペナルティで 12 個の負荷のうち 7 個が 0 になり、第 2 成分は消費支出だけ(1.0)になった。Kernel PCA は座標 (47, 2) を返すだけで負荷量を持たないので、軸の意味は元の変数との相関を別に計算して確かめる。

⑤ scipy.linalg.svd — SVD で PCA を手動実装

🎯 解説: 中心化した行列を特異値分解(SVD)し、 スコア Z = U·Σ が PCA の主成分得点と一致することを確認する。 PCA が「中心化 + SVD」と等価であることを手で示す。
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))  # 固有値
📥 入力例: X_std = 上の t-SNE と同じ標準化済みデータ (47 都道府県 × 4 指標: A1101, A1303, A4101, L3221)
📤 実行例(実測) [3.19061052e+00 8.74016731e-01 2.04391496e-02 1.89012090e-03] → SVD から求めた固有値 S²/(n-1)。 sklearn の PCA の explained_variance_ と一致する。
💬 読み方: 固有値は 3.19・0.874・0.020・0.0019 で、第 1 成分だけで合計 4.087 の 78.1%、2 成分で 99.5% を占める。合計が変数の数 4 ではなく 4.087 になるのは、StandardScaler が n=47 で割って標準化し、ここでは n−1=46 で割っているため(4×47/46)。スコアは U·Σ、負荷量は V に対応し、主成分の符号は一意でないため反転しうる。

🐍 拡張 Python 実装例

以下は SSDSE-B-2026 を題材にした実コード例集です。 すべて data/raw/SSDSE-B-2026.csv を読み込み、 実値で動作確認しています。

🎯 解説: SSDSE-B-2026 をロードし、 次元削減に関連する基本統計量を計算。
1
2
3
4
5
6
7
8
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)
📥 入力例: data/raw/SSDSE-B-2026.csv, 47 都道府県 2023 年
📤 実行例(実測) aging birth_rate count 47.000 47.000 mean 0.316 5.726 std 0.033 0.704 min 0.228 3.951 25% 0.300 5.347 50% 0.318 5.616 75% 0.340 6.111 max 0.391 8.548 最高齢化: [['秋田県' 0.39059080962800874] ['高知県' 0.3633633633633634] ['徳島県' 0.3539568345323741]] 最低高齢化: [['東京都' 0.227530881726537] ['沖縄県' 0.23841961852861035] ['愛知県' 0.25718871205028754]]
💬 読み方: 47 県の高齢化率は平均 0.316、最小 0.228(東京都)から最大 0.391(秋田県)まで。人口千人あたりの出生数は平均 5.726、最大 8.548 で、高齢化率の低い側に沖縄県・愛知県が並ぶことと合わせると、高齢化率と出生率は逆向きに動く組み合わせに見える。次元削減で 2 つを 1 軸にまとめられるかは、この 2 列の相関を確かめてから判断する。
🎯 解説: 次元削減の可視化:箱ひげ図とヒストグラム。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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)
from scipy import stats
q1, q3 = d23['aging'].quantile([0.25, 0.75])
iqr = q3 - q1
out = d23[(d23['aging'] < q1 - 1.5 * iqr) | (d23['aging'] > q3 + 1.5 * iqr)]
print('歪度:', round(stats.skew(d23['aging']), 3))
print('箱ひげ図の外れ値:', out[['Prefecture', 'aging']].round(3).values.tolist())
📥 入力例: 47 県の高齢化率データ
📤 実行例(実測) 歪度: -0.558 箱ひげ図の外れ値: [['東京都', 0.228], ['沖縄県', 0.238]]
💬 読み方: 高齢化率の歪度は -0.558 で、右ではなく左に裾が長い。箱ひげ図のひげの外に出るのは東京都 0.228 と沖縄県 0.238 の低い側だけで、最も高い秋田県 0.391 は外れ値の基準(第 3 四分位 0.340 + 1.5×IQR = 0.400)の内側に収まる。「高齢化が極端な県」より「若い 2 都県」のほうが分布から浮いている。
🎯 解説: 次元削減関連の統計検定を実行。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
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}')
📥 入力例: 47 県 2023 年データ、 都市部 vs 地方の比較
📤 実行例(実測) t = -4.58, p = 0.0055, Cohen d = -2.10
💬 読み方: 都市部 5 都府県の高齢化率は残り 42 道県より低く、t = -4.58、p = 0.0055、Cohen の d = -2.10 と差は大きい。Welch の t 検定なので自由度は都市部の 5 県側に引きずられて小さく、p 値は 5 県の値のばらつきに強く左右される。どの県を「都市部」に入れるかを先に決めてから検定しないと、有意になる組み合わせを探す形になる。
🎯 解説: 次元削減と時系列:2012-2023 年度の推移。
1
2
3
4
5
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 全年度の県別データ
📤 実行例(実測) mean std min max SSDSE-B-2026 2012 0.256 0.026 0.177 0.307 2013 0.266 0.027 0.183 0.315 2014 0.275 0.027 0.189 0.327 2015 0.280 0.028 0.194 0.336 2016 0.290 0.028 0.203 0.347 2017 0.295 0.029 0.209 0.354 2018 0.300 0.030 0.215 0.362 2019 0.304 0.031 0.220 0.369 2020 0.303 0.032 0.221 0.373 2021 0.311 0.032 0.229 0.381 2022 0.314 0.033 0.228 0.386 2023 0.316 0.033 0.228 0.391
💬 読み方: 全国の高齢化率(47 県の単純平均)は 2012 年度 0.256 から 2023 年度 0.316 へ 6.0 ポイント上がり、県間の標準偏差も 0.026 から 0.033 へ広がった。最大は 0.307 → 0.391、最小は 0.177 → 0.228 で、上側の伸び(+0.084)が下側(+0.051)より大きいことが地域差の拡大を生んでいる。2020 年度は 0.303 と前年の 0.304 をわずかに下回っており、毎年必ず単調に増えるわけではない。

🎓 上級者向け議論:次元削減の使い分けと注意点

1. データの性質と適用範囲

次元削減は前提条件次第で意味が変わります。 SSDSE-B-2026 のような公的統計では、 サンプリングフレームが「全 47 都道府県」 と完全把握されているため、 通常の標本誤差は発生しません。 しかし「2023 年の 1 時点を全体集団とみなすか、 もっと長期の集団からの 1 サンプルとみなすか」で解釈が変わります。

2. 多重比較問題

SSDSE-B-2026 のような 100 超の列を扱うと、 多重比較(同じデータで多数の検定を行う)の罠が発生します。 Bonferroni 補正、 Benjamini-Hochberg などで補正してから 次元削減に関連する統計量を解釈すべきです。

3. 階層構造の考慮

都道府県の中に市区町村があり、 階層構造を持つ場合、 階層線形モデル(HLM)で 次元削減を扱うことを検討します。 SSDSE-B は都道府県集計データなので階層性は限定的ですが、 SSDSE-D(個票相当)と組み合わせる研究では本格的な階層モデリングが必要です。

4. 時間変動の扱い

SSDSE-B-2026 は 2012〜2023 年度の 12 年間のパネル構造を持ちます。 次元削減を時間軸込みで扱うときは、 固定効果モデル・ランダム効果モデルなどパネルデータ手法を併用します。

5. 因果と相関の区別

SSDSE-B-2026 の県別データから「次元削減に関わる関係」を抽出できても、 それは多くの場合「相関」であり、 「因果」を主張するには無作為化試験・自然実験・操作変数などの追加設計が必須です。

⚠️ 11. よくある落とし穴

落とし穴 対処
標準化せずに PCA大スケール変数だけが第1主成分に。 必ず StandardScaler。
t-SNE の大局構造を信用クラスタ間の距離・大きさは意味なし。 局所構造のみ。
PCA と FA を混同FA は潜在変数モデル、 PCA は射影。 目的に応じて使い分け。
主成分を符号付きで解釈主成分の符号は任意。 解釈には絶対値の大小と方向を見る。
寄与率の低い PC で結論第3主成分以降は寄与率が低いと解釈価値も低い。
t-SNE / UMAP で外挿新データに transform できない(UMAP は parametric なら可)。
LDA でクラスが少ないK クラスなら K-1 次元まで。 多クラス分類前段で。

🏋️ 12. 練習問題(SSDSE-B-2026)

Q1. SSDSE-B の数値変数すべてで PCA を行い、 累積寄与率 80% を満たす K と主成分の意味を答えなさい。
🎯 解説: SSDSE-B-2026 の数値変数すべてを標準化して PCA にかけ、 累積寄与率が 80% を超える最小の主成分数 K を求め、 上位 3 成分の負荷量から軸の意味を読む。
📥 入力例(SSDSE-B-2026 から 2023 年度の 47 行を取り出し、年度以外の数値 109 列を使う) 年度 地域コード 都道府県 A1101(総人口) A1303(65歳以上人口) A4101(出生数) … 2023 R01000 北海道 5,092,000 1,681,000 24,430 … 2023 R13000 東京都 14,086,000 3,205,000 86,348 … 2023 R47000 沖縄県 1,468,000 350,000 12,549 … …(残りの列は住宅・家計・教育・医療など)
1
2
3
4
5
6
7
8
9
10
11
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='cp932', skiprows=1)
df = df[df['年度'] == 2023].reset_index(drop=True)   # 2023 年度の 47 都道府県
num = df.select_dtypes(include='number').drop(columns='年度')
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))
📥 入力例: data/raw/SSDSE-B-2026.csv 2023 年度の数値変数 109 列を StandardScaler で標準化 (47 都道府県 × 109 指標)
📤 実行例(実測) 80%超え K = 2 PC1 PC2 PC3 総人口 0.11 0.01 0.03 総人口(男) 0.11 0.02 0.03 総人口(女) 0.11 0.01 0.03 日本人人口 0.11 0.02 0.03 日本人人口(男) 0.11 0.02 0.03 ... ... ... ... 保健医療費(二人以上の世帯) 0.06 0.24 0.06 交通・通信費(二人以上の世帯) -0.04 0.20 -0.16 教育費(二人以上の世帯) 0.07 0.13 0.02 教養娯楽費(二人以上の世帯) 0.07 0.26 -0.03 その他の消費支出(二人以上の世帯) -0.01 0.25 0.01 [109 rows x 3 columns]
💬 読み方: 2023 年度の 109 指標では第 2 主成分までで累積寄与率が 80% を超え、K = 2 になる。PC1 の負荷量は総人口・男女別人口などが 0.11 前後で横並びになっており、人口・世帯数系の多数の列がまとめて乗る「規模」の軸。PC2 は保健医療費 0.24・教養娯楽費 0.26・その他の消費支出 0.25 など家計支出の列で大きく、「家計の水準」の軸と読める。年度で絞らず 564 行で計算すると同じ県を 12 回数えることになり、年度の列そのものも 1 変数として混ざってしまう。
Q2. 同じデータで UMAP と t-SNE を実行し、 都道府県の配置を比較しなさい。
🎯 解説: 同じ標準化済みデータに t-SNE と UMAP をそれぞれ適用して 2 次元に埋め込み、 都道府県の配置がどう異なるかを並べて比較する。
1
2
3
4
5
6
7
8
9
10
11
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)
# プロット比較
import numpy as np
names = df['都道府県'].values
tokyo = list(names).index('東京都')
for name, Z in [('t-SNE', Z_tsne), ('UMAP', Z_umap)]:
    dist = np.linalg.norm(Z - Z[tokyo], axis=1)
    print(f'{name:5s} で東京に近い 3 県:', list(names[np.argsort(dist)[1:4]]))
📥 入力例: X = 上の Q1 で作った標準化済みデータ (47 都道府県 × 109 指標)
📤 実行例(実測) t-SNE で東京に近い 3 県: ['大阪府', '神奈川県', '愛知県'] UMAP で東京に近い 3 県: ['大阪府', '神奈川県', '埼玉県']
💬 読み方: 109 指標の t-SNE でも UMAP でも、東京に最も近いのは大阪府・神奈川県で、3 番目だけが愛知県(t-SNE)と埼玉県(UMAP)で入れ替わった。近所の顔ぶれが 2 手法でほぼ一致するのは大都市圏が指標空間でもまとまっているためで、「東京は大都市圏と似ている」は手法に依存しない読みと言える。どちらも座標の絶対値には意味がないので、比べるなら近所の顔ぶれや trustworthiness で比べる。
Q3. 都市規模ラベル(3分位)を作り、 LDA で 2 次元に削減して可視化しなさい。
🎯 解説: 総人口(A1101)の 3 分位で都市規模ラベル(農村/中規模/都市)を作り、 それを教師として LDA で 2 次元に削減し、 群が最もよく分離する判別軸上で都道府県を可視化する。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import pandas as pd
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.preprocessing import StandardScaler

# この抜粋だけで動くよう、英字コードで読み直してから 3 群に分ける
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023].copy()
X = StandardScaler().fit_transform(
    df[['A1303', 'A4101', 'L3221', 'L322106']].astype(float))

df['region'] = pd.qcut(df['A1101'], q=3, labels=['農村','中規模','都市'])
lda = LinearDiscriminantAnalysis(n_components=2)
Z_lda = lda.fit_transform(X, df['region'])
print(Z_lda.shape, lda.explained_variance_ratio_.round(3))
📥 入力例: X = 標準化済み (47 都道府県 × 複数指標), y = 都市規模ラベル(3 群)
📤 実行例(実測) (47, 2) [0.998 0.002]
💬 読み方: 3 群なので判別軸は 2 本まで作れるが、寄与率は LD1 が 0.998、LD2 が 0.002 で、群を分けているのはほぼ LD1 だけ。X に総人口そのものは入っていないが、65 歳以上人口 A1303 と出生数 A4101 が総人口と強く連動しているので、LD1 は実質「人口規模」の軸になる。2 次元の図にしても縦方向(LD2)の散らばりにはほとんど意味がない。

📝 13. 報告フォーマット

❌ NG例

「PCA で 2 次元にして可視化しました。」

✅ OK例

「30 変数を標準化後 PCA に投入。 第1主成分の寄与率 31%、 第2主成分 22%(累積 53%)。 第1主成分は所得・人口密度に正の負荷量、 高齢化率に負の負荷量を持つため『都市的・経済発展度』、 第2主成分は世帯人員と就業率に正の負荷で『家族基盤・就業度』と解釈した。 上位 5 主成分で累積 82%、 これらを後続のクラスタリングの入力に使用。」

⚠️ 次元削減の落とし穴(深掘り版・6件)

① 標準化を忘れて PCA を実行する

「家計支出(数万円単位)」と「世帯人数(小数の単位)」を混在させて PCA をかけると、 単位が大きい変数(家計支出)が PC1 を完全に支配し、 他の情報が埋もれる。 必ず StandardScaler で各変数を平均 0・分散 1 に標準化してから PCA を行う。 ただし「自然に同単位」の場合(同種計測値の集合)は標準化しない方が良いこともあるので、 ケースごとに判断。

② t-SNE の距離・形を「絶対座標」と読む

t-SNE の出力は「局所構造を保つ」ものの、 クラスタ間の距離やサイズには意味がない。 グラフで離れていても「全く違う」とは限らないし、 大きいクラスタが「種類が多い」わけでもない。 t-SNE の図を見るときは「同じ色は同じグループ」だけを情報として受け取り、 「距離が遠い = 違う」と即断しないこと。 大域構造を見たいなら UMAP か PCA を併用。

③ 主成分の解釈を無理に当てる

「PC1 は所得、 PC2 は都市性」のように強引な意味付けをすると、 後の議論が脆くなる。 主成分は変数の線形結合であり、 必ずしも単純な概念に対応しない。 ローディング(負荷量)を確認し、 0.4 以上の絶対値を持つ変数だけで解釈する。 「解釈可能性」を高めたいなら主成分回転(Varimax)や因子分析を検討。

④ 全データで PCA → 訓練/テスト分割

機械学習で「全データで PCA を計算してから訓練/テスト分割」するのは、 テストデータの情報が前処理に漏れるデータリーク。 必ず train で fit、 test には transform のみ。 scikit-learn の Pipeline なら自動的に正しい順序で実行される。 これは StandardScaler でも同じ問題が発生します。

⑤ 圧縮した次元で「予測精度」を必ず良くなると思う

PCA は応答変数 y を見ないので、 「圧縮した結果 y の予測に重要な情報が失われる」ことがあります。 教師あり学習の特徴量削減なら、 PCA より Partial Least Squares (PLS)、 LDA、 RFE 等を検討。 PCA を盲信せず、 圧縮後と圧縮前で CV スコアを比較する。

⑥ UMAP / t-SNE のハイパーパラメータを無視する

t-SNE の perplexity、 UMAP の n_neighbors / min_dist を変えると、 全く違う図が出ることが普通。 デフォルト値で 1回だけ実行して結論を出すのは危険。 複数の設定で実行し、 安定して見えるパターンだけを信用する。 また乱数シードでも結果が変わるので、 複数 seed で繰り返すと安心。

🗺 概念マップ

関連概念を視覚的に整理した概念マップ。

次元削減 線形代数 (固有値) 特徴量選択 UMAP / t-SNE 可視化・前処理 クラスタリング PCA・SVD

次元削減の概念マップ中央は「高次元 → 低次元の射影 + 構造保持」で、 周辺には PCA (分散最大化)、 t-SNE (局所距離保持)、 UMAP (位相保持)、 Autoencoder (再構成誤差最小化)、 LDA (クラス分離最大化) が並ぶ。 線形 / 非線形、 教師あり / なし、 生成的 / 識別的、 という 3 軸で位置付けると選択基準が明確になる。

🔗 隣接手法への橋渡し

「次元削減」は単独で完結する手法ではなく、 隣接領域と連携することで真価を発揮する。 具体的には次の 3 方向と密接につながる:

次元削減は高次元データの構造を低次元で捉え、 可視化と計算効率化の両面で重要。

🌳 関連トピック:上位・下位・派生概念マップ

🌳 関連トピック:上位・下位・派生概念マップ

関係概念次元削減との接続
上位(一般化)統計推論一般次元削減は推論の構成要素
下位(特殊化)特定の検定・推定次元削減の応用
並列(兄弟)関連手法同じ問題への別アプローチ
前提確率分布・標本次元削減の数学的基礎
応用政策評価・施策効果測定SSDSE-B-2026 のような公的統計での実務

典型的な誤用と対処

📂 拡張ケーススタディ(5 例)

ケース 1:人口動態の県間比較

SSDSE-B-2026 で「人口」「出生数」「死亡数」を比較。 次元削減を使って自然増減のパターンを定量化。 東京・神奈川・愛知の都市集中、 秋田・高知の過疎化。

ケース 2:教育投資と成果

「学校数」「教員数」「進学率」を 次元削減で分析。 県別の教育リソース配分の効率性を評価。 都市と地方の格差を可視化。

ケース 3:医療提供体制

「病院数」「医師数」「平均寿命」 を組み合わせ。 次元削減で医療資源の不均衡と健康成果の関係を推定。 北海道の医師偏在問題。

ケース 4:産業構造と所得

「就業者数」「課税対象所得」「小売業販売額」を 次元削減で関連付け。 製造業県と観光業県のパターン差。

ケース 5:高齢化と財政

「高齢化率」「税収」「社会保障費」を 次元削減で評価。 高齢化が進む県の財政負担の重さを定量化。 県政策への含意。

✅ 再現性チェックリスト

研究結果を 次元削減を使って報告するときに守るべきチェックリスト:

🌍 社会的インパクトと実務応用

次元削減は学術研究だけでなく、 政策・ビジネスの意思決定に直接活用されています。

政策決定での使用例

ビジネスでの応用

学術での発展

計量経済学・教育測定・心理測定・疫学などで 次元削減は基礎ツール。 近年は機械学習との融合で新しい応用が広がっています。

📜 歴史的展開

次元削減 の概念は、 統計学の発展史と並行して洗練されてきました。

日本では、 1947 年の統計法制定以降、 SSDSE-B のような公的統計の整備が進み、 次元削減を学ぶ実データ環境が充実してきました。

🧭 PCA vs ICA vs UMAP vs t-SNE 徹底比較

次元削減手法は「目的によって使い分ける」もの。 同じ SSDSE-B-2026 都道府県データに対しても、 PCA は分散の大きな軸、 ICA は独立な信号源、 UMAP は近傍構造、 t-SNE は局所クラスタを抽出する。 ここでは 4 手法を「数式・前提・出力の意味・落とし穴」で並べる。

📊 4 手法の比較表

手法最適化対象線形/非線形距離保存主な用途
PCA分散最大化線形大域前処理・解釈
ICA統計的独立性線形―信号源分離
t-SNEKL 発散(近傍)非線形局所のみ可視化
UMAPクロスエントロピー非線形局所+ある程度大域可視化+下流タスク

🔬 各手法の数式を言葉で読み解く

🐍 sklearn.decomposition で 4 手法を比較

🎯 このコードでやること:SSDSE-B-2026 都道府県データ(複数指標)を PCA / FastICA / t-SNE / UMAP で 2 次元に落として並べ、 同じデータでも結果がまるで違うことを観察する。

📥 入力データ(SSDSE-B-2026 の 2021 年度 47 都道府県、 下の 5 指標を標準化して使用):

Code 都道府県 総人口 出生数 死亡数 月間有効求人数(一般) 消費支出(二人以上の世帯) R01000 北海道 5183000 28762 69023 773360 268396 R13000 東京都 14010000 95404 127649 1977338 322785 ...
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pandas as pd
import numpy as np
from sklearn.decomposition import PCA, FastICA
from sklearn.manifold import TSNE
from sklearn.preprocessing import StandardScaler
import umap

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=1, encoding='cp932')
df = df[df['年度'] == 2021].reset_index(drop=True)
# 「就業者数」「課税対象所得」は SSDSE-B-2026 に無いので実在列を使う
cols = ['総人口', '出生数', '死亡数', '月間有効求人数(一般)', '消費支出(二人以上の世帯)']
X = StandardScaler().fit_transform(df[cols].values)

pca  = PCA(n_components=2).fit_transform(X)
ica  = FastICA(n_components=2, random_state=0).fit_transform(X)
tsne = TSNE(n_components=2, perplexity=10, random_state=0).fit_transform(X)
ump  = umap.UMAP(n_components=2, n_neighbors=10, random_state=0).fit_transform(X)

tokyo = df.index[df['都道府県'] == '東京都'][0]
print('PCA  寄与率:', PCA(n_components=2).fit(X).explained_variance_ratio_.round(4))
print('PCA  東京の座標:', pca[tokyo].round(3))
print('t-SNE 東京の座標:', tsne[tokyo].round(3))

📤 実行例の出力:

PCA 寄与率: [0.7964 0.1838] PCA 東京の座標: [8.525 0.364] t-SNE 東京の座標: [-8.628 6.358]

💬 PCA では 5 指標の寄与率が PC1 0.7964・PC2 0.1838 で、東京は PC1 が 8.525 と 2 番目の県(4.69)の倍近く離れた端に置かれる。t-SNE の東京の座標 (-8.628, 6.358) は数値そのものに意味がなく、他の県との相対位置だけが情報。「東京がどれだけ離れているか」を議論したい場合は PCA、「クラスタの形を見たい」場合は t-SNE/UMAP を使う。

⚠️ 4 手法の落とし穴(用語固有)

「次元削減した図」を見て議論するときは、 必ず「どの手法・どのパラメータ・どのスケーリングか」をセットで報告する。

🧭 R456 拡張: 次元削減の徹底深掘り (SSDSE-B-2026 都道府県データで再検証)

本セクションでは、 SSDSE-B-2026 の都道府県データ (2023 年度で 47 行 × 109 の数値列) を題材に、 「なぜ次元削減を使うのか」「PCA / ICA / t-SNE / UMAP のどれを選ぶか」「結果をどう読むか」を徹底的に詰める。 単に手法を並べるのではなく、 同じデータに 4 手法を適用したときの可視結果と数値結果を並べ、 結論が変わる所と変わらない所を区別する。 教育上、 ここを曖昧にすると「次元削減した図」を見て勝手な解釈を入れる学習者が出るため、 落とし穴と検証手順を明示する。

🖼 図 3 点: SSDSE-B-2026 の単変量・多群分布・散布

次元削減を語る前に、 そもそも「元データがどう分布しているか」を 1 変量・2 変量・群別の 3 つの基本図で確認する。 ここを飛ばすと「次元削減後の図」だけを見て元情報を見失う。

2023 年度 47 都道府県の総人口と出生数 (標準化) の散布図と第 1 主成分の方向
図 R456-1: SSDSE-B-2026(2023 年度)都道府県 47 件の総人口 × 出生数をそれぞれ標準化した散布図に、 第 1 主成分の方向(オレンジの線)を重ねた図。 r = 0.995 の強い正の相関があり、 PC1 だけで 2 変数の分散の 99.8% を説明する。 2 変量だけでも本質的な「県のサイズ軸」が見え、 東京(右上)はその軸の端にいる。 次元削減は、 こうした「相関の塊」を 1 軸にまとめる作業に相当する。
SSDSE-B-2026 の 109 列の歪度のヒストグラム (元の値と log10 変換後)
図 R456-2: SSDSE-B-2026(2023 年度・47 都道府県)の数値 109 列それぞれの歪度をヒストグラムにした図。 元の値では 109 列中 93 列が歪度 > 1(中央値 2.22)と右に長い裾を持ち、 109 列のうち 90 列で最大値を取るのが東京都である。 正の値だけの 106 列を log10 変換すると歪度 > 1 は 10 列(中央値 0.74)まで減る。 次元削減前に標準化 (z スコア化) だけで済ませるか、 対数変換も入れるかを判断する基礎情報。
7 地方区分別の高齢化率と PC1 得点の箱ひげ図
図 R456-3: 2023 年度 47 都道府県を 7 地方区分に分けた箱ひげ図。 左は元の変数の 1 つである高齢化率(中央値は関東 28.1% が最も低く、 北海道・東北 35.0%・四国 34.8% が高い)。 右はページ内の PCA と同じ 5 列(総人口・15 歳未満人口・65 歳以上人口・出生数・消費支出)を標準化して求めた PC1 得点(寄与率 82.1%)。 PC1 は人数の 4 列にほぼ同じ重み(0.49)がかかる「県のサイズ軸」なので、 関東(中央値 2.65、 東京 8.1)だけが高く、 他の地方は愛知・大阪・福岡・北海道が外れ値として浮くだけで、 高齢化率に見える地方差はほとんど映らない。 次元削減で「群が分かれている / いない」を判定するときは、 元データの群構造をこのように並べて確認すること。

📋 4 手法 OK/NG マトリクス (用途別の選択基準)

目的 PCA ICA t-SNE UMAP
分散の最大方向を取りたい◎×××
独立な信号源を分離×◎××
局所近傍を可視化△×◎◎
大域構造を保持◎○×△
線形仮定を置ける◎◎××
寄与率で説明したい◎×××
新規データへ射影◎◎×○
クラスタを発見△△◎◎
3 次元以下で見せる○○◎◎
大規模 (n>10万)◎○×◎

◎=第一選択、 ○=条件付き可、 △=可能だが他手法のほうが向く、 ×=不適切。 「とりあえず t-SNE」は危険で、 「説明したいのか発見したいのか」を明確化してから手法を選ぶ。 SSDSE-B-2026 のような 47 件・数十変数の県別データなら、 まず PCA で寄与率を見て、 必要に応じて UMAP で局所構造を補う、 という順序が安全。

🐍 Python 実装: 4 手法を同じ前処理で並べて比較

このコードでやること: SSDSE-B-2026 から都道府県別の数値カラムを抽出し、 StandardScaler で標準化したうえで PCA / ICA / t-SNE / UMAP を同じ入力に適用し、 2 次元に落とした結果を比較する。 「同じデータでも手法で結論が変わる」点を体感する。

📥 入力データ (SSDSE-B-2026 抜粋, head):

年度 都道府県 総人口 出生数 死亡数 ... 2023 北海道 5092000 24430 75120 ... 2023 東京都 14086000 86348 137241 ... 2023 大阪府 8763000 55292 104964 ... ...(2023 年度の 47 行 × 年度以外の数値 109 列)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA, FastICA
from sklearn.manifold import TSNE
import umap

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1)
df = df[df['年度'] == 2023].reset_index(drop=True)   # 2023 年度の 47 都道府県
num = df.select_dtypes(include='number').drop(columns='年度').dropna(axis=1)
Xs = StandardScaler().fit_transform(num)

pca   = PCA(n_components=2).fit_transform(Xs)
ica   = FastICA(n_components=2, random_state=0).fit_transform(Xs)
tsne  = TSNE(n_components=2, perplexity=10, random_state=0).fit_transform(Xs)
ump   = umap.UMAP(n_components=2, n_neighbors=10, random_state=0).fit_transform(Xs)

idx_tokyo = df['都道府県'].tolist().index('東京都')
print('PCA   東京:', pca[idx_tokyo].round(2))
print('ICA   東京:', ica[idx_tokyo].round(2))
print('t-SNE 東京:', tsne[idx_tokyo].round(2))
print('UMAP  東京:', ump[idx_tokyo].round(2))

📤 実行例の出力:

PCA 東京: [41.99 -3.13] ICA 東京: [-4.76 -0.3 ] t-SNE 東京: [ 20.6 -19.5] UMAP 東京: [ 9.13 -3.33]

💬 PCA では東京の PC1 が +41.99 で、2 番目に大きい県(19.58)の 2 倍以上離れた端に置かれる。109 列を標準化すると東京は人口系の列の大半で z が大きく、それが PC1 に一斉に足し込まれるため。t-SNE (20.6, -19.5) と UMAP (9.13, -3.33) の座標は数値そのものに意味がなく、他県との相対位置だけが情報。ICA の成分は順番も符号も一意に決まらないので、東京の -4.76 は「どの成分でどちら向きに外れているか」を別に確かめないと読めない。

🔍 PCA と t-SNE の数値的差: 距離保存 vs 近傍保存

このコードでやること: PCA と t-SNE の埋め込み座標を使って、 「元空間での距離」と「埋め込み空間での距離」の Pearson 相関を計算する。 PCA は大域距離を保持、 t-SNE は近傍だけ保持、 という違いを数値で確認する。

📥 入力: 上と同じ Xs(2023 年度 47 行 × 109 列)と PCA・t-SNE の座標を、このブロックの中で作り直す

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
from scipy.spatial.distance import pdist
from scipy.stats import pearsonr

# ── この抜粋だけで動くように、元データと 2 つの埋め込みを作り直す ──
# (直前のブロックは umap を使うため、ブラウザでは実行できない)
_d = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1)
_d = _d[_d['年度'] == 2023].reset_index(drop=True)   # 2023 年度の 47 都道府県
_num = _d.select_dtypes(include='number').drop(columns='年度').dropna(axis=1)
Xs = StandardScaler().fit_transform(_num)
pca = PCA(n_components=2).fit_transform(Xs)
# 標本が数千未満なら method='exact' のほうが正確で、しかも速い
tsne = TSNE(n_components=2, perplexity=10, random_state=0,
            method='exact').fit_transform(Xs)

# 元の距離が、2 次元に落としたあとどれだけ保たれているかを比べる
d_orig = pdist(Xs)
d_pca  = pdist(pca)
d_tsne = pdist(tsne)
print('元 vs PCA   距離相関:', round(pearsonr(d_orig, d_pca)[0], 3))
print('元 vs t-SNE 距離相関:', round(pearsonr(d_orig, d_tsne)[0], 3))

📤 実行例の出力:

元 vs PCA 距離相関: 0.993 元 vs t-SNE 距離相関: 0.681

💬 県どうしの距離を元の 109 次元と 2 次元で比べると、PCA は相関 0.993 でほぼそのまま保っているのに対し、t-SNE は 0.681 にとどまる。PCA は 2 成分で分散の 82% しか持たないが、残りの 18% は多数の小さな方向に散っているので、県どうしの距離の大小関係はほとんど崩れない(東京を除いても 0.987)。t-SNE の図で「クラスタ間の距離」「クラスタの大きさ」を議論してはいけない理由がここにある。

📊 SSDSE-B-2026 における手法選択の数値根拠

指標 PCA (2D) t-SNE UMAP 推奨条件
寄与率 (PC1+PC2)0.82——分散説明 70% 以上で PCA 採用可
距離相関 (元 vs 埋め込み)0.990.680.590.8 以上なら距離議論可
trustworthiness (k=10)0.920.910.91局所近傍評価。 0.9 以上で良
計算時間 (47×109 行列)< 0.01s0.3s1.2s大規模化で差が拡大
再現性 (シード固定)完全条件付き条件付き論文用は PCA か乱数固定
新規 1 都市の射影可能不可parametric 版で可運用フェーズは PCA
外れ値の扱い強く反映局所のみ局所のみ東京除外で再計算推奨
解釈性 (軸の意味)高 (loading)低低レポート用は PCA 必須

trustworthiness は sklearn.manifold.trustworthiness(X, X_embedded, n_neighbors=10) で計算できる。 局所近傍の保存度を 0〜1 で評価する指標で、 t-SNE / UMAP の品質確認に必須。 数値根拠なしに「t-SNE のほうが綺麗」と言うのは禁物。

🐍 trustworthiness で品質を数値化する

このコードでやること: 4 手法それぞれの埋め込みについて trustworthiness を計算し、 「どの手法が局所構造を最も保存しているか」を数値で示す。 図の見栄えではなく数値で選ぶ訓練。

📥 入力: 上と同じ Xs(2023 年度 47 行 × 109 列)から PCA / ICA / t-SNE をこのブロックの中で作り直す(UMAP はブラウザ版に無いので除く)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA, FastICA
from sklearn.manifold import TSNE, trustworthiness

# ── この抜粋だけで動くように、比べる埋め込みをここで作る ──
# UMAP はブラウザ版 Python に無いので、ここでは PCA / ICA / t-SNE の 3 つを比べる
_d = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1)
_d = _d[_d['年度'] == 2023].reset_index(drop=True)   # 2023 年度の 47 都道府県
_num = _d.select_dtypes(include='number').drop(columns='年度').dropna(axis=1)
Xs = StandardScaler().fit_transform(_num)
pca = PCA(n_components=2, random_state=0).fit_transform(Xs)
ica = FastICA(n_components=2, random_state=0).fit_transform(Xs)
tsne = TSNE(n_components=2, perplexity=10, random_state=0,
            method='exact').fit_transform(Xs)

# trustworthiness = 元の近さが 2 次元でどれだけ保たれているか(1 に近いほど良い)
for name, emb in [('PCA', pca), ('ICA', ica), ('t-SNE', tsne)]:
    t = trustworthiness(Xs, emb, n_neighbors=10)
    print(f'{name:6s} trustworthiness={t:.3f}')

📤 実行例の出力:

PCA trustworthiness=0.922 ICA trustworthiness=0.890 t-SNE trustworthiness=0.910

💬 近所 10 県の保存度は PCA 0.922、t-SNE 0.910、ICA 0.890 で、この 47 県・109 指標では t-SNE が PCA を上回らなかった(同じ設定の UMAP は 0.907)。県の規模の差が支配的で、2 本の線形軸でも近所関係がかなり保てるデータだからである。「局所構造なら t-SNE/UMAP が上」と決めつけず、データごとに数値で確かめて使い分ける。

⚠️ 追加の落とし穴 5 件 (R456 補強)

📝 練習問題 5 問 (基本)

  1. SSDSE-B-2026 で PCA(n_components=5) を実行し、 累積寄与率が 0.9 を超える最小の主成分数を求めよ。
  2. PCA の各 PC について pca.components_ を見て、 PC1 と PC2 の負荷量が最も大きい変数 2 つずつを挙げよ。 解釈名を付けよ。
  3. t-SNE を perplexity=5, 15, 30 の 3 通りで実行し、 東京・大阪・福井・島根の位置がどう変わるかを比較せよ。
  4. UMAP の n_neighbors=5, 15, 30 で同様の比較を行い、 「大域構造重視」と「局所構造重視」のどちらに振れるかを確認せよ。
  5. 4 手法の埋め込みについて trustworthiness と shepard 距離相関を計算し、 表にまとめよ。 結果から最も信頼できる手法を選び理由を述べよ。

📝 応用問題 4 問

  1. SSDSE-B-2026 を「東京・神奈川・大阪を除外」と「全件」の 2 通りで PCA にかけ、 PC1 / PC2 の意味がどう変わるかを負荷量から考察せよ。 報告書には除外条件を必ず明記すること。
  2. PCA を RobustScaler + 中央値中心化で実行し、 通常の StandardScaler 版と比較。 外れ値の影響が緩和されるかを定量的に示せ (寄与率と東京の PC1 値の差で評価)。
  3. UMAP の出力に対して KMeans(k=4) を適用し、 47 県を 4 クラスタに分け、 各クラスタの地理的・経済的特徴を 1 行で説明せよ。 これを PCA 版でも同様に行い、 クラスタ構成の違いを比較せよ。
  4. 1990 年から 2020 年までの SSDSE 系時系列が手に入った場合 (架空想定可)、 各年の県別データを PCA で射影し、 東京の軌跡を時系列でプロットする手順を設計せよ。 PCA を使う理由を「新規データへの射影可能性」から説明せよ。

💡 解答方針 (Hint)

🛠 よくあるエラー対処表

エラー / 症状 原因 対処
ValueError: Input contains NaN欠損が残っているdf.dropna() または SimpleImputer で補完
PC1 が 99% で他が無意味標準化忘れ + 巨大スケール列StandardScaler を必ず適用
t-SNE が毎回違う図シード未固定random_state=0 を指定
UMAP インストール失敗numba / llvmlite の依存pip install umap-learn (umap ではない)
ICA で ConvergenceWarning反復不足 or 入力ガウス的max_iter=1000 + 非ガウス成分確認
PCA の符号が毎回反転主成分の符号は一意でない符号を固定する後処理 (例: PC1 平均が正になるよう反転)
図に東京しか目立たない外れ値が軸を支配対数変換 or 外れ値除外して再計算
trustworthiness が低い (<0.7)パラメータ不適切perplexity / n_neighbors を変えて再評価

📌 R456 まとめ

🧠 PCA をさらに深掘り: 固有値・固有ベクトルから読む

PCA は数学的には共分散行列の固有値分解と等価である。 SSDSE-B-2026 を標準化した後、 np.cov(Xs.T) で共分散行列を作り、 np.linalg.eigh で固有値・固有ベクトルを求めると、 固有値が分散の大きさ (各主成分の寄与)、 固有ベクトルが軸の方向 (元変数への重み) を表す。 sklearn の pca.explained_variance_ が固有値、 pca.components_ が固有ベクトル (行ベクトル) に対応する。 これを理解すると「PC1 は東京を端に置く軸」という現象が、 「東京方向の分散が最大だから固有値が大きい」と数学的に説明できるようになる。 教育用には、 まず PCA を手動で固有値分解で実装させてから sklearn 版と一致することを確認する手順が有効。

このコードでやること: 共分散行列の固有値分解を手動で行い、 sklearn の PCA と結果が一致することを確認する。 「PCA の中身は固有値分解である」を数値で示す。

📥 入力: 標準化済 Xs (2023 年度 47 行 × 109 列)

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 numpy as np
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA

# ── この抜粋だけで動くように、Xs と sklearn の PCA 結果を作り直す ──
_d = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1)
_d = _d[_d['年度'] == 2023].reset_index(drop=True)   # 2023 年度の 47 都道府県
_num = _d.select_dtypes(include='number').drop(columns='年度').dropna(axis=1)
Xs = StandardScaler().fit_transform(_num)
pca = PCA(n_components=2, random_state=0).fit_transform(Xs)
idx_tokyo = _d['都道府県'].tolist().index('東京都')

# 共分散行列の固有値分解で PCA を手計算し、sklearn と一致するか確かめる
cov = np.cov(Xs, rowvar=False)
eigvals, eigvecs = np.linalg.eigh(cov)
order = np.argsort(eigvals)[::-1]
eigvals = eigvals[order]
eigvecs = eigvecs[:, order]
manual_score = Xs @ eigvecs[:, :2]
print('固有値 (上位5):', eigvals[:5].round(3))
print('累積寄与率   :', (eigvals[:5].cumsum() / eigvals.sum()).round(3))
print('手動 PCA 東京:', manual_score[idx_tokyo].round(2))
print('sklearn 東京 :', pca[idx_tokyo].round(2))
# 符号は反転することがある(固有ベクトルの向きは一意でないため)

📤 実行例の出力:

固有値 (上位5): [86.096 5.478 3.906 3.284 2.04 ] 累積寄与率 : [0.773 0.822 0.857 0.887 0.905] 手動 PCA 東京: [41.99 -3.13] sklearn 東京 : [41.99 -3.13]

💬 固有値は 86.096、5.478、3.906 と続き、累積寄与率は PC2 までで 82.2%、PC5 までで 90.5%。手動の固有値分解と sklearn で東京の座標はどちらも (41.99, -3.13) になった。固有ベクトルの符号は一意でないので、環境によってはどちらかの符号が反転して出ることがあり、報告書ではどちらの符号に揃えるかを決めておく。

🧠 t-SNE の数式的理解: KL ダイバージェンスを最小化する

t-SNE は元空間の確率分布 pij (点 i と j が近い確率) と埋め込み空間の確率分布 qij (t 分布で定義) の KL ダイバージェンスを最小化することで「近い点同士は近く、 遠い点は適当に」配置する。 数式は次の通り。

$$ p_{j|i} = \frac{\exp(-\|x_i - x_j\|^2 / 2\sigma_i^2)}{\sum_{k \ne i} \exp(-\|x_i - x_k\|^2 / 2\sigma_i^2)} $$

$$ q_{ij} = \frac{(1 + \|y_i - y_j\|^2)^{-1}}{\sum_{k \ne l} (1 + \|y_k - y_l\|^2)^{-1}} $$

$$ \mathcal{L} = \sum_{i \ne j} p_{ij} \log \frac{p_{ij}}{q_{ij}} $$

ここで σi は perplexity で決まる帯域幅、 t 分布を埋め込み側に使うのは「遠い点を強制的に押し離す」効果を出すため。 これを理解すると、 perplexity が大きいほど σi が広がり多くの点を「近い」と扱うため、 図が 1 つの塊になる現象が説明できる。 SSDSE-B-2026 (n=47) では perplexity を 5〜15 に設定するのが妥当で、 30 では実質全点が「近い」と扱われてしまう。

🧠 UMAP の理論: トポロジカルな貼り合わせ

UMAP は「ファジィ単体集合 (fuzzy simplicial set)」という代数的トポロジーの概念を使って、 元空間と埋め込み空間で同じトポロジー構造を保つように最適化する。 直感的には「n_neighbors 個の最近傍を結ぶ重み付きグラフを作り、 そのグラフを低次元に貼り直す」というイメージ。 t-SNE と比べて高速 (大規模 n に強い) で、 大域構造もある程度保持する。 ただし n_neighbors を変えると結果が大きく変わるため、 「3 通り試して安定する範囲を採用」が実務的な手順。 SSDSE-B-2026 では n_neighbors=10 が安定。

✅ 次元削減を使うときのチェックリスト 10 項目

  1. 目的は「説明」「可視化」「発見」「圧縮」のどれか? を明文化したか。
  2. 欠損を dropna() または imputer で処理したか。
  3. すべての数値変数を標準化 (StandardScaler) したか。 列のスケールが揃っているか。
  4. 外れ値 (東京・神奈川・大阪など) を含めるか除外するか決めたか。 両方計算したか。
  5. 主成分数を「寄与率 0.9 以上」「累積分散プロット (エルボー)」で決めたか。
  6. t-SNE / UMAP のシード (random_state) を固定したか。 3 つの seed で再現性確認したか。
  7. perplexity / n_neighbors を 3 段階で試したか。 結果が変わる範囲を把握したか。
  8. trustworthiness と距離相関を計算し、 数値根拠を持って手法を選んだか。
  9. 得られた図のキャプションに「手法・パラメータ・スケーリング・サンプル数」を必ず明記したか。
  10. 新規データに射影する必要があるか? (ある場合は PCA を選び、 t-SNE を避ける)

🚫 ありがちな誤用パターン 5 件

📖 実データでの活用事例 (SSDSE-B-2026 中心)

SSDSE-B-2026 のような県別データに次元削減を適用する典型シナリオを 3 つ示す。 (1) 経済規模軸での県の順位付け: PC1 を経済規模指標として使い、 県の総合的な経済力を 1 軸で比較。 (2) 人口動態クラスタ抽出: UMAP で 47 県を 4〜6 クラスタに分け、 高齢化・若年層流出パターンの似た県を地理的・政策的に分類。 (3) 異常県検出: PCA の再構成誤差 X - X_reconstructed が大きい県を「他県と構造的に異なる」として抽出し、 政策議論のフックにする。 いずれも「次元削減した結果を最終回答にせず、 仮説生成の起点として使う」のが基本姿勢である。

教育現場では「東京・大阪・福井・島根」の 4 県を比較事例として固定し、 4 手法それぞれの図でこの 4 県がどう配置されるかを表にまとめると学習者の理解が深まる。 PCA では「東京・大阪が経済軸の端、 福井・島根が中央」、 t-SNE では「クラスタ内位置」、 UMAP では「局所近傍構造」と異なる視点が得られ、 「同じデータでも見方で結論が変わる」体験ができる。

📜 次元削減の歴史と現代的位置づけ

PCA は 1901 年 Karl Pearson が「点群を当てはめる直線と平面」として提案、 1933 年 Harold Hotelling が現在の形に整理した。 100 年以上の歴史を持つ古典手法だが、 その安定性・解釈可能性ゆえに今でも第一選択。 ICA は 1994 年 Comon、 2000 年 Hyvärinen らが FastICA を実用化。 t-SNE は 2008 年 van der Maaten & Hinton、 UMAP は 2018 年 McInnes & Healy が発表した比較的新しい手法。 深層学習時代では autoencoder, VAE, ニューラル多様体学習などが台頭しているが、 「再現性・解釈性・新規データ射影」の 3 点で PCA が依然優位。 「新しい手法ほど良い」は次元削減には当てはまらない。

🧭 手法選択フロー (実務向け 8 ステップ)

ステップ 問い Yes ならば No ならば
S1新規データに繰り返し射影するか?PCA / ICA / parametric UMAP次へ
S2線形仮定で十分か?PCA を採用次へ
S3寄与率で説明したいか?PCA を採用次へ
S4独立な信号源を分離したいか?ICA を採用次へ
S5サンプル数 n ≤ 5,000?t-SNE 可UMAP 推奨
S6大域構造も保持したいか?UMAP / PCA を採用t-SNE 可
S7trustworthiness ≥ 0.9?採用パラメータ再調整
S83 シードで結果が安定?最終図として採用手法見直し

この 8 ステップを順に通せば、 「とりあえず t-SNE」「とりあえず UMAP」という選択を避けられる。 SSDSE-B-2026 (n=47, 線形構造優位) では多くの場合 S1〜S3 で PCA に到達する。 学習者には「フローチャートを通して PCA を選ぶ理由を言語化する」訓練を行うこと。

📐 4 手法の数値特性早見表 (R456 補強)

特性 PCA ICA t-SNE UMAP
数学的基礎固有値分解非ガウス性最大化KL ダイバージェンス代数的トポロジー
線形 / 非線形線形線形非線形非線形
主パラメータn_componentsn_componentsperplexityn_neighbors / min_dist
計算量O(p²n) or O(p³)O(iter·p²n)O(n²)O(n log n)
距離保存大域大域局所のみ局所+大域
逆変換可能可能不可parametric 版で可
出力の解釈直接 (loading)独立成分難 (図のみ)難 (図のみ)
適切な n数十〜数百万数百〜数万数百〜数千数百〜数百万

この表を「次元削減を始める前に必ず見る」ハンドアウトとして配布すると、 学習者がパラメータを盲目的に動かす前に「自分のデータに合う手法か?」を考える習慣がつく。 SSDSE-B-2026 (n=47, p≈30) は「数十〜数百」レンジで、 PCA は完全適合、 t-SNE は perplexity を慎重に設定、 UMAP は n_neighbors を 10 前後に絞ることで安定運用できる。

🌍 ドメイン別活用パターン

❓ よくある質問 (FAQ) 10 問

  1. Q. PCA と因子分析の違いは?
    A. PCA は分散最大方向、 因子分析は観測変数の背後にある潜在因子をモデル化する。 数学的には PCA は分散行列、 因子分析は共通分散と独自分散を分けて扱う。 SSDSE 解析では PCA の方が単純で使いやすい。
  2. Q. 主成分の数はどう決める?
    A. (1) 累積寄与率 0.8〜0.9、 (2) スクリープロットのエルボー、 (3) Kaiser 基準 (固有値 > 1)、 (4) 並べ替え検定 (parallel analysis) の 4 つから複数併用が望ましい。
  3. Q. 標準化と中心化の違いは?
    A. 中心化は平均を 0 にするだけ、 標準化は平均 0 + 標準偏差 1。 PCA は中心化必須、 列スケールが大きく違う場合は標準化も必須。
  4. Q. t-SNE の図でクラスタ間の距離は読んで良いか?
    A. 駄目。 t-SNE は近傍だけ保存するため、 クラスタ間距離・クラスタサイズに意味はない。 「2 つのクラスタがある」と言えるだけ。
  5. Q. UMAP は t-SNE の上位互換か?
    A. 大規模 n と大域構造保持の点で優位だが、 パラメータ感度は両者とも高い。 「上位互換」と単純化せず、 trustworthiness で選ぶ。
  6. Q. 次元削減の前にカテゴリ変数はどう扱う?
    A. One-hot エンコーディングで数値化してから入力。 ただし PCA は数値変数の線形結合を前提とするため、 mixed type の場合は FAMD (Factor Analysis of Mixed Data) を検討。
  7. Q. PCA で外れ値が問題なら何を使う?
    A. RobustPCA、 SparsePCA、 または前処理で RobustScaler + 外れ値除外を行う。 SSDSE-B-2026 では東京除外で PC1 の意味が「地方間差」に変わる。
  8. Q. 次元削減の結果は再現可能か?
    A. PCA / ICA は再現可能 (符号反転を除く)。 t-SNE / UMAP は random_state を固定して可能。 ただしライブラリ・バージョンが変わると微妙に異なる。
  9. Q. 可視化以外の用途は?
    A. 特徴量削減 (機械学習の前処理)、 ノイズ除去 (低次元成分のみ復元)、 異常検出 (再構成誤差)、 圧縮 (送信容量削減) などがある。
  10. Q. 学習者向けの初手は?
    A. SSDSE-B-2026 を StandardScaler + PCA(n_components=2) で可視化。 まず PCA で大域構造を掴ませてから、 比較として t-SNE / UMAP を導入する順序が理解しやすい。

🏁 R456 最終まとめ

次元削減は「目的に応じて手法を選ぶ」「数値根拠 (寄与率・距離相関・trustworthiness) を必ず添える」「標準化・シード固定・外れ値処理の 3 点セットを毎回確認する」の 3 原則を守れば、 SSDSE-B-2026 のような小規模県別データから大規模実データまで安全に活用できる。 PCA は解釈性と再現性で第一選択、 t-SNE / UMAP は可視化補助、 ICA は信号分離に限定。 これらを混同せずに使い分けることが、 「次元削減を理解した」と言える状態である。

📘 学習者向け 26 ステップ実習手順 (SSDSE-B-2026)

  1. SSDSE-B-2026 を pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) で読み込む。
  2. df.info() で型・欠損を確認する。
  3. df.select_dtypes(include='number').dropna(axis=1) で数値カラムだけ取り出す。
  4. StandardScaler で標準化する。
  5. 標準化前後の describe() を比較し、 平均 0 / 標準偏差 1 を確認する。
  6. PCA(n_components=5).fit(Xs) を実行。
  7. pca.explained_variance_ratio_ と累積寄与率をプロット (スクリープロット) する。
  8. 累積寄与率 0.9 を超える成分数 k を記録する。
  9. PCA(n_components=2).fit_transform(Xs) で 2 次元埋め込みを得る。
  10. 都道府県名を点ラベルに散布図を描く。
  11. 東京・大阪・神奈川・福井・島根の位置をメモする。
  12. pca.components_ で PC1 / PC2 の負荷量を表示する。
  13. 各 PC の負荷量上位 3 変数を抽出し、 軸の意味を命名する。
  14. FastICA(n_components=2, random_state=0) を実行する。
  15. PCA 散布図と ICA 散布図を並べて比較する。
  16. TSNE(n_components=2, perplexity=10, random_state=0) を実行する。
  17. perplexity を 5, 15, 30 と変えて 3 種類の図を描く。
  18. umap.UMAP(n_components=2, n_neighbors=10, random_state=0) を実行する。
  19. n_neighbors を 5, 15, 30 と変えて 3 種類の図を描く。
  20. 4 手法それぞれで trustworthiness を計算する。
  21. 元空間と各埋め込みの距離相関を計算する。
  22. 表に 4 手法 × (trustworthiness, 距離相関, 計算時間) をまとめる。
  23. 東京を除外して同じ実験を繰り返す。
  24. 除外前後で PC1 / PC2 の意味がどう変わるかを記述する。
  25. 4 手法の図にキャプション (手法・パラメータ・スケーリング・サンプル数) を付ける。
  26. レポートに「目的・選択した手法・数値根拠・制約」の 4 項目を書いて提出する。

この 26 ステップを通すと、 学習者は「次元削減は 1 つの手法ではなく、 比較・検証・解釈までを含む一連のプロセスである」ことを体験的に理解できる。 1 コマ 90 分の授業では Step 1〜15 まで進め、 残りは課題として 1 週間で完成させる構成が現実的。

📎 補論: なぜ「次元削減した図」を盲信してはいけないか

次元削減後の 2 次元プロットは強力な可視化ツールだが、 元情報の何割かを必ず失う。 SSDSE-B-2026 (n=47, p≈30) ですら PC2 までで分散の 11% を捨てている。 これを「単なる縮約」と片付けず、 「失われた情報に重要な構造が隠れていないか?」を常に問う姿勢が必要。 具体的には (1) 高次の主成分も別途プロットする、 (2) 再構成誤差が大きいサンプルを抽出する、 (3) 複数手法で再現性を確認する、 という 3 つの検証作業を必ず行う。 図一枚で結論を出すのは危険で、 「次元削減はあくまで仮説生成の補助ツール」と位置づけるのが安全。 R456 補強は以上。

最後に強調しておきたいのは、 SSDSE-B-2026 のような小規模公的データであっても、 PCA / ICA / t-SNE / UMAP の 4 手法を素直に並べて比較する習慣をつけるだけで、 学習者は「データを多面的に見る」訓練ができるという点である。 単一の手法に固執せず、 数値根拠 (寄与率・距離相関・trustworthiness) を毎回添えて議論する姿勢こそが、 次元削減という強力な道具を安全に使いこなす唯一の道である。

「次元削減」を扱う際の手法選択は、 状況に応じて以下のフローで判断すると迷いが減る。

  1. Step 1: 目的は記述か予測か?
    • 記述 (現状把握・要約) → 集計・可視化・要約統計量で全体像を掴む
    • 予測 (未知データへの推定) → モデル構築・検証フェーズへ移行
  2. Step 2: データの種類・規模は?
    • 数値データ・小〜中規模 → 「次元削減」やその拡張手法を直接適用
    • カテゴリデータ → カテゴリカル変数専用の MCA (多重対応分析) — 数値版 PCA の対応物
    • 大規模・高次元 → UMAP や t-SNE — 大規模・高次元データに計算効率と局所構造保存を両立
  3. Step 3: 結果の解釈・共有は?
    • 専門家向け → 数値指標・統計検定で精緻に評価
    • 非専門家向け → 可視化・自然言語での要約を重視

このフローに沿って判断することで、 「次元削減」を中核とした適切な手法選択ができる。

🎮 触って理解する

次元削減の心臓部である「射影 (projection)」を手で動かして体感するミニ実験です。 相関のある 2 次元の点群 (デモ用に生成した模擬データ) に対し、 射影する軸 (直線) の角度をスライダーまたは図の上のドラッグ/スワイプで回してみてください。 各点をその軸に垂直に落とした「射影点」(緑) と、 潰れて失われる垂直方向の情報 (赤い線) がリアルタイムで描画され、 その軸で保存される分散 (説明分散比) が即座に更新されます。 分散が最大になる方向こそが第 1 主成分 (PC1) です。 自分の手で分散最大の向きを探してみましょう。

この軸で保存される分散
(説明分散比)
–
垂直方向で失う分散
(情報損失)
–
PC1 が保存できる
最大の説明分散比
(ボタンで表示)

スライダーか図をドラッグして、 説明分散比が最大になる向きを探してみましょう。

凡例: ● 元の点 / ● 軸への射影点 / ― 失われる垂直成分。 分散の総和 (2 軸の分散合計) は回転しても不変なので、 説明分散比 + 情報損失 = 100% が常に成り立ちます。

💡 直感 — 「情報を最も保つ方向」を選ぶ

次元削減とは、 高次元データを情報の損失が最小になるように低次元へ落とす操作です。 上の実験で分かるように、 点群が細長く伸びている方向へ軸を合わせると射影後のばらつき (分散) が大きく保たれ、 潰れる赤い線が短くなります。 逆に伸びと直交する向きへ射影すると点が重なり合い、 分散のほとんどを捨ててしまいます。 主成分分析 (PCA) は、 この「分散を最大に保つ向き」を共分散行列の固有ベクトルとして解析的に求める手法です。 説明分散比 (寄与率) は「その軸が元データの何 % のばらつきを説明できるか」を表し、 分散を情報量の代理指標として扱っている点が核心です。

⚠️ よくある落とし穴

🚀 発展 — PCA / t-SNE / UMAP

ここで体感した「分散最大の直線射影」はPCA の 2 次元版です。 実データでは共分散行列の固有値分解 (または SVD) で全次元の主成分を一度に求めます。 一方、 データが非線形に曲がっている場合は、 局所的な近傍関係を保存するt-SNE や、 位相構造を保存するUMAP といった非線形手法が有効です。 カーネルトリックで非線形化したカーネル PCA も選択肢になります。 ただし t-SNE / UMAP はクラスタ間距離やクラスタサイズに意味を持たせられない (近傍しか保存しない) 点が PCA と根本的に異なるため、 「分散を保存する PCA」と「近傍を保存する t-SNE / UMAP」を混同しないことが重要です。

🔖 🔖 キーワード索引(チップから該当箇所へジャンプ)

論文記事から各用語のリンクをクリックすると、 該当箇所が開きます:

なぜ次元削減 次元の呪い PCA 寄与率 スクリープロット 因子負荷量 Kernel PCA 因子分析 因子回転 MDS t-SNE UMAP Isomap LDA(教師あり) オートエンコーダ

🔖 キーワード索引(深掘り版)

論文・記事に登場する用語のリンクで該当箇所へジャンプ:

🧮 SSDSE 実値計算 ⚠️ 落とし穴 6選 🐍 Python バリエーション 🔗 関連用語 PCA t-SNE UMAP オートエンコーダ カーネル PCA

🗜️ 解説深化 — 「圧縮した地図の歪み」を県ごとに実測する

本ページの他の章は「どれだけ分散を残せたか(寄与率)」を中心に次元削減を説明してきました。 この章では視点を反転させ、 低次元表現から元のデータをどれだけ復元できるか(再構成誤差)で次元削減の品質を測ります。 寄与率が「全体平均」の指標であるのに対し、 再構成誤差はサンプル 1 つずつに計算できるため、 「2 次元の地図でどの県が最も歪んでいるか」まで特定できます。

💡 直感 — 次元削減は「圧縮」と「復元」のペアで考える

地球儀を平面地図にすると、 必ずどこかの国の形が歪みます。 しかも歪み方は一様ではなく、 メルカトル図法なら極地方ほどひどく歪みます。 次元削減もまったく同じで、 47 都道府県 × 10 変数を 2 次元に潰せば必ず情報が失われますが、 失われ方は県ごとに不平等です。 PCA は線形写像なので、 低次元スコア $z_i$ から $\hat{x}_i = \bar{x} + V_k z_i$ で元の空間へ「復元」でき、 復元値と実測値の差(残差)がその県の歪みの大きさになります。 寄与率 58.8%(本ページ「実値計算例」の PC2 までの累積、 実測)とは「平均すれば 58.8% 復元できる」という意味であって、 全県が等しく 58.8% 復元されるわけではない — これがこの章の中心的な直感です。

⚠️ 落とし穴(重要) — 平均寄与率の裏で、 特定の県だけが大きく歪む

実際に SSDSE-B-2026(2023 年・47 都道府県)の家計支出 10 項目(L322101〜L322110、 標準化済み)を PCA で 2 次元に圧縮し、 復元したときの県別再構成誤差(RMSE、 標準偏差単位)を計算した実測値が次の表です。

順位 歪みが大きい県(実測 RMSE) 歪みが小さい県(実測 RMSE)
1三重県 1.00島根県 0.26
2北海道 0.98栃木県 0.32
3福井県 0.92山口県 0.35
4大分県 0.90佐賀県 0.41
5青森県 0.84長崎県 0.42

全 47 県の中央値は 0.60。 最大(三重県 1.00)と最小(島根県 0.26)で約 3.8 倍の開きがある(いずれも実測値)。

🎯 再現コード: 上の実測値(県別 RMSE と非標準化 PCA の退化)は次のコードで再現できる。
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) 北海道 5,092,000 東京都 14,086,000 沖縄県 1,468,000 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import pandas as pd, numpy as np
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
d = df[df['SSDSE-B-2026'] == 2023].set_index('Prefecture')
cols = ['L3221%02d' % i for i in range(1, 11)]        # 家計支出10項目
X = d[cols].astype(float)
Z = ((X - X.mean()) / X.std(ddof=0)).values           # 標準化
U, S, Vt = np.linalg.svd(Z - Z.mean(0), full_matrices=False)
Zk = (U[:, :2] * S[:2]) @ Vt[:2]                      # 2次元へ圧縮→復元
rmse = pd.Series(np.sqrt(((Z - Zk)**2).mean(axis=1)), index=X.index)
print(rmse.sort_values(ascending=False).head(5).round(2))  # 三重1.00 北海道0.98 ...
# --- 標準化なしで総人口を混ぜると PC1 が退化する実験 ---
Xr = d[['A1101'] + cols].astype(float).values
Xc = Xr - Xr.mean(0)
_, S2, _ = np.linalg.svd(Xc, full_matrices=False)
print('raw PC1 EVR = %.4f%%' % (S2[0]**2 / (S2**2).sum() * 100))  # 99.9973%
📤 実行例(実測) Prefecture 三重県 1.00 北海道 0.98 福井県 0.92 大分県 0.90 青森県 0.84 dtype: float64 raw PC1 EVR = 99.9973%

💬 家計支出 10 項目を標準化して 2 主成分で復元すると、復元誤差(RMSE)が最も大きいのは三重県 1.00、次いで北海道 0.98、福井県 0.92 で、この 3 県の支出の配分は 2 次元の共通パターンから最も外れている。後半は標準化しないまま総人口を加えた実験で、第 1 主成分の寄与率が 99.9973% になる。総人口の分散が1 世帯あたり月約 1 万〜8 万円の支出項目より桁違いに大きいためで、PC1 はほぼ総人口そのものに退化している。

🚀 発展 — 再構成誤差は「異常検知」への入口

「復元できなかった部分」に注目する発想は、 そのまま PCA ベースの異常検知(SPE / Q 統計量、 Hotelling の T² 統計量)へつながります。 正常データで学習した主成分部分空間から大きく外れたサンプル、 すなわち再構成誤差が閾値を超えたサンプルを異常と判定する手法で、 製造業のプロセス監視などで標準的に使われます。 上の表で言えば、 三重県・北海道は「家計 10 項目の主要 2 軸では説明できない独自プロファイルを持つ県」であり、 外れ値検出の候補として個別に調べる価値がある、 という読み方になります。 また、 この「decoder(復元写像)を持つかどうか」は手法選択の本質的な分岐でもあります。 PCA・因子分析・オートエンコーダは復元写像を持つため再構成誤差が定義できますが、 t-SNE や UMAP は低次元配置を直接最適化するだけで逆写像を持たず、 「この点はどれくらい歪んでいるか」を残差では測れません(近傍保存率 trustworthiness などの代替指標を使います)。 さらに、 非標準化 PCA の退化の実験は、 変数間の強い相関が引き起こす多重共線性の診断に PCA(固有値の縮退チェック)が使われる理由の裏返しにもなっています。

🔗 関連ページ