Silver bullet
Clustering & K-means Algorithm / 클러스터 수 결정 기법 - Elbow method & Silhouette score 본문
AI/AI
Clustering & K-means Algorithm / 클러스터 수 결정 기법 - Elbow method & Silhouette score
밀크쌀과자 2024. 7. 11. 15:08K-means Algorithm - 비지도 학습
- K개의 임의의 중심값을 고른다. (보통 데이터 샘플 중의 하나를 선택)
- 각 데이터마다 중심값까지의 거리를 계산하여 가까운 중심값의 클러스터에 할당한다.
- 각 클러스터에 속한 데이터들의 평균값으로 각 중심값을 이동시킨다.
- 데이터에 대한 클러스터 할당이 변하지 않을 때까지 2와 3을 반복한다.
x 데이터 열이 많아질수록, 클러스터 개수가 많아질수록 계산 시간이 오래걸린다.
from sklearn import cluster
import numpy as np
import warnings
warnings.filterwarnings("ignore") # 불필요한 Warning 메시지를 꺼줍니다.
# 데이터 준비
X = np.array([[2, 4], [2, 8], [2, 0],
[8, 9], [4, 0], [0, 4]])
X
kmeans = cluster.KMeans(n_clusters=2, random_state=0).fit(X)
kmeans
print("Clusters : ", kmeans.labels_)
print("Cluster centroids: ", kmeans.cluster_centers_) # 학습이 끝난 중심값을 확인하려면?
Clusters : [0 1 0 1 0 0]
Cluster centroids: [[2. 2. ]
[5. 8.5]]
# 학습이 끝난 모델 테스트 하기 (on test data)
print("Prediction cluster of [0, 0], [8, 4]: ", (kmeans.predict([[0, 0], [8, 4]])))
Prediction cluster of [0, 0], [8, 4]: [0 1]
K-means for Iris data
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from sklearn import cluster
from sklearn import datasets
from sklearn import metrics
# 붓꽃 데이터 읽어들이기
iris = datasets.load_iris()
X = iris.data
y = iris.target
print(X)
print()
print(y)
# 비어있는 모델 객체 만들기 + 모델 학습시키기
estimators = [('k=8', cluster.KMeans(n_clusters=8)),
('k=3', cluster.KMeans(n_clusters=3)),
('k=3(r)', cluster.KMeans(n_clusters=3, n_init=1, init='random'))] # random init
print(estimators[0]), print()
print(estimators[1]), print()
print(estimators[2])
# K-Means++ 알고리즘 : 최초의 중심값을 설정하기 위한 개선된 알고리즘
# 참고 : https://goo.gl/1ghahK & https://goo.gl/69zSB2
기본적으로 default로는 init이 ' k-means++ '로 설정되어 안정적인 클러스터를 고를 수 있게 되나, init을 cluster.KMeans(n_clusters=3, n_init=1, init='random') 다음과 같이 random으로 설정하면 클러스터 분석이 잘 이루어지지 않을 수도 있다.
3D 모델 시각화 코드
fignum = 1
titles = ['8 clusters', '3 clusters', '3 clusters, bad initialization']
for name, est in estimators: # estimators : ('k=8', cluster.KMeans(n_clusters=8))
fig = plt.figure(fignum, figsize=(7, 7))
ax = Axes3D(fig, elev=48, azim=134) # Set the elevation and azimuth of the axes. (축의 고도와 방위각)
est.fit(X)
labels = est.labels_ # 150행 x데이터 행 각각에 대한 클러스터 번호(150개의 숫자)
# X = iris.data
ax.scatter(X[:, 3], X[:, 0], X[:, 2], c=labels.astype(np.float64), edgecolor='w', s=100)
ax.w_xaxis.set_ticklabels([])
ax.w_yaxis.set_ticklabels([])
ax.w_zaxis.set_ticklabels([])
ax.set_xlabel('Petal width')
ax.set_ylabel('Sepal length')
ax.set_zlabel('Petal length')
ax.set_title(titles[fignum - 1])
ax.dist = 12 # 값이 커지면 전체 plot 이 작아짐
fignum = fignum + 1
plt.show()
- 정답이 존재하지 않는 경우, 클러스터를 몇개로 설정할 지 애매한 경우가 있다. → 클러스터링 모델 품질 평가
최적 클러스터 개수 찾기
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from sklearn import cluster
from sklearn import datasets
from sklearn import metrics
import warnings
warnings.filterwarnings("ignore") # 불필요한 Warning 메시지를 꺼줍니다.
iris = datasets.load_iris()
X = iris.data
y = iris.target
(1) 엘보우(elbow) 기법 :
- SSE(Sum of Squared Errors)의 값이 점점 줄어들다가 어느 순간 줄어드는 비율이 급격하게 작아지는 부분이 생기는데,
- 결과물인 그래프 모양을 보면 팔꿈치에 해당하는 바로 그 부분이 최적의 클러스터 개수가 됨.
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.
# inertia : 각 샘플마다 자신이 속한 클러스터의 센터까지의 거리를 계산한 후, 모든 거리 값들을 제곱해서 합친 값
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()
elbow(X) # Iris case : 2

위의 경우 2 - 3 정도가 적당함
(2) 실루엣(silhouette) 기법 :
- 클러스터링의 품질을 정량적으로 계산해주는 방법 (K-means 뿐만 아니라 모든 클러스터링 기법에 적용 가능)
- i번째 데이터 x(i)에 대한 실루엣 계수(silhouette coefficient) s(i) 값은 아래의 식으로 정의

- a(i)는 클러스터 내 데이터 응집도(cohesion)를 나타내는 값 == 데이터 x(i)와 동일한 클러스터 내의 나머지 데이터들과의 평균 거리
- b(i)는 클러스터 간 분리도(separation)를 나타내는 값 == 데이터 x(i)와 가장 가까운 클러스터 내의 모든 데이터들과의 평균 거리
- 만약 클러스터 개수가 최적화 되어 있다면 b(i)의 값은 크고, a(i)의 값은 작아짐 -> s(i)의 값은 1에 가까운 숫자가 됨
- 반대로 클러스터내 데이터 응집도와 클러스터간 분리도의 값이 같으면 실루엣 계수 s(i)는 0 (데이터들을 클러스터로 분리하는 것이 무의미)
- 요약) 클러스터의 개수가 최적화되어 있으면 실루엣 계수의 값은 1에 가까운 값이 됨
# 활용 x
# 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()
# model = cluster.KMeans(n_clusters=2) # Change the number of clusters
# y_fitted = model.fit_predict(X)
# plotSilhouette(X, y_fitted)
The average silhouette value is 0.68 (near 0.7 or 0.7+ : desirable)

# 간단하게 실루엣 계수의 평균만을 바로 구해 확인해 볼 수 있습니다 (for 문을 활용하여 여러 cluster 수를 기준으로 한 모델을 동시 비교 가능)
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)
The average of silhouette coefficients is : 0.6810461692117462
실루엣 값의 평균값이 0.7 이상이면 클러스터링이 잘 되었다고 말할 수 있다.
'AI > AI' 카테고리의 다른 글
| IQR 기반 Outlier 탐지 및 제거 & SMOTE Over-sampling (0) | 2024.07.12 |
|---|---|
| Dimensionality Reduction & PCA (0) | 2024.07.11 |
| K-Nearest Neighbor Algorithm (0) | 2024.07.11 |
| SVM - Soft-margin Kernelized SVM / StandardScaler, HPO & GridSearchCV (0) | 2024.07.10 |
| Adaboost & Gradient Boosting & XGBoost / Gradient Boosting regression & classification 실습 코드 (0) | 2024.07.10 |