import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
# 3개의 군집을 이루는 500개의 데이터
data, grp = make_blobs(n_samples=500, centers=3, cluster_std=3, random_state=42)
print(data.shape) # (500, 2)
# 시각화
plt.figure(figsize=(5,5))
plt.scatter(data[:,0], data[:,1], c=grp, alpha=.7)
plt.title("Generated Data")
plt.show()
from sklearn.cluster import KMeans
k_list = np.arange(2, 7, 1)
inertia_list = list()
for k in range(2,6):
km = KMeans(n_clusters=k, random_state=42)
grp_km = km.fit_predict(data)
inertia_list.append(km.inertia_)
print("최소 SSE 보유 k 값:", k_list[np.argmin(inertia_list)])
# 최소 SSE 보유 k 값: 5
km = KMeans(n_clusters=5, random_state=42)
grp_km = km.fit_predict(data)
plt.figure(figsize=(5,5))
plt.scatter(data[:,0], data[:,1], c=grp_km, alpha=.7)
plt.title("K-Means (k=5)")
plt.show()
from sklearn.cluster import DBSCAN
from sklearn.metrics import silhouette_score
# 해당 데이터 샘플은 0.1~1.0 범위 내 탐색 시 성능 저하로 탐색 범위 확대
epsilon_list = np.arange(0.1, 3.0, 0.1)
min_samples_list = np.arange(3, 10, 1)
result = list()
# 수동 Grid Search 실시
for epsilon in epsilon_list:
for min_samples in min_samples_list:
dbs = DBSCAN(eps=epsilon, min_samples=min_samples)
grp_dbs = dbs.fit_predict(data)
if len(np.unique(grp_dbs)) == 1:
continue # 실루엣 계수는 최소 2개의 그룹이 존재해야 계산 가능
sil = silhouette_score(data, grp_dbs)
result.append([epsilon, min_samples, sil])
# Grid Search 결과 데이터프레임 생성
res = pd.DataFrame(result, columns=['epsilon', 'min_samples', 'sil']).\
sort_values(by="sil", ascending=False)
print(res.head())
## 출력 결과
# epsilon min_samples sil
# 117 2.1 4 0.486884
# 118 2.1 5 0.483196
# 110 2.0 4 0.480973
# 119 2.1 6 0.478070
# 136 2.3 9 0.473304
from sklearn.cluster import DBSCAN
db = DBSCAN(min_samples=4, eps=2.1)
grp_dbs = db.fit_predict(data)
# 분홍색 점(그룹값: -1)을 이상치로 탐지하는 방식으로도 활용 가능
plt.figure(figsize=(5,5))
plt.scatter(data[:,0], data[:,1], c=grp_dbs, alpha=.7)
plt.title("DBSCAN (eps=2.1, min_samples=4)")
plt.show()
from sklearn.cluster import AgglomerativeClustering
n_clusters_list = np.arange(2, 10, 1)
sil_list = list()
for n_clusters in n_clusters_list:
agc = AgglomerativeClustering(n_clusters=n_clusters)
grp_agc = agc.fit_predict(data)
sil = silhouette_score(data, grp_agc)
sil_list.append(sil)
print("최적 n_clusters 값:", n_clusters_list[np.argmax(sil_list)])
print(f"최고 실루엣 계수 값: {np.max(sil_list):.3f}")
# 최적 n_clusters 값: 3
# 최고 실루엣 계수 값: 0.536
agc = AgglomerativeClustering(n_clusters=3)
grp_agc = agc.fit_predict(data) # 기본 "Euclidean" 거리, "ward" 연결법 사용
plt.figure(figsize=(5,5))
plt.scatter(data[:,0], data[:,1], c=grp_agc, alpha=.7)
plt.title("Agg. H-Clustering (n_clusters=2)")
plt.show()
from scipy.cluster.hierarchy import dendrogram, linkage
Z = linkage(data, method="ward")
plt.figure(figsize=(12,5))
# color_threshold는 덴드로그램을 그려가며 적절하게 조절 필요
dendrogram(Z, color_threshold=100, above_threshold_color="grey")
plt.title("Dendrogram")
plt.xticks([])
plt.show()
from sklearn.cluster import KMeans
def DivisiveClustering(data, k):
# 그룹별로 리스트에 담음
grps = [data]
# 원하는 k개의 그룹이 만들어질 떄까지 반복
while len(grps) < k:
# 가장 큰 그룹을 두 하위 그룹으로 분할
tgt_grp_idx = np.argmax([len(grp) for grp in grps])
tgt_grp = grps.pop(tgt_grp_idx)
km = KMeans(n_clusters=2, random_state=42)
grp_km = km.fit_predict(tgt_grp)
# 분할된 두 그룹을 리스트에 다시 추가
grps.append(tgt_grp[grp_km == 0])
grps.append(tgt_grp[grp_km == 1])
# 리스트 내 각 그룹별 데이터가 다시 리스트로 담겨있는 형태로 반환
return grps
# 분할형 군집분석 실시
grp_dvc = DivisiveClustering(data, 3)
# 그룹 정보를 담은 데이터프레임 생성
res = pd.DataFrame(columns=["col1", "col2", "grp"])
for idx, grp in enumerate(grp_dvc):
df = pd.DataFrame(grp, columns=["col1", "col2"])
df["grp"] = idx
res = pd.concat([res, df], axis=0).reset_index(drop=True)
print(res.shape) # (500, 3)
print(res.head())
# col1 col2 grp
# 0 -3.431807 -8.989639 0
# 1 0.800626 -7.168289 0
# 2 -8.754083 -6.801836 0
# 3 -10.247793 -5.732880 0
# 4 -6.632775 -3.683668 0
print(res.tail())
# col1 col2 grp
# 495 -3.899451 7.617097 2
# 496 -1.478343 3.725166 2
# 497 -5.233270 4.777375 2
# 498 -2.316358 5.781052 2
# 499 -2.740503 10.037742 2
# 시각화
plt.figure(figsize=(5,5))
plt.scatter(res.iloc[:,0], res.iloc[:,1], c=res.grp, alpha=.7)
plt.title("Div. H-Clustering (k=3)")
plt.show()
*이 글은 제로베이스 데이터 취업 스쿨의 강의 자료 일부를 발췌하여 작성되었습니다.