TOP
class="layout-aside-left paging-number">
본문 바로가기
[파이썬 Projects]/<파이썬 머신러닝>

[머신러닝] 군집화: GMM

by 기록자_Recordian 2024. 10. 27.
728x90
반응형
군집화란?
 

[머신러닝] 군집화 (Clustering)

군집화(Clustering) [군집]군집은 비슷한 샘플을 클러스터 또는 비슷한 샘플의 그룹으로 할당하는 작업으로, 데이터 분석, 고객 분류, 추천 시스템, 검색 엔진, 이미지 분할, 준지도 학습, 차원 축소

puppy-foot-it.tistory.com


이전 내용
 

[머신러닝] 군집화: 평균 이동

군집화란? [머신러닝] 군집화 (Clustering)군집화(Clustering) [군집]군집은 비슷한 샘플을 클러스터 또는 비슷한 샘플의 그룹으로 할당하는 작업으로, 데이터 분석, 고객 분류, 추천 시스템, 검색 엔

puppy-foot-it.tistory.com


GMM(Gaussian Mixture Model)

 

- GMM 군집화: 군집화를 적용하고자 하는 데이터가 여러 개의 가우시안 분포(GaussianDistribution) 를 가진 데이터 집합들이 섞여서 생성된 것이라는 가정하에 군집화를 수행하는 방식.

※ 가우시안 분포: 정규 분포로도 알려진 이 분포는 좌우 대칭형의 종 형태를 가진 통계학에서 가장 잘 알려진 연속 확률 함수이다.

[정규 분포 관련 글]

 

[개발자를 위한 수학] 기술 통계: 평균, 분산, 정규 분포(+파이썬)

기술 통계 평균, 중앙값, 모드, 차트, 종, 곡선을 계산하거나 데이터를 설명하기 위한 통계.측정이나 실험에서 수집한 자료(data)의 정리, 요약, 해석, 표현 등을 통해 자료의 특성을 규명

puppy-foot-it.tistory.com

 

GMM은 데이터를 여러 개의 가우시안 분포가 섞인 것으로 간주하며, 섞인 데이터 분포에서 개별 유형의 가우시안 분포를 추출한다. 전체 데이터 세트는 서로 다른 정규 분포를 가진 여러 가지 확률 분포 곡선으로 구성될 수 있으며, 이러한 서로 다른 정규 분포에 기반해 군집화를 수행하는 것이 GMM 군집화 방식이다. 예를 들어 1000개의 데이터 세트가 있다면 이를 구성하는 여러 개의 장규 분포 곡선을 추출하고, 개별 데이터가 이 중 어떤 정규 분포에 속하는지 결정하는 방식이다.

이와 같은 방식을 GMM에서는 모수 추정이라고 하는데, 모수 추정은 대표적으로 2가지를 추정하는 것이다.

  • 개별 정규 분포의 평균과 분산
  • 각 데이터가 어떤 정규 분포에 해당되는지의 확률

모수 추정을 위해 GMM은 EM(Expectation and Maximization) 방법을 적용한다.

※ 기댓값 최대화 알고리즘(expectation-maximization algorithm, 약자 EM 알고리즘): 관측되지 않는 잠재변수에 의존하는 확률 모델에서 최대가능도(maximum likelihood)나 최대사후확률(maximum a posteriori, 약자 MAP)을 갖는 모수의 추정값을 찾는 반복적인 알고리즘이다. EM 알고리즘은 모수에 관한 추정값으로 로그가능도(log likelihood)의 기댓값을 계산하는 기댓값 (E) 단계와 이 기댓값을 최대화하는 모수 추정값들을 구하는 최대화 (M) 단계를 번갈아가면서 적용한다. 최대화 단계에서 계산한 변수값은 다음 기댓값 단계의 추정값으로 쓰인다.


GMM을 이용한 붓꽃 데이터 세트 군집화

 

사이킷런은 GMM의 EM 방식을 통한 모수 추정 군집화를 지원하기 위해 GaussianMixture 클래스를 지원하며, sklearn.mixture 패키지에 위치해 있다.

GMM은 확률 기반 군집화이고, K-평균은 거리 기반 군집화이다. 붓꽃 데이터 세트로 이 두 가지 방식을 이용해 군집화를 수행한 뒤 양쪽 방식을 비교해 본다.

GaussianMixture 객체의 가장 중요한 초기화 파라미터는 n_components이며, 이는 gaussian mixture의 모델의 총 개수이다. K-평균의 n_clusters와 같이 군집의 개수를 정하는 데 중요한 역할을 수행한다.

