without haste but without rest

08. Clustering - K-means, Hierarchical 본문

Homework/DataMining

08. Clustering - K-means, Hierarchical

JinungKim 2020. 5. 12. 12:43

0. 개요

- 앞으로 다룰 4가지 학습은 비지도 학습이다. - k-mean, hierarchical, dbscan, spectral

 

 

(1) k-means

- 유저가 hyperparameter value인 k를 인위적으로 정하고 군집을 k개 만큼 만든다.  

 

 

(2) hierarchical clustering (계층적 군집화)

- 두 점의 거리를 기준으로 군집화 해 나가는 방법

- 단 이때 정해준 리미트 거리(y 값)에 따라서 군집의 개수가 달라진다.

- 계산량이 많다.

- 거리에 따른 군집 개수는 dendrogram으로 확인 할 수 있다.

 

 

(3) 실루엣 스코어

- 클러스터링 모델을 평가하는 스코어

 

 


1. 샘플 데이터 생성

import pandas as pd
import seaborn as sns
sns.set_context("paper", font_scale = 1.5)
sns.set_style("white")



## 클러스터링 알고리즘 학습을 위한 가상 자료 생성 ##
###########################################################################

from sklearn import datasets

def make_blobs():
    # build blobs for demonstration
    n_samples = 1500
    blobs = datasets.make_blobs(n_samples = n_samples,
                                 centers = 5,
                                 cluster_std = [3.0, 0.9, 1.9, 1.9, 1.3],
                                 random_state = 51)
    
    # create a Pandas dataframe for the data
    df = pd.DataFrame(blobs[0], columns=['Feature_1', 'Feature_2'])
    df.index.name = 'record'
    return df

df = make_blobs()
print(df.head(10))

# plot scatter of blob set
sns.lmplot(x = 'Feature_2', y = 'Feature_1', 
           data = df, fit_reg=False)

 

 

 

 

 


2. k-means

 

(1) 2~6개 군집으로 군집화 해보기

## k-means 클러스터링 ##
###########################################################################

from sklearn.cluster import KMeans

## k = 2

clus = KMeans(n_clusters = 2, tol = 0.004, max_iter = 300)

# fit to input data
clus.fit(df)

# get cluster assignments of input data and print first five labels
df['K-means Cluster Labels'] = clus.labels_
print(df['K-means Cluster Labels'][:5].tolist())

df.head()

## 클러스터링 결과 시각화 ##
sns.lmplot(x = 'Feature_2', y = 'Feature_1', 
           hue = "K-means Cluster Labels", data = df, fit_reg = False)

 


## k = 3

clus = KMeans(n_clusters = 3, tol = 0.004, max_iter = 300)

# fit to input data
clus.fit(df)

# get cluster assignments of input data and print first five labels
df['K-means Cluster Labels'] = clus.labels_
print(df['K-means Cluster Labels'][:5].tolist())

## 클러스터링 결과 시각화 ##
sns.lmplot(x = 'Feature_2', y = 'Feature_1', 
           hue = "K-means Cluster Labels", data = df, fit_reg = False)

 

 


## k = 4

clus = KMeans(n_clusters = 4, tol = 0.004, max_iter = 300)

# fit to input data
clus.fit(df)

# get cluster assignments of input data and print first five labels
df['K-means Cluster Labels'] = clus.labels_
print(df['K-means Cluster Labels'][:5].tolist())

## 클러스터링 결과 시각화 ##
sns.lmplot(x = 'Feature_2', y = 'Feature_1', 
           hue = "K-means Cluster Labels", data = df, fit_reg = False)

 

 


 

## k = 5

clus = KMeans(n_clusters = 5, tol = 0.004, max_iter = 300)

# fit to input data
clus.fit(df)

# get cluster assignments of input data and print first five labels
df['K-means Cluster Labels'] = clus.labels_
print(df['K-means Cluster Labels'][:5].tolist())

## 클러스터링 결과 시각화 ##
sns.lmplot(x = 'Feature_2', y = 'Feature_1', 
           hue = "K-means Cluster Labels", data = df, fit_reg = False)

 


## k = 6

clus = KMeans(n_clusters = 6, tol = 0.004, max_iter = 300)

# fit to input data
clus.fit(df)

