logo

불균형한 데이터의 처리

불균형 데이터 처리

  • 불균형 데이터: 클래스 간 데이터 포인트 수가 현저히 차이 나는 데이터셋
  • 분류 문제에서 주로 발생
  • 모델이 다수 클래스에 치우쳐 학습하면 소수 클래스의 예측 성능이 저하됨
  • 정확도(accuracy) 같은 평가 지표가 모델 성능을 잘 나타내지 않을 수 있음
  • 예: 사기 거래 탐지
    • 100,000개의 거래 데이터 중 100개만 사기 거래라면 클래스 비율은 999:1
    • 모든 거래를 정상 거래로 예측해도 99.9%의 정확도를 가짐
  • 리샘플링(resampling)
    • 불균형 데이터에 대한 일반적인 대처
    • 데이터를 복제하거나 합성해 늘리는 오버샘플링
    • 데이터를 삭제해 줄이는 언더샘플링

실습 준비

pip install imbalanced-learn

실습 데이터

from sklearn.datasets import make_classification

X, y = make_classification(
    n_samples=1000,         # 사례 수
    n_features=2,           # 특징(차원)
    n_informative=2,
    n_redundant=0,
    n_repeated=0,
    n_classes=2,            # 클래스 수
    n_clusters_per_class=1, # 클래스별 군집 수
    weights=[0.02, 0.98],   # 비율
    class_sep=1.0,          # 간격
    flip_y=0.0,             # 오분류 비율
    random_state=0,
)

시각화

import matplotlib.pyplot as plt

plt.scatter(X[:, 0], X[:, 1], alpha=0.5, c=y)

불균형 분류 데이터 산점도

선형 판별 분석

  • 선형 판별 분석으로 분류
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis

lda = LinearDiscriminantAnalysis()
lda.fit(X, y)

lda.score(X, y)

결과 시각화

x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1

xx, yy = np.meshgrid(
    np.linspace(x_min, x_max, 200),
    np.linspace(y_min, y_max, 200),
)

Z = lda.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)

plt.scatter(X[:, 0], X[:, 1], alpha=0.5, c=y, edgecolor="k")
plt.contourf(
    xx,
    yy,
    Z,
    alpha=0.3,
    levels=np.linspace(Z.min(), Z.max(), 3),
    zorder=-1,
)

선형 판별 분석의 결정 경계 시각화

오버샘플링

  • 오버샘플링(oversampling): 소수 클래스의 데이터를 복제하거나 합성해 늘림
  • 소수 클래스의 분류 성능이 향상
  • 정보가 손실되지 않음
  • 과적합 위험
  • 훈련 시간 증가

랜덤 오버샘플링

  • 소수 클래스에서 무작위로 골라 복제
from imblearn.over_sampling import RandomOverSampler

sampler = RandomOverSampler(random_state=0)
X_resampled, y_resampled = sampler.fit_resample(X, y)

lda = LinearDiscriminantAnalysis()
lda.fit(X_resampled, y_resampled)
plt.scatter(
    X_resampled[:, 0],
    X_resampled[:, 1],
    alpha=0.5,
    c=y_resampled,
    edgecolor="k",
)

랜덤 오버샘플링 후 결정 경계

SMOTE

  • SMOTE: Synthetic Minority Over-sampling Technique
  • 랜덤 오버샘플링은 과적합 우려가 있음
  • 가까운 두 사례에서 0에서 1 사이의 랜덤한 비율로 내분하는 새로운 점을 합성

SMOTE의 소수 클래스 데이터 합성 방식

SMOTE 실습

from imblearn.over_sampling import SMOTE

sampler = SMOTE(random_state=0)
X_resampled, y_resampled = sampler.fit_resample(X, y)

SMOTE 적용 후 결정 경계

ADASYN

  • ADASYN: Adaptive Synthetic
  • SMOTE처럼 모든 데이터를 고르게 증가시키는 대신, 경계선 근방의 데이터를 더 많이 증가시킴
from imblearn.over_sampling import ADASYN

sampler = ADASYN(random_state=0)
X_resampled, y_resampled = sampler.fit_resample(X, y)

ADASYN 적용 후 결정 경계

언더샘플링

  • 언더샘플링(undersampling): 다수 클래스의 데이터를 삭제해 줄임
  • 다수 클래스의 분류 성능이 하락할 수 있음
  • 정보가 손실됨
  • 과적합 위험이 낮음
  • 훈련 시간 감소

랜덤 언더샘플링

from imblearn.under_sampling import RandomUnderSampler

rus = RandomUnderSampler(random_state=0)
X_resampled, y_resampled = rus.fit_resample(X, y)

랜덤 언더샘플링 후 결정 경계

NearMiss

  • 경계선 근처의 사례만 남김
from imblearn.under_sampling import NearMiss

sampler = NearMiss()
X_resampled, y_resampled = sampler.fit_resample(X, y)

NearMiss 적용 후 결정 경계

  • 소수 클래스와 접한 다수 클래스를 삭제
from imblearn.under_sampling import TomekLinks

sampler = TomekLinks()
X_resampled, y_resampled = sampler.fit_resample(X, y)

Tomek Links에서 접한 클래스 쌍의 개념

Tomek Links 적용 후 결정 경계

Previous
결측치 처리