데이터 분석/왕초보를 위한 머신러닝

[머신러닝 기초] 비지도학습(Unsupervised-learning) - 군집화(Clustering)

ai-creator 2021. 10. 19. 15:02
반응형

ㅁ 들어가기

ㅁ 군집화 알고리즘 종류

ㅁ 군집 평가

ㅁ 군집화 알고리즘 - Kmeans

ㅁ 군집화 알고리즘 - DBSCAN

 


ㅁ 들어가기

우리가 트럼프 카드를 군집을 만들 때 군집의 수를 과연 둘로 하는 것이 좋을까, 넷으로 하는 게 좋을까?

색깔로 하면 두 개가 될 것이고, 우리가 모양으로 하면 네 개로 나눌 수 있는데, 어떤 것이 좋다는 정답이 존재하는 것은 아니다!

 

군집화에 가장 직관적인 예시는 MBTI라고 볼 수 있다.

다수개의 질문을 통해 인간의 성격을 16가지로 군집을 지어 놓은 것이다.

각 군집마다 네이밍을 하고(ex. 세상의 소금형) 그 특징을 설명하고 있다. 

 

우리가 MBTI를 하면서 본인의성격유형을 파악하고, 공감을 하고 재밌어 한다.

MBTI별 기도문짤

하지만 여기서 끝나지 않는다. 이성에게 호감을 갖는 방법, 상사와 즐겁게 회사생활을 할 수 있는 방법을 알아내고, 활용한다.

 

https://youtu.be/6K_vQu9daTg

이와 같이 군집화는 특정 목적을 위해 군집의 유형을 나누고 -> 정의하고 -> 특징을 요약하여  -> 활용하게 된다.

어찌보면 군집화의 알고리즘을 배우는것 보다 "군집의 유형을 나누고 -> 정의하고 -> 특징을 요약하여  -> 활용"을 고민 하는것이 군집화의 핵심이라고 생각한다. (데이터사이언티스트의 역량이 중요한 분석이다)

 

성격유형은 MBTI만 있진 않다. 다른 여러가지 성격유형검사가 있으며, 군집이 있다. MBTI가 절대적으로 맞다/틀리다라고 이야기 할 수 없듯이 군집화 결과도 절대적으로 맞다/틀리다를 규정지을 수 없다. 즉, 절대적인 기준이 존재하지 않는다.

즉, 어떤 군집화가 가장 좋은 군집화인가? 라고 물어본다면,

군집을 만든 후 '인사이트를 얻고, 잘 활용할 수 있는' 이라고 말하고 싶다.

 

군집화는 비지도학습으로 다양한 산업군에 다양한 목적으로 사용한다.

ㅁ 군집화 알고리즘 종류

군집화 알고리즘은 다양하며, 데이터의 특성과 목적에 맞춰 적절한 알고리즘을 선택해야 한다.

 

https://scikit-learn.org/stable/auto_examples/cluster/plot_cluster_comparison.html

위의 그래프로 알 수 있듯이 데이터 분포에 따라 군집화가 잘 되는 알고리즘과 그렇지 않은 알고리즘이 있음을 알 수 있다. 

이번 장에서는 다양한 군집화 알고리즘 중에서 Kmeans 와 DBSCAN에 대해서 알아보고자 한다.

 

ㅁ 군집 평가

군집화는 정답이 없는 unsupervised-learning이다. 하여, 적절한 군집임을 평가 기준을 세우는 일이 어렵다.

군집이 얼마나 잘 됐느냐를 평가하는 척도는 데이터 집합을 클러스터링한 결과 그 자체를 놓고 평가하는 방식이다. 이러한 방식에서는 클러스터 내 높은 유사도 (high intra-cluster similarity) 를 가지고, 클러스터 간 낮은 유사도 (low inter-cluster similarity) 를 가진 결과물에 높은 점수를 준다. 오로지 데이터를 클러스터링한 결과물만을 보고 판단하기 때문에, 평가 점수가 높다고 해서 실제 참값 (ground truth) 에 가깝다는 것을 반드시 보장하지는 않는다는 단점이 있다.

여러 평가 지표 중 실루엣(silhouette) 지표를 살펴보겠다.

1) 실루엣 분석

- '개별데이터'가 가지는 군집화 지표

- 개별데이터가 가지는 실루엣 계수는 해당 데이터가 같은 군집 내의 데이터와 얼마나 가깝게 군집화돼 있고, 다른 군집에 있는 데이터와는 얼마나 멀리 분리돼 있는지 나타내는 지표이다.

 

출처 : https://velog.io/@yepark/%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD%EA%B0%80%EC%9D%B4%EB%93%9C-Chap.7-%EA%B5%B0%EC%A7%91%ED%99%94
실수엣계수

