군집 평가(Cluster Evaluation)
- 군집화는 classification과 달리 타깃 레이블을 가지고 있지 않고, 동일한 분류 값에 속하더라도 그 안에서 더 세분화된 군집화를 추구하거나 서로 다른 분류 값의 데이터도 더 넓은 군집화 레벨화 등의 영역을 가지고 있음
- 군집 평가를 위한 방법으로 실루엣 분석을 이용
<실루엣 분석의 개요>
- 실루엣 분석은 각 군집 간의 거리는 떨어져 있고 동일 군집끼리의 데이터는 서로 가깝게 잘 뭉쳐있는지, 즉 얼마나 효율적으로 잘 분리돼있는지를 나타냄
- 실루엣 계수 s(i) : 개별 데이터가 가지는 군집화 지표로 해당 데이터가 같은 군집 내의 데이터와 얼마나 가깝게 군집화 되어있고, 다른 군집 데이터와는 얼마나 멀리 분리돼있는지를 나타냄
- a(i) : i번째 데이터에서 자신이 속한 클러스터 내의 다른 데이터 포인트들의 평균 거리
- b(i) : i번째 데이터에서 가장 가까운 타 클래스터 내의 다른 데이터 포인트들의 평균 거리
- -1 에서 1 사이 값을 가짐.
- 1 에 가까울 수록 근처의 군집과 더 멀리 떨어지고 0에 가까울수록 근처의 군집과 가까워짐. -값은 다른 군집에 데이터 포인트가 할당됐음을 뜻함
- 실루엣 분석을 위한 사이킷런 메서드
- sklearn.metrics.silhouette_samples(X, labels, metric=’euclidean’, *kwds) : 각 데이터 포인트의 실루엣 계수 반환
- sklearn.metrics.silhouette_score(X, labels, metric=’euclidean’, sample_size=None, **kwds): 전체 데이터의 실루엣 계수 값의 평균 반환 = np.mean(silhouette_samples())
- 좋은 군집화의 조건
- 전체 실루엣의 평균값인 silhouette_score() 값은 0~1 사이의 값을 가지며 1에 가까울 수록 좋음
- 전체 실루엣 계수의 평균값과 더불어 개별 군집 평균값의 편차가 크지 않아야 함. 예를 들어, 전체 실루엣 계수의 평균값은 높지만, 특정 군집의 실루엣 계수 평균값만 유난히 높고 다른 군집들의 실루엣계수 평균값은 낮으면 좋은 군집화 조건이 아님
붓꽃 데이터 세트를 이용한 군집 평가
#붓꽃 데이터 세트를 이용한 군집 평가
from sklearn.preprocessing import scale
from sklearn.datasets import load_iris
from sklearn.cluster import KMeans
#실루엣 분석 평가 지표 값을 구하기 위한 API 추가
from sklearn.metrics import silhouette_samples, silhouette_score
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
%matplotlib inline
iris = load_iris()
feature_names = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
irisDF = pd.DataFrame(data=iris.data, columns=feature_names)
kmeans = KMeans(n_clusters=3, init='k-means++', max_iter=300, random_state=0).fit(irisDF)
irisDF['cluster'] = kmeans.labels_
#iris의 모든 개별 데이터에 실루엣 계수 값을 구함.
score_samples = silhouette_samples(iris.data, irisDF['cluster'])
print('silhouette_samples() return 값의 shape', score_samples.shape)
#irisDF에 실루엣 계수 칼럼 추가
irisDF['silhouette_coeff'] = score_samples
#모든 데이터의 평균 실루엣 계수 값을 구함.
avarage_score = silhouette_score(iris.data, irisDF['cluster'])
print('붓꽃 데이터 세트 Silhouette Analysis Score:{0:.3f}'.format(avarage_score))
irisDF.head(3)
[output]
silhouette_samples() return 값의 shape (150,)
붓꽃 데이터 세트 Silhouette Analysis Score:0.553
- 붓꽃 데이터 세트의 평균 실루엣 계수 값은 0.533
- irisDF 의 맨 앞 3개의 로우는 1번 군집에 해당되는 데이터로 실루엣 계수 값이 대략 0.8정도의 높은 실루엣 값을 나타냄
- 1번 군집의 평균값과 전체 실루엣 계수의 평균값의 편차가 큰 것으로 해석됨
- 군집별 평균 실루엣 계수 값을 확인해보면 1번 군집 평균 값은 0.79인데 반해, 다른 군집들은 상대적으로 낮은 평균 값을 가지고 있는 것을 확인할 수 있음
군집별 평균 실루엣 계수의 시각화를 통한 군집 개수 최적화 방법
- 군집의 개수를 2개로 정했을 때
- 실루엣 계수 약 0.704로 높게 나타남
- 1번 군집의 모든 데이터의 평균 실루엣 값 이상이지만, 0번 군집의 경우는 평균보다 적은 값이 많음
- 1번 군집의 경우 0번 군집과 멀리 떨어져 있고, 내부 데이터끼리도 잘 뭉쳐져 있지만 0번 군집의 경우는 내부 데이터끼리 많이 떨어져있음
2. 군집의 개수를 3개로 정했을 때
- 1번, 2번 군집의 겨우 평균보다 높은 실루엣 계수를 가지고 있지만, 0번의 경우 모두 평균보다 낮음
- 0번의 경우 내부 데이터 간의 거리도 멀지만, 2번 군집과도 가까이 위치하고 있기 때문
3. 군집의 개수를 4개로 정했을 때
- 개별 군집의 평균 실루엣 계수 값이 비교적 균일하게 위치
visualize_silhouette() 을 만들어 군집 개수를 변화시키면서 K-평균 군집을 수행했을 때 개별 군집별 평균 실루엣 계수 값을 시각화
### 여러개의 클러스터링 갯수를 List로 입력 받아 각각의 실루엣 계수를 면적으로 시각화한 함수 작성
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 math
# 입력값으로 클러스터링 갯수들을 리스트로 받아서, 각 갯수별로 클러스터링을 적용하고 실루엣 개수를 구함
n_cols = len(cluster_lists)
# plt.subplots()으로 리스트에 기재된 클러스터링 수만큼의 sub figures를 가지는 axs 생성
fig, axs = plt.subplots(figsize=(4*n_cols, 4), nrows=1, ncols=n_cols)
# 리스트에 기재된 클러스터링 갯수들을 차례로 iteration 수행하면서 실루엣 개수 시각화
for ind, n_cluster in enumerate(cluster_lists):
# KMeans 클러스터링 수행하고, 실루엣 스코어와 개별 데이터의 실루엣 값 계산.
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])
# 클러스터링 갯수별로 fill_betweenx( )형태의 막대 그래프 표현.
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="--")
#make_blobs()를 통해 군집화를 위한 4개의 군집 중심의 500개 2차원 데이터 세트 생성
from sklearn.datasets import make_blobs
X,y = make_blobs(n_samples=500, n_features=2, centers=4, cluster_std=1,
center_box=(-10.0,10.0), shuffle=True, random_state=1)
#군집 개수가 2개, 3개, 4개, 5개일 때 군집 실루엣 계수 평균값을 시각화
visualize_silhouette([2,3,4,5],X)
4개의 군집일 때 가장 최적이 됨을 알 수 있음
#붓꽃 데이터를 이용해 K-평균 수행 시 최적의 군집 개수
from sklearn.datasets import load_iris
iris = load_iris()
visualize_silhouette([2,3,4,5],iris.data)
군집 개수를 2개로 설정하는 것이 가장 좋아보임
- 실루엣 계수를 통한 K-평균 군집 평가 방법은 직관적으로 이해하기 쉽지만, 각 데이터 별로 다른 데이터와의 거리를 반복적으로 계산해야하므로 데이터양이 늘어나면 수행시간이 크게 늘어난다는 단점이 있음.
- 이러한 경우 임의의 데이터를 샘플링해 실루엣 계수를 평가하는 방안을 고민해봐야함
Ref) 파이썬 머신러닝 완벽가이드
'데이터 > 머신러닝' 카테고리의 다른 글
[RecSys] Chapter 9 | 추천시스템 (0) | 2023.02.01 |
---|---|
[Clustering] Chapter 7 | 군집화 실습 - 고객 세그멘테이션 (1) | 2023.01.28 |
[Clustering] Chapter 7 | 군집화 (01. K-평균 알고리즘의 이해) (0) | 2023.01.22 |
[Classification] Chapter 4 | 분류(01. 분류의 개요~02. 결정 트리) (0) | 2022.09.05 |
[Evaluation] Chapter 3 | 평가 (06. 피마 인디언 당뇨병 예측) (0) | 2022.08.29 |