군집 알고리즘 종류 - gunjib algolijeum jonglyu

ㅁ 들어가기

ㅁ 군집화 알고리즘 종류

ㅁ 군집 평가

ㅁ 군집화 알고리즘 - Kmeans

ㅁ 군집화 알고리즘 - DBSCAN


ㅁ 들어가기

군집 알고리즘 종류 - gunjib algolijeum jonglyu

군집 알고리즘 종류 - gunjib algolijeum jonglyu
군집 알고리즘 종류 - gunjib algolijeum jonglyu

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

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

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

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

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

군집 알고리즘 종류 - gunjib algolijeum jonglyu
군집 알고리즘 종류 - gunjib algolijeum jonglyu

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

군집 알고리즘 종류 - gunjib algolijeum jonglyu
군집 알고리즘 종류 - gunjib algolijeum jonglyu

MBTI별 기도문짤

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

군집 알고리즘 종류 - gunjib algolijeum jonglyu
군집 알고리즘 종류 - gunjib algolijeum jonglyu

https://youtu.be/6K_vQu9daTg

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

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

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

군집 알고리즘 종류 - gunjib algolijeum jonglyu

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

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

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

군집 알고리즘 종류 - gunjib algolijeum jonglyu

ㅁ 군집화 알고리즘 종류

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

군집 알고리즘 종류 - gunjib algolijeum jonglyu
군집 알고리즘 종류 - gunjib algolijeum jonglyu
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) 에 가깝다는 것을 반드시 보장하지는 않는다는 단점이 있다.

군집 알고리즘 종류 - gunjib algolijeum jonglyu

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

1) 실루엣 분석

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

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

군집 알고리즘 종류 - gunjib algolijeum jonglyu
출처 : 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
군집 알고리즘 종류 - gunjib algolijeum jonglyu
실수엣계수

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

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

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

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

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

군집 알고리즘 종류 - gunjib algolijeum jonglyu
  • 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)
군집 알고리즘 종류 - gunjib algolijeum jonglyu

ㅁ 군집화 알고리즘 - Kmeans

알고리즘 특징

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

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

알고리즘 매커니즘

군집 알고리즘 종류 - gunjib algolijeum jonglyu

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

군집 알고리즘 종류 - gunjib algolijeum jonglyu
출처 : 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)

군집 알고리즘 종류 - gunjib algolijeum jonglyu
군집 알고리즘 종류 - gunjib algolijeum jonglyu

Step 1 : P1을 기준으로 이웃 포인트가 6개 이므로 P1은 핵심 포인트 /&nbsp;Step 2 : P2를 기준으로 이웃 포인트 5개이므로 P2는 핵심 포인트

군집 알고리즘 종류 - gunjib algolijeum jonglyu
군집 알고리즘 종류 - gunjib algolijeum jonglyu

Step 3 : P1의 이웃 포인트 P2가 핵심 포인트이므로 직접 접근 가능 /&nbsp;Step 4 : P1에서 직접 접근이 가능한 P2를 서로 연결하여 군집화 구성
군집 알고리즘 종류 - gunjib algolijeum jonglyu
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