#!/usr/bin/env python3


Face Datasets Analysis with DBSCAN


# load library

from sklearn.datasets import fetch_lfw_people

import numpy as np

import matplotlib

import matplotlib.pyplot as plt

from sklearn.decomposition import PCA, NMF

from sklearn.preprocessing import MinMaxScaler

from sklearn.cluster import DBSCAN


# matplotlib 설정 

matplotlib.rc('font', family='AppleGothic')

plt.rcParams['axes.unicode_minus'] = False

people = fetch_lfw_people(min_faces_per_person=20, resize=0.7, color=False# min_faces_per_person = 겹치지 않는 최소 얼굴 수, 

image_size = people.images[0].shape


# outlier 있는지 확인 

_, bins = np.histogram(people.target, bins=100)

plt.hist(people.target, bins=bins)

plt.xticks(range(len(people.target_names)), people.target_names, rotation=90, ha='center')

plt.hlines(50, xmin=0, xmax=bins[-1], linestyles='--')# 수평선

plt.show()

각 특성별 히스토그램 

# 특성이 50개

idx = np.zeros(people.target.shape, dtype=np.bool)

for tg in np.unique(people.target):

    idx[np.where(people.target == tg)[0][:50]] = 1


# 데이터 분할

x_people = people.data[idx]

y_people = people.target[idx]


# 전처리

scaler_mms = MinMaxScaler()

x_people_scaled = scaler_mms.fit_transform(x_people)

# pca는 whiten 옵션을 True를 주면 전처리효과가 발생


# 훈련데이터를 PCA주성분 100개로 변환

pca = PCA(n_components=100, random_state=0, whiten=True).fit(x_people)

x_pca = pca.transform(x_people)


# 훈련데이터를 NMF 성분 100개로 변환

nmf = NMF(n_components=100, random_state=0).fit(x_people_scaled)

x_nmf = nmf.transform(x_people_scaled)


# DBSCAN에서 알맞은 min_sample값과 eps구하기

for min_sample in [3, 5, 7, 9]:

    for eps in [0.2, 0.4, 0.9, 1, 3, 5, 7, 9, 11, 13, 15, 17]:

        dbscan = DBSCAN(n_jobs=-1, min_samples=min_sample, eps=eps)

        labels_pca = dbscan.fit_predict(x_pca) # pca를 이용한 성분을 이용한 dbscan을 예측

        labels_nmf = dbscan.fit_predict(x_nmf) # nmf를 이용한 성분을 이용한 dbscan으로 예측

        print('︎=== min_sample:{}, eps:{} ==='.format(min_sample, eps))

        print('')

        print('pca ==> cluster 수: {}'.format(len(np.unique(labels_pca))))

        print('pca ==> cluster 크기: {}\n'.format(np.bincount(labels_pca+1)))


        print('nmf ==> cluster 수: {}'.format(len(np.unique(labels_nmf))))

        print('nmf ==> cluster 크기: {}'.format(np.bincount(labels_nmf+1)))

        print('---------------------------------------')

알맞은 min_sample과 eps를 찾는 과정

### pca : min_sample=3, eps=7일 때 가장 많은 클러스터가 생김

### nmf : min_sample=3, eps=0.9일 때 가장 많은 클러스터가 생김


# 가장 많은 클러스터가 생긴 eps와 n_sample 츨력

dbscan = DBSCAN(min_samples=3, eps=7, n_jobs=-1) # n_jobs = 코어의 갯수

labels_pca = dbscan.fit_predict(x_pca)


dbscan = DBSCAN(min_samples=3, eps=0.9, n_jobs=-1)

labels_nmf = dbscan.fit_predict(x_nmf)


# pca 주성분, DBSCAN 을 이용한 시각화

for cluster in range(labels_pca.max() + 1):

    idx = labels_pca == cluster 

    n_images = np.sum(idx) # idx중 true인 것의 갯수

    fig, axes = plt.subplots(1,n_images, figsize=(n_images*1.5, 4), # figsize=(a,b) axb 그림사이즈

                            subplot_kw={'xticks':(), 'yticks':()})

    

    for image, label, ax in zip(x_people[idx], y_people[idx], axes.ravel()):

        ax.imshow(image.reshape(image_size))

        ax.set_title(people.target_names[label].split()[-1])


plt.gray()

plt.show()

0123456789101112

PCA 주성분을 이용한 DBSCAN 





#!/usr/bin/env python3


DBSCAN



0. 살펴보기

DBSCANdensity-based spatial clustering of application with noise은 클러스터의 갯수를 미리 지정하지 않는 군집 알고리즘

DBSCAN은 병합 군집이나 k-평균보다는 다소 느리지만 비교적 큰 데이터셋에도 적용


데이터의 밀집지역이 한 클러스터를 구성하며 비교적 비어있는 지역을 경계로 다른 클러스터와 구분함


DBSCAN은 특성 공간에서 가까이 있는 데이터가 많아 붐비는 지역의 포인트를 찾음

이런 지역을 밀집 지역dense region이라 함

밀집 지역에 있는 포인트를 핵심 포인트core point라고함


핵심 포인트: min_samples, epsepsilon

한 데이터 포인트에서 eps 거리 안에 데이터가 min_samples 갯수만큼 들어 있으면 이 데이터 포인트를 핵심 포인트로 분류

eps(거리)보다 가까운 핵심 샘플은 동일한 클러스터로 분류


알고리즘

1. 무작위로 데이터 포인트를 선택


2. 그 포인트에서 eps 거리안의 모든 포인트를 찾음

2-1 eps 거리 안에 있는 데이터 포인트 수가 min_samples보다 적다면 어떤 클래스에도 속하지 않는 잡음noise로 레이블

2-2 eps 거리 안에 있는 데이터 포인트 수가 min_samples보다 많으면 핵심 포인트로 레이블하고 새로운 클러스터 레이블할당


3. 2-2의 핵심 포인트의 eps거리안의 모든 이웃을 살핌

3-1 만약 어떤 클러스터에도 아직 할당되지 않았다면 바로 전에 만든 클러스터 레이블을 할당

3-2 만약 핵심 포인트면 그 포인트의 이웃을 차례로 확인


4. eps 거리안에 더이상 핵심 포인트가 없을 때까지 진행


핵심포인트, 경계포인트(핵심 포인트에서 eps거리 안에 있는 포인트), 잡음 포인트가 핵심


DBSCAN을 한 데이터셋에 여러 번 실행하면 핵심 포인트의 군집은 항상 같고, 매번 같은 포인트를 잡음으로 레이블함

그러나 경계포인트는 한 개 이상의 핵심 포인트 샘플의 이웃일 수 있음


# library import

import mglearn

import matplotlib.pyplot as plt

from matplotlib import rc


# matplotlib 설정

rc('font', family='AppleGothic'

plt.rcParams['axes.unicode_minus'] = False


# 예제

mglearn.plots.plot_dbscan()

plt.show()


min_samples와 eps 매개변수를 바꿔가며 DBSCAN으로 계산한 클러스터


이 그래프에서 클러스터에 속한 포인트는 색을 칠하고 잡음 포인트는 하얀색으로 남겨둠

핵심포인트는 크게 표시하고 경계 포인트는 작게 나타냄

eps를 증가시키면(왼쪽 -> 오른쪽) 하나의 클러스터에 더 많은 포인트가 포함

이는 클러스터를 커지게 하지만 여러 클러스터를 하나로 합치게도 함

min_samples를 키우면(위 -> 아래) 핵심 포인트 수가 줄어들며 잡음 포인트가 늘어남




1. make_blobs(인위적 데이터)로 DBSCAN 적용

eps 매개변수가까운 포인트의 범위를 결정하기 때문에 매우 중요

eps를 매우 작게 하면 어떤 포인트도 핵심 포인트가 되지 못하고, 모든 포인트가 잡음 포인트가 될 수 있음

eps를 매우 크게 하면 모든 포인트가 단 하나의 클러스터에 속하게 됨


min_samples 설정은 덜 조밀한 지역에 있는 포인트들이 잡은 포인트가 될 것인지, 아니면 하나의 클러스터가 될 것인지를 결정

min_samples보다 작은 클러스터들은 잡음포인트가 되기 때문에 클러스터의 최소 크기를 결정


DBSCAN은 클러스터의 갯수를 지정할 필요가 없지만 eps의 값은 간접적으로 클러스터의 갯수 제어

적절한 eps 값을 찾기 위해 전처리preprocessing(StandardScaler, MinMaxScaler)로 조정하는 것이 좋음


### DBSCAN은 새로운 테스트 데이터에 대해 예측

### 할 수 없으므로(병합군집, 매니폴드학습과 동일) fit_predict를 사용

# library import

from sklearn.cluster import DBSCAN

from sklearn.datasets import make_blobs


# dataset

x, y = make_blobs(n_samples=12, random_state=0)


# 모델생성 및 클러스터 레이블

dbscan = DBSCAN()

clusters = dbscan.fit_predict(x)


# 클러스터 레이블 출력

print('clusters \n클러스터레이블: {}'.format(clusters))

### 모든 포인트에 잡은 포인트를 의미하는 '-1'이 할당

### eps와 min_samples 기본값이 작은 데이터셋에 적절하지 않음



2. 전처리 후 make_blobs(인위적 데이터)에 DBSCAN적용

# library import

from sklearn.datasets import make_moons

from sklearn.preprocessing import StandardScaler

from sklearn.preprocessing import MinMaxScaler

import numpy as np


# dataset

x, y = make_moons(n_samples=200, noise=0.05, random_state=0)


# MinMaxScaler 메소드로 전처리

scaler_MMS = MinMaxScaler().fit(x)

x_scaled_MMS = scaler_MMS.transform(x) # 전처리 메소드를 훈련데이터에 적용

dbscan = DBSCAN() # 모델생성

clusters_MMS = dbscan.fit_predict(x_scaled_MMS) # 모델 학습

print('np.unique(clusters_MMS)\n예측한 레이블: {}'.format(np.unique(clusters_MMS))) # [0]

### 예측한 레이블이 0으로 전부 하나의 클러스터로 표현

### MinMaxScaler전처리가 적합하지 않음


scaler_ss = StandardScaler().fit(x)

x_scaled_ss = scaler_ss.transform(x) 

dbscan = DBSCAN()

clusters_ss = dbscan.fit_predict(x_scaled_ss)

print('np.unique(clusters_ss)\n예측한 레이블:{}'.format(np.unique(clusters_ss))) # [0 ,1]

### 2차원 데이터셋을 0과 1로 구분했기 때문에 전처리가 잘되었음을 확인


# visualization

df = np.hstack([x_scaled_ss, clusters_ss.reshape(-1, 1)]) # x_scaled_ss 오른쪽에 1열 붙이기


df_ft0 = df[df[:,2]==0, :] # 클러스터 0 추출

df_ft1 = df[df[:,2]==1, :] # 클러스터 1 추출


# matplotlib로 그래프 그리기

plt.scatter(df_ft0[:, 0], df_ft0[:, 1], label='cluster 0', cmap='Pairs'# x, y, label, 색상

plt.scatter(df_ft1[:, 0], df_ft1[:, 1], label='cluster 1', cmap='Pairs')

plt.xlabel('feature 0')

plt.ylabel('feature 1')

plt.legend()

plt.show()

기본값 eps=0.5를 사용해 DBSCAN으로 찾은 클러스터



+ Recent posts