07-03. 평균 이동(Mean Shift)

Park Jong Hun·2021년 3월 24일
0

위키북스의 파이썬 머신러닝 완벽 가이드 책을 토대로 공부한 내용입니다.


1. 평균 이동의 개요


평균 이동(Mean Shift)은 K-평균과 유사하게 중심을 군집의 중심으로 지속적으로 움직이면서 군집화를 수행한다. 하지만 K-평균이 중심에 소속된 데이터의 평균 거리 중심으로 이동하는 데 반해, 평균 이동은 중심을 데이터가 모여 있는 밀도가 가장 높은 곳으로 이동시킨다.

평균 이동 군집화는 데이터의 분포도를 이용하여 군집 중심적을 찾는다. 군집 중심점은 데이터 포인트가 모여있는 곳이라는 생각에서 착안한 것이며 이를 위해 확률 밀도 함수(probability density function)를 이용한다. 가장 집중적으로 데이터가 모여있어 확률 밀도 함수가 피크인 점을 군집 중심점으로 선정하며 일반적으로 주어진 모델의 확률 밀도 함수를 찾기 위해서 KDE(Kernel Density Estimation)를 이용한다.

KDE(Kernel Density Estimation)는 Kernal 함수를 통해 어떤 변수의 확률 밀도 함수를 추정하는 대표적인 방법이다. 관측된 데이터 각각에 커널 함수를 적용한 값을 모두 더한 뒤 데이터 건수로 나눠 확률 밀도 함수를 추정한다. 확률 밀도 함수 PDF는 확률 변수의 분포를 나타내는 함수로, 널리 알려진 정규분포 함수를 포함하여 감마 분포, t-분포 등이 있으며 대표적으로 가우시안 분포 함수를 사용한다. 확률 밀도 함수를 알면 특정 변수가 어떤 값을 갖게 될지에 대한 확률을 알게 되므로 이를 통해 변수의 특성, 확률 분포 등 변수의 많은 요소를 알 수 있다.

KDE=1ni=1nKh(xxi)=1nhi=1nK(xxih)KDE={1 \over n}\sum_{i=1}^nK_h(x-x_i)={1\over nh}\sum_{i=1}^nK({x-x_i\over h})

K는 커널 함수, x는 확률 변수값, xi는 관측값, h는 대역폭(bandwidth)이다. 대역폭 h는 KDE 형태를 부드러운 형태로 평활화(Smoothing)하는 데 적용되며, 이 h를 어떻게 설정하느냐에 따라 확률 밀도 추정 성능을 크게 좌우할 수 있다. 아래 그림은 h를 작은 값에서 큰 값으로 증가하면서 KDE가 어떻게 변화하는지 본 것이다. h가 작을 경우엔 좁고 뾰족한 KDE를 가지게 되며, 이는 변동성이 큰 방식으로 확률 밀도 함수를 추정하므로 과적합(over-fitting)하기 쉽다. 반대로 매우 큰 h값은 과도하게 smoothing 된 KDE로 인해 지나치게 단순화된 방식으로 확률 밀도 함수를 추정하며 결과적으로 과소적합(under-fitting)하기 쉽다. 따라서 적절한 KDE의 대역폭 h를 계산하는 것은 KDE 기반의 평균 이동(Mean Shift) 군집화에서 매우 중요하다.

평균 이동 군집화는 대역폭 설정에 따라 군집 중심정의 개수가 달라지며, 따로 개수를 지정하지 않는다. 사이킷런은 평균 이동 군집화를 위해 MeanShift 클래스를 제공한다. 대역폭 크기 설정이 군집화의 품질에 큰 영향을 미치기 때문에 사이킷런은 최적의 대역폭 계산을 위해 estimate_bandwidth() 함수를 제공한다. make_blobs()로 3개의 군집 데이터를 만든 후 bandwidth에 따라 군집을 생성해보겠다.

import numpy as np
from sklearn.datasets import make_blobs
from sklearn.cluster import MeanShift

X, y = make_blobs(n_samples=200, n_features=2, centers=3, 
                  cluster_std=0.7, random_state=0)

meanshift= MeanShift(bandwidth=0.8)
cluster_labels = meanshift.fit_predict(X)
print('[bandwidth=0.8] cluster labels 유형:', np.unique(cluster_labels))

meanshift= MeanShift(bandwidth=1)
cluster_labels = meanshift.fit_predict(X)
print('[bandwidth=1.0] cluster labels 유형:', np.unique(cluster_labels))

[output]
bandwidth가 0.8로 작게 설정되었을 경우 6개의 군집으로 분류되었지만 1로 설정하자 3개의 군집으로 잘 군집화되었다.

from sklearn.cluster import estimate_bandwidth

bandwidth = estimate_bandwidth(X)
print('bandwidth 값:', round(bandwidth,3))

[output]
estimate_bandwidth는 최적의 bandwidth 값을 찾아준다. 이렇게 찾은 bandwidth 값으로 군집화를 수행해보고 군집 중심점과 군집을 시각화해 보겠다.

import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline

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

# estimate_bandwidth()로 최적의 bandwidth 계산
best_bandwidth = estimate_bandwidth(X)

meanshift= MeanShift(bandwidth=best_bandwidth)
cluster_labels = meanshift.fit_predict(X)

clusterDF['meanshift_label']  = cluster_labels
print(clusterDF.groupby('target')['meanshift_label'].value_counts())

centers = meanshift.cluster_centers_
unique_labels = np.unique(cluster_labels)
markers=['o', 's', '^', 'x', '*']
for label in unique_labels:
    label_cluster = clusterDF[clusterDF['meanshift_label']==label]
    center_x_y = centers[label]
    # 군집별로 다른 마커로 산점도 적용
    plt.scatter(x=label_cluster['ftr1'], y=label_cluster['ftr2'], edgecolor='k', marker=markers[label] )
   
    # 군집별 중심 표현
    plt.scatter(x=center_x_y[0], y=center_x_y[1], s=200, color='gray', 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.show()

[output]
target 값과 군집 label 값이 1:1로 잘 매칭되었다. 평균 이동의 장점은 dataset의 형태를 특정 형태나 특정 분포도 기반의 모델로 가정하지 않기 때문에 좀 더 유연한 군집화가 가능하다. 또한 이상치의 영향력도 크기 않으며, 미리 군집의 개수를 정할 필요도 없다. 하지만 알고리즘의 수행 시간이 오래 걸리고 무엇보다도 bandwidth의 크기에 따른 군집화 영향도가 매우 크다. 이와 같은 특석 때문에 일반적으로 평균 이동 군집화 기법은 분석 업무 기반의 dataset 보다는 컴퓨터 비전 영역에서 더 많이 사용된다. 이미지나 영상 데이터에서 특정 개체를 구분하거나 움직임을 추적하는 데 뛰어난 역할을 수행하는 알고리즘이다.

profile
NLP, AI, LLM, MLops

0개의 댓글