Posts 클러스터링(Clustering)
Post
Cancel

클러스터링(Clustering)

1.K-Means


1.1 K-Means

  • 군집화에서 가장 일반적인 알고리즘
  • 군집 중심이라는 임의의 지점을 선핵해서 해당 중심에 가장 가까운 포인트들을 선택하는 군집화
  • 일반적인 군집화에서 가장 많이 사용되는 기법
  • 거리 기반 알고리즘으로 속성의 개수(K)가 매우 많을 경우 군집화의 정확도가 떨어짐


1.2 원리

  • 초기 중심점을 설정
  • 각 데이터는 가장 가까운 중심점에 소속
  • 중심점에 할당된 평균값으로 중심점 이동
  • 각 데이터는 이동된 중심점 기준으로 가장 가까운 중심점에 소속
  • 다시 중심점에 할당된 데이터들의 평균값으로 중심점 이동
  • 데이터들의 중심점 소속 변경이 없으면 종료됨


2. Iris 데이터로 실습


2.1 Data Load

1
2
3
4
5
6
7
8
9
from sklearn.preprocessing import scale
from sklearn.datasets import load_iris
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
%matplotlib inline

iris = load_iris()
  • 사이킷런에 있는 Iris 데이터를 불러옴


1
iris.feature_names
1
2
3
4
['sepal length (cm)',
 'sepal width (cm)',
 'petal length (cm)',
 'petal width (cm)']


1
2
cols = [each[:-5] for each in iris.feature_names]
cols
1
['sepal length', 'sepal width', 'petal length', 'petal width']
  • 특성 이름의 (cm)이 전처리하기 힘드니 삭제함


2.2 Data Preprocessing

1
2
iris_df = pd.DataFrame(iris.data, columns=cols)
iris_df.head()
sepal lengthsepal widthpetal lengthpetal width
05.13.51.40.2
14.93.01.40.2
24.73.21.30.2
34.63.11.50.2
45.03.61.40.2


1
2
feature = iris_df[['petal length','petal width']]
feature.head()
petal lengthpetal width
01.40.2
11.40.2
21.30.2
31.50.2
41.40.2
  • 편의상 꽃잎의 넓이와 길이, 2개의 특성만 사용


2.3 군집화

1
2
model = KMeans(n_clusters= 3)
model.fit(feature)
1
KMeans(n_clusters=3)
  • n_clusters : 군집화할 개수, 즉 군집 중심점의 갯수
  • init : 초기 군집 중심점의 좌표를 설정하는 방식을 결정
  • max_iter : 최대 반복 횟수, 모든 데이터의 중심점 이동이 없으면 종료


2.4 결과

1
model.labels_
1
2
3
4
5
6
7
array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int32)
  • 군집화이기 때문에 지도학습의 라벨과는 다름


2.5 군집 중심값

1
model.cluster_centers_
1
2
3
array([[5.59583333, 2.0375    ],
       [1.462     , 0.246     ],
       [4.26923077, 1.34230769]])
  • 라벨의 0부터 2까지의 중심값을 표현함
  • 시각화 할때 유용함


2.6 시각화를 위해 정리

1
2
3
predict = pd.DataFrame(model.predict(feature), columns=['cluster'])
feature = pd.concat([feature, predict], axis = 1)
feature.head()
petal lengthpetal widthcluster
01.40.21
11.40.21
21.30.21
31.50.21
41.40.21
  • 예측값을 데이터프레임으로 만들고 이전에 있던 feature 데이터프레임에 붙임


2.7 시각화

1
2
3
4
5
6
7
8
9
10
centers = pd.DataFrame(model.cluster_centers_, columns=[
                       'petal length', 'petal width'])
center_x = centers['petal length']
center_y = centers['petal width']

plt.figure(figsize=(12, 8))
plt.scatter(feature['petal length'], feature['petal width'],
            c=feature['cluster'], alpha=0.5)
plt.scatter(center_x, center_y, s=50, marker='D', c='r')
plt.show()

  • 2개의 특성을 3개로 군집화 시켰으며, 빨간점이 각 군집의 중심임
  • 2개짜리 특성을 3개로 나눌수도 있음!


2. Make Blobs


2.1 Make Blobs

