前回のplotlyの記事で実践編は暇あったら書きます的なこと言ったのですが,今回はそれに当たる内容です.
内容量はかなり少なく薄いですが,plotlyの使用例程度に思ってくれると有難いです.
t-SNEとは
t-SNE
とは,皆さまご存知の通り次元圧縮の手法ですね.高次元データを人間が認知できる次元まで綺麗に落とし込める手法なので使っている人は多いのではないでしょうか.
今回はplotlyの使い方を重視した記事なので,理論の話はしませんが需要があったらまとめますね.一応参考になる資料をここにまとめておきます.
論文:
https://lvdmaaten.github.io/publications/papers/JMLR_2008.pdf
参考サイト:
理論とか置いといてt-sneをアプリケーションとして使う人は読むべき
高次元のデータを可視化するt-SNEの効果的な使い方 - DeepAge
ざっと理論の概要を知りたい人はこちらで.
t-SNE を用いた次元圧縮方法のご紹介 | ALBERT Official Blog
実践してみる
上のt-SNE を用いた次元圧縮方法のご紹介 | ALBERT Official Blogでやってることをpythonに移植する流れでやりたいと思います.
データセットはcoil-20を使用し,sklearn
に実装されているtsne
を用います.
まずは3D
まずは3次元まで落とし込んでみましょう.
import os import numpy as np import cv2 from sklearn.manifold import TSNE from sklearn import preprocessing import plotly.offline as offline import plotly.graph_objs as go offline.init_notebook_mode() # 画像の前処理.標準化やらL2正規化やら. def preprocess_image(path, size): img = cv2.imread(path, cv2.IMREAD_GRAYSCALE) resized = cv2.resize(img, (size, size), cv2.INTER_LINEAR).astype("float") normalized = cv2.normalize(resized, None, 0.0, 1.0, cv2.NORM_MINMAX) timg = normalized.reshape(np.prod(normalized.shape)) return timg/np.linalg.norm(timg) ROOT = "./coil-20-proc" ls = os.listdir(ROOT) # 名前からラベルを持って来ます. obj_ls = [name.split("_")[0] for name in ls] ALL_IMAGE_PATH = [ROOT+"/"+path for path in ls] # 全画像に対して前処理する preprocess_images_as_vecs = [preprocess_image(path, 32) for path in ALL_IMAGE_PATH] # tsneを実行 tsne = TSNE( n_components=3, #ここが削減後の次元数です. init='random', random_state=101, method='barnes_hut', n_iter=1000, verbose=2 ).fit_transform(preprocess_images_as_vecs)
たったこれだけで次元削減できてしまいます.sklearn
に感謝です.
さて,現在tsne
という変数に次元削減後のarrayが入っているのでコイツをplotly
を用いて可視化してみます.
# 3Dの散布図が作れるScatter3dを使います. trace1 = go.Scatter3d( x=tsne[:,0], # それぞれの次元をx, y, zにセットするだけです. y=tsne[:,1], z=tsne[:,2], mode='markers', marker=dict( sizemode='diameter', color = preprocessing.LabelEncoder().fit_transform(obj_ls), colorscale = 'Portland', line=dict(color='rgb(255, 255, 255)'), opacity=0.9, size=2 # ごちゃごちゃしないように小さめに設定するのがオススメです. ) ) data=[trace1] layout=dict(height=700, width=600, title='coil-20 tsne exmaple') fig=dict(data=data, layout=layout) offline.iplot(fig, filename='tsne_example')
こんな感じで出力されます.グリグリ動かしてみてください.とても綺麗に分離できていることがわかります.尚,円形にplotされていることに関する考察などは先のブログでされているので是非参考にしてみてください.
2Dもやってみる.
ほぼ上と同じようにtsne
を実行し,Scatter2d
を用いて可視化してみます.
# tsneには2dまで落とし込んだarrayが入っている想定です. trace = go.Scatter( x=tsne[:,0], y=tsne[:,1], mode='markers', marker=dict( sizemode='diameter', color = preprocessing.LabelEncoder().fit_transform(obj_ls), colorscale = 'Portland', line=dict(color='rgb(255, 255, 255)'), opacity=0.9, size=4 ) ) data=[trace] layout=dict(height=800, width=800, title='coil-20 tsne exmaple 2D') fig=dict(data=data, layout=layout) offline.iplot(fig, filename='tsne2D_example')
この世の生データに比べたらかなり綺麗に分かれていますが,若干バラついてる部分も見受けられますね.やはり3Dと2Dでは元のデータに対する説明量が違いますので,この程度の差は出てしまいます.
内容としては以上です.
あとがき
plotly
は最近かなり使っているのですが,せっかく使っているのに実践編として記事にできてない状況になっています・・・.これからは,今回くらいの内容の薄さでもいいやぁって開き直って記事の更新頻度を上げていきたいと思います.
次はディリクレ分布を可視化してみようと思います.よろしければそちらも是非.
以上です.