
→ "정답 없이, 데이터 자체를 분석해서 비슷한 것끼리 뭉쳐보자."는 것이 Clustering이다.
비지도 학습 → 정답(y)이 없음패턴 탐색 → 비슷한 데이터끼리 그룹 찾기거리 기반 → 보통 거리(distance)를 사용해서 유사성 판단| 알고리즘 | 특징 |
|---|---|
| K-Means | 가장 대표적인 Clustering 알고리즘. 거리 기반, 중심(k개)을 정해서 묶음 |
| Hierarchical Clustering | 계층적으로 그룹을 합치거나 쪼갬 (덴드로그램 트리로 표현 가능) |
| DBSCAN | 밀집된 지역을 클러스터로 정의, 노이즈에 강함 |
| Gaussian Mixture Model (GMM) | 데이터가 여러 개의 가우시안(정규분포)으로 이루어졌다고 가정 |
| 문제점 | 이유 |
|---|---|
| 클러스터 개수(k) 사전에 정해야 함 (k-means) | 자동으로 안 정해줌 |
| 이상치에 민감할 수 있음 | 특히 거리 기반 알고리즘은 이상치에 약함 |
| 데이터 모양에 따라 잘 안 될 수도 있음 | 동그란 그룹은 잘 되는데, 복잡한 모양은 힘듦 |
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import numpy as np
# 샘플 데이터 생성
X = np.random.rand(100, 2)
# KMeans 모델 만들기
kmeans = KMeans(n_clusters=3, random_state=42)
kmeans.fit(X)
# 결과
labels = kmeans.labels_ # 데이터가 속한 클러스터
centers = kmeans.cluster_centers_ # 각 클러스터 중심
# 시각화
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis')
plt.scatter(centers[:, 0], centers[:, 1], c='red', marker='X', s=200)
plt.title('K-Means Clustering')
plt.grid()
plt.show()
from sklearn.datasets import load_iris
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
# load iris
iris = load_iris()
# 전처리
cols = [each[:-5] for each in iris.feature_names]
iris_df = pd.DataFrame(iris.data, columns=cols)
iris_df.head()
# 사용할 feature 정의
features = iris_df[['petal length', 'petal width']]
features.head()
model = KMeans(n_clusters=3)
model.fit(features)
model.labels_

model.cluster_centers_

# Feature와 예측값 합친 데이터프레임 생성
predict = pd.DataFrame(model.predict(features), columns=['cluster'])
feature = pd.concat([features, predict], axis=1)
# 시각화를 위해 각 cluster의 x, y 좌표값 추출
centers = pd.DataFrame(model.cluster_centers_, columns=['petal length', 'petal width'])
center_x = centers['petal length']
center_y = centers['petal width']
# 시각화
plt.figure(figsize=(10,5))
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()

군집 결과 평가를 위해서는 실루엣 분석을 주로 활용한다.
# Import
from sklearn.metrics import silhouette_samples, silhouette_score
# 데이터 읽기
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).fit(iris_df)
# 군집 결과 정리
iris_df['cluster'] = kmeans.labels_
# 군집 결과 평가를 위한 작업
avg_value = silhouette_score(iris_df, iris_df['cluster'])
score_values = silhouette_samples(iris_df, iris_df['cluster'])
# 실루엣 플랏 그리는 함수 정의
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)
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="--")
# 실루엣 플랏 그리기
visualize_silhouette([2, 3, 4], iris.data)

실루엣 플랏을 통해 cluster 수는 몇개가 가장 적절한지를 시각적으로 확인해볼 수 있다. 여기서 cluster 2개가 가장 적절하다고 해석할 수 있겠다. (실루엣 플랏에 대한 설명은 아래에)
클러스터링 결과가 얼마나 잘 나왔는지를 보여주는 그래프.
실루엣 점수는 -1 ~ 1 사이 값을 가진다.
| 점수 범위 | 해석 |
|---|---|
| 1에 가까움 | 잘 군집화됨 (다른 클러스터와 확실히 분리됨) |
| 0 근처 | 두 클러스터 경계에 걸쳐 있음 (모호) |
| 0보다 작음 | 잘못 군집화됨 (다른 클러스터에 속했어야 함) |
(이 글은 제로베이스 데이터 취업 스쿨의 강의 자료 일부를 발췌하여 작성되었습니다.)