#!/usr/bin/env python3
t-SNE를 이용한 매니폴드 학습
데이터를 산점도로 시각화할 수 있다는 이점 때문에 PCA가 데이터 변환에 가장 먼저 시도해볼 만한 방법이지만,
LFW(Labeled Faces in the Wild) 데이터셋의 산점도에서 본 것처럼 알고리즘의(회전하고 방향을 제거하는) 유용성이 떨어짐
maniford learning매니폴드 학습 알고리즘이라고 하는 시각화 알고리즘들은 훨씬 복잡한 매핑을 만들어 더 나은 시각화를 제공
t-SNE(t-Distributed Stochastic Neighbor Embedding) 알고리즘을 아주 많이 사용함
maniford learnning 알고리즘은 그 모적이 시각화라 3개이상의 특성을 뽑는 경우는 거의 없음
t-SNE를 포함해서 일부 maniford learnning 알고리즘들은 훈련 데이터를 새로운 표현으로 변환시키지만 새로운 데이터에는 변활할 수 없음
즉 테스트세트에는 적용할 수 없고, 단지 훈련데이터에만 변환할 수 있음
따라서 maniford learnning은 탐색적 데이터 분석에 유용하지만 지도학습용으로는 거의 사용하지 않음
t-SNE의 아이디어는 데이터 포인트 사이의 거리를 가장 잘 보존하는 2차원 표현을 찾는 것
먼저 t-SNE는 각 데이터 포인트를 2차원에 무작위로 표현한 후 원본 특성 공간에서 가까운 포인트는 가깝게, 멀리 떨어진 포인트는 멀어지게 만듬
t-SNE는 가까이 있는 포인트에 더 많은 비중을 둠 ==> 이웃 데이터 포인트에 대한 정보를 보존하려함
1. 손글씨 숫자 데이터셋에 t-SNE maniford learnning을 적용
# load library
from sklearn.datasets import load_digits
import matplotlib
import matplotlib.pyplot as plt
# matplotlib 설정
matplotlib.rc('font', family='AppleGothic') # 한글 출력
plt.rcParams['axes.unicode_minus'] = False # 축 - 설정
# data load
digits = load_digits()
# subplot 객체 생성
fig, axes = plt.subplots(2, 5, # subplot객체(2x5)를 axes에 할당
subplot_kw={'xticks':(), 'yticks':()}) # subplot 축 눈금 해제
for ax, img in zip(axes.ravel(), digits.images): # axes.ravel()과 digits.images를 하나씩 할당
ax.imshow(img)
plt.gray() # 그래프 흑백
plt.show() # 그래프 출력
숫자 데이터셋의 샘플 이미지
2. PCA를 사용하여 데이터를 2차원으로 축소해 시각화
### 처음 두 개의 주성분을 이용해 그래프를 그리고 각 샘플을 해당하는 클래스의 숫자로
from sklearn.decomposition import PCA
# PCA 모델을 생성
pca = PCA(n_components=2) # 주성분 갯수
pca.fit(digits.data) # PCA 적용
# 처음 두 개의 주성분으로 숫자 데이터를 변환
digits_pca = pca.transform(digits.data) # PCA를 데이터에 적용
colors = ['#476A2A', '#7851B8', '#BD3430', '#4A2D4E', '#875525',
'#A83683', '#4E655E', '#853541', '#3A3120', '#535D8E']
for i in range(len(digits.data)): # digits.data의 길이까지 정수 갯수
# 숫자 텍스트를 이용해 산점도 그리기
plt.text(digits_pca[i, 0], digits_pca[i, 1], str(digits.target[i]), # x, y, 그룹; str은 문자로 변환
color=colors[digits.target[i]], # 산점도 색상
fontdict={'weight':'bold', 'size':9}) # font 설정
plt.xlim(digits_pca[:, 0].min(), digits_pca[:,1].max()) # 최소, 최대
plt.ylim(digits_pca[:, 1].min(), digits_pca[:,1].max()) # 최소, 최대
plt.xlabel('first principle component') # x 축 이름
plt.ylabel('second principle componet') # y 축 이름
plt.show()
처음 두 개의 주성분을 사용한 숫자 데이터셋의 산점도
각 클래스가 어디 있는지 보기 위해 실제 숫자를 사용해 산점도를 출력
숫자 0, 6, 4는 두 개의 주성분만으로 잘 분리 됨
다른 숫자들은 대부분 많은 부분이 겹쳐 있음
3. 같은 데이터셋에 t-SNE를 적용해 결과를 비교
### TSNE모델에는 transform 메소드가 없고 fit_transform만 있음
# library import
from sklearn.manifold import TSNE
# t-SNE 모델 생성 및 학습
tsne = TSNE(random_state=0)
digits_tsne = tsne.fit_transform(digits.data)
# 시각화
for i in range(len(digits.data)): # 0부터 digits.data까지 정수
plt.text(digits_tsne[i, 0], digits_tsne[i, 1], str(digits.target[i]), # x, y , 그룹
color=colors[digits.target[i]], # 색상
fontdict={'weight': 'bold', 'size':9}) # font
plt.xlim(digits_tsne[:, 0].min(), digits_tsne[:, 0].max()) # 최소, 최대
plt.ylim(digits_tsne[:, 1].min(), digits_tsne[:, 1].max()) # 최소, 최대
plt.xlabel('t-SNE 특성0') # x축 이름
plt.ylabel('t-SNE 특성1') # y축 이름
plt.show() # 그래프 출력
t-SNE로 찾은 두 개의 성분을 사용한 숫자 데이터셋의 산점도
모든 클래스가 확실히 잘 구분 되었음
이 알고리즘은 클래스 레이블 정보를 사용하지 않으므로 완전한 비지도 학습
그럼에도 원본 데이터 공간에서 포인트들이 얼마나 가가이 있는지에 대한 정보로 클래스가 잘 구분되는 2차원 표현을 찾음
t-SNE의 매개변수는 perplexity, early_exaggeration
perplexity: 값이 크면 더 많은 이웃을 포함하여 작은 그룹은 무시
기본값 = 30
보통 5~50사이의 값을 가짐
early_exaggeration: 원본 공간의 클러스터들이 얼마나 멀게 2차원에 나타낼지를 정함, 기본값은 4
최소한 1보다 커야하고 값이 클수록 간격이 커짐