1. 군집분석의 이론적 이해
1. 군집분석 개요 및 목적
- 정의: 군집분석(Cluster Analysis)은 유사한 특성을 가진 **대상(표본, 개체)**을 몇 개의 집단(cluster)으로 묶어주는 분석 기법
- 목적
- **대상 분류**: 표본 간의 유사성을 기준으로 집단화
- **탐색적 분석**: 데이터 내 숨겨진 패턴이나 집단 구조 발견
- **활용 예시**
- 마케팅: 소비자를 특성별로 세분화(예: 가격 민감형, 품질 중시형, 편의성 중시형)
- 생물학: 종(種) 분류
- 교육: 학습 유형별 학생 그룹 분류
👉 **요인분석**은 변수를 묶는 분석, **군집분석**은 대상을 묶는 분석이라는 점을 구분해 강조
2. 군집분석 자료의 조건
- **변수 수준**
- 주로 **등간척도·비율척도** 자료 사용
- 예: 키(cm), 몸무게(kg), 시험 점수
- **표준화 필요성**
- 거리 기반 분석이므로 변수의 단위가 다르면 큰 값의 변수가 더 큰 영향
- 따라서 **표준화(Z-score 변환)** 필수
- 평균=0, 표준편차=1로 변환
- 예: 소득(단위: 만 원)과 나이(단위: 세)를 같이 사용할 때
3. 유사성 측정 방법
- **거리 기반 측정**
- 대상 간 유사성 = 두 점 사이의 거리로 측정
- **유클리디안 거리 (Euclidean Distance)**
$$ d_{ij} = \sqrt{\sum_{k=1}^p (x_{ik} - x_{jk})^2} $$- 가장 직관적이고 널리 사용됨
- 두 대상의 각 변수 차이를 제곱한 뒤 합산 → 제곱근
- **그 외 거리 측정 방법(소개만)**
- 맨해튼 거리(Manhattan Distance): 절댓값 차이의 합
- 마할라노비스 거리(Mahalanobis Distance): 변수 간 상관관계 반영
- **군집분석**: 유사한 대상을 그룹화하는 기법
- **요인분석과 차이점**: 요인분석은 변수를 묶음, 군집분석은 대상을 묶음
- **자료 조건**: 등간·비율척도 자료, 표준화 필수
- **유사성 측정**: 가장 기본은 **유클리디안 거리**
2. Python 실습: 계층적 군집분석
- 준비까지 15분: 표준화·링키지·덴드로그램
- 본 분석 20분: 군집 수 선택·라벨링·프로파일링
- 평가/비교 15분: 실루엣 점수·연결법 비교·주의사항
A) 덴드로그램 기반 군집 수 고르기 & 라벨 부여
from scipy.cluster.hierarchy import fcluster
# (선택) 덴드로그램의 고도(거리)를 보며 3개 군집으로 가정
k = 3
# 방법 1: 군집 개수로 자르기
labels_k = fcluster(linked, t=k, criterion='maxclust')
# (대안) 방법 2: 거리 기준으로 자르기 (예: 임계값 t_dist)
# labels_dist = fcluster(linked, t=7.0, criterion='distance')
# 라벨 붙이기
df['cluster'] = labels_k
df.head()
시각적으로 “자르는 높이” 보기(색으로 표시)
# 덴드로그램에 color_threshold 표시 (임계값은 데이터에 맞게 조정)
plt.figure(figsize=(10, 7))
dendrogram(linked,
orientation='top',
labels=df['고객ID'].tolist(),
distance_sort='descending',
show_leaf_counts=True,
color_threshold=15) # 예: 높이 15 지점
plt.title('고객 군집화 덴드로그램 (color_threshold 예시)')
plt.xlabel('고객')
plt.ylabel('거리')
plt.show()
B) 군집 프로파일링(해석용 요약표 & 표준화 평균)
# 원척도 기준 요약
profile_raw = df.groupby('cluster')[['나이', '월평균_소득', '월평균_소비']].agg(['mean','median','count'])
print("\n[군집 프로파일(원척도)]")
print(profile_raw)
# 표준화 점수로 각 변수의 상대적 높낮이 비교
X_scaled_df = pd.DataFrame(X_scaled, columns=X.columns)
X_scaled_df['cluster'] = labels_k
profile_std = X_scaled_df.groupby('cluster')[['나이','월평균_소득','월평균_소비']].mean().round(2)
print("\n[군집 프로파일(표준화 평균, 0=평균, ±값=평균 대비 편차)]")
print(profile_std)
간단한 레이더/막대 그래프(막대형 예시)
# 군집별 표준화 평균 막대그래프
ax = profile_std.plot(kind='bar', figsize=(8,5))
ax.set_title('군집별 표준화 평균(나이/소득/소비)')
ax.set_xlabel('Cluster')
ax.set_ylabel('표준화 평균')
plt.axhline(0, color='gray', linestyle='--')
plt.tight_layout()
plt.show()
해석 가이드
- 표준화 평균이 **+**면 전체 평균보다 높은 특성, **-**면 낮은 특성
- 예) `cluster 1`: 소득/소비 +, 나이 - → **젊고 소득·소비 높은 그룹**
- 예) `cluster 2`: 나이 +, 소비 - → **연령 높고 소비 낮은 절약형 그룹**
- 예) `cluster 3`: 전반적으로 평균 근처 → **중간형** …(실제 수치로 해석)
C) 군집 품질 간단 평가(실루엣 점수)
from sklearn.metrics import silhouette_score
# 계층 군집 라벨로 실루엣 점수 계산(표준화 데이터 사용)
sil = silhouette_score(X_scaled, labels_k, metric='euclidean')
print(f"\n[실루엣 점수] k={k} → {sil:.3f}")
- 해석: **1에 가까울수록** 군집이 잘 분리, **0 부근**은 경계, **음수**는 군집 혼선.
- 실무에서는 k 값을 바꿔가며(예: 2~6) 실루엣 점수를 비교해 “설득력 있는 k”를 선택하세요.
D) 연결법(method)·거리(metric) 비교(선택)
from scipy.spatial.distance import pdist
from scipy.cluster.hierarchy import cophenet
# 다양한 연결법 비교: 'ward'(기본), 'average', 'complete', 'single'
methods = ['ward', 'average', 'complete']
results = []
Y = pdist(X_scaled, metric='euclidean')
for m in methods:
Zm = linkage(X_scaled, method=m)
coph_corr, _ = cophenet(Zm, Y) # 코페네틱 상관계수 (덴드로그램 보존력 지표)
# 동일 k로 라벨링해 실루엣 점수도 비교
labels_m = fcluster(Zm, t=k, criterion='maxclust')
sil_m = silhouette_score(X_scaled, labels_m)
results.append((m, coph_corr, sil_m))
print("\n[연결법 비교: 코페네틱 상관계수 & 실루엣]")
for m, coph, sil_m in results:
print(f"method={m:8s} cophenetic={coph:.3f} silhouette={sil_m:.3f}")
- **cophenetic**: 원거리 구조를 덴드로그램이 얼마나 충실히 보존했는지(높을수록 좋음)
- **silhouette**: 실제 군집 분리가 얼마나 잘 되었는지(높을수록 좋음)
- 두 지표를 함께 보고, **설명 가능한 k**와 **비즈니스 해석이 의미 있는 구조**를 고르세요.
E) 결과 보고 템플릿(요약 문장 예시)
- **군집 수**: k=3 (덴드로그램 팔꿈치 & 실루엣 비교 결과 채택)
- **프로파일(표준화 평균)**
- Cluster 1: 소득/소비 높고 나이 낮음 → **젊은 고소득·고소비층**
- Cluster 2: 나이 높고 소비 낮음 → **중장년 절약형**
- Cluster 3: 전반 평균 근처 → **중간형**
- **분석 메모**: 표본 수가 작을수록 군집 경계가 불안정할 수 있으니, 추후 표본 확장/변수 추가로 재검증 권장.
F) 실습 체크리스트(요약)
- **표준화** 필수(단위 차이 보정)
- **덴드로그램**으로 구조 파악 → k 후보 선정
- **fcluster**로 라벨 부여
- **프로파일링**으로 해석(원척도/표준화 평균)
- **실루엣·cophenetic** 등으로 기본 품질 점검
- **연결법 비교**로 강건성 확인(ward/average/complete)
3. 군집 결과 해석 및 프로파일링
1. 덴드로그램 해석
- 덴드로그램의 **수평 막대 길이 = 군집 간 거리**
- 긴 수평 막대가 나타나는 지점에서 자르면 적절한 군집 수 결정 가능
- 이번 데이터에서는 **3개의 군집**으로 나누는 것이 합리적
👉 해석 포인트:
- 너무 많은 군집 → 집단 간 차이가 모호해짐
- 너무 적은 군집 → 중요한 차이가 묻힘
2. 군집 할당 및 특성 요약
from scipy.cluster.hierarchy import fcluster
# 1. 3개 군집으로 데이터에 군집 할당
num_clusters = 3
df['군집_레이블'] = fcluster(linked, num_clusters, criterion='maxclust')
# 2. 군집별 특성 파악 (평균값 계산)
cluster_profiles = df.groupby('군집_레이블')[['나이', '월평균_소득', '월평균_소비']].mean()
print("\n--- 군집별 평균 특성 ---")
print(cluster_profiles)
- 출력된 평균값을 통해 각 군집의 특징을 정리
- **표준화된 값**을 함께 비교하면, 전체 평균 대비 어떤 특성이 높은지/낮은지 더 직관적으로 해석 가능
3. 군집별 프로파일링 및 명명
예시 해석:
- **군집 1**: 평균적으로 **나이가 낮고, 소득·소비도 낮음** → *저연령-저소득-저소비 집단*
- **군집 2**: **중년, 중간 수준 소득·소비** → *중년-중간 집단*
- **군집 3**: **연령·소득·소비 모두 높음** → *고연령-고소득-고소비 집단*
👉 이렇게 명명하면 **타겟팅 전략**을 세울 때 유용
- 군집 1: **미래 소비 잠재력** 높은 고객군 (청년층 마케팅)
- 군집 2: **안정적인 소비층** (중년층 중심 상품)
- 군집 3: **프리미엄 소비층** (고소득자 맞춤 전략)
수업 정리
- 덴드로그램으로 군집 수를 시각적으로 확인 → 이번 케이스는 **3개 군집**
- 각 군집에 라벨을 붙이고 **평균 특성**으로 프로파일링
- 군집 이름 부여는 **분석자 해석 + 비즈니스 맥락**을 반영해야 함
K-means 군집분석 비교 실습
1. 데이터 준비 및 표준화
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
import matplotlib.pyplot as plt
# (이전 단계 동일 데이터 사용)
data = {
'고객ID': range(1, 16),
'나이': [25, 30, 45, 50, 35, 60, 28, 40, 55, 33, 48, 52, 29, 38, 43],
'월평균_소득': [300, 350, 500, 550, 400, 650, 320, 450, 600, 380, 520, 580, 310, 420, 480],
'월평균_소비': [100, 120, 250, 280, 180, 320, 110, 200, 290, 150, 260, 270, 120, 190, 240]
}
df = pd.DataFrame(data)
X = df[['나이', '월평균_소득', '월평균_소비']]
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
2. Elbow Method
inertia = []
K_range = range(1, 8) # 1~7개 군집 시험
for k in K_range:
kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
kmeans.fit(X_scaled)
inertia.append(kmeans.inertia_)
# Elbow Plot
plt.figure(figsize=(8, 5))
plt.plot(K_range, inertia, marker='o')
plt.title('Elbow Method')
plt.xlabel('군집 수 (k)')
plt.ylabel('Inertia (군집 내 제곱합)')
plt.grid(True)
plt.show()
- **해석**: Inertia가 급격히 줄어들다가 완만해지는 지점이 **적절한 k** (보통 3 근처).
- 계층적 분석에서 3개 군집이 적합했던 것과 비교 가능.
3. Silhouette Score
sil_scores = {}
for k in range(2, 7): # 2~6개 군집에 대해 계산
kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
labels = kmeans.fit_predict(X_scaled)
sil = silhouette_score(X_scaled, labels)
sil_scores[k] = sil
print("\n--- Silhouette Scores ---")
for k, score in sil_scores.items():
print(f"k={k}: {score:.3f}")
# 시각화
plt.figure(figsize=(8, 5))
plt.plot(list(sil_scores.keys()), list(sil_scores.values()), marker='o')
plt.title('Silhouette Score by k')
plt.xlabel('군집 수 (k)')
plt.ylabel('Silhouette Score')
plt.grid(True)
plt.show()
- **해석**: 실루엣 점수가 가장 높은 k 선택
- 보통 0.5 이상이면 양호, 0.7 이상이면 매우 잘 분리된 군집
4. K-means 군집 실행 및 프로파일링
# 최종 군집 수 (예: 3개)
best_k = 3
kmeans_final = KMeans(n_clusters=best_k, random_state=42, n_init=10)
df['Kmeans_군집'] = kmeans_final.fit_predict(X_scaled)
# 군집별 평균 특성
kmeans_profiles = df.groupby('Kmeans_군집')[['나이', '월평균_소득', '월평균_소비']].mean()
print("\n--- K-means 군집별 평균 특성 ---")
print(kmeans_profiles)
# 시각화 (산점도)
plt.figure(figsize=(8, 6))
plt.scatter(df['월평균_소득'], df['월평균_소비'], c=df['Kmeans_군집'], cmap='viridis', s=100)
plt.xlabel('월평균 소득')
plt.ylabel('월평균 소비')
plt.title('K-means 군집 결과 시각화')
plt.colorbar(label='군집')
plt.show()
5. 결과 해석 및 계층적 군집과 비교
- **계층적 군집분석 결과**
- 군집 1: 저연령-저소득-저소비 집단
- 군집 2: 중년-중간 소득-중간 소비 집단
- 군집 3: 고연령-고소득-고소비 집단
- **K-means 군집분석 결과**
- 유사한 3개 그룹으로 분류됨
- 실루엣 점수 기준으로도 k=3이 합리적
비교 요약
- 두 방법 모두 **3개 군집**이 최적 → 결과 일관성 ↑
- 계층적 분석: **소표본에 적합**, 시각화(덴드로그램)로 직관적 이해 용이
- K-means 분석: **대규모 데이터에 적합**, 빠른 계산과 반복 최적화 가능
수업 마무리 포인트
- **계층적 군집 vs K-means**: 데이터 크기와 목적에 맞게 선택
- **Elbow + Silhouette**: 군집 수 결정 시 반드시 함께 고려
- **프로파일링**: 단순한 수치 요약이 아니라, **군집 특성을 바탕으로 이름을 붙이고 전략 제시**
4. 질의응답 및 요약
1. 최종 정리
군집분석의 핵심 요약
- **군집분석 정의**: 유사한 특성을 가진 대상을 몇 개의 집단(cluster)으로 분류하는 탐색적 분석 기법
- **분석 목적**: 집단별 **특성 파악 & 프로파일링** → 타겟팅 전략·정책 수립에 활용
분석 과정 핵심
- **데이터 준비**
- 변수는 등간/비율척도
- 단위 차이 보정을 위해 **표준화 필수**
- **군집 수 결정**
- 계층적 군집: **덴드로그램** 해석
- K-means: **Elbow Method, Silhouette Score**
- **군집 해석(프로파일링)**
- 각 군집의 평균값을 비교 → 의미 있는 이름 부여
- 예: *저연령-저소득-저소비*, *중년-중간 소비층*, *고연령-고소득 소비층*
방법론 비교
- **계층적 군집**: 표본이 작을 때, 구조적 이해(덴드로그램) 용이
- **K-means 군집**: 대규모 데이터에 적합, 빠른 계산
2. 질의응답
- **예상 질문 & 답변 예시**
- *“덴드로그램에서 군집 수가 애매하면 어떻게 하나요?”*
→ Elbow/Silhouette 같은 보조 지표 활용 - *“군집 결과가 통계적으로 유의한지 검정할 수 있나요?”*
→ 군집분석은 탐색적 성격이 강함, 후속분석(ANOVA, 분산분석 등)으로 검증 가능 - *“군집명이 주관적이지 않나요?”*
→ 네, 연구자/분석자의 해석에 따라 다르므로 **비즈니스·정책 맥락**을 반영해야 함
- *“덴드로그램에서 군집 수가 애매하면 어떻게 하나요?”*