비선형 차원축소
- s자 패턴이 보임
- 곡선의 패턴을 새로운 축으로 잡음
- 축을 직선으로 펼침
- 2차원 공간에 있던 데이터가 1차원에서 존재
비선형 차원축소의 방법들
- Autoencoders
- 뉴럴네트워크나 딥러닝에서 많이 볼 수 있음
- Kernel principal component analysis
- 커널 트릭을 넣어 선형 방법을 비선형 방법으로 바꿈
- IsoMap
- Locally-linear embedding(LLE)
- Modified Locally-Linear Embedding(MLLE)
- LLE를 확장한 개념
-
t-distributed stochastic neighbor embedding
-
이번 강의에서는 Isomap, Locally-linear embedding, t-distributed stochastic neighbor embedding 세 가지 방법을 다룰 예정
IsoMap
- MDS와 비슷
- MDS는 모든 데이터들의 거리를 거리 행렬로 만들어 그 행렬에 맞게 점들을 위치시킴
- IsoMap은 이웃에 있는 점들과의 거리만을 사용함
- 멀리 떨어진 점들과의 거리는 이웃한 점들을 이어서 사용함
- 그 이유는 공간이 휘어져 있을 때 상대적으로 가까이 있지만 끊어진 부분이 있을 수 있는데 IsoMap은 끊어진 부분들을 무시하고 이어진 부분을 연속으로 따라가서 거리를 재기 때문
- 스위스 롤케익 문제
- 이러한 데이터를 MDS나 PCA를 하게 되면 평평하게 되거나 모양이 말려 있는 쪽의 면을 보여줌
- 그러나 IsoMap을 이용하면 말려 있는 것을 펼칠 수 있음
LLE
- IsoMap과 비슷함
- PCA와 비슷함
- 원래 차원에서 한 점과 이웃한 점들의 관계를 찾음
- 낮은 차원에서 같은 관계가 유지되도록 점의 좌표를 찾음
- 휘어진 데이터라고 해도 부분만 보면 직선처럼 보임
- 각 색만 보면 평평함
- 따라서 각 색별로 이어 평평하게 만들 수 있음
t-SNE
- IsoMap과 LLE는 연속적인 형태에 유리하기 때문에 끊어져 있는 데이터나 흩어져 있는 데이터와는 잘 맞지 않음
- t-SNE는 데이터의 부분적 구조에 초점, 복잡한 형태에 유리
- 큰 차원의 데이터를 낮은 차원으로 내리기 때문에 전체적인 구조를 잘 보존하지 못하고 부분적인 구조를 잘 보존함
- 돌아가는데 시간이 오래 걸림
- 돌릴 때마다 결과가 달라짐
비선형 차원 축소 실습
- 목적: 말려 있는 데이터를 펼쳐 2차원에 보기 좋게 보여주기
디렉토리 설정 후 데이터 불러오기
roll = read.csv('swissroll.csv')
패키지 설치
install.packages(c('rgl', 'lle', 'tsne', 'vegan'))
3차원 그래프 그리기
library(rgl)
plot3d(roll)
시각화를 위해 점들에 색깔 정하기
cent.dist = sqrt(rowSums(roll[,c(1,3)]^2))
min.dist = min(cent.dist)
max.dist = max(cent.dist)
color = rainbow(12)[round(1 + 11*(cent.dist - min.dist)/(max.dist - min.dist))]
plot3d(roll, col = color)
PCA
p = prcomp(roll)
plot(p$x, col = color)
MDS
d = dist(roll)
mds = cmdscale(d)
plot(mds, col = color)
IsoMap
library(vegan)
d = dist(roll)
iso = isomap(d, ndim = 2, k = 30)
plot(iso$points, col = color)
ndim = 2
: 2차원으로 줄일 예정
- k = 30
: 이웃할 점들의 개수 30개
- 가까이에 있는 점들을 MDS해서 2차원에 그림
- 3차원 이상이어도 가능함
- 그래프의 세로 및 가로 축의 숫자는 크게 신경 쓰지 않아도 됨
LLE
library(lle)
lin = lle(roll, 2, 30)
plot(lin$Y, col = color)
t-SNE
library(tsne)
ts = tsne(roll, initial_dims = 3)
plot(ts, col = color)
initial_dims = 3
: 초기의 차원을 몇 개로 할 것인지
- 계속 반복해서 돌면서 조금씩 결과를 좋게 바꿔나가는 식으로 계산
- 기본 옵션이 계산을 1000번 함
- 100번마다 결과를 알려줌
- 결과를 알려줄 때마다 에러를 보여주는데 그 에러가 점점 줄음
- 부분적인 구조는 보존하지만 전체적인 구조는 보존하지 않아 모양이 특이함
- 중간에 끊어진 부분들이 있음
- 연속적으로 이어진 경우에는 LLE나 IsoMap이 더 좋음정리
차원 축소를 할 때 시각화를 해보지 않으면 잘 알 수 없기 때문에 아는 방법들을 한 번씩 해보고 제일 좋은 결과를 도출하는 방법을 선택
사례 연구: 이미지 데이터의 시각화
- 목적: 손글씨 이미지 파일을 2차원에 시각화하기
- 8 X 8 사이즈의 이미지 파일, 즉 64차원
- 밝기: 1~16
패키지 설치
install.packages(c('lle', 'tsne', 'vegan'))
데이터 파일 불러오기
data = read.csv('digit.csv')
데이터 정보
dim(data)
- 1797
- 65
- 1797개의 손글씨 이미지
- 65개의 종: 64개의 점의 밝기 + 손글씨 숫자가 무슨 숫자인지에 대한 정보
첫 번째 손글씨의 정보
data[1,1:8]
V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 |
---|---|---|---|---|---|---|---|
0 | 0 | 5 | 13 | 9 | 1 | 0 | 0 |
data[1,9:16]
V9 | V10 | V11 | V12 | V13 | V14 | V15 | V16 |
---|---|---|---|---|---|---|---|
0 | 0 | 13 | 15 | 10 | 15 | 5 | 0 |
data[1,17:24]
V17 | V18 | V19 | V20 | V21 | V22 | V23 | V24 |
---|---|---|---|---|---|---|---|
0 | 3 | 15 | 2 | 0 | 11 | 8 | 0 |
data[1,25:32]
V25 | V26 | V27 | V28 | V29 | V30 | V31 | V32 |
---|---|---|---|---|---|---|---|
0 | 4 | 12 | 0 | 0 | 8 | 8 | 0 |
시각화를 위한 사전 작업
image = data[1:64]
number = as.character(data[,65])
color = rainbow(10)[data[,65]+1]
image
: 이미지에 해당하는 부분number
: 숫자 정보에 해당하는 부분number
는 후에 텍스트 형태로 출력을 하기 위해 문자 형태로 변환함color
: 숫자 별로 색을 지정
PCA
pca = prcomp(image)
plot(pca$x, typ = 'n')
text(pca$x, number, col = color)
- 64차원의 이미지를 2차원으로 축소
- 비슷한 숫자들끼리 비슷한 위치에 있음
- 5, 7, 8이 잘 구분이 안되어 있음
- 비선형적인 패턴을 많이 가진 부분은 잘 표현되지 못함
MDS
d = dist(image)
mds = cmdscale(d)
plot(mds, typ = 'n')
text(mds, number, col = color)
- 5, 7, 8이 잘 구분이 안되어 있음
IsoMap
library(vegan)
iso = isomap(d, ndim = 2, k = 30)
plot(iso$points, typ = 'n')
text(iso$points, number, col = color)
Loading required package: permute
Loading required package: lattice
This is vegan 2.5-6
- 앞에서 했던 것보다 숫자들끼리 덜 겹쳐짐
- 원래 공간에 복잡하게 접혀져 있는 것들을 잘 펼쳐서 표현
- IsoMap은 거리만을 이용하니까 이번 사례에서는 LLE보다 잘 나옴
LLE
library(lle)
lin = lle(image, 2, 30)
plot(lin$Y, typ = 'n')
text(lin$Y, number, col = color)
Loading required package: scatterplot3d
Loading required package: MASS
Loading required package: snowfall
Loading required package: snow
finding neighbours
calculating weights
computing coordinates
- 결과가 좋지 않음
- LLE는 평면이 있을 것이라고 가정을 하는데 이 데이터에는 평면이 없어 이런 결과를 도출한 듯함
tsne
library(tsne)
ts = tsne(image, initial_dims = 64)
plot(ts, typ = 'n')
text(ts, number, col = color)
sigma summary: Min. : 0.221408575610339 |1st Qu. : 0.620063784622015 |Median : 0.675069430571825 |Mean : 0.687671788667607 |3rd Qu. : 0.739130003054694 |Max. : 1.52805698437237 |
Epoch: Iteration #100 error is: 19.217536943355
Epoch: Iteration #200 error is: 1.3587223315932
Epoch: Iteration #300 error is: 1.14080852254214
Epoch: Iteration #400 error is: 1.04440997888217
Epoch: Iteration #500 error is: 1.00637787550838
Epoch: Iteration #600 error is: 0.986854976155903
Epoch: Iteration #700 error is: 0.975567595309222
Epoch: Iteration #800 error is: 0.968378888065802
Epoch: Iteration #900 error is: 0.963365469441065
Epoch: Iteration #1000 error is: 0.959970056385717
- 숫자별로 구분이 잘 되었음
- 겹치는 숫자도 거의 없음
- 부분적인 구조를 잘 보존했기 때문에 이런 결과가 나옴
- 전체적인 구조를 잘 보존하지 못한다는 단점이 이 사례에서는 장점이 되었음