線形代数学 講義ノート 第46回
講義情報と予習ガイド
講義回: 第46回
テーマ: 非線形次元削減法:t-SNEとUMAP
関連項目: 主成分分析、次元削減、マニフォールド学習
予習すべき内容: 主成分分析、特異値分解、確率分布の基礎知識
学習目標
- 線形次元削減手法の限界を理解し、非線形次元削減の必要性を説明できる
- t-SNE(t-distributed Stochastic Neighbor Embedding)の理論的背景と動作原理を理解する
- UMAP(Uniform Manifold Approximation and Projection)の基本概念と数学的フレームワークを把握する
- t-SNEとUMAPの違いと使い分けの基準を説明できる
- 健康データ科学における非線形次元削減の応用例を理解する
1. 基本概念:非線形次元削減の必要性
1.1 線形次元削減手法の限界
これまで私たちは主成分分析(PCA)や因子分析といった線形次元削減手法について学んできました。これらの手法は、データの分散を最大化する直交軸を見つけることで次元削減を行います。しかし、実世界のデータは必ずしも線形の関係だけで表現できるわけではありません。
線形次元削減の限界: 1. 非線形の関係性を捉えることができない 2. 局所的な構造を保存することが難しい 3. データが曲面(マニフォールド)上に分布している場合に適切に表現できない
例えば、「スイスロール」と呼ばれる有名な3次元のデータ構造を考えてみましょう。これは巻物のような形状をしており、データ点は2次元の曲面上に分布しています。PCAなどの線形手法でこれを2次元に削減すると、巻物の構造が完全に失われてしまいます。
1.2 マニフォールド仮説
非線形次元削減の理論的基礎となっているのが「マニフォールド仮説」です。
マニフォールド仮説: 高次元の実世界データは、実際にはより低い次元の曲面(マニフォールド)上に分布していることが多い。
例えば、人間の顔画像は数千〜数万次元のピクセル空間で表現されますが、実際の顔の変化は数十程度のパラメータ(年齢、表情、角度など)で説明できると考えられます。
1.3 局所的構造と大域的構造の保存
非線形次元削減手法の重要な特徴は、データの局所的な構造を保存しながら、大域的な構造も可能な限り維持することです。
- 局所的構造: 近接点間の関係性(類似点は近くに配置)
- 大域的構造: データ全体の分布パターン(クラスターの分離など)
2. t-SNE (t-distributed Stochastic Neighbor Embedding)
2.1 基本概念と開発背景
t-SNEは2008年にLaurens van der MaatenとGeoffrey Hintonによって開発された非線形次元削減手法です。SNE(Stochastic Neighbor Embedding)を改良したもので、高次元データを低次元空間に埋め込む際に、特に局所的な構造を保存することに優れています。
t-SNEの目的: 高次元空間での点間の類似度関係を、低次元空間でも可能な限り保存すること。特に、近傍点間の関係性を重視する。
2.2 数学的フレームワーク
t-SNEのアルゴリズムは以下の手順で進行します:
2.2.1 高次元空間での条件付き確率の計算
まず、高次元空間でのデータポイント間の類似度を条件付き確率として定義します。
点 \(x_i\) から見た点 \(x_j\) の条件付き確率 \(p_{j|i}\) は次のように定義されます:
ここで \(\sigma_i\) はガウス分布の分散パラメータで、点 \(x_i\) の有効近傍数(パープレキシティ)に基づいて調整されます。
続いて、対称化された結合確率 \(p_{ij}\) を以下のように定義します:
ここで \(n\) はデータポイントの総数です。
2.2.2 低次元空間での確率分布(t分布の採用)
低次元空間(通常は2次元か3次元)での対応する点 \(y_i\) と \(y_j\) の間の類似度は、自由度1のt分布(コーシー分布)を用いて以下のように定義されます:
t分布が採用された理由は、高次元空間での近接点が低次元空間でも近くにマッピングされやすくなる「クラウディング問題」を軽減するためです。t分布は正規分布よりも裾が重いため、遠い点同士をより離れた位置に配置できます。
2.2.3 Kullback-Leibler発散の最小化
t-SNEは二つの確率分布 \(P\) と \(Q\) の間のKullback-Leibler発散を最小化することで、最適な低次元表現を求めます:
この目的関数の勾配は以下のように計算されます:
この勾配を用いて、勾配降下法で低次元埋め込みを最適化します。
2.3 パラメータの役割
2.3.1 パープレキシティ (Perplexity)
パープレキシティは、各データポイントの有効近傍数を制御するパラメータで、t-SNEの最も重要なハイパーパラメータです。
パープレキシティ: 2のエントロピーの指数で表される有効近傍数。通常5〜50の範囲で設定される。 \(\(Perp(P_i) = 2^{H(P_i)}\)\) ここで \(H(P_i) = -\sum_j p_{j|i} \log_2 p_{j|i}\) はエントロピーです。
- 小さいパープレキシティ(5〜10): 局所的構造を重視
- 大きいパープレキシティ(30〜50): より大域的な構造を重視
2.3.2 学習率とイテレーション数
- 学習率: 勾配降下法でのステップサイズ。通常200〜1000の範囲
- イテレーション数: 1000〜5000程度が一般的
2.4 計算量の問題と高速化手法
t-SNEの計算量は \(O(n^2)\) で、データポイント数 \(n\) が増えると計算時間が急激に増加します。このため、大規模データセットでの利用には高速化技術が必要です。
Barnes-Hutアルゴリズム: - 空間を四分木(2D)や八分木(3D)で分割 - 遠い点の集団を一つの点として近似 - 計算量を \(O(n \log n)\) に削減
3. UMAP (Uniform Manifold Approximation and Projection)
3.1 基本概念と開発背景
UMAPは2018年にLeland McInnesらによって開発された非線形次元削減手法で、t-SNEの後継として急速に普及しています。トポロジー理論に基づいており、局所的構造と大域的構造の両方を保存することを目指しています。
UMAPの特徴: 1. 計算効率がt-SNEより高い 2. 大域的構造の保存性が優れている 3. 理論的な基盤がより堅固(リーマン幾何学とトポロジー)
3.2 数学的フレームワーク
3.2.1 リーマン幾何学とトポロジーの観点
UMAPはデータの分布をリーマン多様体と見なし、その位相的構造を低次元空間に近似しようとします。具体的には、各点の局所的な近傍をファジー単体複体(fuzzy simplicial complex)として表現します。
3.2.2 局所的距離関係のモデリング
各点 \(x_i\) について、その \(k\)-近傍内の点 \(x_j\) までの距離を以下のように正規化します:
ここで \(\rho_i\) は最も近い点までの距離、\(\sigma_i\) は近傍の広がりを制御するパラメータです。
この正規化距離から、高次元空間での局所的な接続強度を以下のように計算します:
3.2.3 ファジー集合理論の応用
UMAPは高次元空間と低次元空間それぞれでファジー集合を構築し、これらを近似しようとします。高次元ファジー集合 \(\mu\) と低次元ファジー集合 \(\nu\) の間のクロスエントロピーを最小化します:
ここで低次元での接続強度 \(\nu_{ij}\) は以下のように定義されます:
\(a\) と \(b\) はハイパーパラメータで、低次元空間での距離の振る舞いを制御します。
3.2.4 確率的勾配降下法による最適化
上記のクロスエントロピー目的関数を確率的勾配降下法で最小化することで、低次元埋め込みを学習します。
3.3 パラメータの役割
3.3.1 近傍数 (n_neighbors)
各点の局所的近傍を定義するパラメータで、t-SNEのパープレキシティに相当します。
- 小さい値: 局所的構造を重視
- 大きい値: 大域的構造を重視
3.3.2 最小距離 (min_dist)
低次元空間での点の最小距離を制御します。これは埋め込み空間での点の密集度に影響します。
- 小さい値: 点が密集したクラスターを形成
- 大きい値: より均一な分布
3.3.3 ネガティブサンプル比率
最適化過程で使用する負例の数で、計算効率とモデルの精度のトレードオフを制御します。
4. t-SNEとUMAPの比較
4.1 理論的背景の違い
- t-SNE: 確率的な点間の類似度を保存
- UMAP: トポロジカルなデータ構造を保存
4.2 パフォーマンスの違い
- 計算効率: UMAPはt-SNEより高速(特に大規模データセット)
- 大域的構造の保存: UMAPの方が優れている傾向
- 局所的構造の保存: どちらも優れているが、特性が異なる
4.3 使い分けの基準
- 探索的分析: 初期段階ではUMAPが効率的
- 詳細な局所構造の可視化: t-SNEも考慮
- 大規模データ: UMAPの方が適している
- 処理速度が重要: UMAPを選択
- 安定性が重要: UMAPはt-SNEよりもイテレーション間の安定性が高い
5. 健康データ科学における応用例
5.1 単一細胞RNAシーケンスデータの視覚化
単一細胞RNAシーケンス(scRNA-seq)データは、数万の遺伝子発現レベルで各細胞を特徴づける非常に高次元のデータです。
- t-SNEとUMAPは細胞タイプの同定と可視化のデファクトスタンダード
- 同じ細胞タイプはクラスターを形成
- 発生過程のトラジェクトリ解析にも利用
5.2 医療画像の特徴空間における患者のクラスタリング
医療画像(MRI、CT、病理画像など)から抽出された特徴を低次元に埋め込むことで、患者グループの自動分類が可能になります。
- 脳MRI画像からのアルツハイマー病の早期診断
- 皮膚病変の分類と診断支援
- 病理組織画像からのがんサブタイプの同定
5.3 生理学的時系列データのパターン発見
ウェアラブルデバイスや医療モニターから得られる時系列データを分析し、異常パターンや疾患リスクを可視化します。
- 心電図データからの不整脈パターンの検出
- 睡眠ポリグラフデータからの睡眠障害の分類
- 連続血糖モニタリングデータからの血糖パターンの同定
5.4 医薬品開発における分子構造の類似性マッピング
薬物分子の高次元特徴表現を低次元空間に埋め込み、構造的・機能的に類似した化合物を可視化します。
- 仮想スクリーニングと創薬
- 既存薬のリポジショニング
- 薬物副作用の予測
6. Pythonによる実装と可視化
6.1 データの準備と前処理
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_digits
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
import umap
# サンプルデータの読み込み(手書き数字)
digits = load_digits()
X = digits.data
y = digits.target
# スケーリング
X_scaled = StandardScaler().fit_transform(X)
print(f"元のデータ形状: {X.shape}")
6.2 PCA(線形次元削減)との比較
# PCAによる次元削減
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
# 可視化
plt.figure(figsize=(10, 8))
plt.scatter(X_pca[:, 0], X_pca[:, 1], c=y, cmap='tab10', s=50, alpha=0.8)
plt.colorbar(label='数字のクラス')
plt.title('PCAによる手書き数字の2次元表示')
plt.xlabel(f'第1主成分 (分散: {pca.explained_variance_ratio_[0]:.2f})')
plt.ylabel(f'第2主成分 (分散: {pca.explained_variance_ratio_[1]:.2f})')
plt.grid(True, alpha=0.3)
plt.show()
# 累積寄与率
plt.figure(figsize=(8, 5))
plt.plot(np.cumsum(pca.explained_variance_ratio_), marker='o')
plt.axhline(y=0.9, color='r', linestyle='--')
plt.grid(True, alpha=0.3)
plt.xlabel('主成分の数')
plt.ylabel('累積寄与率')
plt.title('PCAの累積寄与率')
plt.show()
6.3 t-SNEの実装と可視化
# t-SNEを実行
# 注意: 計算時間がかかる場合があります
tsne = TSNE(n_components=2, perplexity=30, random_state=42)
X_tsne = tsne.fit_transform(X_scaled)
# t-SNEの結果を可視化
plt.figure(figsize=(10, 8))
scatter = plt.scatter(X_tsne[:, 0], X_tsne[:, 1], c=y, cmap='tab10', s=50, alpha=0.8)
plt.colorbar(scatter, label='数字のクラス')
plt.title('t-SNEによる手書き数字の2次元表示 (パープレキシティ=30)')
plt.xlabel('t-SNE 次元 1')
plt.ylabel('t-SNE 次元 2')
plt.grid(True, alpha=0.3)
plt.show()
# 異なるパープレキシティでの比較(オプション)
fig, axes = plt.subplots(1, 3, figsize=(18, 6))
perplexities = [5, 30, 50]
for i, perplexity in enumerate(perplexities):
tsne = TSNE(n_components=2, perplexity=perplexity, random_state=42)
X_tsne = tsne.fit_transform(X_scaled)
scatter = axes[i].scatter(X_tsne[:, 0], X_tsne[:, 1], c=y, cmap='tab10', s=30, alpha=0.7)
axes[i].set_title(f't-SNE (パープレキシティ={perplexity})')
axes[i].set_xlabel('t-SNE 次元 1')
axes[i].set_ylabel('t-SNE 次元 2')
axes[i].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
6.4 UMAPの実装と可視化
# UMAPを実行
umap_reducer = umap.UMAP(n_neighbors=15, min_dist=0.1, random_state=42)
X_umap = umap_reducer.fit_transform(X_scaled)
# UMAPの結果を可視化
plt.figure(figsize=(10, 8))
scatter = plt.scatter(X_umap[:, 0], X_umap[:, 1], c=y, cmap='tab10', s=50, alpha=0.8)
plt.colorbar(scatter, label='数字のクラス')
plt.title('UMAPによる手書き数字の2次元表示 (n_neighbors=15, min_dist=0.1)')
plt.xlabel('UMAP 次元 1')
plt.ylabel('UMAP 次元 2')
plt.grid(True, alpha=0.3)
plt.show()
# 異なるパラメータでの比較(オプション)
fig, axes = plt.subplots(2, 2, figsize=(14, 12))
neighbors = [5, 30]
min_dists = [0.1, 0.5]
for i, n in enumerate(neighbors):
for j, d in enumerate(min_dists):
umap_reducer = umap.UMAP(n_neighbors=n, min_dist=d, random_state=42)
X_umap = umap_reducer.fit_transform(X_scaled)
scatter = axes[i, j].scatter(X_umap[:, 0], X_umap[:, 1], c=y, cmap='tab10', s=30, alpha=0.7)
axes[i, j].set_title(f'UMAP (n_neighbors={n}, min_dist={d})')
axes[i, j].set_xlabel('UMAP 次元 1')
axes[i, j].set_ylabel('UMAP 次元 2')
axes[i, j].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
6.5 実行時間の比較
import time
# 実行時間を計測する関数
def measure_time(algorithm, data):
start_time = time.time()
result = algorithm.fit_transform(data)
end_time = time.time()
return result, end_time - start_time
# 各アルゴリズムの実行
print("実行時間の比較:")
# PCA
pca = PCA(n_components=2)
_, pca_time = measure_time(pca, X_scaled)
print(f"PCA: {pca_time:.2f}秒")
# t-SNE
tsne = TSNE(n_components=2, perplexity=30, random_state=42)
_, tsne_time = measure_time(tsne, X_scaled)
print(f"t-SNE: {tsne_time:.2f}秒")
# UMAP
umap_reducer = umap.UMAP(n_neighbors=15, min_dist=0.1, random_state=42)
_, umap_time = measure_time(umap_reducer, X_scaled)
print(f"UMAP: {umap_time:.2f}秒")
# 実行時間のバープロット
algorithms = ['PCA', 't-SNE', 'UMAP']
times = [pca_time, tsne_time, umap_time]
plt.figure(figsize=(10, 6))
plt.bar(algorithms, times, color=['blue', 'green', 'red'])
plt.ylabel('実行時間(秒)')
plt.title('次元削減アルゴリズムの実行時間比較')
plt.grid(True, alpha=0.3, axis='y')
plt.show()
6.6 健康データ分析の例: 糖尿病データの可視化
from sklearn.datasets import load_diabetes
# 糖尿病データの読み込み
diabetes = load_diabetes()
X_diabetes = diabetes.data
y_diabetes = diabetes.target
# スケーリング
X_diabetes_scaled = StandardScaler().fit_transform(X_diabetes)
# 3つの次元削減手法の適用
# PCA
pca_diabetes = PCA(n_components=2).fit_transform(X_diabetes_scaled)
# t-SNE
tsne_diabetes = TSNE(n_components=2, perplexity=30, random_state=42).fit_transform(X_diabetes_scaled)
# UMAP
umap_diabetes = umap.UMAP(random_state=42).fit_transform(X_diabetes_scaled)
# 結果の可視化(カラーは疾患進行度を示す)
fig, axes = plt.subplots(1, 3, figsize=(18, 6))
# PCA
scatter1 = axes[0].scatter(pca_diabetes[:, 0], pca_diabetes[:, 1], c=y_diabetes,
cmap='coolwarm', s=40, alpha=0.8)
axes[0].set_title('PCA: 糖尿病データ')
axes[0].set_xlabel('第1主成分')
axes[0].set_ylabel('第2主成分')
axes[0].grid(True, alpha=0.3)
# t-SNE
scatter2 = axes[1].scatter(tsne_diabetes[:, 0], tsne_diabetes[:, 1], c=y_diabetes,
cmap='coolwarm', s=40, alpha=0.8)
axes[1].set_title('t-SNE: 糖尿病データ')
axes[1].set_xlabel('t-SNE 次元 1')
axes[1].set_ylabel('t-SNE 次元 2')
axes[1].grid(True, alpha=0.3)
# UMAP
scatter3 = axes[2].scatter(umap_diabetes[:, 0], umap_diabetes[:, 1], c=y_diabetes,
cmap='coolwarm', s=40, alpha=0.8)
axes[2].set_title('UMAP: 糖尿病データ')
axes[2].set_xlabel('UMAP 次元 1')
axes[2].set_ylabel('UMAP 次元 2')
axes[2].grid(True, alpha=0.3)
# カラーバーの追加
cbar = fig.colorbar(scatter3, ax=axes.ravel().tolist())
cbar.set_label('疾患進行度')
plt.tight_layout()
plt.show()
7. 演習問題
基本問題
-
問題1: 線形次元削減手法(PCA)の限界を3つ挙げ、それぞれについて簡潔に説明しなさい。
-
問題2: t-SNEにおけるパープレキシティパラメータの役割を説明し、値が小さい場合と大きい場合でどのような違いが生じるか述べなさい。
-
問題3: UMAPの理論的背景について、t-SNEとの違いを中心に説明しなさい。
-
問題4: 次の各ケースでは、PCA、t-SNE、UMAPのうちどれが最適か選択し、理由を説明しなさい。 a) 10万患者の電子カルテから抽出した1000次元の特徴量を可視化したい b) 多次元データの分散を最大化する軸を見つけたい c) 単一細胞RNAシーケンスデータのクラスタリングを行いたい d) 次元削減後のデータに対して、新たなデータ点をマッピングしたい
-
問題5: t-SNEとUMAPの計算効率の違いを説明し、大規模データセットの場合にUMAPが優れている理由を述べなさい。
応用問題
- 問題6: 以下のPythonコードの誤りを指摘し、修正しなさい。
# 次元削減の比較コード
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
# データのスケーリングなしで直接適用
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)
# パープレキシティにマイナス値を設定
tsne = TSNE(n_components=2, perplexity=-5)
X_tsne = tsne.fit_transform(X)
# 結果の可視化
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.scatter(X_pca[0], X_pca[1], c=y) # インデックス指定が誤っている
plt.title('PCA')
plt.subplot(1, 2, 2)
plt.scatter(X_tsne[:, 0], X_tsne[:, 1], c=y)
plt.title('t-SNE')
plt.show()
-
問題7: 2次元平面上の3つの同心円からなるデータセット(各円には100点ずつ、合計300点)を生成し、PCA、t-SNE、UMAPの3つの手法で2次元に埋め込んだ結果を比較しなさい。各手法の結果の違いを考察し、このようなデータ構造に適した手法はどれか、理由とともに説明しなさい。
-
問題8: 健康データ科学の観点から、以下のシナリオに対して最適な次元削減手法とその具体的な適用方法を提案しなさい。
あなたは医療研究機関で働いており、様々な生理指標(血圧、心拍数、体温、血糖値など20種類)と生活習慣データ(食事、運動、睡眠など10種類)を日々収集した3年分の時系列データ(1000人分)を分析することになりました。目的は、健康状態の変化パターンを可視化し、将来の疾患リスクを予測するためのサブグループを同定することです。
8. よくある質問と解答
Q1: なぜPCAなどの線形手法ではなく、非線形次元削減手法を使うべき場合があるのですか?
A: 実世界のデータは多くの場合、非線形の関係性を持っています。例えば、画像データや遺伝子発現データなどは単純な線形関係では表現できない複雑な構造を持っています。PCAなどの線形手法は、データの分散を最大化する直交軸を見つけるだけであり、データが曲面(マニフォールド)上に分布している場合や、局所的な関係が重要な場合には適切に表現できません。非線形次元削減手法は、データの局所的な関係性を保存しながら大域的な構造も維持するため、複雑なデータの可視化に優れています。
Q2: t-SNEとUMAPのどちらを選べばよいですか?
A: 選択はあなたの分析目的によります。
-
t-SNE は局所的な構造保存に優れており、クラスター間の距離よりもクラスター内の関係性をよく表現します。計算時間が長いこと、大規模データセットでは遅いこと、グローバルな構造の保存が弱いことが欠点です。
-
UMAP はt-SNEよりも計算が速く、大域的構造もより良く保存します。また、新しいデータ点の埋め込みも可能です。ただし、パラメータ調整が複雑で、理論的理解にはトポロジーの知識が必要です。
探索的分析の初期段階や大規模データでは、まずUMAPを試してみることをお勧めします。より詳細な局所構造分析が必要な場合は、t-SNEも検討してください。
Q3: パラメータ設定のガイドラインはありますか?
A: 一般的なガイドラインは以下の通りです:
t-SNEのパープレキシティ: - 小さいデータセット(n < 100): 5〜15 - 中規模データセット(100 < n < 1000): 15〜30 - 大規模データセット(n > 1000): 30〜50
UMAPのパラメータ:
- n_neighbors
: 局所/大域的構造のバランスを制御(小さい値は局所的、大きい値は大域的)
- min_dist
: 埋め込み空間での点の密集度を制御(小さい値は密集、大きい値は分散)
どちらのアルゴリズムでも、異なるパラメータ設定で複数回実行し、結果を比較することが重要です。
Q4: 次元削減の結果をどのように解釈すればよいですか?
A: 次元削減の結果を解釈する際の注意点:
-
距離の解釈: t-SNEやUMAPでは、近い点は高次元空間でも近いことを示唆しますが、遠い点同士の距離は必ずしも意味を持ちません。
-
クラスター: 形成されたクラスターは、データ内の自然な群れを表している可能性がありますが、アルゴリズムの特性によるアーティファクトの可能性もあります。
-
視覚的検証: 複数のパラメータ設定や複数の手法で結果を比較し、一貫したパターンを確認することが重要です。
-
元の特徴との関連: 低次元表現と元の特徴との関連を調査することで、形成されたパターンの意味を理解できます。
Q5: なぜt-SNEは標準的な正規分布ではなくt分布を採用しているのですか?
A: t-SNEがt分布を採用している主な理由は「クラウディング問題」を解決するためです。高次元空間では点間の距離が比較的均一になる傾向(「次元の呪い」)があります。これを低次元に埋め込む際、すべての距離関係を正確に保存することは不可能です。
通常の正規分布(SNEで使用)では、低次元空間での確率分布の裾が急速に減少するため、類似していない点を十分に遠くに配置できません。t分布は裾が重い(heavy-tailed)ため、類似度の低い点をより遠くに配置できます。これにより、局所的な構造がより明確に保存され、クラスターが視覚的に分離しやすくなります。