1
2
3
4
5
6
7
from sklearn.datasets import make_blobs

X, y = make_blobs(n_samples= 200, n_features=2, centers=3, cluster_std= 0.8, random_state= 0)
print(X.shape, y.shape)

unique, counts = np.unique(y, return_counts= True)
print(unique, counts)
1
2
(200, 2) (200,)
[0 1 2] [67 67 66]
  • Make Blobs : 군집화 연습을 위한 데이터 생성기
  • n_samples : 생성되는 샘플의 수
  • n_features : 샘플이 가지는 특성의 수
  • centers : 군집화되는 라벨
  • cluter_std : 군집의 표준편차


2.2 데이터 정리

1
2
3
cluster_df = pd.DataFrame(data = X, columns=['ftr1', 'ftr2'])
cluster_df['target'] = y
cluster_df.head()
ftr1ftr2target
0-1.6924273.6220252
10.6979404.4288670
21.1002284.6063170
3-1.4487243.3842452
41.2148615.3648960
  • Make Blobs로 만든 데이터를 데이터 프레임화 시킴


2.3 군집화

1
2
3
4
kmeans = KMeans(n_clusters=3, init='k-means++', max_iter = 200, random_state=13)
cluster_labels = kmeans.fit_predict(X)
cluster_df['kmeans_label'] = cluster_labels
cluster_df.head()
ftr1ftr2targetkmeans_label
0-1.6924273.62202522
10.6979404.42886701
21.1002284.60631701
3-1.4487243.38424522
41.2148615.36489601
  • Kmeans를 사용하여 예측함.
  • 실제 target과 예측한 label을 비교하는 데이터프레임을 생성


2.4 시각화

1
2
3
4
5
6
7
8
9
10
11
centers = kmeans.cluster_centers_
unique_labels = np.unique(cluster_labels)
markers = ['o', 's', '^', 'P', 'D', 'H', 'x']

for label in unique_labels:
    label_cluster = cluster_df[cluster_df['kmeans_label'] == label]
    center_x_y = centers[label]
    plt.scatter(x = label_cluster['ftr1'], y=label_cluster['ftr2'], edgecolors='k', marker=markers[label])
    plt.scatter(x = center_x_y[0], y = center_x_y[1], s=200, color = 'white', alpha = 0.9, edgecolors = 'k', marker=markers[label])
    plt.scatter(x = center_x_y[0], y = center_x_y[1], s=70, color = 'white', alpha = 0.9, edgecolors = 'k', marker='$%d$' % label)
plt.show()    

  • 예측한 군집의 모형


2.5 결과 확인

1
cluster_df.groupby('target')['kmeans_label'].value_counts()
1
2
3
4
5
6
7
target  kmeans_label
0       1               66
        2                1
1       0               67
2       2               65
        0                1
Name: kmeans_label, dtype: int64
  • target 0을 kmeans_label 1로 66개, 2로 1개 즉, target0을 kmeans_label 1로 군집,
  • target 1을 kmeans_label 0으로 모두 군집화
  • target 2을 kmeans_label 2로 65개, 1개는 0으로 군집화
  • target의 0,1,2를 맞추는것이 아닌, 0,1,2를 제대로 군집화시키는지를 봐야함


3. 군집 평가


3.1 군집 결과의 평가

  • 분류기는 평가 기준을 가지고 있지만, 군집은 그렇지 않을떄가 많음
  • 군집 결과를 평가하기 위해 실루엣 분석을 많이 활용함


3.2 실루엣 분석

  • 각 군집 간의 거리가 얼마나 효율적으로 분리돼어 있는지를 나타냄
  • 다른 군집과의 거리는 떨어져 있고, 동일 군집끼리의 데이터는 서로 가깝게 잘 뭉쳐 있는지 확인
  • 군집화가 잘 되어 있을 수록 개별 군집은 비슷한 정도의 여유 공간을 가지고 있음
  • 실루엣 계수 : 개별 데이터가 가지는 군집화 지표


3.3 n = 2인 경우

  • 1번 군집의 경우 0번 군집과 잘 떨어져 있고, 잘 뭉쳐 있음
  • 0번 군집의 경우 내부 데이터끼리 많이 떨어져있는 것을 알수 있음


