025 불균형 데이터 처리 - SMOTE 활용
키워드: SMOTE, 오버샘플링
개요
SMOTE(Synthetic Minority Over-sampling Technique)는 소수 클래스의 합성 샘플을 생성하는 대표적인 오버샘플링 기법입니다. 이 글에서는 SMOTE의 원리와 다양한 변형을 다룹니다.
실습 환경
- Python 버전: 3.11 권장
- 필요 패키지:
pycaret[full]>=3.0,imbalanced-learn
SMOTE 원리
- 소수 클래스에서 샘플 선택
- k개의 최근접 이웃 찾기
- 이웃 중 하나를 무작위 선택
- 두 점 사이에 새 샘플 생성
# 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
)
하이브리드 방법: SMOTE + Tomek Links
오버샘플링 후 노이즈 제거:
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를 사용하면 안 되나?
- 클래스 중첩이 심할 때: 노이즈 증가
- 소수 클래스가 너무 적을 때 (< 6개): k-neighbors 문제
- 고차원 데이터: 차원의 저주
# 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