A.I
비지도 학습( Unsupervised Learning ) 본문
비지도 학습(Unspervised Learning)¶
1. 클러스터링 K-means¶
1-1. 데이터생성¶
In [1]:
%matplotlib inline
from sklearn.datasets import make_blobs
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import random
# 중심점이 5개인 100개의 점 데이터를 무작위로 생성합니다.
points, labels = make_blobs(n_samples=100, centers=5, n_features=2, random_state=135)
print(points.shape, points[:10]) # 무작위로 생성된 점의 좌표 10개 출력
print(labels.shape, labels[:10]) # 10개의 점들이 각각 대응하는 중심점(label) 값 출력
(100, 2) [[ 4.63411914 -6.52590383] [-6.52008604 7.16624288] [ 2.14142339 -5.21092623] [ 1.70054231 8.54077897] [-0.33809159 8.76509668] [-7.69329744 7.94546313] [ 3.89090121 -3.06531839] [ 3.22338498 -2.93209009] [-6.63962964 5.34777334] [ 6.37904965 -6.46617328]] (100,) [2 1 0 3 3 1 0 0 1 2]
In [2]:
# 축 그리기
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
# 위에서 생성한 점 데이터들을 pandas DataFrame 형태로 변환하기
points_df = pd.DataFrame(points, columns=['X', 'Y'])
display(points_df.head())
# 점 데이터를 X-Y grid에 시각화하기
ax.scatter(points[:, 0], points[:, 1], c='black', label='random generated data')
# 축 이름을 라벨에 달고, 점 데이터 그리기
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.legend()
ax.grid()
X | Y | |
---|---|---|
0 | 4.634119 | -6.525904 |
1 | -6.520086 | 7.166243 |
2 | 2.141423 | -5.210926 |
3 | 1.700542 | 8.540779 |
4 | -0.338092 | 8.765097 |
1-2. 생성한 데이터에 K-means 알고리즘 적용¶
In [3]:
from sklearn.cluster import KMeans
# 1), 2) 위에서 생성한 무작위 점 데이터(points)에 클러스터의 수(K)가 5인 K-means 알고리즘을 적용
kmeans_cluster = KMeans(n_clusters=5)
# 3) ~ 6) 과정이 전부 함축되어 있는 코드입니다. points에 대하여 K가 5일 때의 K-means iteration을 수행
kmeans_cluster.fit(points)
print(type(kmeans_cluster.labels_))
print(np.shape(kmeans_cluster.labels_))
print(np.unique(kmeans_cluster.labels_))
<class 'numpy.ndarray'> (100,) [0 1 2 3 4]
In [4]:
# n 번째 클러스터 데이터를 어떤 색으로 도식할 지 결정하는 color dictionary
color_dict = {0: 'red', 1: 'blue', 2:'green', 3:'brown', 4:'indigo'}
# 점 데이터를 X-Y grid에 시각화합니다.
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
# K-means clustering의 결과대로 색깔별로 구분하여 점에 색칠한 후 도식
for cluster in range(5):
cluster_sub_points = points[kmeans_cluster.labels_ == cluster] # 전체 무작위 점 데이터에서 K-means 알고리즘에 의해 군집화된 sub data를 분리합니다.
ax.scatter(cluster_sub_points[:, 0], cluster_sub_points[:, 1], c=color_dict[cluster], label='cluster_{}'.format(cluster)) # 해당 sub data를 plot합니다.
# 축 이름을 라벨에 달고, 점 데이터 그리기
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.legend()
ax.grid()
1-3. K-means 알고리즘이 잘 동작하지 않는 예시¶
In [5]:
# K-means algorithm이 잘 동작하지 않는 예시 (1) 원형 분포
# 바깥 원과 안의 원으로 분류하려고 하였으나 잘 동작하지 않음
from sklearn.datasets import make_circles
# 원형 분포 데이터 생성
circle_points, circle_labels = make_circles(n_samples=100, factor=0.5, noise=0.01) # 원형 분포를 가지는 점 데이터 100개를 생성합니다.
# 캔버스 생성
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
# 원형 분포에 대해 K-means 수행
circle_kmeans = KMeans(n_clusters=2)
circle_kmeans.fit(circle_points)
color_dict = {0: 'red', 1: 'blue'}
for cluster in range(2):
cluster_sub_points = circle_points[circle_kmeans.labels_ == cluster]
ax.scatter(cluster_sub_points[:, 0], cluster_sub_points[:, 1], c=color_dict[cluster], label='cluster_{}'.format(cluster))
ax.set_title('K-means on circle data, K=2')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.legend()
ax.grid()
In [6]:
# K-means algorithm이 잘 동작하지 않는 예시 (2) 달 모양 분포
# 두개의 달 형태로 분류하려 하였으나 안됨
from sklearn.datasets import make_moons
# 달 모양 분포의 데이터 생성
moon_points, moon_labels = make_moons(n_samples=100, noise=0.01) # 달 모양 분포를 가지는 점 데이터 100개를 생성합니다.
# 캔버스 생성
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
# 달 모양 분포 데이터 plot
moon_kmeans = KMeans(n_clusters=2)
moon_kmeans.fit(moon_points)
color_dict = {0: 'red', 1: 'blue'}
for cluster in range(2):
cluster_sub_points = moon_points[moon_kmeans.labels_ == cluster]
ax.scatter(cluster_sub_points[:, 0], cluster_sub_points[:, 1], c=color_dict[cluster], label='cluster_{}'.format(cluster))
ax.set_title('K-means on moon-shaped data, K=2')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.legend()
ax.grid()
In [7]:
# K-means algorithm이 잘 동작하지 않는 예시 (3) 대각선 모양 분포
from sklearn.datasets import make_circles, make_moons, make_blobs
# 대각선 모양 분포의 데이터 생성
diag_points, _ = make_blobs(n_samples=100, random_state=170) #대각선 분포를 가지는 점 데이터 100개를 생성합니다.(현재는 무작위 분포)
transformation = [[0.6, -0.6], [-0.4, 0.8]] #대각선 변환을 위한 대각 행렬
diag_points = np.dot(diag_points, transformation) #본 과정을 통해 무작위 분포의 점 데이터를 대각선 분포로 변환합니다.
# 캔버스 생성
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
# 대각선 모양 분포 데이터 plot
diag_kmeans = KMeans(n_clusters=3)
diag_kmeans.fit(diag_points)
color_dict = {0: 'red', 1: 'blue', 2: 'green'}
for cluster in range(3):
cluster_sub_points = diag_points[diag_kmeans.labels_ == cluster]
ax.scatter(cluster_sub_points[:, 0], cluster_sub_points[:, 1], c=color_dict[cluster], label='cluster_{}'.format(cluster))
ax.set_title('K-means on diagonal-shaped data, K=2')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.legend()
ax.grid()
K-means 정리¶
K-means의 동작 원리¶
- 원하는 클러스터의 수(K)를 결정
- 무작위로 클러스터의 수와 같은 K개의 중심점(centroid)을 선정
- 나머지 점들과 모든 중심점 간의 유클리드 거리를 계산한 후, 가장 가까운 거리를 가지는 중심점에 클러스터링
- 각 K개의 클러스터의 중심점을 재조정
- 특정 클러스터에 속하는 모든 점들의 평균값이 해당 클러스터 다음 iteration의 중심점이 됨
- 재조정된 중심점을 바탕으로 모든 점들과 새로 조정된 중심점 간의 유클리드 거리를 다시 계산한 후, 가장 가까운 거리를 가지는 클러스터에 해당 점을 재배정
- 반복을 통해 특정 iteration 이상이 되면 수렴(중심점이 더이상 바뀌지 않음)하게 됨
K-means의 단점¶
- 군집의 개수(K 값)를 미리 지정해야 하기 때문에 이를 알거나 예측하기 어려운 경우에는 사용하기 어려움
- 유클리드 거리가 가까운 데이터끼리 군집이 형성되기 때문에 데이터의 분포에 따라 유클리드 거리가 멀면서 밀접하게 연관되어 있는 데이터들의 군집화를 성공적으로 수행하지 못할 수 있음.
2. 클러스터링 DBSCAN - 밀도 기반의 군집화¶
In [10]:
# DBSCAN으로 circle, moon, diagonal shaped data를 군집화한 결과
from sklearn.cluster import DBSCAN
fig = plt.figure()
ax= fig.add_subplot(1, 1, 1)
color_dict = {0: 'red', 1: 'blue', 2: 'green', 3:'brown',4:'purple'} # n 번째 클러스터 데이터를 어떤 색으로 도식할 지 결정하는 color dictionary
# 원형 분포 데이터 plot
epsilon, minPts = 0.2, 3 # 2)와 3) 과정에서 사용할 epsilon, minPts 값을 설정
circle_dbscan = DBSCAN(eps=epsilon, min_samples=minPts) # 위에서 생성한 원형 분포 데이터에 DBSCAN setting
circle_dbscan.fit(circle_points) # 3) ~ 5) 과정을 반복
n_cluster = max(circle_dbscan.labels_)+1 # 3) ~5) 과정의 반복으로 클러스터의 수 도출
print(f'# of cluster: {n_cluster}')
print(f'DBSCAN Y-hat: {circle_dbscan.labels_}')
# DBSCAN 알고리즘의 수행결과로 도출된 클러스터의 수를 기반으로 색깔별로 구분하여 점에 색칠한 후 도식
for cluster in range(n_cluster):
cluster_sub_points = circle_points[circle_dbscan.labels_ == cluster]
ax.scatter(cluster_sub_points[:, 0], cluster_sub_points[:, 1], c=color_dict[cluster], label='cluster_{}'.format(cluster))
ax.set_title('DBSCAN on circle data')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.legend()
ax.grid()
# of cluster: 2 DBSCAN Y-hat: [0 1 0 1 0 0 1 0 0 1 0 1 1 0 1 0 0 0 1 0 1 1 0 1 0 1 0 0 0 1 0 0 1 1 1 1 1 0 0 0 0 0 0 1 0 1 1 0 1 0 0 0 0 1 1 0 1 1 1 1 0 1 1 0 1 1 1 1 0 1 1 1 1 1 0 0 0 0 1 0 1 0 1 1 1 0 0 1 1 0 0 1 0 0 0 0 1 1 1 0]
In [11]:
# 달 모양 분포 데이터 plot - 위와 같은 과정 반복
fig = plt.figure()
ax= fig.add_subplot(1, 1, 1)
color_dict = {0: 'red', 1: 'blue', 2: 'green', 3:'brown',4:'purple'} # n 번째 클러스터 데이터를 어떤 색으로 도식할 지 결정하는 color dictionary
epsilon, minPts = 0.4, 3
moon_dbscan = DBSCAN(eps=epsilon, min_samples=minPts)
moon_dbscan.fit(moon_points)
n_cluster = max(moon_dbscan.labels_)+1
print(f'# of cluster: {n_cluster}')
print(f'DBSCAN Y-hat: {moon_dbscan.labels_}')
for cluster in range(n_cluster):
cluster_sub_points = moon_points[moon_dbscan.labels_ == cluster]
ax.scatter(cluster_sub_points[:, 0], cluster_sub_points[:, 1], c=color_dict[cluster], label='cluster_{}'.format(cluster))
ax.set_title('DBSCAN on moon data')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.legend()
ax.grid()
# of cluster: 2 DBSCAN Y-hat: [0 1 0 1 1 0 0 1 0 1 0 1 0 0 1 0 0 1 1 0 1 1 1 0 0 1 1 0 1 1 1 1 1 1 1 0 0 1 1 0 1 0 0 0 1 1 1 1 0 1 0 1 0 0 1 0 0 1 0 0 0 1 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 1 0 1 1 0 1 0 0 1 0 0 1]
In [12]:
# 대각선 모양 분포 데이터 plot - 위와 같은 과정 반복
fig = plt.figure()
ax= fig.add_subplot(1, 1, 1)
color_dict = {0: 'red', 1: 'blue', 2: 'green', 3:'brown',4:'purple'} # n 번째 클러스터 데이터를 어떤 색으로 도식할 지 결정하는 color dictionary
epsilon, minPts = 0.7, 3
diag_dbscan = DBSCAN(eps=epsilon, min_samples=minPts)
diag_dbscan.fit(diag_points)
n_cluster = max(diag_dbscan.labels_)+1
print(f'# of cluster: {n_cluster}')
print(f'DBSCAN Y-hat: {diag_dbscan.labels_}')
for cluster in range(n_cluster):
cluster_sub_points = diag_points[diag_dbscan.labels_ == cluster]
ax.scatter(cluster_sub_points[:, 0], cluster_sub_points[:, 1], c=color_dict[cluster], label='cluster_{}'.format(cluster))
ax.set_title('DBSCAN on diagonal shaped data')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.legend()
ax.grid()
# of cluster: 3 DBSCAN Y-hat: [ 0 1 1 0 0 2 2 0 1 2 2 2 0 2 0 1 2 2 2 1 1 1 1 1 2 2 0 1 0 2 1 0 2 1 2 0 0 0 0 0 1 0 1 0 0 2 1 1 0 2 1 1 2 1 0 2 -1 2 0 0 2 0 0 1 0 1 1 2 2 2 -1 0 2 0 0 0 1 2 2 -1 2 2 1 2 0 0 2 1 1 2 1 1 2 0 -1 1 0 0 0 1]
In [13]:
# DBSCAN 알고리즘과 K-means 알고리즘의 시간을 비교하는 코드
import time
n_samples= [100, 500, 1000, 2000, 5000, 7500, 10000, 20000, 30000, 40000, 50000]
kmeans_time = []
dbscan_time = []
x = []
for n_sample in n_samples:
dummy_circle, dummy_labels = make_circles(n_samples=n_sample, factor=0.5, noise=0.01) # 원형의 분포를 가지는 데이터 생성
kmeans_start = time.time()
circle_kmeans = KMeans(n_clusters=2)
circle_kmeans.fit(dummy_circle)
kmeans_end = time.time()
dbscan_start = time.time()
epsilon, minPts = 0.2, 3
circle_dbscan = DBSCAN(eps=epsilon, min_samples=minPts)
circle_dbscan.fit(dummy_circle)
dbscan_end = time.time()
x.append(n_sample)
kmeans_time.append(kmeans_end-kmeans_start)
dbscan_time.append(dbscan_end-dbscan_start)
print("# of samples: {} / Elapsed time of K-means: {:.5f}s / DBSCAN: {:.5f}s".format(n_sample, kmeans_end-kmeans_start, dbscan_end-dbscan_start))
# K-means와 DBSCAN의 소요 시간 그래프화
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.scatter(x, kmeans_time, c='red', marker='x', label='K-means elapsed time')
ax.scatter(x, dbscan_time, c='green', label='DBSCAN elapsed time')
ax.set_xlabel('# of samples')
ax.set_ylabel('time(s)')
ax.legend()
ax.grid()
# of samples: 100 / Elapsed time of K-means: 0.01671s / DBSCAN: 0.00096s # of samples: 500 / Elapsed time of K-means: 0.02290s / DBSCAN: 0.00281s # of samples: 1000 / Elapsed time of K-means: 0.01941s / DBSCAN: 0.00502s # of samples: 2000 / Elapsed time of K-means: 0.02534s / DBSCAN: 0.01569s # of samples: 5000 / Elapsed time of K-means: 0.03598s / DBSCAN: 0.05572s # of samples: 7500 / Elapsed time of K-means: 0.05483s / DBSCAN: 0.10326s # of samples: 10000 / Elapsed time of K-means: 0.04651s / DBSCAN: 0.15465s # of samples: 20000 / Elapsed time of K-means: 0.06247s / DBSCAN: 0.45903s # of samples: 30000 / Elapsed time of K-means: 0.06544s / DBSCAN: 0.71455s # of samples: 40000 / Elapsed time of K-means: 0.09633s / DBSCAN: 1.16032s # of samples: 50000 / Elapsed time of K-means: 0.13840s / DBSCAN: 1.77751s
DBSCAN 정리¶
용어 정리¶
- epsilon: 클러스터의 반경(미리 지정)
- minPts: 클러스터를 이루는 개체의 최솟값(미리 지정)
- core point: 반경 epsilon 내에 minPts 개 이상의 점이 존재하는 중심점
- border point: 군집의 중심이 되지는 못하지만, 군집에 속하는 점
- noise point: 군집에 포함되지 못하는 점
동작 원리¶
- 임의의 점 p를 설정하고, p를 포함하여 주어진 클러스터의 반경(elipson)안에 포함되어 있는 점들의 갯수를 셈
- 만일 해당 원에 minPts 개 이상의 점이 포함되어 있으면, 해당 점 p를 core point로 간주하고 원에 포함된 점들을 하나의 클러스터로 묶음
- 해당 원에 minPts 개 미만의 점이 포함되어 있으면, 일단 pass
- 모든 점에 대하여 돌아가면서 1~3 번의 과정을 반복하는데, 만일 새로운 점 p'가 core point가 되고 이 점이 기존의 클러스터 (p를 core point로 하는)에 속한다면, 두 개의 클러스터는 연결되어 있다고 하며 하나의 클러스터로 묶음
- 모든 점에 대하여 클러스터링 과정을 끝냈는데, 어떤 점을 중심으로 하더라도 클러스터에 속하지 못하는 점이 있으면 이를 noise point로 간주 또한, 특정 군집에는 속하지만 core point가 아닌 점들을 border point라고 함
DBSCAN의 단점¶
- 군집화할 데이터의 수가 많아질수록 DBSCAN의 알고리즘 수행시간이 급격하게 상승하는 것을 볼 수 있음
- 클러스터의 수를 지정해 줄 필요가 없으나 데이터 분포에 맞는 epsilon과 minPts의 값을 지정해 주어야 함
3. 차원 축소 PCA¶
- 차원축소를 해나가지만 주어진 좌표축 방향이 아니라, 가장 분산이 길게 나오는 기저(basis) 방향을 찾아서 그 방향의 기저만 남기고, 덜 중요한 기저 방향을 삭제하는 방식으로 진행
In [14]:
# 차원 축소 예제: 유방암 데이터셋
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
# 데이터 로드
cancer=load_breast_cancer()
# y = 0(Malignant - 악성 종양), y=1(Benign - 양성 종양)
cancer_X, cancer_y= cancer.data, cancer['target']
train_X, test_X, train_y, test_y = train_test_split(cancer_X, cancer_y, test_size=0.1, random_state=10) # train 데이터셋과 test 데이터셋으로 나눔
print("전체 검사자 수: {}".format(len(cancer_X)))
print("Train dataset에 사용되는 검사자 수: {}".format(len(train_X)))
print("Test dataset에 사용되는 검사자 수: {}".format(len(test_X)))
cancer_df = pd.DataFrame(cancer_X, columns=cancer['feature_names'])
cancer_df.head()
전체 검사자 수: 569 Train dataset에 사용되는 검사자 수: 512 Test dataset에 사용되는 검사자 수: 57
Out[14]:
mean radius | mean texture | mean perimeter | mean area | mean smoothness | mean compactness | mean concavity | mean concave points | mean symmetry | mean fractal dimension | ... | worst radius | worst texture | worst perimeter | worst area | worst smoothness | worst compactness | worst concavity | worst concave points | worst symmetry | worst fractal dimension | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 17.99 | 10.38 | 122.80 | 1001.0 | 0.11840 | 0.27760 | 0.3001 | 0.14710 | 0.2419 | 0.07871 | ... | 25.38 | 17.33 | 184.60 | 2019.0 | 0.1622 | 0.6656 | 0.7119 | 0.2654 | 0.4601 | 0.11890 |
1 | 20.57 | 17.77 | 132.90 | 1326.0 | 0.08474 | 0.07864 | 0.0869 | 0.07017 | 0.1812 | 0.05667 | ... | 24.99 | 23.41 | 158.80 | 1956.0 | 0.1238 | 0.1866 | 0.2416 | 0.1860 | 0.2750 | 0.08902 |
2 | 19.69 | 21.25 | 130.00 | 1203.0 | 0.10960 | 0.15990 | 0.1974 | 0.12790 | 0.2069 | 0.05999 | ... | 23.57 | 25.53 | 152.50 | 1709.0 | 0.1444 | 0.4245 | 0.4504 | 0.2430 | 0.3613 | 0.08758 |
3 | 11.42 | 20.38 | 77.58 | 386.1 | 0.14250 | 0.28390 | 0.2414 | 0.10520 | 0.2597 | 0.09744 | ... | 14.91 | 26.50 | 98.87 | 567.7 | 0.2098 | 0.8663 | 0.6869 | 0.2575 | 0.6638 | 0.17300 |
4 | 20.29 | 14.34 | 135.10 | 1297.0 | 0.10030 | 0.13280 | 0.1980 | 0.10430 | 0.1809 | 0.05883 | ... | 22.54 | 16.67 | 152.20 | 1575.0 | 0.1374 | 0.2050 | 0.4000 | 0.1625 | 0.2364 | 0.07678 |
5 rows × 30 columns
In [15]:
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn import svm
from sklearn.metrics import accuracy_score
from collections import Counter
# color dictionary
color_dict = {0: 'red', 1: 'blue', 2:'red', 3:'blue'}
target_dict = {0: 'malignant_train', 1: 'benign_train', 2: 'malignant_test', 3:'benign_test'}
#Train data에 PCA 알고리즘 적용
train_X_ = StandardScaler().fit_transform(train_X) # 불러온 데이터에 대한 정규화 -> 각 column의 range of value가 전부 다르기 때문에 정규화를 진행해 주어야 합니다.
train_df = pd.DataFrame(train_X_, columns=cancer['feature_names'])
pca = PCA(n_components=2) # 주성분의 수를 2개, 즉 기저가 되는 방향벡터를 2개로 하는 PCA 알고리즘 수행
pc = pca.fit_transform(train_df)
In [16]:
#Test data에 PCA 알고리즘 적용
test_X_ = StandardScaler().fit_transform(test_X) # normalization
test_df = pd.DataFrame(test_X_, columns=cancer['feature_names'])
pca_test = PCA(n_components=2)
pc_test = pca_test.fit_transform(test_df)
In [17]:
# 훈련한 classifier의 decision boundary를 그리는 함수
def plot_decision_boundary(X, clf, ax):
h = .02 # step size in the mesh
# create a mesh to plot in
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
ax.contour(xx, yy, Z, cmap='Blues')
# PCA를 적용한 train data의 classifier 훈련: classfier로 Support Vector Machine(SVM) 사용
clf = svm.SVC(kernel = 'rbf', gamma=0.5, C=0.8) # 여기서는 classifier로 SVM을 사용한다는 정도만 알아둡시다!
clf.fit(pc, train_y) # train data로 classifier 훈련
# PCA를 적용하지 않은 original data의 SVM 훈련
clf_orig = svm.SVC(kernel = 'rbf', gamma=0.5, C=0.8) # 여기서는 classifier로 SVM을 사용한다는 정도만 알아둡시다!
clf_orig.fit(train_df, train_y)
Out[17]:
SVC(C=0.8, gamma=0.5)
In [19]:
# 캔버스 도식
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
# malignant와 benign의 SVM decision boundary 그리기
plot_decision_boundary(pc, clf, ax)
#Train data 도식
for cluster in range(2):
sub_cancer_points = pc[train_y == cluster]
ax.scatter(sub_cancer_points[:, 0], sub_cancer_points[:, 1], edgecolor=color_dict[cluster], c='none', label=target_dict[cluster])
#Test data 도식
for cluster in range(2):
sub_cancer_points = pc_test[test_y == cluster]
ax.scatter(sub_cancer_points[:, 0], sub_cancer_points[:, 1], marker= 'x', c=color_dict[cluster+2], label=target_dict[cluster+2])
ax.set_xlabel('PC1')
ax.set_ylabel('PC2')
ax.set_title('PCA-Breast cancer dataset')
ax.legend()
ax.grid()
# Scoring
pca_test_accuracy_dict = Counter(clf.predict(pc_test) == test_y)
orig_test_accuracy_dict = Counter(clf_orig.predict(test_df) == test_y)
print("PCA분석을 사용한 Test dataset accuracy: {}명/{}명 => {:.3f}".format(pca_test_accuracy_dict[True], sum(pca_test_accuracy_dict.values()), clf.score(pc_test, test_y)))
print("PCA를 적용하지 않은 Test dataset accuracy: {}명/{}명 => {:.3f}".format(orig_test_accuracy_dict[True], sum(orig_test_accuracy_dict.values()), clf_orig.score(test_df, test_y)))
PCA분석을 사용한 Test dataset accuracy: 54명/57명 => 0.947 PCA를 적용하지 않은 Test dataset accuracy: 43명/57명 => 0.754
PCA 정리¶
- 전체 feature를 사용하였을 경우 종양의 악성,양성과 관련 없는 것이 존재하기때문에 필요한 feature만 추출하여 분류하는 방식이 정확도가 더 높을 수 있음
- PCA는 필요한 상관관계에 있는 feature만을 추려서 사용할 경우 유용하게 쓰이는 비지도학습방법
- 선형적인 데이터의 분포(키와 몸무게 등)를 가지고 있을 때, 정보가 가장 잘 보존됨( 데이터가 가진 고유한 물리적 정보량을 보존하는데 주력 )
4. 차원 축소 T-SNE - 기존 차원의 공간에서 가까운 점들은 차원축소된 공간에서도 여전히 가깝게 유지¶
In [20]:
from sklearn.datasets import fetch_openml
# 784 pixel로 이뤄진 mnist 이미지 데이터 호출
mnist = fetch_openml("mnist_784",version=1)
X = mnist.data / 255.0
y = mnist.target
print("X shape: ",X.shape)
print("Y shape: ",y.shape)
X shape: (70000, 784) Y shape: (70000,)
In [21]:
n_image = X.shape[0]
n_image_pixel = X.shape[1]
pixel_columns = [ f"pixel{i}" for i in range(n_image_pixel) ] # 픽셀정보가 있는 칼럼의 이름을 담은 목록
len(pixel_columns)
Out[21]:
784
In [22]:
import pandas as pd
df = pd.DataFrame(X,columns=pixel_columns)
df['y'] = y
df['label'] = df['y'].apply(lambda i: str(i)) # 숫자 라벨을 스트링으로 만드는 함수를 파이썬 람다 문법으로 전체 데이터에 적용합니다.
X, y = None, None
In [23]:
import numpy as np
# 결과가 재생산 가능하도록 랜덤 시드를 지정합니다.
np.random.seed(30)
# 이미지 데이터의 순서를 랜덤으로 뒤바꾼(permutation) 배열을 담습니다.
rndperm = np.random.permutation(n_image)
# 랜덤으로 섞은 이미지 70000만개 중 10,000개를 뽑고, df_subset에 담습니다.
n_image_sample = 10000
random_idx = rndperm[:n_image_sample]
df_subset = df.loc[rndperm[:n_image_sample],:].copy()
df_subset.shape
Out[23]:
(10000, 786)
In [24]:
%matplotlib inline
import seaborn as sns
import matplotlib.pyplot as plt
plt.gray()
fig = plt.figure( figsize=(10,6) )
n_img_sample = 15
width,height = 28,28
# 15개 샘플을 시각화해 봅니다.
for i in range(0,n_img_sample):
row = df_subset.iloc[i]
ax = fig.add_subplot(3,5,i+1, title=f"Digit: {row['label']}")
ax.matshow(row[pixel_columns]
.values.reshape((width,height))
.astype(float))
plt.show()
<Figure size 432x288 with 0 Axes>
PCA로 차원축소¶
In [25]:
from sklearn.decomposition import PCA
print("df_subset의 shape: {}".format(df_subset.shape))
n_dimension = 2 # 축소시킬 목표 차원의 수
pca = PCA(n_components=n_dimension)
pca_result = pca.fit_transform(df_subset[pixel_columns].values) # 차원을 축소한 결과
df_subset['pca-one'] = pca_result[:,0] # 축소한 결과의 첫 번째 차원 값
df_subset['pca-two'] = pca_result[:,1] # 축소한 결과의 두 번째 차원 값
print("pca_result의 shape: {}".format(pca_result.shape))
df_subset의 shape: (10000, 786) pca_result의 shape: (10000, 2)
In [26]:
# 차원을 축소한 댓가로 차원의 정보량 중 일부만 남기때문에 PCA 모듈은 PC 축 마다 보존하는 정보량의 비율을 제시해줌
print(f"pca-1: {round(pca.explained_variance_ratio_[0],3)*100}%")
print(f"pca-2: {round(pca.explained_variance_ratio_[1],3)*100}%")
pca-1: 9.6% pca-2: 7.3%
In [27]:
plt.figure(figsize=(10,6))
sns.scatterplot(
x="pca-one", y="pca-two",
hue="y",
palette=sns.color_palette("hls", 10),
data=df_subset, # 2개의 PC축만 남은 데이터프레임 df_subset 을 시각화해 보자.
legend="full",
alpha=0.4
)
Out[27]:
<AxesSubplot:xlabel='pca-one', ylabel='pca-two'>
T-SNE로 차원축소¶
In [28]:
from sklearn.manifold import TSNE
print("df_subset의 shape: {}".format(df_subset.shape))
data_subset = df_subset[pixel_columns].values
n_dimension = 2
tsne = TSNE(n_components=n_dimension)
tsne_results = tsne.fit_transform(data_subset)
print("tsne_results의 shape: {}".format(tsne_results.shape))
df_subset의 shape: (10000, 788) tsne_results의 shape: (10000, 2)
In [29]:
# tsne 결과를 차원별로 추가합니다.
df_subset['tsne-2d-one'] = tsne_results[:,0]
df_subset['tsne-2d-two'] = tsne_results[:,1]
# 시각화해 봅니다.
plt.figure(figsize=(10,6))
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
)
Out[29]:
<AxesSubplot:xlabel='tsne-2d-one', ylabel='tsne-2d-two'>
T-SNE 정리¶
- 차원 축소 전후의 거리를 유지하기 때문에 시각화에 좋음
- 축소 과정에서 물리적 의므를 무시하므로 시각화 이외의 다른 분석으로는 사용하기 어려움
'파이썬 & AI 학습' 카테고리의 다른 글
데이터 전처리 (0) | 2021.02.03 |
---|---|
파이썬 문법 (0) | 2021.02.01 |
포켓몬 찾기 (0) | 2021.01.27 |
주사위 만들기 (0) | 2021.01.25 |
sklearn의 이해 (0) | 2021.01.22 |