GaussianMixture 객체의 fit(데이터 세트)와 predict(피처 데이터 세트)를 수행해 군집을 결정한 뒤 irisDF DataFrame에 'gmm_cluster' 칼럼명으로 저장하고 나서 타깃별로 군집이 어떻게 매핑됐는지 확인.

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

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

# 데이터 핸들링을 위해 DataFrame 변환
irisDF = pd.DataFrame(data=iris.data, columns=feature_names)
irisDF['target'] = iris.target

gmm = GaussianMixture(n_components=3, random_state=0).fit(iris.data)
gmm_cluster_labels = gmm.predict(iris.data)

# 군집화 결과를 irisDF의 'gmm_cluster' 칼럼며으로 저장
irisDF['gmm_cluster'] = gmm_cluster_labels
irisDF['target'] = iris.target

# target 값에 따라 gmm_cluster 값이 어떻게 매핑됐는지 확인
iris_result = irisDF.groupby(['target'])['gmm_cluster'].value_counts()
print(iris_result)

▶ Target 0은 cluster 1로, Target 2는 cluster 2로 매핑되었고, Target1은 cluster 0과 2로 분할되어 매핑되었다.

 

[붓꽃 데이터 세트의 K-평균 군집화 수행 결과 확인]

kmeans = KMeans(n_clusters=3, init='k-means++', max_iter=300, random_state=0).fit(iris.data)
kmeans_cluster_labels = kmeans.predict(iris.data)
irisDF['kmeans_cluster'] = kmeans_cluster_labels
iris_result = irisDF.groupby(['target'])['kmeans_cluster'].value_counts()
print(iris_result)

▶  K-평균은 평균 거리 중심으로 중심을 이동하면서 군집화를 수행하는 방식이므로 개별 군집 내의 데이터가 원형으로 흩어져 있는 경우에 매우 효과적으로 군집화가 수행될 수 있다.


GMM vs K-평균

 

KMeans는 원형의 범위에서 군집화를 수행하여 데이터 세트가 원형의 범위를 가질수록 군집화 효율이 더욱 높아진다. cluster_std를 작게 설정하면 데이터가 원형 형태로 분산될 수 있다.

그러나 KMeans는 원형의 범위로 퍼져 있지 않는 경우, 예를 들면 데이터가 길쭉한 타원형으로 늘어선 경우에 군집화를 잘 수행하지 못한다.

이를 시각화해보기 위해 visualize_cluster_plot 함수를 만든다. 해당 함수는 인자로 다음과 같은 값을 입력받는다.

visualize_cluster_plot(clusterobj, dataframe, label_name, iscluster=True)
  • clusterobj: 사이킷런의 군집 수행 객체. KMeans나 GaussianMixture의 fit()와 predict()로 군집화를 완료한 객체. 만약 군집화 결과 시각화가 아니고 make_blobs()로 생성한 데이터의 시각화일 경우 None 입력
  • dataframe: 피처 데이터 세트와 label 값을 가진 DataFrame
  • label_name: 군집화 결과 시각화일 경우 dataframe 내의 군집화 label 칼럼명, make_blobs() 결과 시각화일 경우는 dataframe 내의 target 칼럼명
  • iscenter: 사이킷런 Cluster 객체가 군집 중심 좌표를 제공하면 True, 그렇지 않으면 False
def visualize_cluster_plot(clusterobj, dataframe, label_name, iscenter=True):
    
    # 군집별 중심 위치: K-Means, Mean Shift 등
    if iscenter:
        centers = clusterobj.cluster_centers_
    
    # Cluster 값 종류
    unique_labels = np.unique(dataframe[label_name].values)
    
    markers=['o', 's', '^', 'x', '*']
    isNoise=False

    for label in unique_labels:
        # 군집별 데이터 프레임
        label_cluster = dataframe[dataframe[label_name]==label]
        
        if label == -1:
            cluster_legend = 'Noise'
            isNoise=True
        else:
            cluster_legend = 'Cluster '+str(label)
        
        # 각 군집 시각화
        plt.scatter(x=label_cluster['ftr1'], y=label_cluster['ftr2'], s=70,
                    edgecolor='k', marker=markers[label], label=cluster_legend)
        
        # 군집별 중심 위치 시각화
        if iscenter:
            center_x_y = centers[label]
            plt.scatter(x=center_x_y[0], y=center_x_y[1], s=250, 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)
            
    if isNoise:
        legend_loc='upper center'
    else: 
        legend_loc='upper right'
    
    plt.legend(loc=legend_loc)
    plt.show()

 

