머신러닝 - 비지도학습(덴드로그램, K-Means)
26 Aug 2025 | Machine Learning개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.
비지도 학습?
보유한 데이터에 타겟값(y)가 없는 경우
- 계층적 군집화 > 덴드로그램
- 비계층적 군집화 > K-Means, DBSCAN 등을 사용
덴드로그램
모델을 구동 후 사후적으로 군집을 나눌 수 있음

위 그림에서 내가 2000을 기준으로 군집을 나눈다면, 위에서 군집은 총 4개로 나뉘게 됨! (2000을 기준으로 가로 직선을 그어보면 됨)
하지만 이는 연산이 많아질 수 있고, 초반에 잘못 분류되면 오분류의 가능성이 있다는 단점이 존재함.
K-Means

라이브러리 불러오기
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
데이터 불러오기
iris = load_iris()
X = iris.data
모델 정의
# n_clusters: 데이터의 센트로이드를 설정
# 센트로이드: 군집의 중심 > 그 중심을 내가 정해주는 것 > 몇개의 군집으로 설정할 것인지?
kmeans = KMeans(n_clusters=3, random_state=42)
모델 훈련
kmeans.fit(X)
cluster = kmeans.fit_predict(X)
시각화 > 주성분 분석(PCA)
labels = kmeans.labels_
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)
centroids = pca.transform(kmeans.cluster_centers_)
plt.figure(figsize=(10, 7))
plt.scatter(X_pca[:, 0], X_pca[:, 1], c=labels, cmap='viridis', marker='o', edgecolor='k', s=50)
plt.scatter(centroids[:, 0], centroids[:, 1], c='red', marker='X', s=200, label='Centroids')
plt.title('K-Means Clustering on Iris Dataset')
plt.xlabel('PCA Component 1')
plt.ylabel('PCA Component 2')
plt.legend()
plt.show()

K-Means의 약점은 초반 센트로이드를 선택해야하는 것이다. 이를 보완한 라이브러리로는
- 엘보우
- 실루엣 계수 가 있다.
실습해보기
data = {
'연간구매금액': [20, 25, 30, 100, 120, 110, 200, 250, 220],
'연간방문횟수': [5, 8, 6, 20, 25, 22, 40, 45, 38]
}
df = pd.DataFrame(data)
데이터 스케일링
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X = scaler.fit_transform(df)
K-Means
kmeans = KMeans(n_clusters=3, random_state=42)
# kmeans.fit(X)
# cluster_labels = kmeans.labels_
cluster_labels = kmeans.fit_predict(X)
결과 확인
df['고객그룹'] = cluster_labels
시각화
plt.figure(figsize=(10, 6))
colors = ['red', 'blue', 'green']
for i in range(3):
mask = cluster_labels == i
plt.scatter(df[mask]['연간구매금액'], df[mask]['연간방문횟수'],
c=colors[i], label=f'그룹 {i+1}', s=100)
# 중심점 표시
centers_original = scaler.inverse_transform(kmeans.cluster_centers_)
plt.scatter(centers_original[:, 0], centers_original[:, 1],
c='black', marker='x', s=200, linewidths=3, label='중심점')
plt.xlabel('연간 구매금액 (만원)')
plt.ylabel('연간 방문횟수')
plt.title(' 고객 세분화 결과')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
