실루엣 분석: 각 군집 간의 거리가 얼마나 효율적으로 분리돼 있는지를 나타내는 것
다른 방법으로는 Elbow Method가 있음 (Inertia)
실루엣 계수 (Silhouette Coefficient)
즉, 가 낮고, 가 높으면 잘 군집화 된 것!
-> 나와 나의 군집의 샘플들과는 가깝고, 다른 군집과는 멀기 때문
실루엣 스코어 (Silhouette Score)
시각화는 실습하면서 봐보자
scikit-learn을 이용해서 실루엣 계수와 실루엣 스코어를 구해보고,
시각화를 통한 군집 수 최적화까지 해보자
scikit-learn에서 관련 클래스를 제공함
각 샘플의 실루엣 계수: sklearn.metric.silhouette_samples
실루엣 스코어 (실루엣 계수의 평균): sklearn.metric.silhouette_score
iris 데이터 사용
데이터프레임으로 만들고, K-Means 군집화 후 군집 결과 칼럼 추가
from sklearn.preprocessing import scale
from sklearn.datasets import load_iris
from sklearn.cluster import KMeans
# 실루엣 분석 metric 값을 구하기 위한 API 추가
from sklearn.metrics import silhouette_samples, silhouette_score
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
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)
kmeans.fit(irisDF)
# 개별 데이터에 대한 군집 결과를 cluster 컬럼으로 DataFrame에 저장
irisDF['cluster'] = kmeans.labels_
irisDF.head(10)
각 샘플의 실루엣 계수를 구하고 칼럼으로 추가함
결과로 보이는 것처럼 1차원 ndarray로 반환
# iris 의 모든 개별 데이터에 실루엣 계수값을 구함
score_samples = silhouette_samples(iris.data, irisDF['cluster'])
print('silhouette_samples( ) return 값의 shape' , score_samples.shape)
# irisDF에 실루엣 계수 컬럼 추가
irisDF['silhouette_coeff'] = score_samples
silhouette_samples( ) return 값의 shape (150,)
실루엣 스코어도 확인해보자
print(np.mean(score_samples))
print(silhouette_score(iris.data, irisDF['cluster']))
0.5528190123564091
0.5528190123564091
보통 0.5가 넘으면 꽤 좋은 수치라고 함
각 군집별 실루엣 스코어도 확인
irisDF.groupby('cluster')['silhouette_coeff'].mean()
cluster
0 0.417320
1 0.798140
2 0.451105
Name: silhouette_coeff, dtype: float64
cluster 1이 setosa로 추정됨
0.79면 엄청 높은 수치인데, 이전에 해본 경험으로 보면
처음부터 군집이 잘 되어있었음
원본 코드 출처: https://scikit-learn.org/stable/auto_examples/cluster/plot_kmeans_silhouette_analysis.html
시각화 코드 설명은 생략
군집별 실루엣 계수를 시각화해보자
### 여러개의 클러스터링 갯수를 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 을 통해 clustering 을 위한 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)
# cluster 개수를 2개, 3개, 4개, 5개 일때의 클러스터별 실루엣 계수 평균값을 시각화
visualize_silhouette([ 2, 3, 4, 5], X)
- 각 군집별 실루엣 스코어를 나타내고, 실루엣 계수를 시각화한 것임
- 각 군집별 샘플의 실루엣 계수를 아래에서 위로 오름차순으로 쭉 이어서 만든 것
- 실루엣 스코어만 보면 군집이 2일 때가 제일 좋지만, 보통 군집이 4일 때처럼 개별 군집의 실루엣 계수의 평균값의 편차가 작은 게 좋다.
- 군집 수 최적화는 이런식으로 시각화를 주로 이용함!
iris 데이터로도 해보자
from sklearn.datasets import load_iris
iris=load_iris()
visualize_silhouette([ 2, 3, 4,5 ], iris.data)
그나마 군집이 3개일 때가 제일 괜찮을 것 같다.
원래 iris의 Label도 3종류였으니까..