次元削減アルゴリズムの使い分け（主にTSNE）

# 次元削減アルゴリズムの使い分け
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3966994/89b7257a-6689-d89a-fa0c-c3f5c81815c5.png)


# t-SNEと既存の次元削減アルゴリズムの違い

次元削減アルゴリズムにはいくつかの種類がありますが、t-SNEは特に「非線形次元削減」として注目されています。他のアルゴリズムとの違いを以下にまとめます。

## t-SNEと主成分分析（PCA）の違い

| **特性**              | **t-SNE**                                          | **PCA**                               |
|-----------------------|---------------------------------------------------|---------------------------------------|
| **目的**              | 局所的な類似性を維持する                           | 線形関係を維持する                     |
| **アルゴリズムの種類** | 非線形次元削減                                     | 線形次元削減                           |
| **結果の解釈**        | クラスターが視覚的に分離される                     | 分散が最大となる軸に沿った次元削減     |
| **計算コスト**        | 高い（データサイズが大きいと遅くなる）             | 比較的低い                             |
| **応用範囲**          | データのクラスタリングや可視化                     | 主成分の意味を考えるデータ解析         |
| **制限**              | データのグローバル構造は失われる場合がある         | 非線形な構造は捉えられない             |

## t-SNEの特徴
- **強み**:
  - 局所的な類似性を非常によく表現。
  - データクラスタリングや視覚化に適している。
- **弱み**:
  - 計算コストが高い。
  - グローバル構造が必ずしも保存されない。

---

t-SNEは特に視覚化目的で優れていますが、データの特性に応じて他の手法との使い分けが重要。


```python
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.manifold import TSNE

# Irisデータセットを読み込む
data = load_iris()
X = data.data
y = data.target

# t-SNEで次元削減
tsne = TSNE(n_components=2, random_state=42, perplexity=30, n_iter=1000)
X_tsne = tsne.fit_transform(X)

# 結果を可視化
plt.figure(figsize=(8, 6))
for target in np.unique(y):
    plt.scatter(X_tsne[y == target, 0], X_tsne[y == target, 1], label=f"Class {target}")
plt.title("t-SNE Visualization of Iris Dataset")
plt.xlabel("Component 1")
plt.ylabel("Component 2")
plt.legend()
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3966994/8c86d286-6ac6-1cdf-3599-b8849d4c49df.png)

# 全体の流れ
1. irisデータセットを取得し、特徴量とクラスラベルに分ける。
1. ランダムに100サンプルを抽出して計算負荷を軽減。
1. t-SNEを用いて4次元データを2次元に次元削減。
1. 次元削減後のデータをクラスごとに色分けして散布図として可視化。

# スイスロールデータでt-SNEを実装してみる
```python
import numpy as np
from sklearn.datasets import make_swiss_roll
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# 1. スイスロールデータの生成（高次元データ）
X, color = make_swiss_roll(n_samples=1000, noise=0.1, random_state=42)

# 2. t-SNEで低次元に変換（2次元）
tsne = TSNE(n_components=2, perplexity=30, random_state=42)
X_embedded = tsne.fit_transform(X)

# 3. 可視化
# 3次元データのプロット
fig = plt.figure(figsize=(16, 6))
ax = fig.add_subplot(121, projection='3d')
scatter = ax.scatter(X[:, 0], X[:, 1], X[:, 2], c=color, cmap=plt.cm.Spectral)
ax.set_title("Original 3D Data (Swiss Roll)")
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")

# 2次元データのプロット
ax2 = fig.add_subplot(122)
scatter2 = ax2.scatter(X_embedded[:, 0], X_embedded[:, 1], c=color, cmap=plt.cm.Spectral)
ax2.set_title("2D Visualization by t-SNE")
ax2.set_xlabel("Dimension 1")
ax2.set_ylabel("Dimension 2")

plt.colorbar(scatter2, ax=ax2, label='Data Color Mapping')
plt.tight_layout()
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3966994/71c69cef-cc81-7941-5f29-2b429d1f3f83.png)

1. 3次元プロット：高次元のスイスロールデータ。データはねじれたリボン状。
1. 2次元プロット：右側のグラフでは、t-SNEを用いて2次元に変換されたデータが表示。元の構造を保ちながら2次元に圧縮されている。

# t-SNEの実行ステップ
* 1.高次元での類似度計算
```python
from scipy.spatial.distance import pdist, squareform

# ユークリッド距離を計算
distances = squareform(pdist(X, 'euclidean')) ** 2

# ガウス分布に基づく条件付き確率 p_{j|i} を計算
P = np.exp(-distances / (2 * np.var(X)))
np.fill_diagonal(P, 0)  # 自分自身との類似度は0に
P /= np.sum(P, axis=1, keepdims=True)  # 確率として正規化
```


* 2.低次元での配置
```python
# 初期配置（ランダム）
Y = np.random.randn(X.shape[0], 2)

# 低次元での類似度計算
distances_low = squareform(pdist(Y, 'euclidean')) ** 2
Q = 1 / (1 + distances_low)
np.fill_diagonal(Q, 0)
Q /= np.sum(Q)  # 確率として正規化
```

* 3.勾配降下法による最適化
```python
# コスト関数の勾配計算
grad = np.zeros_like(Y)
PQ_diff = P - Q
for i in range(Y.shape[0]):
    grad[i] = 4 * np.sum((PQ_diff[i, :, None] * (Y[i] - Y)) / (1 + distances_low[i, :, None]), axis=0)

# 座標の更新
learning_rate = 0.1
Y -= learning_rate * grad
```
# 今後のステップ
・ガウス分布に基づく距離計算。
・コスト計算に基づく勾配降下法にアルゴリズム。