3.4 n = 3인 경우

  • 0번 군집의 경우 2번 군집과 가깝게 위치해 있다


  • 군집이 4개로 잘 나뉘어져 있는것을 알수 있다

  • 실루엣 분석의 그래프가 균일한 칼 모양을 가지고 있으면 군집화가 잘 된것


3.5 Iris 데이터로 실습

1
2
3
4
5
6
7
8
from sklearn.datasets import load_iris
from sklearn.cluster import KMeans
import pandas as pd

iris = load_iris()
feature_names = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
iris_df = pd.DataFrame(iris.data, columns= feature_names)
kmeans = KMeans(n_clusters=3, init = 'k-means++', max_iter = 300, random_state = 0).fit(iris_df)
  • iris 데이터를 불러오고 4개의 특성을 모두 사용하여 3개의 군집으로 군집화를 해봄


3.6 군집 결과 정리

1
2
iris_df['cluster'] = kmeans.labels_
iris_df.head()
sepal_lengthsepal_widthpetal_lengthpetal_widthcluster
05.13.51.40.21
14.93.01.40.21
24.73.21.30.21
34.63.11.50.21
45.03.61.40.21


3.7 군집 결과 평가

1
2
3
4
5
6
7
from sklearn.metrics import silhouette_samples, silhouette_score

avg_value = silhouette_score(iris.data, iris_df['cluster'])
score_values = silhouette_samples(iris.data, iris_df['cluster'])

print(f'avg_vale : {avg_value}')
print(f'silhouette_samples() return값의 shape : {score_values.shape}')
1
2
avg_vale : 0.5528190123564091
silhouette_samples() return값의 shape : (150,)
  • silhouette score는 집단이 멀리 떨어질수록 1로 나옴


3.8 실루엣 시각화

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
def visualize_silhouette(cluster_lists, X_features): 
    from sklearn.datasets import make_blobs
    from sklearn.cluster import KMeans
    from sklearn.metrics import silhouette_samples, silhouette_score
    import matplotlib.pyplot as plt
    import matplotlib.cm as cm
    import numpy as np
    import math
    n_cols = len(cluster_lists)
    fig, axs = plt.subplots(figsize=(4*n_cols, 4), nrows=1, ncols=n_cols)
    for ind, n_cluster in enumerate(cluster_lists):
        clusterer = KMeans(n_clusters = n_cluster, max_iter=500, random_state=0)
        cluster_labels = clusterer.fit_predict(X_features)
        sil_avg = silhouette_score(X_features, cluster_labels)
        sil_values = silhouette_samples(X_features, cluster_labels)
        y_lower = 10
        axs[ind].set_title('Number of Cluster : '+ str(n_cluster)+'\n' \
                          'Silhouette Score :' + str(round(sil_avg,3)) )
        axs[ind].set_xlabel("The silhouette coefficient values")
        axs[ind].set_ylabel("Cluster label")
        axs[ind].set_xlim([-0.1, 1])
        axs[ind].set_ylim([0, len(X_features) + (n_cluster + 1) * 10])
        axs[ind].set_yticks([])  # Clear the yaxis labels / ticks
        axs[ind].set_xticks([0, 0.2, 0.4, 0.6, 0.8, 1])
        for i in range(n_cluster):
            ith_cluster_sil_values = sil_values[cluster_labels==i]
            ith_cluster_sil_values.sort()
            size_cluster_i = ith_cluster_sil_values.shape[0]
            y_upper = y_lower + size_cluster_i
            color = cm.nipy_spectral(float(i) / n_cluster)
            axs[ind].fill_betweenx(np.arange(y_lower, y_upper), 0, 
                                   ith_cluster_sil_values, facecolor=color, 
                                   edgecolor=color, alpha=0.7)
            axs[ind].text(-0.05, y_lower + 0.5 * size_cluster_i, str(i))
            y_lower = y_upper + 10
        axs[ind].axvline(x=sil_avg, color="red", linestyle="--")
1
visualize_silhouette([2,3,4], iris.data)

  • n_cluster의 갯수가 늘어날수록 실루엣 그래프가 칼 모양을 하고 있다.
This post is licensed under CC BY 4.0 by the author.