- 실루엣계수는 -1~1사이의 값을 가지며, 1로 가까워질수록 근처의 군집과 멀리 떨어져 있음 (군집화가 잘됨)을 의미한다. -1은 아에 다른 군집에 데이터포인트가 할당 되었음을 의미한다.

- '일반적으로' 이 값이 높을 수록 군집화가 어느정도 잘 됐다고 판단할 수 있다. 무조건 이 값이 높다고 해서 군집화가 잘 됐다고 판단할 수는 없다. 

 

좋은 군집화가 되려면 다음 기준 조건을 만족해야 한다.

1. 전체 실루엣계수의 평균값이 0~1사이의 값을 가지며, 1에 가까울수록 좋음

2. 개별 군집의 평균값의 편차가 크지 않아야 함. 즉, 개별 군집의 실루엣 계수 평균값이 전체 실루엣 계수의 평균값에 크게 벗어나지 않는 것이 중요함

  • X축: 실루엣 계수 값
    Y축: 개별 군집과 이에 속하는 데이터(높이로 추측)
  • 점선: 전체 실루엣 계수 평균

군집별 평균 실루엣 계수의 시각화를 수행하였다. 몇개의 군집이 적절할까?

 

1) 군집 계수 = 2 (평균 실루엣 계수: 0.704)

Cluster를 2개로 나눈 첫번째는 두 군집에 할당된 데이터수가 차이가 많다. 그러나, 개별군집의 평균값이 0보다 크고, 편차가 크지 않다.

2) 군집 계수 = 3 (평균 실루엣 계수: 0.588)

Cluster를 3개로 나눈 두번째를 보면, 2번 군집의 실루엣 계수가 마이너스(-)가 되었다. 2번 군집의 실루엣계수와 전체군집의 평균실루엣계수의 편차가 있음을 알 수 있다.

3) 군집 계수= 4 (평균 실루엣 계수: 0.65)

Cluster 4가 최적으로 보인다. 각 군집별 데이터 분포도 비슷하며, 실루엣계수 편차도 크지 않다.

 

하지만, 명심해야 할 것은 평균 실루엣 계수값이 높다고 해서 반드시 최적의 군집 개수로 군집화가 되었다고 볼 수 없다. 각 군집에 대한 특징을 파악하고, 해석하고, 이해가 되는 군집이 최고의 군집이다. 

 

Sklearn API

이를 위해 sklearn에서는 API를 지원한다.

목적 import API
평균실루엣계수
from sklearn.metrics import silhouette_score silhouette_score()

코드에서 보면,

from sklearn.preprocessing import scale
from sklearn.datasets import load_iris
from sklearn.cluster import KMeans
# 실루엣 분석 metric 값을 구하기 위한 API 추가
from sklearn.metrics import silhouette_samples, silhouette_score
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

%matplotlib inline

iris = load_iris()
feature_names = ['sepal_length','sepal_width','petal_length','petal_width']
irisDF = pd.DataFrame(data=iris.data, columns=feature_names)
kmeans = KMeans(n_clusters=3, init='k-means++', max_iter=300,random_state=0).fit(irisDF)

irisDF['cluster'] = kmeans.labels_

# iris 의 모든 개별 데이터에 실루엣 계수값을 구함. 
score_samples = silhouette_samples(iris.data, irisDF['cluster'])
print('silhouette_samples( ) return 값의 shape' , score_samples.shape)

# irisDF에 실루엣 계수 컬럼 추가
irisDF['silhouette_coeff'] = score_samples

# 모든 데이터의 평균 실루엣 계수값을 구함. 
average_score = silhouette_score(iris.data, irisDF['cluster'])
print('붓꽃 데이터셋 Silhouette Analysis Score:{0:.3f}'.format(average_score))

 실루엣 계수 시각화

- 실루엣 계수를 시각화하는 함수이다.

