Programming

Gaussian Mixture Model(GMM) 군집화– K-Means의 한계를 극복하는 확률 기반 군집 알고리즘

Lucas.Kim 2026. 1. 12. 14:47
반응형

1. 개요

K-Means는 거리 기반 군집화 알고리즘으로,
군집이 원형(spherical) 이고 중심점을 기준으로 고르게 퍼져 있을 때 매우 효과적입니다.

하지만 실제 데이터는 다음과 같은 경우가 많습니다.

  • 군집이 길게 늘어진 타원형 분포
  • 군집마다 분산 크기가 서로 다름
  • 중심 거리보다 분포 형태가 중요한 경우

이러한 상황에서는 K-Means가 군집을 잘못 나누는 문제가 발생합니다.
이를 해결하기 위해 등장한 알고리즘이 Gaussian Mixture Model(GMM) 입니다.


2. K-Means의 구조적 한계

K-Means의 핵심 가정

  • 각 군집은 하나의 중심점(Centroid) 을 가짐
  • 모든 군집은 유사한 크기와 분산
  • 거리(Euclidean Distance)가 군집 결정의 기준

👉 결과적으로 원형 군집에는 강하지만,
타원형·비대칭 분포에는 취약합니다.


3. Gaussian Mixture Model(GMM) 개념 이해

3-1. GMM이란?

GMM은 데이터를 다음과 같이 가정합니다.

“전체 데이터는 여러 개의 가우시안(정규) 분포가 섞여 있는 혼합 모델이다.”

즉,

  • 하나의 군집 = 하나의 정규분포
  • 전체 데이터 = 여러 정규분포의 혼합(Mixture)

3-2. GMM의 핵심 아이디어

  • 각 데이터는 어떤 군집에 속할 확률을 가짐
  • 군집 할당은 확률 기반(soft assignment)

👉 K-Means는 “가장 가까운 군집 1개”만 선택
👉 GMM은 “각 군집에 속할 확률”을 계산


4. EM(Expectation–Maximization) 알고리즘

GMM은 EM 알고리즘을 이용해 모수를 추정합니다.

(1) E-step (Expectation)

  • 각 데이터가 각 가우시안 분포에 속할 확률 계산
  • 가장 높은 확률을 가진 분포에 임시 할당

(2) M-step (Maximization)

  • 할당된 데이터를 기반으로
    • 평균(mean)
    • 분산(covariance)
    • 혼합 확률(weight)
  • 가능도를 최대화하도록 모수 재계산

(3) 수렴 조건

  • 평균·분산이 더 이상 변하지 않음
  • 데이터 소속이 더 이상 변경되지 않음

👉 수렴 시 최종 군집 확정


5. 붓꽃 데이터셋 GMM 군집화 실습

5-1. 데이터 로딩 및 DataFrame 생성

import pandas as pd
from sklearn.datasets import load_iris

# 붓꽃 데이터 로드
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

👉

  • target은 정답 레이블
  • GMM은 비지도 학습이므로 학습에는 사용하지 않음

5-2. GMM 군집화 수행

from sklearn.mixture import GaussianMixture

# 3개의 가우시안 분포를 가진 GMM 생성 및 학습
gmm = GaussianMixture(
    n_components=3,     # 군집 개수
    random_state=0
).fit(iris.data)

# 각 데이터의 군집 예측
gmm_cluster_labels = gmm.predict(iris.data)

# 결과를 DataFrame에 저장
irisDF['gmm_cluster'] = gmm_cluster_labels

5-3. 실제 타깃과 GMM 결과 비교

iris_result = irisDF.groupby(['target'])['gmm_cluster'].value_counts()
print(iris_result)

target  gmm_cluster
0       1              50
1       0              45
        2               5
2       2              50

👉

  • Setosa(0), **Virginica(2)**는 완벽하게 분리
  • Versicolor(1) 일부만 혼합됨
  • 전체적으로 K-Means보다 안정적

6. 동일 데이터에 K-Means 적용 비교

from sklearn.cluster import KMeans

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)

target  kmeans_cluster
0       1                 50
1       0                 47
        2                  3
2       2                 36
        0                 14

👉

  • Virginica(2) 군집에서 오분류 증가
  • 타원형 분포를 제대로 반영하지 못함

7. 군집 결과 시각화 함수 정의

def visualize_cluster_plot(clusterobj, dataframe, label_name, iscenter=True):
    """
    clusterobj  : 학습된 클러스터링 객체
    dataframe   : 피처 + 클러스터 결과를 가진 DataFrame
    label_name  : 클러스터 라벨 컬럼명
    iscenter    : 중심점 표시 여부
    """
    if iscenter:
        centers = clusterobj.cluster_centers_
        
    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',
                edgecolor='k',
                alpha=0.9,
                marker=markers[label]
            )
            plt.scatter(
                x=center_x_y[0],
                y=center_x_y[1],
                s=70,
                color='k',
                edgecolor='k',
                marker='$%d$' % label
            )

    plt.legend(loc='upper right')
    plt.show()

👉

  • K-Means, DBSCAN, GMM 모두 재사용 가능
  • GMM은 중심점 개념이 없으므로 iscenter=False

8. 타원형 데이터 생성 및 비교 실험

8-1. 타원형 데이터 생성

from sklearn.datasets import make_blobs
import numpy as np

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)

clusterDF = pd.DataFrame(
    data=X_aniso,
    columns=['ftr1', 'ftr2']
)
clusterDF['target'] = y

# 실제 타깃 시각화
visualize_cluster_plot(None, clusterDF, 'target', iscenter=False)

8-2. K-Means 적용

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)

8-3. GMM 적용

gmm = GaussianMixture(n_components=3, random_state=0)
gmm_label = gmm.fit(X_aniso).predict(X_aniso)
clusterDF['gmm_label'] = gmm_label

visualize_cluster_plot(gmm, clusterDF, 'gmm_label', iscenter=False)

8-4. 정량적 비교 결과

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 Clustering ###
target  kmeans_label
0       2                73
        0                27
1       1               100
2       0                86
        2                14

### Gaussian Mixture Clustering ###
target  gmm_label
0       2            100
1       1            100
2       0            100

👉 GMM이 완벽하게 분리 성공


9. 결론 정리

  • K-Means
    • 빠르고 단순
    • 원형 군집에 적합
    • 거리 기반 한계 존재
  • GMM
    • 확률 기반 군집화
    • 타원형·비대칭 분포에 강함
    • EM 알고리즘 기반

👉 실제 데이터가 정규분포 혼합 형태라면 GMM이 훨씬 안정적인 선택입니다.

반응형