iMind Developers Blog

iMind開発者ブログ

t-SNEによる高次元データの可視化

概要

t-SNEとPCAでMNISTの手書き文字やファッション画像を2〜3次元に圧縮して可視化してみる。

バージョン情報

  • scikit-learn==0.21.2
  • Keras==2.2.4 (fashion_mnistのデータセットで利用)

手書き文字 - t-SNE - 2次元

sklearn.datasetsのdigitsを使って2次元にしてみる。

データのロード。

import sklearn.datasets

digits, label = sklearn.datasets.load_digits(return_X_y=True)
digits = digits / 255

sklearnに入っている手書き文字データは8x8の64次元。

digits.shape                                                            
    #=> (1797, 64)

これをt-SNEで二次元に変換する。

from sklearn.manifold import TSNE
digits2d = TSNE(n_components=2).fit_transform(digits)

可視化してみる。

from matplotlib import pylab as plt

f, ax = plt.subplots(1, 1, figsize=(10, 10))
for i in range(10):
    target = digits2d[label == i]
    ax.scatter(x=target[:, 0], y=target[:, 1], label=str(i), alpha=0.5)
plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left')

なかなかキレイに分かれた。

f:id:mwsoft:20190624002336p:plain

手書き文字 - PCA - 2次元

同じ処理をPCAでもやってみる。

from sklearn.decomposition import TruncatedSVD

pca = TruncatedSVD(n_components=2)
digits2d = pca.fit_transform(digits)

f, ax = plt.subplots(1, 1, figsize=(10, 10))
for i in range(10):
    target = digits2d[label == i]
    ax.scatter(x=target[:, 0], y=target[:, 1], label=str(i), alpha=0.5)
plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left')

なんとなく傾向は取れてはいる。

f:id:mwsoft:20190624002529p:plain

手書き文字 - 3次元

3次元で可視化してみる。

まずはt-SNE

digits3d = TSNE(n_components=3).fit_transform(digits)

from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure(figsize=(10, 10)).gca(projection='3d')
for i in range(10):
    target = digits3d[label == i]
    fig.scatter(target[:, 0], target[:, 1], target[:, 2], label=str(i), alpha=0.5)
fig.legend(bbox_to_anchor=(1.02, 0.7), loc='upper left')

f:id:mwsoft:20190624002742p:plain

PCA。

pca = TruncatedSVD(n_components=3)
digits3d = pca.fit_transform(digits)

fig = plt.figure(figsize=(10, 10)).gca(projection='3d')
for i in range(10):
    target = digits3d[label == i]
    fig.scatter(target[:, 0], target[:, 1], target[:, 2], label=str(i), alpha=0.5)
fig.legend(bbox_to_anchor=(1.02, 0.7), loc='upper left')

f:id:mwsoft:20190624002825p:plain

ファッション - t-SNE - 2次元

kerasのdatasetsを使ってファッション画像のダウンロード。

60,000 x 28 x 28でデータが返るので、reshapeして60,000 x 784にしておく。

import keras

(train_images, train_labels), (test_images, test_labels) = keras.datasets.fashion_mnist.load_data()
train_images = train_images.reshape(60000, 28*28)

t-SNEの実行。この処理はうちの環境では1時間以上かかった。scikit-learnのTSNEはシングルスレッドで動くのである程度の大きさのデータを扱う場合は実行速度の速い他の実装を検討する必要がある。

from sklearn.manifold import TSNE
from matplotlib import pylab as plt

fashion2d = TSNE(n_components=2).fit_transform(train_images)

labels = [
    'T-shirt/top',
    'Trouser',
    'Pullover',
    'Dress',
    'Coat',
    'Sandal',
    'Shirt',
    'Sneaker',
    'Bag',
    'Ankle boot',
]

f, ax = plt.subplots(1, 1, figsize=(10, 10))
for i in range(10):
    target = fashion2d[train_labels == i]
    ax.scatter(x=target[:500, 0], y=target[:500, 1], label=labels[i], alpha=0.5)
plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left')

各ラベル500件ずつ表示。

Bag(カバン)やTrouser(ズボーン・ドカーン・バキューン)は独立しており、Sandal(サンダル)、Sneaker(スニーカー)、Ankle Boot(アンクルブーツ)が固まっている。

f:id:mwsoft:20190624030028p:plain

ファッション - PCA - 2次元

PCAは数秒で実行が終わる。

fashion2d = pca.fit_transform(train_images)

f, ax = plt.subplots(1, 1, figsize=(10, 10))
for i in range(10):
    target = fashion2d[train_labels == i]
    ax.scatter(x=target[:500, 0], y=target[:500, 1], label=labels[i], alpha=0.5)
plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left')

f:id:mwsoft:20190624030633p:plain

ファッション - 3次元

t-SNE。見づらかったので各ラベル300件ずつ表示。

fashion3d = TSNE(n_components=3).fit_transform(train_images)

fig = plt.figure(figsize=(10, 10)).gca(projection='3d')
for i in range(10):
    target = fashion3d[train_labels == i]
    fig.scatter(target[:300, 0], target[:300, 1], target[:300, 2], label=labels[i], alpha=0.5)
fig.legend(bbox_to_anchor=(1.02, 0.7), loc='upper left')

f:id:mwsoft:20190624025838p:plain

PCA。

pca = TruncatedSVD(n_components=3)
fashion3d = pca.fit_transform(train_images)

fig = plt.figure(figsize=(10, 10)).gca(projection='3d')
for i in range(10):
    target = fashion3d[train_labels == i]
    fig.scatter(target[:300, 0], target[:300, 1], target[:300, 2], label=labels[i], alpha=0.5)
fig.legend(bbox_to_anchor=(1.02, 0.7), loc='upper left')

f:id:mwsoft:20190624030900p:plain

改定履歴

Author: Masato Watanabe, Date: 2019-06-25, 記事投稿