본문 바로가기

ML/MLops

SMOTE - ML에 쓰일 데이터의 불균형을 해소해보자.

 

 

SMOTE(Synthetic Minority Over-sampling Technique)는  클래스별 비중(불균형 비율)  해소를 위해 사용하는 오버샘플링(Oversampling) 기법이다.

 

분류(Classification) 모델을 학습할 때, 각 클래스의 데이터 양이 비슷해야 모델이 편향되지 않고 잘 학습된다. 그러나 현실 데이터는 대부분이 불균형 상태이다. 

  • 이탈(0) 클래스가 300,000건, 유지(1) 클래스가 35,000건처럼 비율이 극단적으로 치우쳐 있으면, 모델은 자연스럽게 다수 클래스(이탈)만 잘 예측하도록 학습된다.
  • 결과적으로 소수 클래스(유지)에 대한 민감도가 떨어져 precision·recall·F1이 낮아진다.

 

SMOTE

  • 단순 복제가 아니라, 소수 클래스 샘플끼리 “k-최근접 이웃”을 찾아 그 사이를 선형 보간(interpolation)해서 새로운 가상 샘플을 만들수 있다. 
  • 소수 클래스가 더 고르게 퍼지고, 모델이 경계(boundary) 근처의 특징을 더 잘 학습할 수 있게 된다.
  • 특정 클래스의 데이터가 다른 클래스에 비해 현저히 적을 경우(소수 클래스의 비율이 10~20% 이하) 사용
from collections import Counter
from sklearn.datasets import make_classification
from imblearn.over_sampling import SMOTE

# 불균형한 예시 데이터 생성
X, y = make_classification(n_classes=2, class_sep=2,
                           weights=[0.1, 0.9], n_informative=3, n_redundant=1, flip_y=0,
                           n_features=20, n_clusters_per_class=1, n_samples=1000, random_state=10)

print(f'Original dataset shape: {Counter(y)}')
# 출력 결과: Original dataset shape: Counter({1: 900, 0: 100})

# SMOTE 객체 생성 및 적용
smote = SMOTE(random_state=42)
X_resampled, y_resampled = smote.fit_resample(X, y)

print(f'Resampled dataset shape: {Counter(y_resampled)}')
# 출력 결과: Resampled dataset shape: Counter({0: 900, 1: 900})

 

SMOTE 단점

  1. 현실에 없는 데이터 생성: SMOTE는 소수 클래스의 데이터들을 연결하고 그 사이의 가상 지점에 새로운 데이터를 만든다. 만약 소수 클래스 데이터들이 서로 멀리 떨어져 흩어져 있다면, 두 클래스의 경계나 비어있는 공간에 비현실적인 데이터가 생성될 수 있다. 해당 데이터를 학습하게 된다면 더욱 성능이 않좋아진다.
  2. 노이즈 증가: 다수 클래스와 소수 클래스가 많이 겹쳐있는 영역에서 SMOTE를 사용하면, 오히려 두 클래스의 경계가 더 모호해지는 노이즈가 발생하여 모델 학습을 방해할 수도 있다.

 

 

해결책:

  • 클래스 가중치(class_weight='balanced' 또는 compute_sample_weight)
  • 비용 민감 학습(cost-sensitive learning)
  • 앙상블(예: BalancedBagging, EasyEnsemble)
  • 데이터 수집을 통해 소수 클래스 실샘플을 보강

 

랜덤 언더샘플링 (Random Undersampling)

SMOTE를 사용하지 않고 0과 1의 숫자를 똑같이 맞추는 가장 간단한 방법은 다수 클래스(이탈)의 데이터를 무작위로 버려서 소수 클래스(유지)의 수에 맞추는 '랜덤 언더샘플링(Random Undersampling)' 을 사용한다. 

  • 장점: 매우 빠르고 간단합니다. 인위적인 데이터를 만들지 않는다.
  • 단점: 다수 클래스의 수많은 데이터를 버리기 때문에, 모델이 학습할 수 있는 중요한 정보 손실이 발생한다.