次元削減の全体像 — PCA・t-SNE・UMAPの使い分け

100次元のデータを人間が理解するにはどうすればよいでしょうか。100個の散布図を個別に見ても全体像は掴めません。そこで必要になるのが次元削減(dimensionality reduction)です。

次元削減は、高次元データの「本質的な構造」を保ちながら低次元(通常2-3次元)に圧縮する技術です。これにより、データの可視化、ノイズの除去、計算効率の向上が可能になります。

しかし、「本質的な構造」の定義は手法によって異なります。PCAは分散の方向を保ち、t-SNEは局所的な類似性を保ち、UMAPはトポロジカルな構造を保ちます。この違いを理解することが、適切な手法を選ぶ鍵です。

次元削減を理解すると、以下のような場面で活用できます。

  • データ可視化: 高次元データの2次元プロットによる探索的分析
  • 前処理: 次元の呪いへの対処と計算効率の向上
  • ノイズ除去: 重要でない変動(ノイズ)を除去してモデルの性能を向上
  • 特徴量抽出: 元の特徴量の線形/非線形組み合わせで新しい特徴量を作成

本記事の内容

  • PCA(主成分分析)の理論と固有値分解
  • t-SNEの確率的近傍埋め込み
  • UMAPのトポロジカルデータ解析に基づくアプローチ
  • 3手法の比較と使い分け
  • Pythonでの実装と可視化

前提知識

この記事を読む前に、以下の記事を読んでおくと理解が深まります。

PCA(主成分分析)

直感

PCAの直感は「データの分散が最大になる方向を見つける」ことです。2次元データが楕円形に散らばっているとき、楕円の長軸方向が第1主成分、短軸方向が第2主成分です。

数学的定式化

$n$ 個の $d$ 次元データ $\bm{X} \in \mathbb{R}^{n \times d}$(中心化済み: $\bar{\bm{x}} = \bm{0}$)に対して、共分散行列は

$$ \bm{C} = \frac{1}{n}\bm{X}^T\bm{X} $$

分散を最大化する方向 $\bm{u}$ は

$$ \max_{\bm{u}} \bm{u}^T\bm{C}\bm{u} \quad \text{subject to} \quad \|\bm{u}\| = 1 $$

ラグランジュの未定乗数法より、$\bm{C}\bm{u} = \lambda\bm{u}$ が得られます。つまり主成分方向は共分散行列の固有ベクトルであり、その方向の分散は固有値 $\lambda$ です。

固有値を大きい順に $\lambda_1 \geq \lambda_2 \geq \cdots \geq \lambda_d$ と並べ、対応する固有ベクトルを $\bm{u}_1, \bm{u}_2, \ldots, \bm{u}_d$ とすると、上位 $k$ 個の固有ベクトルで張られる空間への射影が $k$ 次元PCAです。

寄与率と次元の選択

第 $j$ 主成分の寄与率は $\lambda_j / \sum_k \lambda_k$ であり、上位 $k$ 個の累積寄与率が十分大きい(例: 95%以上)$k$ を選びます。

t-SNE

動機

PCAは線形的な構造しか捉えられません。非線形な多様体構造(例: スイスロール)を持つデータには不向きです。

t-SNE(t-distributed Stochastic Neighbor Embedding; van der Maaten & Hinton, 2008)は、高次元空間での近傍関係を低次元空間で保存する非線形手法です。

アルゴリズム

高次元空間でのデータ点 $\bm{x}_i, \bm{x}_j$ の類似度を条件付きガウス分布で定義します。

$$ p_{j|i} = \frac{\exp(-\|\bm{x}_i – \bm{x}_j\|^2 / 2\sigma_i^2)}{\sum_{k \neq i}\exp(-\|\bm{x}_i – \bm{x}_k\|^2 / 2\sigma_i^2)} $$

対称化して $p_{ij} = (p_{j|i} + p_{i|j}) / 2n$ とします。

低次元空間ではt分布(自由度1、コーシー分布)で類似度を定義します。

$$ q_{ij} = \frac{(1 + \|\bm{y}_i – \bm{y}_j\|^2)^{-1}}{\sum_{k \neq l}(1 + \|\bm{y}_k – \bm{y}_l\|^2)^{-1}} $$

t分布を使う理由は、裾が重いため遠い点をさらに遠くに配置でき、クラウディング問題(中間距離の点が混雑する問題)を緩和するためです。

$p$ と $q$ のKLダイバージェンスを最小化します。

$$ \text{KL}(P \| Q) = \sum_{i \neq j} p_{ij} \ln \frac{p_{ij}}{q_{ij}} $$

t-SNEの注意点

  • 非確定的: ランダムな初期化により結果が毎回異なる
  • perplexityパラメータ: 近傍の範囲を制御(通常5-50)
  • 大域的構造の非保存: クラスター間の距離は意味を持たない
  • 計算コスト: $O(n^2)$(Barnes-Hut近似で $O(n \log n)$)

UMAP

理論的背景