# get cluster assignments of input data and print first five labels
df['K-means Cluster Labels'] = clus.labels_
print(df['K-means Cluster Labels'][:5].tolist())

## 클러스터링 결과 시각화 ##
sns.lmplot(x = 'Feature_2', y = 'Feature_1', 
           hue = "K-means Cluster Labels", data = df, fit_reg = False)

 

 

군집 개수를 2개부터 6개까지 설정해서 군집화를 진행했다. 그런데 사람의 눈으로는 어떤 군집이 최적인지 판단하기가 어렵다. 따라서 루소가 제안한 실루엣 스코어를 기준으로 군집의 개수를 선택한다. 

 

실루엣 스코어는 -1~1 사이의 값을 가지며 1에 가까울 수록 최적화가 되었다는 뜻이며, -1에 가까울수록 이질적이라는 의미이다.


(2) 실루엣 스코어로 군집 개수 결정하기

## 클러스터 수 결정 ##
from sklearn import metrics

# create list of k values to test and then use for loop
n_clusters = [2, 3, 4, 5, 6, 7, 8]
for k in n_clusters:
    kmeans = KMeans(n_clusters = k, random_state = 42).fit(df)
    cluster_labels = kmeans.predict(df)
    S = metrics.silhouette_score(df, cluster_labels)
    print("n_clusters = {:d}, silhouette score {:1f}".format(k, S))

 

군집이 6개일 때 0.56으로 가장 높은 스코어를 기록했다. 하지만 군집이 5개일 때와 큰 차이가 아니므로 군집이 5개인 모델을 선택하는 것도 고려해볼 수 있다.

 

 

 

 


3. hierarchical clustering

 

(1) 샘플 데이터 생성

## 계층적 클러스터링 알고리즘 ##
## 순차적으로 가까운 점들끼리 군집을 만들어 나가는 군집화 방법
## 자료 수가 많아지면 계산량이 기하급수적으로 많아진다. 
## Agglomerative clustering == hierarchical clustering
###########################################################################


## 알고리즘 스케치

data = {'x': [1, 2, 2, 4, 5], 'y': [1, 1, 4, 3, 4]}

data = pd.DataFrame(data)

print(data)

# plot scatter of blob set
sns.lmplot(x = 'x', y = 'y', 
           data = data, fit_reg=False)

 


 

(2) 과정 - 각 점들의 거리를 확인하며 군집화

from scipy.spatial.distance import pdist, squareform

distances = pdist(data.values, metric = 'euclidean') ** 2
print(distances)

dist_matrix = squareform(distances)
print(dist_matrix)

 

scipy의 pdist, squareform 라이브러리로 생성한 각 점들의 거리다. (0, 1) 좌표는 첫번째 점과 두 번째 점과의 거리다 두 점의 거리가 1로 제일 가까우므로 첫 번째 군집화 대상이 될 것이다.

 

 

 

data['cluster'] = [0, 0, 1, 2, 3]

data_0 = data.groupby('cluster').mean()
print(data_0.values)

1, 2번째 데이터를 인위적으로 0번 그룹으로 묶어주고 평균을 계산한다. (1, 1) 과 (2, 1) 좌표 간의 거리의 평균인 (1.5, 1)이 새로운 좌표가 된다. 1, 2번 데이터의 중간 위치다.

 

 

 

distances = pdist(data_0.values, metric = 'euclidean') ** 2
dist_matrix = squareform(distances)

print(dist_matrix)

군집화한 데이터를 다시 유클리디안 거리를 기준으로 거리를 계산한다. 이번에는 2, 3 번째 컬럼에 있는 값들 끼리의 거리 차이가 가장 작으므로 두 점을 군집화할 것이다.

 

 

data['cluster'] = [0, 0, 1, 2, 2]

data_0 = data.groupby('cluster').mean()
print(data_0.values)

군집화한 새로운 점(데이터)들의 값이다. 군집화를 하면 두 점의 평균 거리로 새롭게 이동한다. (4, 3) (5, 4) 였으므로 평균 값인 (4.5, 3.5) 좌표가 군집의 중앙이 되는 것이다.

 


 

distances = pdist(data_0.values, metric = 'euclidean') ** 2
dist_matrix = squareform(distances)

print(dist_matrix)

