머신러닝 기초 (14) - 군집화: K-means와 계층군집
레이블 없는 데이터에서 비슷한 표본을 묶는 군집화를 다룹니다. K-means의 원리와 k 선택(엘보우, 실루엣), 계층군집, 표준화의 필요성을 iris로 확인한 14편입니다.
머신러닝 기초 시리즈의 14편입니다. 13편까지 지도학습을 다뤘습니다. 여기서부터 세 편은 레이블이 없는 데이터에서 구조를 찾는 비지도학습입니다.
13편까지 다룬 지도학습에는 공통점이 있습니다. 데이터마다 정답 레이블 y가 있었고, 모델은 입력 X에서 그 y를 맞히도록 배웠습니다. 그런데 현실의 데이터에는 y가 없는 경우가 더 많습니다. 고객 목록, 문서 더미, 센서 로그처럼 정답이 붙어 있지 않은 데이터에서 “비슷한 것끼리 묶으면 어떤 무리가 보이는가”를 묻는 것이 군집화입니다.
이 편은 가장 널리 쓰는 두 방법, K-means와 계층군집을 봅니다. 군집화에는 정답이 없으므로 평가 방식도 지도학습과 다릅니다. 그 차이까지 함께 정리합니다.
비지도학습: 정답 없이 구조를 찾는다
지도학습은 (X, y) 쌍으로 학습했습니다. 입력 X와 정답 y가 함께 주어지고, 모델은 그 대응을 배워 새 입력의 y를 예측합니다. 잘 배웠는지는 예측과 실제 y를 비교해 잽니다.
비지도학습에는 y가 없습니다. X만 있습니다. 그래서 목표가 예측이 아니라 데이터 자체의 구조를 드러내는 것으로 바뀝니다. 군집화는 그중에서도 “비슷한 표본을 그룹으로 묶는” 문제입니다. 누가 어느 그룹이라는 정답이 없는 상태에서, 데이터의 생김새만 보고 무리를 나눕니다.
K-means: 중심으로 묶기
K-means는 각 군집을 하나의 중심점(centroid)으로 대표합니다. 군집이 k개면 중심도 k개입니다. 학습은 두 단계를 번갈아 반복합니다.
- 할당: 각 점을 가장 가까운 중심에 배정합니다.
- 갱신: 각 군집에 배정된 점들의 평균 위치로 중심을 다시 계산합니다.
배정이 더 바뀌지 않을 때까지 이 두 단계를 반복합니다. 반복이 진행될수록 각 점에서 자기 중심까지의 거리 제곱합이 줄어듭니다. 이 값을 관성(inertia)이라고 부르며, K-means가 실제로 작게 만드는 대상입니다.
여기서 k는 알고리즘이 찾아 주지 않습니다. 사람이 미리 정해 넣는 값입니다. 알고리즘은 주어진 k에 대해 중심 k개를 배치할 뿐이고, k가 몇이어야 하는지는 뒤에서 따로 정합니다.
K-means는 초기 중심을 어디에 두느냐에 따라 다른 결과로 수렴할 수 있습니다.
n_init은 서로 다른 초기값으로 여러 번 시도해 관성이 가장 작은 결과를 고르는 횟수입니다. 여기서는n_init=10을 쓰고,random_state=42로 고정해 다시 실행해도 같은 결과가 나오게 합니다.
정답이 없으면 평가도 다르다
지도학습은 정확도나 RMSE처럼 예측을 실제 정답과 비교해 평가했습니다(7편, 8편). 군집화에는 비교할 정답이 없습니다. 그래서 정답 없이도 잴 수 있는 내부 지표를 씁니다. 군집이 얼마나 잘 뭉쳤고 서로 얼마나 잘 갈라졌는지를 데이터만으로 재는 값입니다.
대표적인 것이 실루엣(silhouette)입니다. 한 점에 대해, 같은 군집 안 다른 점들과의 평균 거리를 a, 가장 가까운 다른 군집에 속한 점들과의 평균 거리를 b라 하면, 그 점의 실루엣은 다음과 같습니다.
1
(b - a) / max(a, b) # 값의 범위는 -1과 1 사이
1에 가까우면 자기 군집에는 가깝고 이웃 군집과는 멀다는 뜻이라 잘 나뉜 점입니다. 0 근처면 두 군집의 경계에 걸쳐 있고, 음수면 오히려 다른 군집에 더 가까워 잘못 묶인 점입니다. 전체 실루엣 점수는 모든 점의 실루엣을 평균한 값이고, 높을수록 군집이 또렷하게 나뉘었다는 신호입니다.
거리 기반이라 스케일에 민감하다
K-means의 할당도, 실루엣의 계산도 모두 점 사이의 거리로 이뤄집니다. 그런데 거리는 값의 크기에 좌우됩니다. 한 특성은 0에서 1000까지 움직이고 다른 특성은 0에서 1까지만 움직이면, 거리의 대부분을 큰 특성이 차지하고 작은 특성은 사실상 무시됩니다. 군집이 큰 값 특성 하나에 끌려가는 것입니다.
그래서 거리 기반 방법에서는 군집화 전에 표준화를 합니다. 각 특성을 평균 0, 분산 1로 맞춰 같은 눈금에 올리면 특성들이 거리에 고르게 기여합니다. 표준화는 12편에서 다뤘습니다.
iris는 네 특성이 모두 cm 단위라 스케일 차이가 크지 않아 표준화의 영향이 작습니다. 하지만 스케일이 제각각인 데이터에서는 표준화를 빼먹는 순간 결과가 큰 값 특성 하나에 끌려갑니다. 군집화 전에 표준화부터 하는 것을 습관으로 두는 편이 안전합니다.
iris로 K-means 돌려보기
load_iris로 표준화한 뒤 군집 3개로 K-means를 돌려, 관성과 실루엣을 확인합니다. 데이터에는 원래 세 종(species)의 정답 레이블이 있지만, 군집화는 그 y를 쓰지 않습니다. 학습이 끝난 뒤 결과를 확인하는 용도로만 y를 봅니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
X, y = load_iris(return_X_y=True) # 표본 150, 특성 4. y는 확인용으로만
X_scaled = StandardScaler().fit_transform(X) # 거리 기반이라 표준화부터
km = KMeans(n_clusters=3, random_state=42, n_init=10).fit(X_scaled)
labels = km.labels_ # 각 표본이 배정된 군집 번호 0, 1, 2
print(round(km.inertia_, 2)) # 139.82
print(round(silhouette_score(X_scaled, labels), 3)) # 0.46
관성 139.82는 그 자체로는 해석하기 어렵습니다. 절대 크기보다는 k를 바꿔 가며 비교할 때 의미가 있습니다. 실루엣 0.46은 세 군집이 어느 정도 나뉘긴 했지만 완벽하게 갈라지지는 않았다는 정도의 값입니다.
군집 번호 0, 1, 2는 이름표일 뿐 종 번호와 일치하지 않습니다. labels를 y와 대조해 보면, setosa 50개는 한 군집에 온전히 모입니다. 반면 versicolor와 virginica는 경계에서 서로 조금씩 섞입니다. 실루엣이 아주 높지 않은 이유가 여기에 있습니다. 두 종이 특성상 겹치기 때문입니다.
k는 몇으로 정하나: 엘보우와 실루엣
K-means는 k를 사람이 정해야 합니다. 두 가지 방법이 흔히 쓰입니다.
첫째는 엘보우입니다. k를 늘리면 관성은 항상 줄어듭니다. 중심이 많아지니 각 점이 더 가까운 중심을 갖기 때문입니다. 극단적으로 k를 표본 수만큼 늘리면 관성은 0이 됩니다. 그래서 관성의 절대값이 아니라, 관성이 급히 줄다가 감소폭이 뚜렷이 완만해지는 지점을 봅니다.
둘째는 실루엣입니다. k별로 실루엣 점수를 계산해 가장 높은 k를 고릅니다.
1
2
3
4
5
6
7
8
9
# 엘보우용: k=1~6의 관성
for k in range(1, 7):
m = KMeans(n_clusters=k, random_state=42, n_init=10).fit(X_scaled)
print(k, round(m.inertia_, 2)) # 관성은 k가 커질수록 단조 감소
# 실루엣은 군집이 최소 2개여야 정의된다
for k in range(2, 7):
m = KMeans(n_clusters=k, random_state=42, n_init=10).fit(X_scaled)
print(k, round(silhouette_score(X_scaled, m.labels_), 3))
출력을 표로 정리하면 이렇습니다.
| k | 관성(inertia) | 실루엣 |
|---|---|---|
| 1 | 600.00 | (정의 안 됨) |
| 2 | 222.36 | 0.582 |
| 3 | 139.82 | 0.460 |
| 4 | 114.09 | 0.387 |
| 5 | 90.93 | 0.346 |
| 6 | 81.54 | 0.317 |
관성부터 읽습니다. k가 1에서 2로 갈 때 약 378 급감하고, 2에서 3으로 갈 때 약 83 줄어듭니다. 그 뒤로는 26, 23, 9로 감소폭이 완만해집니다. 감소가 뚜렷이 꺾이는 지점은 k가 2에서 3 사이입니다.
실루엣은 k=2에서 0.582로 가장 높고, k=3은 0.460입니다. 즉 두 지표 모두 k=2 쪽을 가리킵니다.
iris의 실제 종은 세 가지인데 두 지표는 k=2를 가리킵니다. versicolor와 virginica가 특성상 겹쳐서, 데이터만 보면 setosa 한 덩이와 나머지 한 덩이로 나뉘어 보이기 때문입니다. 이것이 군집화의 성격을 보여줍니다. 내부 지표는 “진짜 군집 수”를 모릅니다. 엘보우와 실루엣은 후보를 좁혀 줄 뿐, 최종 k는 도메인 지식과 함께 판단해야 합니다.
계층군집과 덴드로그램
계층군집(agglomerative)은 접근이 다릅니다. 처음에는 점 하나하나가 각자 하나의 군집입니다. 그다음 가장 가까운 두 군집을 반복해서 병합해 나갑니다. 모든 점이 하나로 합쳐질 때까지 이 과정을 이어 갑니다.
병합 순서를 나무 모양으로 그린 것이 덴드로그램입니다. 아래에서 위로 올라가며 군집이 합쳐지는 과정을 보여 줍니다. 원하는 높이에서 이 나무를 가로로 자르면 군집 수가 정해집니다. 낮게 자르면 군집이 많아지고 높게 자르면 적어집니다. K-means와 달리 k를 미리 넣지 않고, 병합 구조를 다 만든 뒤 나중에 자른다는 점이 특징입니다.
scikit-learn에서는 AgglomerativeClustering으로 군집 수만 지정해 바로 결과를 얻을 수 있습니다.
1
2
3
4
from sklearn.cluster import AgglomerativeClustering
agg = AgglomerativeClustering(n_clusters=3).fit(X_scaled)
print(round(silhouette_score(X_scaled, agg.labels_), 3)) # 0.447
같은 iris에서 군집 3개의 실루엣은 0.447로, K-means의 0.460과 비슷합니다. 겹치는 두 종 때문에 어느 방법을 써도 세 군집을 또렷이 가르기는 어렵다는 결과입니다. 다만 계층군집은 모든 점 쌍의 거리를 다루므로 데이터가 커지면 K-means보다 느립니다.
정리
| 개념 | 한 줄 요약 |
|---|---|
| 비지도학습 | 레이블 y 없이 X만으로 데이터의 구조를 찾음 |
| 군집화 | 비슷한 표본끼리 그룹으로 묶는 문제 |
| K-means | 중심(centroid) 기반. 할당과 중심 갱신을 반복, k는 사람이 지정 |
| 관성(inertia) | 각 점에서 자기 중심까지 거리 제곱합. 엘보우로 k 후보 판단 |
| 실루엣 | 뭉침과 분리를 -1과 1 사이로 나타냄. 높을수록 좋고 k 비교에 씀 |
| 스케일 민감성 | 거리 기반이라 표준화 필요 (12편) |
| 계층군집 | 가까운 군집을 반복 병합. 덴드로그램을 잘라 k 결정 |
| 평가 | 정답이 없어 내부 지표로 평가. 실제 군집 수와 다를 수 있음 |
다음 글: 머신러닝 기초 (15) - 차원축소: PCA </content> </invoke>