데이터 한 그릇

군집화)평균 이동 본문

머신러닝/군집화

군집화)평균 이동

장사이언스 2021. 5. 26. 17:20

평균 이동(Mean Shift)의 개요

 

  군집화 머신러닝 중에 하나인 k-means은 임의의 군집 중심점을 잡은 이후에 그 주변의 데이터의 평균 거리로 이동을 하면서 군집화를 진행한다. 평균 이동 알고리즘도 이와 비슷하다. 단, 평균 데이터의 거리로 이동하던 k-means에 반해서, 평균 이동은 데이터의 밀도를 기준으로 삼아서 군집 중심점이 이동한다.

 

  그렇다면 어떤 방식으로 밀도가 가장 높은 곳으로 군집 중심점이 이동할까? 평균 이동 군집화는 데이터의 분포도를 이용해서 군집 중심점을 찾는다. 이를 위해서 확률 밀도 함수를 이용한다.  죽, 확률 밀도 함수가 가장 피크인 지점을 군집 중심점으로 이동한다. 그리고 일반적으로 주어진 모델의 확률 밀도 함수를 찾기 위해서 KDE(Kernal Density Estimation)를 이용한다. 밑은 평균 이동 알고리즘의 과정을 설명하고 있다.

 

  1. 개별 데이터의 특정 반경 내에 주변 데이터를 포함한 데이터 분포도를 KDE 기반의 Mean Shift 알고리즘으로 계산
  2. KDE로 계산된 데이터 분포도가 높은 방향으로 데이터 이동
  3. 모든 데이터를 1~2까지 수행하면 데이터를 이동. 개별 데이터들이 군집중심점으로 모임
  4. 지정된 반복(iteration) 횟수만큼 전체 데이터에 대해서 KDE기반으로 데잍터를 이동시키면서 군집화 수행
  5. 개별 데이터들이 모인 중심점을 군집 중심점으로 설정

  알고리즘의 과정을 보면 알다시피, KDE가 가장 중요한 개념이라고 할 수 있다. KDE는 어떤 변수의 확률 밀도 함수를 추정하는 대표적인 방식이다. 그 방식은 관측된 데이터에 커널 함수를 적용하고 그 값들을 모조리 더한 후에 관측 데이터의 수로 나누는 방식이다. 이때 각 데이터에 적용하는 대표적인 커널 함수는 가우시안 분포 함수이다. 

 

 

  KDE는 커널 함수 K, 확률 변숫값, 관측값 그리고 대역폭이 존재한다. 이때 가장 주목해야할 인자는 대역폭이라고 할 수 있다. 대역폭은 확률 분포의 폭을 조절한다. 만일 폭이 과하게 좁다면 과적합 되어 있다고 할 수 있으며 폭이 넓다면 과소적합 되어 있다고 할 수 있다. 따라서 적당한 대역폭을 찾아야만 한다. 또한 대역폭이 넓을수록 평활화된 KDE로 인해서 적은 수의 군집 중심점을 가지게 되고, 대역폭이 적을수록 많은 수의 군집 중심점을 가지게 된다. KMEANS같은 경우에는 직접 n_clusters를 통해서 군집 중심점을 설정하였지만 평균 이동같은 경우에는 스스로 알고리즘이 군집의 개수를 결정한다. (설정한 대역폭에 따라서 달라질 수 있음)

 

  사이킷런 패키지는 평균 이동 군집화를 위해서 MeanShift를 제공한다. MeanShift의 가장 중요한 파라미터 값은 대역폭이라고 할 수 있다. (bandwidth). 이때 적절한 대역폭의 값을 찾기 위해서 최적의 대역폭 계산을 위한 estimate_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('cluster labels 유형:', np.unique(cluster_labels))

 

  평균 이동 알고리즘을 테스트해보기 위해서 필요한 데이터 셋을 make_blobs 모듈을 통해서 만든다. 그리고 MeanShift 인스턴스를 만들고 파라미터 값을 0.8로 설정을 한다. 그 이후 모델을 통한 결과 값을 변수에 저장하고 군집화 된 개수를 넘파이의 unique를 통해서 파악한다. 이 결고로 6개의 군집화가 이루어졌음을 확인할 수 있다.

 

meanshift = MeanShift(bandwidth = 1)
cluster_labels = meanshift.fit_predict(X)
print(np.unique(cluster_labels))

 

  앞서 평균 이동 군집화 경우에는 확률 분포의 넓이에 따라서 군집화의 개수가 달라짐을 살펴봤다. 넓다면 군집화의 개수가 적어지고 좁다면 군집화의 개수는 많아진다. 위처럼 0.2를 더 늘려 1로 모델을 만들었을 때 군집화의 개수는 3개로 줄었다.

#bandwidth 최적화하기

from sklearn.cluster import estimate_bandwidth

bandwidth = estimate_bandwidth(X)
print('최적화 bandwidth : ', np.round(bandwidth,3))

 

  임의로 bandwidth를 설정하는 것보다 최적의 파라미터 값을 찾아야만 한다. 사이킷런의 esimate_bandwidth에 데이터를 집어 넣어서 최적의 대역폭을 찾는다. "최적화 bandwidth : 1.816" 로 도출된다.

 

import pandas as pd


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

best_bandwidth = estimate_bandwidth(X)

meanshift = MeanShift(bandwidth = best_bandwidth)
cluster_labels = meanshift.fit_predict(X)
print(np.unique(cluster_labels))

 

  실제의 타겟 데이터와 군집화를 비교해보니 군집화 개수가 똑같다.

import matplotlib.pyplot as plt
%matplotlib inline

clusterDF['meanshift_label'] = cluster_labels
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()

 

 

   최적의 대역폭을 통한 군집화를 시각화하면 다음과 같다.

 

clusterDF.groupby('target')['meanshift_label'].value_counts()

 

  최종적으로 타겟 데이터와 잘 부합하는지 그룹바이를 통해서 살펴볼 수 있다.

 

'머신러닝 > 군집화' 카테고리의 다른 글

Customer Personality Analysis  (0) 2021.12.08
군집화)DBSCAN 군집화  (0) 2021.05.25
군집화) GMM(Gaussian Mixture Model)  (0) 2021.05.21
군집화 개요, k-평균 알고리즘  (0) 2021.05.21
Comments