빅데이타 & 머신러닝/머신러닝

클러스터링 #1 - KMeans

Terry Cho 2017. 10. 9. 22:41

클러스터링과 KMeans를 이용한 데이타의 군집화

조대협 (http://bcho.tistory.com)

클러스터링 문제

클러스터링은 특성이 비슷한 데이타 끼리 묶어주는 머신러닝 기법이다. 비슷한 뉴스나 사용 패턴이 유사한 사용자를 묶어 주는것과 같은 패턴 인지나, 데이타 압축등에 널리 사용되는 학습 방법이다.

클러스터링은 라벨링 되어 있지 않은 데이타를 묶는 경우가 일반적이기 때문에 비지도학습 (Unsupervised learning) 학습 방법이 사용된다.


클러스터링 알고리즘은 KMeans, DBSCAN, Hierarchical clustering, Spectral Clustering 등 여러가지 기법이 있으며, 알고르즘의 특성에 따라 속도나 클러스터링 성능에 차이가 있기 때문에, 데이타의 모양에 따라서 적절한 클러스터링 알고리즘을 선택하는 것이 중요하다. 다음은 sklearn에 나와 있는 각 클러스터링 알고리즘의 성능에 대한 비교표이다.



출처 : http://scikit-learn.org/stable/auto_examples/cluster/plot_cluster_comparison.html#sphx-glr-auto-examples-cluster-plot-cluster-comparison-py


이 글에서는 클러스터링 알고리즘 중에서 간단하게 사용할 수 있는 KMeans와 Hierachical Clustering 알고리즘을 파이썬 sklearn 라이브러리를 이용하여 설명한다.


KMeans

KMeans 클러스터링 알고리즘은 n개의 중심점을 찍은 후에, 이 중심점에서 각 점간의 거리의 합이 가장 최소화가 되는 중심점 n의 위치를 찾고, 이 중심점에서 가까운 점들을 중심점을 기준으로 묶는 클러스터링 알고리즘이다.

아래 그림을 보면 3개의 군집이 존재하는 것을 볼 수 있다. 각 군집별로 중심점이 찍혀 있는데, 이 중심점의 위치를 움직여 가면서 각 군집의 데이타와 중심점의 거리가 가장 작은 중심점을 찾는 것이다.



이 중심점은 결국 각 군집의 데이타의 평균값을 위치로 가지게 되는데, 이런 이유로 Means(평균) 값 알고리즘이라고 한다.


IRIS 데이타를 이용한 KMeans Clustering

그러면 파이썬 sklearn 라이브러리를 이용하여 IRIS 데이타를 KMeans 알고리즘을 이용하여 클러스터링 해보자

Iris 데이타는 붓꽃의 데이타를 머신러닝 학습용으로 잘 정리해놓은 테스트 데이타 셋으로 꽃잎(Petal)의 크기와 꽃받침(Petal)의 크기에 따라 Iris 꽃의 종류를 분리해놓았다.

이 Iris 데이타는 sklearn 라이브러리 안에 샘플 데이타로 제공되고 있다. 이 데이타셋에는 세가지 붓꽃의 종류별로 50장, 총 150장의 데이타를 샘플로 제공한다.



출처 : https://www.google.co.kr/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&ved=0ahUKEwi0u5aAxePWAhXCNpQKHbTlAWwQjRwIBw&url=https%3A%2F%2Fwww.datacamp.com%2Fcommunity%2Ftutorials%2Fkeras-r-deep-learning&psig=AOvVaw2LZqoz0__VGKTODVDAbJnu&ust=1507638255303298


전체 소스 코드는 https://github.com/bwcho75/dataanalyticsandML/blob/master/Clustering/1.%20KMeans%20clustering-IRIS%202%20feature.ipynb 에 있다.


먼저 Iris 데이타를 로딩해보자


데이타를 로딩한 후에, 이 예제에서는 두개의 속성만 사용해서 분류하기로 해보자.  “Sepal length”와 “Sepal width” 컬럼 두개만 추출하여 학습용 feature라는 데이타 프레임으로 학습용 데이타를 만든다. Iris 데이타는 skearn.datasets에 들어있고 이를 로딩하려면 iris = datasets.load_iris()를 하면 로딩이 된다.

데이타는 로딩된 iris 데이타의 iris.data 필드에 들어가 있고, label은 iris.labels 컬럼에 들어가 있다.


from sklearn import datasets

import pandas as pd

iris = datasets.load_iris()


labels = pd.DataFrame(iris.target)

labels.columns=['labels']

data = pd.DataFrame(iris.data)

data.columns=['Sepal length','Sepal width','Petal length','Petal width']

data = pd.concat([data,labels],axis=1)

feature = data[ ['Sepal length','Sepal width']]

feature.head()




다음 K Means 라이브러리를 이용하여 학습을 시켜보자.


from sklearn.cluster import KMeans

import matplotlib.pyplot  as plt

import seaborn as sns


# create model and prediction

model = KMeans(n_clusters=3,algorithm='auto')

model.fit(feature)

predict = pd.DataFrame(model.predict(feature))

predict.columns=['predict']


sklearn.cluster에서 KMeans 라이브러리를 import 한후에, KMeans 객체를 생성하여 model에 저장한다. 이때 3개의 클러스터로 데이타를 군집화할것이기 때문에, 인자로 n_clusters=3으로 클러스터의 수를 정해준다.

model.fit(학습데이타)를 실행하면 학습 데이타를 이용하여 클러스터링을 위한 학습을 시작하고 학습 데이타에 맞는 중심점 3개를 추출해낸다. 이 학습이 된 모델을 가지고 model.predict(데이타) 를 수행하면 데이타를 학습된 모델에 맞춰서 군집화를 해서 어느 클러스터로 군집화가 되었는지 라벨을 리턴해준다.


클러스터링시, 클러스터의 라벨은 자동으로 0,1,2로 지정되는데, 이 순서는 학습을 할때 마다 임의로 변경이 될 수 있다.  클러스터링 된 라벨과 Sepal length, Sepal width를 하나의 데이타 프레임 r에  저장해서 출력해보자


# concatenate labels to df as a new column

r = pd.concat([feature,predict],axis=1)

시각화

K Means를 이용해서 클러스터링된 데이타를 Scatter plot을 이용해서 시각화 해보자


plt.scatter(r['Sepal length'],r['Sepal width'],c=r['predict'],alpha=0.5)


Scatter plot을 이용하여 클러스터링된 데이타를 그리고, 각 클러스터링 된 데이타를 라벨 (0,1,2)에 따라 색을 다르게 표시한다.

그리고 각 클러스터의 중심점을 붉은 색으로 점을 찍어서 나타내자.

클러스터별 중심점은 model.clsuter_centers 값에 저장이 된다. 중심점을 읽어서 center_x, center_y에 에 각 클러스터의 중심점 좌표를 저장하고 출력하자


centers = pd.DataFrame(model.cluster_centers_,columns=['Sepal length','Sepal width'])

center_x = centers['Sepal length']

center_y = centers['Sepal width']

plt.scatter(center_x,center_y,s=50,marker='D',c='r')

plt.show()


그래프로  출력된 결과는 다음과 같다.




데이타 스케일링를 통한 학습 데이타 정재

학습 데이타의 각 속성의 값이 범위가 크게 차이가 나면 머신러닝 학습이 잘 안되는 경우가 있는데, 예를 들어 속성 A의 범위가 1~1000이고, 속성 B의 범위가 1~10이면, 학습이 제대로 되지 않을 수 있다. 그래서 각 속성의 값의 범위를 동일하게 맞추는 것을 스케일링 (Feature scaling)이라고 한다


그림 좌측은 스케일링전의 원본 데이타, 우측은 데이타는 모든 속성을 0~1 사이로 조정한 결과이다. .

( 데이타 스케일링 대한 내용은 http://bcho.tistory.com/tag/data%20frame 참고 )



여러가지 알고리즘이 있는데 여기서 사용하는 스케일링 방법은 속성의 모든 값을 0~1 사이로 만들어주는 StandardScaling 방법을 사용한다.


즉 학습이 되기전에 데이타를 StandardScaler를 이용하여 스케일링을 조정한 후에, 스케일된 데이타를 KMeans 모델에 넣어서 학습 시키는 방법으로 두 단계를 거치는데, 이렇게 여러 단계를 거쳐서 데이타가 정재되고 학습되는 것을 파이프라인이라고 하고, sklearn.pipeline을 이용하여 손쉽게 구현이 가능하다.

아래 코드를 보자


from sklearn.pipeline import make_pipeline

from sklearn.preprocessing import StandardScaler

from sklearn.cluster import KMeans


scaler = StandardScaler()

model = KMeans(n_clusters=3)

pipeline = make_pipeline(scaler,model)


먼저 StandardScaler 객체 scaler를 만든 후, KMeans 모델 객체를 model로 선언한다. 다음에 make_pipeline 메서드를 이용하여 scaler 아 kmeans 모델을 순차로 실행하도록 파이프라인을 만든다.


pipeline.fit(feature)

predict = pd.DataFrame(pipeline.predict(feature))


다음 pipeline.fit과 .predict 메서드를 이용하여 모델을 학습 시키고 예측을 수행한다.

위의 iris 예제의 경우 스케일링을 적용하더라도 크게 모델의 정확도가 향상된것을 확인할 수 없는데, 이유는 Sepal length의 범위가 4~8, Sepal width의 범위가 2~5로 각 범위의 편차가 크지 않기 때문에 스케일링이 효과가 없다.

Inertia value를 이용한 적정 군집수 판단

K Means를 수행하기전에는 클러스터의 개수를 명시적으로 지정해줘야 한다. 데이타를 2개로 군집화할것인지, 3개로 할것인지등을 정해야 하는데, 몇개의 클러스터의 수가 가장 적절할지는 어떻게 결정할 수 있을까? Inertia value 라는 값을 보면 적정 클러스터 수를 선택할 수 있는 힌트를 얻을 수 있는데, Inertia value는 군집화가된 후에, 각 중심점에서 군집의 데이타간의 거리를 합산한것이으로 군집의 응집도를 나타내는 값이다, 이 값이 작을 수록 응집도가 높게 군집화가 잘되었다고 평가할 수 있다.


이 inertia value는 KMeans 모델이 학습된 후에, model.inertia_ 값으로 뽑아 볼 수 있다.

다음은 iris 데이타를 가지고 1~6개의 클러스터로 클러스터링을 했을때, 각 클러스터 개수별로 inertia value를 출력해보는 코드이다.


ks = range(1,10)

inertias = []


for k in ks:

   model = KMeans(n_clusters=k)

   model.fit(feature)

   inertias.append(model.inertia_)

   

# Plot ks vs inertias

plt.plot(ks, inertias, '-o')

plt.xlabel('number of clusters, k')

plt.ylabel('inertia')

plt.xticks(ks)

plt.show()


다음은 출력된 그래프이나. Inertia 값이 급격하게 하강해서 3~5사이에서는 변화의 폭이 크지 않은 것을 볼 수 있다.


이 값을 보면, iris 데이타는 3~5개의 클러스터로 분류하는 것이 적절하다고 판단할 수 있다.

크로스 테이블 체크를 이용한 모델 판단

클러스터링 모델을 검증하는 방법이 inertia 값을 사용하는 방법도 있지만 학습용 데이타가 라벨링이 되어 있는 경우에는 Cross tabulation (교차 분석)를 통해서 모델을 검증할 수 있다.

Cross tabulation 은 Pandas 라이브러리의 .crosstab 함수를 이용하면 쉽게 수행이 가능하다.


ct = pd.crosstab(data['labels'],r['predict'])

print (ct)


다음은 iris 모델에 대한 교차 분석 결과 인데



새로 축이 원본 데이타의 라벨링 된 값을 나타내고 가로가 KMeans로 인해서 클러스터링 된 결과이다.

원래 라벨 값이 0 인 값이  KMeans 에서 클러스터링 된 결과 predict값을 보면, 2 로 결과가 나온것이 50개이다. 즉 49개는 제대로 분류했다는 이야기지만, label이 1로 된 데이타는 38 제대로 분리되고 12개는 잘못 분리된것을 볼 수 있다. 그리고 마지막으로 label이 2인 데이타는 35개가 제대로 분리되고 15개는 제대로 분리되지 않았음을 볼 수 있다.

KMeans 알고리즘의 문제점

K Means 알고리즘은 사용이 편하고 속도가 비교적 빠른 알고리즘인데 비해서 몇가지 문제점을 가지고 있다. 먼저 클러스터의 수를 정해줘야 하고, 결정적으로 K Means에서는 중심점을 측정할때 처음에 랜덤으로 중심점의 위치를 찾기 때문에,  잘못하면, 중심점과 점간의 거리가 Global optimum 인 최소 값을 찾는 게 아니라 중심점이 Local optimum 에 에 수렴하여 잘못된 분류를 할 수 있다는 취약점을 가지고 있다.



출처 : http://www.cenaero.be/Page.asp?docid=27087&langue=EN


다음 글에서는 비지도 학습 기반의 클러스터링 알고리즘중의 하나인 Hierachical Clustering 알고리즘에 대해서 소개해보도록 하겠다. Hierarchical Clustering은 이름에서도 알 수 있듯이 각 클러스터가 유사한 특징을 가지고 있는 여러 계층으로 되어 있을 때 효과적으로 사용할 수 있으며, 클러스터의 수 n을 정의하지 않고도 사용이 가능하다.