### 여러개의 클러스터링 갯수를 List로 입력 받아 각각의 실루엣 계수를 면적으로 시각화한 함수 작성
def visualize_silhouette(cluster_lists, X_features): 
    
    from sklearn.datasets import make_blobs
    from sklearn.cluster import KMeans
    from sklearn.metrics import silhouette_samples, silhouette_score

    import matplotlib.pyplot as plt
    import matplotlib.cm as cm
    import math
    
    # 입력값으로 클러스터링 갯수들을 리스트로 받아서, 각 갯수별로 클러스터링을 적용하고 실루엣 개수를 구함
    n_cols = len(cluster_lists)
    
    # plt.subplots()으로 리스트에 기재된 클러스터링 수만큼의 sub figures를 가지는 axs 생성 
    fig, axs = plt.subplots(figsize=(4*n_cols, 4), nrows=1, ncols=n_cols)
    
    # 리스트에 기재된 클러스터링 갯수들을 차례로 iteration 수행하면서 실루엣 개수 시각화
    for ind, n_cluster in enumerate(cluster_lists):
        
        # KMeans 클러스터링 수행하고, 실루엣 스코어와 개별 데이터의 실루엣 값 계산. 
        clusterer = KMeans(n_clusters = n_cluster, max_iter=500, random_state=0)
        cluster_labels = clusterer.fit_predict(X_features)
        
        sil_avg = silhouette_score(X_features, cluster_labels)
        sil_values = silhouette_samples(X_features, cluster_labels)
        
        y_lower = 10
        axs[ind].set_title('Number of Cluster : '+ str(n_cluster)+'\n' \
                          'Silhouette Score :' + str(round(sil_avg,3)) )
        axs[ind].set_xlabel("The silhouette coefficient values")
        axs[ind].set_ylabel("Cluster label")
        axs[ind].set_xlim([-0.1, 1])
        axs[ind].set_ylim([0, len(X_features) + (n_cluster + 1) * 10])
        axs[ind].set_yticks([])  # Clear the yaxis labels / ticks
        axs[ind].set_xticks([0, 0.2, 0.4, 0.6, 0.8, 1])
        
        # 클러스터링 갯수별로 fill_betweenx( )형태의 막대 그래프 표현. 
        for i in range(n_cluster):
            ith_cluster_sil_values = sil_values[cluster_labels==i]
            ith_cluster_sil_values.sort()
            
            size_cluster_i = ith_cluster_sil_values.shape[0]
            y_upper = y_lower + size_cluster_i
            
            color = cm.nipy_spectral(float(i) / n_cluster)
            axs[ind].fill_betweenx(np.arange(y_lower, y_upper), 0, ith_cluster_sil_values, \
                                facecolor=color, edgecolor=color, alpha=0.7)
            axs[ind].text(-0.05, y_lower + 0.5 * size_cluster_i, str(i))
            y_lower = y_upper + 10
            
        axs[ind].axvline(x=sil_avg, color="red", linestyle="--")
from sklearn.datasets import load_iris

iris=load_iris()
visualize_silhouette([ 2, 3, 4,5 ], iris.data)

ㅁ 군집화 알고리즘 - Kmeans

알고리즘 특징

가장 일반적으로 사용하는 알고리즘이다.

몇개로 군집화 할지(K)를 정한다.

 

알고리즘 매커니즘

Step 1: 군집화의 기준이 되는 중심을 구성하려는 군집 개수만큼 정함
Step 2: 각 데이터는 가장 가까운 곳에 위치한 중심점에 속함
Step 3: 소속이 결정되면 군집 중심점을 소속된 데이터의 평균 중심으로 이동함
Step 4: 기존에 속한 중심점보다 더 가까운 중심점이 있다면 해당 중심점으로 다시 소속 변경
Step 5: 다시 중심을 소속된 데이터의 평균 중심으로 이동
Step 6: 위 프로세스를 반복, 데이터의 중심점 변경이 없으면 반복 중단 및 군집화 종료

출처 : https://github.com/bheemnitd/2D-KMeans-Clustering

 

장점

  • 일반적인 군집화에서 가장 많이 활용
  • 알고리즘이 쉽고 간결

단점

  • 거리 기반 알고리즘이기 때문에 속성의 개수가 매우 많을 경우 군집화 정확도가 감소(PCA 차원 축소가 필요할 수 있음)
  • 반복 수행 횟수가 많아지면 수행 시간이 증가
  • 몇 개의 군집을 선택해야할지 가이드가 어려움

Sklearn API

이를 위해 sklearn에서는 API를 지원한다.

목적 import API Parameters
K-means
from sklearn.cluster import KMeans KMeans()
input n_clusters=k # 군집 개수=군집 중심점의 개수
output kmeans.labels_

코드에서 보면, 

from sklearn.datasets import load_iris
from sklearn.cluster import KMeans

iris = load_iris()
# 보다 편리한 데이터 Handling을 위해 DataFrame으로 변환
irisDF = pd.DataFrame(data=iris.data, columns=['sepal_length','sepal_width','petal_length','petal_width'])
irisDF.head(3)

# 개정판 소스 코드 수정(2019.12.24)
kmeans = KMeans(n_clusters=3, init='k-means++', max_iter=300,random_state=0)
kmeans.fit(irisDF)

 

1) 실습 (Kmeans) 

iris데이터를 활용하여, kmeans알고리즘을 적용해보자. (Link)

2) 실습 (Kmeans)