데이터 세트를 make_blobs() 의 데이터를 변환해 타원형으로 생성해본다.

from sklearn.datasets import make_blobs

# make_blobs()로 300개의 데이터 세트, 3개의 군집 세트, cluster_std=0.5
X, y = make_blobs(n_samples=300, n_features=2, centers=3, cluster_std=0.5, random_state=0)

# 길게 늘어난 타원형의 데이터 세트를 생성하기 위해 변환
transformation = [[0.60834549, -0.63667341], [-0.40887718, 0.85253229]]
X_aniso = np.dot(X, transformation)
# feature 데이터 세트와 make_blobs()의 y결괏값을 DataFrame으로 저장
clusterDF = pd.DataFrame(data=X_aniso, columns=['ftr1', 'ftr2'])
clusterDF['target'] = y
# 생성된 데이터 세트를 target 별로 다른 마커로 표시해 시각화
visualize_cluster_plot(None, clusterDF, 'target', iscenter=False)

 

[KMeans 군집화 확인]

위와 같은 데이터 세트에서는 KMeans의 군집화 정확성이 떨어지는데, KMeans가 위 데이터 세트를 어떻게 군집화하는지 확인

# 3개의 군집 기반 KMeans를 X_aniso 데이터 세트에 적용
kmeans = KMeans(3, random_state=0)
kmeans_label = kmeans.fit_predict(X_aniso)
clusterDF['kmeans_label'] = kmeans_label

visualize_cluster_plot(kmeans, clusterDF, 'kmeans_label', iscenter=True)

▶ KMeans로 군집화를 수행할 경우, 주로 원형 영역 위치로 개별 군집화가 되면서 원하는 방향으로 구성되지 않는데, KMeans가 평균 거리 기반으로 군집화를 수행하므로 같은 거리상 원형으로 군집을 구성하면서 위와 같이 길쭉한 방향으로 데이터가 밀접해 있을 경우에는 최적의 군집화가 어렵다.

 

[GMM 군집화 수행]

# 3개의 n_components 기반 GMM을 X_aniso 데이터 세트에 적용
gmm = GaussianMixture(n_components=3, random_state=0)
gmm_label = gmm.fit(X_aniso).predict(X_aniso)
clusterDF['gmm_label'] = gmm_label

# GaussianMixture는 cluster_centers_ 속성이 없으므로 iscenter를 False로 설정
visualize_cluster_plot(gmm, clusterDF, 'gmm_label', iscenter=False)

데이터가 분포된 방향에 따라 정확하게 군집화됐음을 알 수 있다. 

GMM은 K-평균과 다르게 군집의 중심 좌표를 구할 수 없기 때문에 군집 중심 표현이 함수에서 시각화되지 않는다. make_blobs()의 target 값과 KMeans, GMM의 군집 label 값을 서로 비교해 위와 같은 데이터 세트에서 얼만큼의 군집화 효율 차이가 발생하는지 확인

print('### KMeans Clustering ###')
print(clusterDF.groupby('target')['kmeans_label'].value_counts())
print('\n### Gaussian Mixture Clustering ###')
print(clusterDF.groupby('target')['gmm_label'].value_counts())

▶ KMeans의 경우 군집 1번만 정확히 매핑됐으나, 나머지 군집의 경우 target 값과 어긋나는 경우가 발생하고 있다.

GMM의 경우는 군집이 target 값과 잘 매핑돼 있다. 이를 통해 GMM의 경우는 KMeans 보다 유연하게 다양한 데이터 세트에 잘 적용될 수 있다는 장점이 있음을 알 수 있다. 그러나 GMM은 군집화를 위한 수행 시간이 오래 걸린다는 단점이 있다.


다음 내용

 

[머신러닝] 군집화: DBSCAN

군집화란? [머신러닝] 군집화 (Clustering)군집화(Clustering) [군집]군집은 비슷한 샘플을 클러스터 또는 비슷한 샘플의 그룹으로 할당하는 작업으로, 데이터 분석, 고객 분류, 추천 시스템, 검색 엔

puppy-foot-it.tistory.com


[출처]

파이썬 머신러닝 완벽 가이드

위키백과

dlsalfkd11 코딩코딩 - T Sotry

데이터 사이언스 스쿨

728x90
반응형