튜토리얼
10. Imbalanced Data

10. Imbalanced Data (불균형 데이터) 완전정복

SMOTE, Class Weight, 평가 지표 선택


학습 목표

이 튜토리얼을 완료하면 다음을 할 수 있습니다:

  1. 불균형 데이터의 정의와 실제 문제 사례 이해
  2. 오버샘플링 기법 (SMOTE, ADASYN) 구현 및 원리 이해
  3. 언더샘플링 기법 (Random, Tomek Links) 구현
  4. Class Weight 조정을 통한 비용 민감 학습
  5. 적절한 평가 지표 (F1, ROC-AUC, PR-AUC) 선택 및 해석
  6. Threshold 조정을 통한 성능 최적화

핵심 개념

1. 불균형 데이터란?

클래스 간 샘플 수 차이가 크게 나는 데이터입니다.

실제 사례다수 클래스소수 클래스 비율
사기 탐지정상 거래사기 0.1%
의료 진단정상 환자희귀 질환 1%
제조 불량정상 제품불량품 2%
고객 이탈유지 고객이탈 고객 5%

왜 문제인가?

예: 1000개 데이터 (정상 990개, 사기 10개)

모델: "모든 거래가 정상" 예측
→ Accuracy: 99%  (높아 보이지만...)
→ 사기 탐지율: 0%  (완전히 무용지물!)
⚠️

Accuracy가 높아도 소수 클래스를 전혀 탐지하지 못할 수 있습니다. 불균형 데이터에서는 Accuracy를 신뢰하면 안 됩니다.


2. 해결 방법 분류

카테고리방법설명
데이터 레벨Over/Under Sampling샘플 수 조정
알고리즘 레벨Class Weight, Cost-Sensitive손실 함수 조정
평가 레벨적절한 메트릭 선택F1, AUC 등
임계값 레벨Threshold 조정확률 기준값 변경

3. 오버샘플링 (Oversampling)

소수 클래스의 샘플 수를 늘려 균형을 맞춥니다.

Random Oversampling

소수 클래스 샘플을 무작위로 복제합니다.

from imblearn.over_sampling import RandomOverSampler
 
ros = RandomOverSampler(random_state=42)
X_resampled, y_resampled = ros.fit_resample(X, y)

SMOTE (Synthetic Minority Over-sampling Technique)

소수 클래스의 합성 샘플을 생성합니다.

from imblearn.over_sampling import SMOTE
 
smote = SMOTE(random_state=42)
X_resampled, y_resampled = smote.fit_resample(X, y)

SMOTE 원리:

  1. 소수 클래스 샘플 선택
  2. k-최근접 이웃 중 하나 선택
  3. 두 샘플 사이의 선형 보간으로 새 샘플 생성

SMOTE는 단순 복제가 아닌 새로운 합성 샘플을 생성하므로, 다양성을 증가시켜 과적합 위험을 줄입니다.

ADASYN (Adaptive Synthetic Sampling)

SMOTE의 변형으로, 학습하기 어려운 샘플에 더 집중합니다.

from imblearn.over_sampling import ADASYN
 
adasyn = ADASYN(random_state=42)
X_resampled, y_resampled = adasyn.fit_resample(X, y)

4. 언더샘플링 (Undersampling)

다수 클래스의 샘플 수를 줄여 균형을 맞춥니다.

Random Undersampling

다수 클래스에서 무작위로 샘플을 제거합니다.

from imblearn.under_sampling import RandomUnderSampler
 
rus = RandomUnderSampler(random_state=42)
X_resampled, y_resampled = rus.fit_resample(X, y)
⚠️

Random Undersampling은 정보 손실이 크게 발생할 수 있습니다. 예: 8000개 → 800개 (90% 손실)

Tomek Links

클래스 경계의 모호한 샘플을 제거하여 경계를 명확히 합니다.

from imblearn.under_sampling import TomekLinks
 
tomek = TomekLinks()
X_resampled, y_resampled = tomek.fit_resample(X, y)

Tomek Link: 서로 다른 클래스의 가장 가까운 이웃 쌍

  • 다수 클래스의 Tomek Link 샘플 제거 → 경계 명확화

5. 복합 기법 (Over + Under)

오버샘플링과 언더샘플링을 결합하여 장점을 극대화합니다.

from imblearn.combine import SMOTETomek
 
smote_tomek = SMOTETomek(random_state=42)
X_resampled, y_resampled = smote_tomek.fit_resample(X, y)

SMOTETomek 원리:

  1. SMOTE로 소수 클래스 합성
  2. Tomek Links로 노이즈 제거

6. Class Weight

손실 함수에서 소수 클래스에 더 큰 가중치를 부여합니다.

from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
 
# 자동 계산 (불균형 비율의 역수)
model = LogisticRegression(class_weight='balanced')
 
# 직접 지정
model = RandomForestClassifier(class_weight={0: 1, 1: 10})

balanced 공식: weight = n_samples / (n_classes * n_samples_class)

가중치 계산 예시

from sklearn.utils.class_weight import compute_class_weight
 
# 예: 7600개 vs 400개 (19:1 비율)
weights = compute_class_weight('balanced', classes=[0, 1], y=y_train)
# Class 0: 0.5263
# Class 1: 10.0000  (19배 높은 가중치)

Class Weight는 데이터 자체를 변경하지 않으므로, 원본 데이터 분포를 유지하면서 불균형을 보정할 수 있습니다.

Random Forest의 balanced_subsample

rf_balanced = RandomForestClassifier(
    n_estimators=100,
    class_weight='balanced_subsample',  # 각 트리 부트스트랩 샘플에 적용
    random_state=42
)

7. 평가 지표 선택

