t-Stochastic Neighbor Embedding(t-SNE, "티스니"라 읽음)은 2008년 Journal of Machine Learning Research에 실린 Laurens van der Maaten과 Geoffrey Hinton의 Visualizing Data using t-SNE 논문에서 제안되었으며, 해당 논문은 9000회 이상 인용된 인기 논문이다. t-SNE의 주요 목적은 Data Visualization으로 고차원 데이터(high-dimensional data)를 2차원 또는 3차원의 저차원 데이터로 시각화하여 데이터 분석 과정에서 활용하기 위한 방법이다.
데이터 분석 시 가장 먼저 하는 일이 데이터의 시각화인데 가장 기초적인 방법으로 주성분분석법(principal component analysis, PCA)이 있다. 이는 데이터의 공분산(covariance)을 분석하여 선형변환 행렬(linear transformation matriix)을 얻어 차원을 축소하는 방법이다. PCA는 선형변환을 이용하기 때문에 비선형 특성을 가진 데이터에 대해서는 데이터의 특성을 잘 추출하지 못하는 한계가 있다.
데이터에 내재된 비선형적 특성을 고려하기 위해 다양한 비선형 차원 축소 기법들 - Stochastic Neighbor Embedding(SNE, Hinton and Roweis, 2002), Isomap (Tenenbaum et al, 2000), Locally Linear Embedding (LLE, Roweis ans Saul, 2000), etc - 이 제안되었는데, t-SNE도 그 중 하나이다.
t-SNE는 인기있는 내용이다 보니 관련글들이 상당히 많았는데 t-SNE를 이해하고 활용하는데 있어 참고할만한 자료들을 아래에 정리하였다.
1) t-SNE 이론 정리
■ t-SNE를 이용한 차원 감소 (Dimension reduction), 조대협의 블로그
https://bcho.tistory.com/1210
■ t-SNE, ratsgo's blog
https://ratsgo.github.io/machine%20learning/2017/04/28/tSNE/
■ t-SNE 정리, 홍게
2) t-SNE 예제 (python - scikit-learn 활용, PCA와 함께)
■ Visualising high-dimensional datasets using PCA and t-SNE in Python, Luuk Derksen(Towards Data Science)
■ 고차원 데이터의 차원 축소와 시각화 방법 (PCA vs. t-SNE) ※ 바로 위 사이트 번역 + 추가 정리
3) t-SNE 코드 실행시 오류 해결 (scikit-learn fetch_mldata 오류)
■ scikit-learn의 fetch-mldata('MNIST original') 에러, TAEWAN.KIM 블로그
http://taewan.kim/post/sklearn_mnist_fetch_error/
※ 초보자의 경우, 라이브러리 코드에서 오류가 발생하면 손도 되지 못하고 어찌할 수 없는 경우가 많은 위 블로그와 같이 몸소 나서서 해결하시는 훌륭한 분들이 있어 고마울 따름
4) t-SNE 활용 (perplexity의 역할)
■ t-Stochatic Neighbor Embeddding (t-SNE)와 perplexity, LOVIT x DATA SCIENCE
https://lovit.github.io/nlp/representation/2018/09/28/tsne/
5) 샘플 코드 (2019.08.12 기준)
■ Python Configuration
Python 3.6.8 / numpy 1.16.1 / pandas 0.24.1 / scikit-learn 0.20.2 / matplotlib 3.0.2 / seaborn 0.9.0
■ Code File Download
■ Plot of sampled MNIST data (N=10000)
■ Python Code (tSNE-MNIST.py)
# code by Luuk Derksen
# https://towardsdatascience.com/visualising-high-dimensional-datasets-using-pca-and-t-sne-in-python-8ef87e7915b
from __future__ import print_function
import time
import numpy as np
import pandas as pd
from sklearn.datasets import fetch_mldata
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
# %matplotlib inline
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import seaborn as sns
## Download MNIST mat file from GitHub
import os
from sklearn import datasets
import urllib.request
basedir = datasets.get_data_home()
targetdir = os.path.join(basedir, "mldata")
targetfile = os.path.join(targetdir, "mnist-original.mat")
if os.path.isfile(targetfile):
print("The MNIST data file exists in your directory")
print(targetdir)
else:
print("Download the MNIST data file from github URL")
fileURL = "https://github.com/amplab/datascience-sp14/raw/master/lab7/mldata/mnist-original.mat"
urllib.request.urlretrieve(fileURL, targetfile)
## loading data
mnist = fetch_mldata("MNIST original", data_home=basedir)
X = mnist.data / 255.0
y = mnist.target
print(X.shape, y.shape)
## Convert matrix/vector to Pandas DataFrame
feat_cols = [ 'pixel'+str(i) for i in range(X.shape[1]) ]
df = pd.DataFrame(X,columns=feat_cols)
df['y'] = y
df['label'] = df['y'].apply(lambda i: str(i))
X, y = None, None
print('Size of the dataframe: {}'.format(df.shape))
## For Reproducibility of the results
np.random.seed(42)
rndperm = np.random.permutation(df.shape[0])
## Plot image
fig = plt.figure( figsize=(16,7) )
plt.gray()
for i in range(0,15):
ax = fig.add_subplot(3,5,i+1, title="Digit: {}".format(str(df.loc[rndperm[i],'label'])) )
ax.matshow(df.loc[rndperm[i],feat_cols].values.reshape((28,28)).astype(float))
plt.show()
## PCA for full data
pca = PCA(n_components=3)
pca_result = pca.fit_transform(df[feat_cols].values)
df['pca-one'] = pca_result[:,0]
df['pca-two'] = pca_result[:,1]
df['pca-three'] = pca_result[:,2]
print('Explained variation per principal component: {}'.format(pca.explained_variance_ratio_))
# plot PCA features, 1st & 2nd components
plt.figure(figsize=(16,10))
sns.scatterplot(
x="pca-one", y="pca-two",
hue="y",
palette=sns.color_palette("hls", 10),
data=df.loc[rndperm,:],
legend="full",
alpha=0.3
)
plt.show()
# plot PCA features, 1st, 2nd, and 3rd components
ax = plt.figure(figsize=(16,10)).gca(projection='3d')
ax.scatter(
xs=df.loc[rndperm,:]["pca-one"],
ys=df.loc[rndperm,:]["pca-two"],
zs=df.loc[rndperm,:]["pca-three"],
c=df.loc[rndperm,:]["y"],
cmap='tab10'
)
ax.set_xlabel('pca-one')
ax.set_ylabel('pca-two')
ax.set_zlabel('pca-three')
plt.show()
## t-SNE
# PCA for sampled data (N=10000)
N = 10000
df_subset = df.loc[rndperm[:N],:].copy()
data_subset = df_subset[feat_cols].values
pca = PCA(n_components=3)
pca_result = pca.fit_transform(data_subset)
df_subset['pca-one'] = pca_result[:,0]
df_subset['pca-two'] = pca_result[:,1]
df_subset['pca-three'] = pca_result[:,2]
print('Explained variation per principal component: {}'.format(pca.explained_variance_ratio_))
# t-SNE
time_start = time.time()
tsne = TSNE(n_components=2, verbose=1, perplexity=40, n_iter=300)
tsne_results = tsne.fit_transform(data_subset)
print('t-SNE done! Time elapsed: {} seconds'.format(time.time()-time_start))
# plot
df_subset['tsne-2d-one'] = tsne_results[:,0]
df_subset['tsne-2d-two'] = tsne_results[:,1]
plt.figure(figsize=(16,10))
sns.scatterplot(
x="tsne-2d-one", y="tsne-2d-two",
hue="y",
palette=sns.color_palette("hls", 10),
data=df_subset,
legend="full",
alpha=0.3
)
plt.show()
## PCA vs. t-SNE
plt.figure(figsize=(16,7))
ax1 = plt.subplot(1, 2, 1)
sns.scatterplot(
x="pca-one", y="pca-two",
hue="y",
palette=sns.color_palette("hls", 10),
data=df_subset,
legend="full",
alpha=0.3,
ax=ax1
)
ax2 = plt.subplot(1, 2, 2)
sns.scatterplot(
x="tsne-2d-one", y="tsne-2d-two",
hue="y",
palette=sns.color_palette("hls", 10),
data=df_subset,
legend="full",
alpha=0.3,
ax=ax2
)
plt.show()
## t-SNE after PCA 50
# PCA 50
pca_50 = PCA(n_components=50)
pca_result_50 = pca_50.fit_transform(data_subset)
print('Cumulative explained variation for 50 principal components: {}'.format(np.sum(pca_50.explained_variance_ratio_)))
# t-SNE
time_start = time.time()
tsne = TSNE(n_components=2, verbose=0, perplexity=40, n_iter=300)
tsne_pca_results = tsne.fit_transform(pca_result_50)
print('t-SNE done! Time elapsed: {} seconds'.format(time.time()-time_start))
# plot
df_subset['tsne-pca50-one'] = tsne_pca_results[:,0]
df_subset['tsne-pca50-two'] = tsne_pca_results[:,1]
plt.figure(figsize=(16,4))
ax1 = plt.subplot(1, 3, 1)
sns.scatterplot(
x="pca-one", y="pca-two",
hue="y",
palette=sns.color_palette("hls", 10),
data=df_subset,
legend="full",
alpha=0.3,
ax=ax1
)
ax2 = plt.subplot(1, 3, 2)
sns.scatterplot(
x="tsne-2d-one", y="tsne-2d-two",
hue="y",
palette=sns.color_palette("hls", 10),
data=df_subset,
legend="full",
alpha=0.3,
ax=ax2
)
ax3 = plt.subplot(1, 3, 3)
sns.scatterplot(
x="tsne-pca50-one", y="tsne-pca50-two",
hue="y",
palette=sns.color_palette("hls", 10),
data=df_subset,
legend="full",
alpha=0.3,
ax=ax3
)
plt.show()
댓글