본문으로 건너뛰기

025 불균형 데이터 처리 - SMOTE 활용

키워드: SMOTE, 오버샘플링

개요

SMOTE(Synthetic Minority Over-sampling Technique)는 소수 클래스의 합성 샘플을 생성하는 대표적인 오버샘플링 기법입니다. 이 글에서는 SMOTE의 원리와 다양한 변형을 다룹니다.

실습 환경

  • Python 버전: 3.11 권장
  • 필요 패키지: pycaret[full]>=3.0, imbalanced-learn

SMOTE 원리

  1. 소수 클래스에서 샘플 선택
  2. k개의 최근접 이웃 찾기
  3. 이웃 중 하나를 무작위 선택
  4. 두 점 사이에 새 샘플 생성
# 025 시각적 이해
# 025 원본: A와 B가 소수 클래스 샘플
# 025 A ●─────────● B
#
# 025 SMOTE: A와 B 사이에 새 샘플 생성
# 025 A ●────●────● B
# 025 ↑
# 025 합성 샘플

기본 SMOTE 사용

from pycaret.classification import *
from pycaret.datasets import get_data
from imblearn.over_sampling import SMOTE

data = get_data('credit')

# 025 원본 클래스 분포
print("원본 분포:")
print(data['default'].value_counts())

# 025 SMOTE 적용
clf = setup(
data,
target='default',
fix_imbalance=True,
fix_imbalance_method=SMOTE(random_state=42),
session_id=42,
verbose=False
)

# 025 모델 학습
model = create_model('rf', verbose=False)

SMOTE 파라미터

from imblearn.over_sampling import SMOTE

# 025 기본 SMOTE
smote_basic = SMOTE(
sampling_strategy='auto', # 자동 균형
k_neighbors=5, # 이웃 수
random_state=42
)

# 025 sampling_strategy 옵션
smote_half = SMOTE(
sampling_strategy=0.5, # 다수:소수 = 2:1
random_state=42
)

smote_full = SMOTE(
sampling_strategy=1.0, # 완전 균형 (1:1)
random_state=42
)

SMOTE 변형들

1. Borderline-SMOTE

결정 경계 근처의 샘플에만 적용:

from imblearn.over_sampling import BorderlineSMOTE

borderline = BorderlineSMOTE(
kind='borderline-1', # 또는 'borderline-2'
random_state=42
)

clf = setup(
data, target='default',
fix_imbalance=True,
fix_imbalance_method=borderline,
session_id=42, verbose=False
)

2. SVM-SMOTE

SVM을 사용해 결정 경계 식별:

from imblearn.over_sampling import SVMSMOTE

svm_smote = SVMSMOTE(random_state=42)

clf = setup(
data, target='default',
fix_imbalance=True,
fix_imbalance_method=svm_smote,
session_id=42, verbose=False
)

3. ADASYN

어려운 샘플 위주로 더 많이 생성:

from imblearn.over_sampling import ADASYN

adasyn = ADASYN(random_state=42)

clf = setup(
data, target='default',
fix_imbalance=True,
fix_imbalance_method=adasyn,
session_id=42, verbose=False
)

오버샘플링 후 노이즈 제거:

from imblearn.combine import SMOTETomek

smote_tomek = SMOTETomek(random_state=42)

clf = setup(
data, target='default',
fix_imbalance=True,
fix_imbalance_method=smote_tomek,
session_id=42, verbose=False
)

SMOTE + ENN (Edited Nearest Neighbors)

from imblearn.combine import SMOTEENN

smote_enn = SMOTEENN(random_state=42)

clf = setup(
data, target='default',
fix_imbalance=True,
fix_imbalance_method=smote_enn,
session_id=42, verbose=False
)

SMOTE 방법 비교 실험

from pycaret.classification import *
from pycaret.datasets import get_data
from imblearn.over_sampling import SMOTE, BorderlineSMOTE, SVMSMOTE, ADASYN
from imblearn.combine import SMOTETomek, SMOTEENN

data = get_data('credit')

methods = {
'SMOTE': SMOTE(random_state=42),
'BorderlineSMOTE': BorderlineSMOTE(random_state=42),
'SVMSMOTE': SVMSMOTE(random_state=42),
'ADASYN': ADASYN(random_state=42),
'SMOTETomek': SMOTETomek(random_state=42),
'SMOTEENN': SMOTEENN(random_state=42)
}

results = []

for name, method in methods.items():
print(f"\n=== {name} ===")

clf = setup(
data, target='default',
fix_imbalance=True,
fix_imbalance_method=method,
session_id=42, verbose=False
)

model = create_model('rf', verbose=False)
metrics = pull()

results.append({
'method': name,
'recall': metrics['Recall'].mean(),
'precision': metrics['Prec.'].mean(),
'f1': metrics['F1'].mean(),
'auc': metrics['AUC'].mean()
})

import pandas as pd
df = pd.DataFrame(results)
print("\n=== 결과 비교 ===")
print(df.sort_values('f1', ascending=False))

SMOTE 사용 시 주의사항

1. k_neighbors 설정

# 025 소수 클래스 샘플이 적을 때
# 025 k_neighbors를 샘플 수보다 작게 설정

minority_count = data['default'].sum()
k = min(5, minority_count - 1)

smote = SMOTE(k_neighbors=k, random_state=42)

2. 범주형 변수 처리

# 025 SMOTE는 수치형 데이터에 적합
# 025 범주형이 많으면 SMOTENC 사용

from imblearn.over_sampling import SMOTENC

# 025 categorical_features: 범주형 컬럼 인덱스 리스트
smotenc = SMOTENC(
categorical_features=[0, 2, 5], # 범주형 컬럼 인덱스
random_state=42
)

3. 과적합 방지

# 025 SMOTE는 학습 데이터에만 적용
# 025 교차 검증 시 각 폴드에서 독립적으로 적용해야 함
# 025 PyCaret은 이를 자동으로 처리

언제 SMOTE를 사용하면 안 되나?

  1. 클래스 중첩이 심할 때: 노이즈 증가
  2. 소수 클래스가 너무 적을 때 (< 6개): k-neighbors 문제
  3. 고차원 데이터: 차원의 저주
# 025 대안: 클래스 가중치 사용
clf = setup(data, target='default', session_id=42, verbose=False)

model = create_model(
'rf',
class_weight='balanced', # 클래스 가중치 자동 조정
verbose=False
)

정리

  • SMOTE는 소수 클래스의 합성 샘플을 생성
  • k-neighbors 기반으로 새로운 샘플 생성
  • BorderlineSMOTE, SVMSMOTE, ADASYN 등 변형 존재
  • SMOTETomek, SMOTEENN으로 노이즈 제거 가능
  • 범주형 데이터에는 SMOTENC 사용
  • 교차 검증과 함께 사용 시 주의 (PyCaret은 자동 처리)

다음 글 예고

다음 글에서는 로지스틱 회귀 상세를 다룹니다.


PyCaret 머신러닝 마스터 시리즈 #025