Accuracy를 쓰면 안 되는 이유

99% 정상, 1% 사기 데이터에서:
→ 모두 정상 예측해도 Accuracy = 99%
→ 하지만 사기 탐지 완전 실패!

권장 지표

지표공식의미사용 시점
PrecisionTP/(TP+FP)양성 예측 중 실제 양성 비율FP 비용 클 때
RecallTP/(TP+FN)실제 양성 중 탐지 비율FN 비용 클 때
F1-Score2×P×R/(P+R)Precision과 Recall 조화평균균형 필요
PR-AUCPR 곡선 면적불균형에 민감한 종합 평가불균형 심할 때
ROC-AUCROC 곡선 면적분류 능력 종합 평가일반적

ROC-AUC vs PR-AUC: 불균형 데이터에서는 PR-AUC가 더 민감합니다. ROC-AUC는 TN이 많을 때 높게 나오는 경향이 있어, 극심한 불균형에서는 PR-AUC를 권장합니다.


8. Threshold 조정

기본 threshold (0.5) 대신 비즈니스 요구사항에 맞게 조정합니다.

from sklearn.metrics import precision_recall_curve
 
# Threshold 별 Precision/Recall 계산
precision, recall, thresholds = precision_recall_curve(y_test, y_proba)
 
# 특정 Recall 보장 threshold 찾기
target_recall = 0.9
idx = np.argmax(recall >= target_recall)
optimal_threshold = thresholds[idx]
 
# 최적 threshold 적용
y_pred_optimal = (y_proba >= optimal_threshold).astype(int)

Threshold를 낮추면 Recall 증가, Precision 감소, 높이면 그 반대입니다. 비즈니스 비용을 고려하여 선택하세요.


코드 요약

SMOTE + Model Pipeline

from imblearn.over_sampling import SMOTE
from imblearn.pipeline import Pipeline as ImbPipeline
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, roc_auc_score
 
# SMOTE + Model Pipeline
pipeline = ImbPipeline([
    ('smote', SMOTE(random_state=42)),
    ('classifier', RandomForestClassifier(random_state=42))
])
 
pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_test)
 
# 평가
print(classification_report(y_test, y_pred))

Class Weight 방식

model_weighted = RandomForestClassifier(
    class_weight='balanced',
    random_state=42
)
model_weighted.fit(X_train, y_train)

올바른 Cross-Validation with SMOTE

from imblearn.pipeline import Pipeline as ImbPipeline
from sklearn.model_selection import cross_val_score, StratifiedKFold
 
# imblearn Pipeline (SMOTE + 모델)
pipeline = ImbPipeline([
    ('smote', SMOTE(random_state=42)),
    ('classifier', LogisticRegression(max_iter=1000, random_state=42))
])
 
# Stratified K-Fold (각 fold 내에서 SMOTE 적용)
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(pipeline, X_train, y_train, cv=skf, scoring='f1')
 
print(f'Mean F1: {scores.mean():.3f}{scores.std():.3f})')
🚫

중요: 리샘플링은 Train 데이터에만 적용해야 합니다. Test 데이터는 원본을 유지하세요. CV에서는 imblearn의 Pipeline을 사용하면 각 fold 내에서만 SMOTE가 적용됩니다.


방법 비교

방법장점단점
Random Undersampling빠름, 학습 시간 단축정보 손실 큼
Random Oversampling정보 보존과적합 위험 (단순 복제)
SMOTE다양성 증가, 새로운 샘플 생성노이즈 생성 가능
ADASYN어려운 샘플에 집중SMOTE보다 더 많은 노이즈 가능
Tomek Links경계 명확화소량만 제거됨
SMOTETomek장점 결합계산 비용 증가
Class Weight데이터 변경 없음모델 의존적

실전 가이드

상황권장 방법
데이터 충분Undersampling 또는 Class Weight
데이터 부족SMOTE 또는 ADASYN
트리 기반 모델Class Weight (balanced/balanced_subsample)
노이즈가 많음SMOTETomek (노이즈 제거)
심각한 불균형 (100:1 이상)SMOTE + Class Weight 결합
실시간 예측 필요Class Weight (학습 시간 단축)

Best Practices

  1. 항상 층화 샘플링 사용: stratify=y로 Train/Test 분할
  2. 리샘플링은 Train에만: Test 데이터는 원본 유지
  3. Cross-Validation 주의: StratifiedKFold 사용, 각 fold 내에서 리샘플링
  4. 평가 지표 선택: Accuracy 대신 F1, ROC-AUC, PR-AUC 사용
  5. Threshold 조정 고려: 비즈니스 요구사항에 맞게 최적화

면접 질문 맛보기

  1. 불균형 데이터에서 Accuracy가 왜 부적절한가요?
  2. SMOTE의 원리와 한계는 무엇인가요?
  3. Precision과 Recall 중 무엇을 중시해야 하나요?
  4. ROC-AUC와 PR-AUC의 차이는?
  5. Class Weight는 어떻게 계산되나요?

더 많은 면접 질문은 Premium Interviews (opens in a new tab)에서 확인하세요.


실습 노트북

불균형 데이터 처리의 모든 기법을 직접 실습해보세요:

노트북에서는 추가로 다음 내용을 다룹니다:

  • 불균형 데이터 생성 및 시각화 (PCA 2D 투영)
  • 모든 방법의 성능 비교 실험 (6가지 방법)
  • ROC Curve vs PR Curve 비교 분석
  • Threshold 변화에 따른 성능 변화 시각화
  • Random Forest의 balanced_subsample 활용
  • 연습문제 (극단적 불균형, 비용 민감 학습, 다중 클래스)

이전: 09. Anomaly Detection | 다음: 11. Time Series