fruits_300.npy 데이터(Link)를 활용하여, kmeans 알고리즘을 적용해보고, 그 결과를 확인해보자.

import numpy as np

### 데이터 로드
fruits = np.load('fruits_300.npy')
fruits_2d = fruits.reshape(-1, 100*100)

### 시각화
import matplotlib.pyplot as plt
%matplotlib inline

def draw_fruits(arr, ratio=1):
    n = len(arr)    # n은 샘플 개수입니다
    # 한 줄에 10개씩 이미지를 그립니다. 샘플 개수를 10으로 나누어 전체 행 개수를 계산합니다. 
    rows = int(np.ceil(n/10))
    # 행이 1개 이면 열 개수는 샘플 개수입니다. 그렇지 않으면 10개입니다.
    cols = n if rows < 2 else 10
    fig, axs = plt.subplots(rows, cols, 
                            figsize=(cols*ratio, rows*ratio), squeeze=False)
    for i in range(rows):
        for j in range(cols):
            if i*10 + j < n:    # n 개까지만 그립니다.
                axs[i, j].imshow(arr[i*10 + j], cmap='gray_r')
            axs[i, j].axis('off')
    plt.show()
    

### TODO - kmeans 군집화 수행
    
    
### 군집별 데이터 확인  
#draw_fruits(fruits[km.labels_==0])

 

3) 실습 (Kmeans, RFM) 

- RFM 분석 빈칸 버전 (Link)

- 분석데이터 (Link)

  • Recency (R) : 가장 최근 상품 구입 일에서 오늘까지의 기간
  • Frequencey(F) : 상품 구매 횟수
  • Monetary value (M) : 총 구매 금액

 

ㅁ 군집화 알고리즘 - DBSCAN

알고리즘 특징

 

특정 공간 내에 데이터 밀도 차이에 기반한 알고리즘으로 군집화 수행

  • 복잡한 기하학적 분포도를 가진 데이터 세트에 대해서 군집화를 잘 수행

 

알고리즘 매커니즘

1) 파라미터

  • 입실론 주변 영역(epsilon): 개별 데이터를 중심으로 입실론 반경을 가지는 원형의 영역
  • 최소 데이터 개수(min points): 개별 데이터의 입실론 주변 영역에 포함되는 타 데이터의 개수

2) 데이터 포인트

  • 핵심 포인트(Core Point): 주변 영역 내에 최소 데이터 개수 이상의 타 데이터를 가지고 있을 경우
  • 이웃 포인트(Neighbor Point): 주변 영역 내에 위치한 타 데이터
  • 경계 포인트(Border Point): 주변 영역 내에 최소 데이터 개수 이상의 이웃 포인트를 가지고 있지 않지만, 핵심 포인트를 이웃 포인트로 가지고 있는 데이터(P3, P4, P6, P7, P8, P11, P9, P10)
  • 잡음 포인트(Noise Point): 최소 데이터 개수 이상의 이웃 포인트를 가지고 있지 않으며, 핵심 포인트도 이웃 포인트로 가지고 있지 않는 데이터 (P5)

Step 1 : P1을 기준으로 이웃 포인트가 6개 이므로 P1은 핵심 포인트 / Step 2 : P2를 기준으로 이웃 포인트 5개이므로 P2는 핵심 포인트
Step 3 : P1의 이웃 포인트 P2가 핵심 포인트이므로 직접 접근 가능 / Step 4 : P1에서 직접 접근이 가능한 P2를 서로 연결하여 군집화 구성
Step 5 : 위 과정을 반복하여 점차적으로 군집 영역 확장

 

  • 일반적으로 eps <= 1, eps가 증가하면 noise 줄어듦
  • 특정 군집 개수로 군집을 강제하지 말고, 파라미터를 통해 최적의 군집을 찾는 것이 중요

 

Sklearn API

이를 위해 sklearn에서는 API를 지원한다.

목적 import API
K-means
from sklearn.cluster import DBSCAN DBSCAN()

코드에서 보면, 

from sklearn.cluster import DBSCAN

dbscan = DBSCAN(eps=0.6, min_samples=8, metric='euclidean')
dbscan_labels = dbscan.fit_predict(iris.data)

irisDF['dbscan_cluster'] = dbscan_labels

1) 실습 (DBSCAN) 

iris데이터를 활용하여, DBSSCAN알고리즘을 적용해보자. (Link)

 

ㅁ Reference

- [책] 파이썬 머신러닝 완벽가이드

- [블로그] 파이썬 머신러닝 완벽가이드 정리본 (Link)

- [책] 혼자 공부하는 머신러닝+딥러닝

- [소스코드 출처] https://github.com/wikibook/pymldg-rev

 
반응형