UMAP(Uniform Manifold Approximation and Projection; McInnes et al., 2018)はリーマン幾何学とトポロジカルデータ解析に基づく手法です。

UMAPは高次元データの位相的構造(ファジー単体集合)を構築し、低次元で同等の位相的構造を持つ埋め込みを見つけます。

t-SNEとの比較

  • 速度: UMAPはt-SNEより大幅に高速($O(n)$ に近い)
  • 大域構造: UMAPはクラスター間の相対的な位置関係をある程度保存
  • パラメータ: n_neighbors(局所/大域のバランス)と min_dist(点の密集度)
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_swiss_roll, load_digits
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
from sklearn.preprocessing import StandardScaler

np.random.seed(42)

# 手書き数字データ
digits = load_digits()
X_digits = digits.data
y_digits = digits.target

# 標準化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X_digits)

fig, axes = plt.subplots(1, 3, figsize=(16, 5))

# (a) PCA
ax = axes[0]
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
scatter = ax.scatter(X_pca[:, 0], X_pca[:, 1], c=y_digits, cmap="tab10",
                     s=5, alpha=0.7)
ax.set_title(f"PCA (var explained={pca.explained_variance_ratio_.sum():.1%})", fontsize=13)
ax.set_xlabel("PC1", fontsize=12)
ax.set_ylabel("PC2", fontsize=12)
ax.grid(True, alpha=0.3)

# (b) t-SNE
ax = axes[1]
tsne = TSNE(n_components=2, perplexity=30, random_state=42, n_iter=1000)
X_tsne = tsne.fit_transform(X_scaled)
scatter = ax.scatter(X_tsne[:, 0], X_tsne[:, 1], c=y_digits, cmap="tab10",
                     s=5, alpha=0.7)
ax.set_title("t-SNE (perplexity=30)", fontsize=13)
ax.set_xlabel("t-SNE 1", fontsize=12)
ax.set_ylabel("t-SNE 2", fontsize=12)
ax.grid(True, alpha=0.3)

# (c) UMAP(UMAPがインストールされていない場合のフォールバック)
ax = axes[2]
try:
    import umap
    reducer = umap.UMAP(n_components=2, n_neighbors=15, min_dist=0.1, random_state=42)
    X_umap = reducer.fit_transform(X_scaled)
    scatter = ax.scatter(X_umap[:, 0], X_umap[:, 1], c=y_digits, cmap="tab10",
                         s=5, alpha=0.7)
    ax.set_title("UMAP (n_neighbors=15)", fontsize=13)
except ImportError:
    # UMAPなしの場合はt-SNEの別パラメータで代替
    tsne2 = TSNE(n_components=2, perplexity=50, random_state=0, n_iter=1000)
    X_tsne2 = tsne2.fit_transform(X_scaled)
    scatter = ax.scatter(X_tsne2[:, 0], X_tsne2[:, 1], c=y_digits, cmap="tab10",
                         s=5, alpha=0.7)
    ax.set_title("t-SNE (perplexity=50, alt params)", fontsize=13)

ax.set_xlabel("Dim 1", fontsize=12)
ax.set_ylabel("Dim 2", fontsize=12)
ax.grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig("dimensionality_reduction.png", dpi=150, bbox_inches="tight")
plt.show()

このグラフから、3手法の特性の違いが読み取れます。

  1. 左図(PCA): 線形的な射影で、クラスター構造がある程度見えますが、クラス間の重なりが大きいです。累積寄与率は2次元で全分散の一部しか説明できていないことを示しています。大域的な分散の方向は保存されていますが、局所的な構造は失われています

  2. 中央図(t-SNE): 各数字のクラスターが明確に分離されており、局所的な構造が非常によく保存されています。ただし、クラスター間の距離は信頼できません。perplexityパラメータが結果に大きく影響します

  3. 右図(UMAP): t-SNEと同様に良好なクラスター分離を示しつつ、クラスター間の相対的な距離もある程度保存されています。計算速度もt-SNEより高速です

使い分けガイド

用途 推奨手法 理由
前処理(回帰/分類の前段) PCA 線形・高速・逆変換可能
可視化(探索的分析) t-SNE / UMAP 非線形構造の可視化に優れる
大規模データの可視化 UMAP t-SNEより大幅に高速
ノイズ除去 PCA 小さい固有値の成分を除去
特徴量抽出 PCA / Kernel PCA 新しい特徴量としてモデルに入力

まとめ

本記事では、主要な次元削減手法の理論と使い分けについて解説しました。

  • PCAは共分散行列の固有値分解に基づく線形手法で、分散を最大化する方向に射影する
  • t-SNEは高次元の近傍関係を低次元で保存する非線形手法で、可視化に優れるが計算コストが高い
  • UMAPはトポロジカルデータ解析に基づく手法で、t-SNEの利点を保ちつつ高速で大域構造も保存する
  • PCAは前処理とノイズ除去に、t-SNE/UMAPはデータの可視化と探索的分析に使い分ける

次のステップとして、以下の記事も参考にしてください。