1. 엘보우(Elbow) 기법
- SSE(Sum of Squared Errors)의 값이 점점 줄어들다가 어느 순간 줄어드는 비율이 급격하게 작아지는 부분이 생긴다.
- 결과물인 그래프 모양을 보면 팔꿈치에 해당하는 바로 그 부분이 최적의 클러스터 개수가 된다.
- 간단하고, 이해하기 쉬워 사람들이 많이 사용하는 기법
- Cluster 내 응집도만 고려하고, Cluster 간 분리도는 고려하지 않는다.
- 보통, 엘보우 기법으로 그래프를 확인한 후, cluster의 개수를 2로 해야할지, 3으로 해야할지 헷갈리는 경우에 추가로 실루엣 기법을 사용한다.
def elbow(X):
total_distance = []
for i in range(1, 11):
model = cluster.KMeans(n_clusters=i, random_state=0)
model.fit(X)
# inertia : Sum of squared distances of samples to their closest cluster center.
total_distance.append(model.inertia_)
plt.plot(range(1, 11), total_distance, marker='o')
plt.xlabel('# of clusters')
plt.ylabel('Total distance (SSE)')
plt.show()
2. 실루엣(Silhouette) 기법
- Cluster 내 응집도 뿐만 아니라, Cluster 간 분리도 또한 고려한다.
- 클러스터링의 품질을 정량적으로 계산해주는 방법 (K-means 뿐만 아니라 모든 클러스터링 기법에 적용 가능)
- a(i): 클러스터 내 데이터 응집도(cohesion)를 나타내는 값
(데이터 x(i)와 동일한 클러스터 내의 나머지 데이터들과의 평균 거리)
- b(i): 클러스터 간 분리도(separation)를 나타내는 값
(데이터 x(i)와 가장 가까운 클러스터 내의 모든 데이터들과의 평균 거리)
- 만약 클러스터 개수가 최적화 되어 있다면 b(i)의 값은 크고, a(i)의 값은 작아짐
-> s(i)의 값은 1에 가까운 숫자가 됨
- 반대로 클러스터내 데이터 응집도와 클러스터간 분리도의 값이 같으면 실루엣 계수 s(i)는 0 (데이터들을 클러스터로 분리하는 것이 무의미)
from sklearn.metrics import silhouette_score
model = cluster.KMeans(n_clusters=2) # Change the number of clusters
y_fitted = model.fit_predict(X)
silhouette_avg = silhouette_score(X, y_fitted)
print("The average of silhouette coefficients is :", silhouette_avg)
c.f.) 실루엣 기법의 코드 작동원리와 시각화 그래프가 궁금하면 아래를 참고하면 된다.
import numpy as np
from sklearn.metrics import silhouette_samples
from matplotlib import cm
def plotSilhouette(X, y_fitted):
cluster_labels = np.unique(y_fitted)
n_clusters = cluster_labels.shape[0] # ex) (3,) -> 3
silhouette_vals = silhouette_samples(X, y_fitted, metric='euclidean') # y_fitted 클러스터 라벨을 기준으로 한 X 데이터 각각이 가지는 실루엣 계수를 계산
y_ax_lower, y_ax_upper = 0, 0
yticks = []
for index, label in enumerate(cluster_labels):
cluster_silhouette_vals = silhouette_vals[y_fitted == label] # 각 라벨(center=3이면 0,1,2)에 해당하는 예측 데이터들의 실루엣 계수
cluster_silhouette_vals.sort()
# 라벨 순서대로 클러스터로 할당된 데이터 수만큼 y_ax_upper 에 더하여 y축 방향으로 쌓음
y_ax_upper += len(cluster_silhouette_vals)
plt.barh(range(y_ax_lower, y_ax_upper), cluster_silhouette_vals, height=1.0) # barh(y, data), edge_color=None
yticks.append((y_ax_lower + y_ax_upper) / 2) # 그래프에서 y축 위에 클러스터 번호 라벨링 적용
# 라벨 순서대로 클러스터로 할당된 데이터 수만큼 y_ax_lower 에 더하여 y축 방향으로 쌓음
y_ax_lower += len(cluster_silhouette_vals)
silhouette_avg = np.mean(silhouette_vals) # 전체 데이터에 대한 실루엣 계수의 평균
plt.axvline(silhouette_avg, color='red', linestyle='--') # 전체 데이터에 대한 실루엣 계수의 평균을 수직선으로 표시
print('The average silhouette value is', round(silhouette_avg, 2), '(near 0.7 or 0.7+ : desirable)')
plt.yticks(yticks, cluster_labels+1)
plt.ylabel('Cluster')
plt.xlabel('Silhouette value')
plt.show()
'멋쟁이 사자처럼 AI SCHOOL 5기 > Today I Learned' 카테고리의 다른 글
[5주차 총정리] 훈련모델 및 Scaler 저장 (joblib, pickle) (0) | 2022.04.13 |
---|---|
[5주차 총정리] 비지도 학습(Unsupervised) 모델 시각화 (K-Means, PCA) (0) | 2022.04.13 |
[5주차 총정리] GridSearch 코드 예시 (SVM 기반) (0) | 2022.04.13 |
[5주차 총정리] 지도학습(Supervised) 모델 시각화 (Linear Regression/Logistic Regression/kNN/SVM) (0) | 2022.04.13 |
[5주차 총정리] Gradient Boosting Regression (+ Deviance graph, Feature importances) (0) | 2022.04.12 |