Python × AI - t-SNE(次元削減)

t-SNE(ティースニー)は、2次元または3次元への圧縮に特化しているアルゴリズムです。

(次元数4以上の場合の結果は保証されていません)

MNISTデータの読み込み

0~9の手書き数字の画像データセットMNIST(エムニスト)を読み込みます。

画像データはベクトル化すると高次元になるため、次元削減アルゴリズムがとても有効です。

[Google Colaboratory]

1
2
3
4
from sklearn.datasets import load_digits
digits = load_digits()
print(digits.data.shape)
print(digits.data)

[実行結果]

1797個の画像データがあり、各データは 8 × 8 = 64 個の数値配列、つまり64次元のデータセットになります。

この64次元のデータセットをt-SNEで2次元に削減し可視化します。

データの先頭から100文字を画像として表示するコードは下記の通りです。

[Google Colaboratory]

1
2
3
4
5
import matplotlib.pyplot as plt 
fig, axes = plt.subplots(10, 10, figsize=(8, 8),subplot_kw={"xticks":[], "yticks":[]})
for i, ax in enumerate(axes.flat):
ax.imshow(digits.images[i], cmap="binary", interpolation="nearest")
ax.text(0, 0, str(digits.target[i]))

[実行結果]

手書き数字の画像データが確認できました。

PCAで次元削減

まずはPCAで次元削減を実行し(2行目)、可視化を行います。

[Google Colaboratory]

1
2
3
4
5
6
7
from sklearn.decomposition import PCA
X_reduced = PCA(n_components=2).fit_transform(digits.data)
for each_label in digits.target_names:
c_plot_bool = digits.target == each_label
plt.scatter(X_reduced[c_plot_bool, 0], X_reduced[c_plot_bool, 1], label="{}".format(each_label))
plt.legend()
plt.show()

[実行結果]

数字ごとに分類されて欲しかったのですが、うまく分類できていないようです。

これはPCAが非線形データに対応できていないためです。

t-SNEで次元削減

次にt-SNEで次元削減を実行し(2行目)、可視化を行います。

[Google Colaboratory]

1
2
3
4
5
6
7
from sklearn.manifold import TSNE
X_reduced = TSNE(n_components=2, random_state=0).fit_transform(digits.data)
for each_label in digits.target_names:
c_plot_bool = digits.target == each_label
plt.scatter(X_reduced[c_plot_bool, 0], X_reduced[c_plot_bool, 1], label="{}".format(each_label))
plt.legend()
plt.show()

[実行結果]

t-SNEは、非線形データに対応できるためうまく分類されています。

1,3,8,9がやや混じっているように見えますが、これは人の目から見ても形が似ている数字があるためしかたがないように思えます。

入力データが複雑になればなるほどPCAはうまく次元削減できなくなることが多いのですが、t-SNEは複雑なデータでもかなり高精度な次元削減を行うことができます。

ただし、次のようなデメリットもあるので注意が必要です。

  • 処理に時間がかかる。
  • 4次元以上には不向き。
  • パラメータ調整が必要になる。