본문 바로가기

Data Science/Machine Learning 구현

[ML] K-means 와 GMM(Gaussian Mixture Model) 구현하기

반응형

이번 포스팅에서는 군집화 모델 중 K-means와 GMM을 Scikit-learn을 이용해서 구현해보려 한다. K-means는 대표적인 Semi-parametric 모델이며 GMM은 Parametric 모델이라는 점에서 두 개의 모델 간에 차이점이 존재한다. 이 각 모델들에 대한 자세한 이론적인 설명이 알고 싶다면 K-means는 여기, GMM은 여기를 참고하자.

 

1. K-means

K-means 알고리즘은 쉽고 간결하며 대용량 데이터에도 활용이 가능하다. 하지만 거리 기반 알고리즘으로 feature의 개수가 너무 많아진다면 군집화의 성능이 저하된다. 따라서 경우에 따라 PCA로 차원을 축소하여 적용하기도 한다. 또한 반복적인(iterative) 알고리즘이기 때문에 반복 횟수가 급격히 많아질 경우 학습 수행 시간이 느려지며 이상치(outlier)에 상당히 민감한 모델이다.

 

Scikit-learn에서 제공하는 K-means API에서는 다음과 같은 주요 파라미터를 제공한다.

 

  • n_clusters : 사전으로 정의하는 군집 갯수로서 K-means가 몇 개의 군집으로 군집화할 것인지 즉, 'K'값을 정의해주는 것이다.
  • init : 초기에 군집 중심점의 좌표를 설정하는 방식으로 보통 'k-means++' 방식으로 설정한다. random한 방식으로 설정하는 것은 엉뚱한 결과를 초래할 수도 있기 때문이다.
  • max_iter : 반복횟수를 설정하는 것이다. 설정한 횟수에 도달하기 이전에 군집화가 완료되면 반복횟수를 채우지 않더라도 중간에 종료된다.

다음은 Scikit-learn에서 제공하는 K-means API가 반환하는 속성값들이다. 즉, K-means가 군집화를 모두 수행한 후 반환하는 값들이다.

 

  • labels_ : 각 개별 데이터 포인트가 속하게 된 군집 label을 반환한다.(단, 이 label값이 실제 원본 데이터의 label값과 동일한 수치로 mapping되는 것이 아님을 명심하자!)
  • cluster_centers_ : K개로 군집화된 후 K개의 군집 각각의 중심점 좌표를 반환해준다. 이를 활용해 중심점 좌표를 시각화 할 수 있다.

이제 실제 코드에 적용해보면서 K-means를 구현하는 방법에 대해 알아보자.

from sklearn.datasets import make_blobs

# X에는 데이터, y에는 클러스터링 된 label값 반환
X, y = make_blobs(n_samples=200, n_features=2, centers=3,
                 cluster_std=0.8, random_state=1)
print(X.shape, y.shape)

# y Target값 분포 확인
# return_counts=True 추가하면 array요소마다 value_counts()해줌
unique, counts = np.unique(y, return_counts=True)

# 클러스터링용으로 생성한 데이터 데이터프레임으로 만들기
cluster_df = pd.DataFrame(data=X, columns=['ftr1','ftr2'])
cluster_df['target'] = y
cluster_df.head()

# 생성 데이터포인트들 시각화해보기
target_lst = np.unique(y)
markers = ['o','s','^','P','D']

for target in target_lst:
    target_cluster = cluster_df[cluster_df['target']==target]
    plt.scatter(x=target_cluster['ftr1'],
               y=target_cluster['ftr2'],
               edgecolor='k', marker=markers[target])
plt.show()

군집화용 데이터셋을 만들어주는 make_blobs함수로 만든 개별 데이터들 분포를 살펴보자.

군집화용으로 만든 데이터 분포도

이제 위 데이터에 K-means를 적용해서 각 군집의 중심점 좌표도 시각화해보자.

# K-means 클러스터링 수행하고 개별 클러스터 중심을 시각화

# 1.K-means 할당
kmeans = KMeans(n_clusters=3, init='k-means++',
               max_iter=200, random_state=12)
    # X는 cluster_df의 feature array임.
cluster_labels = kmeans.fit_predict(X)
cluster_df['kmeans_label'] = cluster_labels

# 2.K-means속성의 cluster_centers_는 개별 클러스터의 중심 위치 좌표를 반환
centers = kmeans.cluster_centers_
unique_labels = np.unique(cluster_labels)
markers = ['o','s','^','P']
# 3. label별로 루프돌아서 개별 클러스터링의 중심 시각화
for label in unique_labels:
    label_cluster = cluster_df[cluster_df['kmeans_label'] == label]
    # 각 클러스터의 중심 좌표 할당
    center_x_y = centers[label]
    # 각 클러스터 데이터들 시각화
    plt.scatter(x=label_cluster['ftr1'],
               y=label_cluster['ftr2'],
               marker=markers[label])
    
    # 각 클러스터의 중심 시각화
        # 중심 표현하는 모형 설정
    plt.scatter(x=center_x_y[0], y=center_x_y[1], s=200,
               color='white', alpha=0.9, edgecolor='k',
               marker=markers[label])
        # 중심 표현하는 글자 설정
    plt.scatter(x=center_x_y[0], y=center_x_y[1], s=70,
               color='k', edgecolor='k',
               marker='$%d$' % label)# label값에 따라 숫자로 표현한다는 의미
plt.show()

결과 화면은 다음과 같다.

K-means를 적용한 후 군집화

 

2. GMM(Gaussian Mixture Model)

GMM은 Parametric 모델로서 EM(Expectation Maximization) 알고리즘을 이용한 대표적인 군집화 모델이다. 개별 데이터가 가우시안 분포에 속한다고 가정을 한 상태에서 특정 정규분포에 속할 확률을 추정하는 것이다. Scikit-learn에서 제공하는 API의 주요 파라미터는 n_components로 사전적으로 정의하는 군집화 개수를 의미한다. 

 

GMM은 특히 잘 적용이 되는 데이터 분포가 있는데 주로 타원형으로 길게 늘어진 데이터 분포에 적용이 용이하다. 

 

GMM은 길게 늘어진 데이터 분포에 적합하다.

 

이제 실제 코드로 한 번 구현해 보자.

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

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']

# 보다 편리한 데이타 Handling을 위해 DataFrame으로 변환
irisDF = pd.DataFrame(data=iris.data, columns=feature_names)
irisDF['target'] = iris.target

# GMM 적용
from sklearn.mixture import GaussianMixture
# n_components로 미리 군집 개수 설정
gmm = GaussianMixture(n_components=3, random_state=42)
gmm_labels = gmm.fit_predict(iris.data)

# GMM 후 클러스터링 레이블을 따로 설정
irisDF['gmm_cluster'] = gmm_labels

# 실제 레이블과 GMM 클러스터링 후 레이블과 비교해보기(두 레이블 수치가 동일해야 똑같은 레이블 의미 아님!)
print(irisDF.groupby('target')['gmm_cluster'].value_counts())

 

결과값은 다음과 같으며 target은 실제 원본 데이터의 label, gmm_cluster는 클러스터링 후 클러스터링의 label이다. 

GMM Cluster 결과

위 결과를 해석하자면, target이 0인 label들 중에서는 모두 2라는 clustering label로 군집화시킨 것이다. 100% 잘 군집화한 것이다. 반면에 target이 1인 label들 중에서는 0인 군집으로 45개 1인 군집으로 5개를 했으므로 잘못 군집화시킨 데이터가 5개 존재한다는 것이다.

 

 

반응형