군집화한 새로운 좌표들 간의 거리다. 1, 2번 그룹들 간의 거리가 6.5로 가장 작으므로 다시 군집화할 수 있다.

 

 

 

distances = pdist(data_0.values, metric = 'euclidean') ** 2
dist_matrix = squareform(distances)

print(dist_matrix)

0, 1번 데이터와 2, 3, 4 데이터가 두 군집으로 구분되는 상태며 위 좌표는 두 군집의 중심 좌표이다.

 

 

 

distances = pdist(data_0.values, metric = 'euclidean') ** 2
dist_matrix = squareform(distances)

print(dist_matrix)

두 군집의 거리는 11.8이다.

 

 


(3) dendrogram

# ward distance
from scipy.cluster.hierarchy import linkage, dendrogram

z = linkage(data.values[:, :2], 'single')

dendrogram(z)
"""
덴드로그램은 y축 크기를 기준으로 클러스터를 어떻게 묶을 수 있는지
겹쳐진 바 차트로 직관적으로 보여줌 


ward -> linkage, 연결에 필요한 거리 기준
"""

 

덴드로그램은 거리 (y 값)을 기준으로 어떤 데이터들끼리 군집이 될 수 있는지 보여준다. 따라서 순서까지도 파악할 수 있다. 제일 첫 번째로 1.0 부근에서 0, 1번 째 데이터들끼리 군집이 되고 1.5 조금 아래에서 3, 4번 째 데이터들이 군집화가 된다. ...

 

 


(4) ward distance

새로운 데이터가 군집에 들어왔을 때의 거리를 계산하는 방법으로 ward가 제안한 방법이다. (깊게 들어가면 통계적이므로 일단은 linkage 옵션에 ward 를 지정해준다는 거 정도로만 알아둔다.)

 

 


 

(5) evalueate

## 가상자료 계층적 클러스터링

from IPython.display import Image
Image("./hca_dendrogram.jpg")    

 

 

*데이터는 제일 위에서 만든 데이터 프레임

from sklearn.cluster import AgglomerativeClustering
clus = AgglomerativeClustering(n_clusters = 5, 
                               affinity = 'euclidean', linkage = 'ward')

# fit to input data
clus.fit(df)

# get cluster assignments
df['HCA Cluster Labels'] = clus.labels_

sns.lmplot(x = 'Feature_2', y = 'Feature_1', 
           hue = "HCA Cluster Labels", data = df, fit_reg = False)

 

 

 

n_clusters = [2, 3, 4, 5, 6, 7, 8]
for num in n_clusters:
    HCA = AgglomerativeClustering(n_clusters = num, 
                               affinity = 'euclidean', linkage = 'ward',
                               memory = './model_storage/dendrogram', 
                               compute_full_tree = True)
    cluster_labels= HCA.fit_predict(df)
    S = metrics.silhouette_score(df, cluster_labels)
    print("n_clusters = {:d}, silhouette score {:1f}".format(num, S))

 

계층적 군집화는 군집이 5개일 때 실루엣 스코어가 가장 높은 결과를 보인다.

 

 


 

4. 클러스터링 모델 성능 비교

 

1번 테스트에서는 density가 좋은 결과를 낸것이라고 할 수 있다.

2번 테스트에서는 k-means가 좋지 않은 결과를 보인다.

3번 테스트에서도 k-means가 좋지 않은 결과다.

4번 테스트는 데이터들이 비교적 멀리 떨어져 있어서 모든 모델이 좋은 성능을 보인다.

5번 테스트에서는 k-means가 좋지 않아 보이고 hierarchical, spectral 이 좋은 결과를 냈다.

6번 테스트에서는 k-means가 가장 좋지 않고 density가 가장 좋은 결과를 보인다.

 

 

 

보통 통계학자들은 k-means를 가장 선호한다고 한다.

density, spectral은 조금 더 요구조건이 있다고 한다. (다음 주차 수업때 다룬다.)

 

'Homework > DataMining' 카테고리의 다른 글

10. OLS, SGD  (0) 2020.05.26
09. Clustering - dbscan, spectal  (0) 2020.05.19
07. PCA(Pincipal Component Analysis)  (0) 2020.05.05
06. Feature Selection  (0) 2020.05.01
05. One-Hot Encoding  (0) 2020.05.01
Comments