오늘 할 일: 끝내주게 숨쉬기
article thumbnail

머신러닝에서 분류 문제를 다룰 때 가장 먼저 데이터의 분포를 확인하죠. 타겟이 두가지 범주를 갖는지(-> binary classification), 세 개 이상의 범주를 갖는지(-> multi-class classification), 하나의 데이터가 여러가지 범주를 동시에 가질 수도 있는지(-> multi-label classification) 살펴봅니다. 그리고 각 범주가 전체의 몇 퍼센트를 차지하고 있는지 비율을 살펴봅니다. 전체 자산 중에 부동산이 50%이고 주식이 30%, 그리고 현금이 20%를 차지한다! 이런 식으로요. 

 

각 범주의 비율이 균일하게 나올 수도 있지만, 현실의 많은 데이터들은 불균형한 비율을 갖고 있습니다. 예를 들어 회원들에게 쿠폰을 주는 앱푸시를 보냈는데 그 알람을 누른 회원은 2%, 알람을 누르지 않은 회원은 98%일 때 데이터가 불균형하다고 합니다. 이렇게 데이터에 편향은 머신러닝을 학습시키는 데 영향을 줍니다. 학습을 시켜도 많은 비율을 차지하는 집단으로 예측을 하게 될 가능성이 높습니다. 많은 머신러닝 문제에서, 적은 비율을 차지하는 범주(집단)가 관심 대상이기 때문에 이 불균형을 해결하는 것은 굉장히 중요한 이슈가 되죠.

 

샘플링은 불균형 데이터를 다루는 여러 방법 중 하나로, 각 범주가 차지하는 비율을 조정하여 데이터를 추출하는 방식을 일컫습니다. 본 포스팅에서는 다양한 샘플링 클래스를 제공하는 imblearn(imbalanced-learn) 모듈 사용법을 알아보겠습니다. 모듈은 아래 코드를 통해 설치합니다.

 

pip install imbalanced-learn

 

예시를 위해 사용할 데이터는 사이킷런의 make_classification 함수를 이용하여 만들었습니다.

 

import numpy as np
import pandas as pd

from sklearn.datasets import make_classification
from collections import Counter

from matplotlib import pyplot as plt
import seaborn as sns

from imblearn.under_sampling import RandomUnderSampler
from imblearn.over_sampling import RandomOverSampler
from imblearn.over_sampling import SMOTE
X, y = make_classification(n_samples=10000, n_features=5, weights=[0.99], flip_y=0)
print(Counter(y))
Counter({0: 9900, 1: 100})

 

make_classification 함수를 이용하여 만개의 데이터를 만들었는데요, 이 중 99%인 9900개 데이터는 y=0을, 1%인 100개 데이터는 y=1을 갖고 있습니다. 

 

 

Under Sampling - RandomUnderSampler

 

많은 비율을 차지하는 다수 집단에서 일부만 샘플링하는 방법입니다. 소수 집단에 데이터가 어느 정도 확보되었다고 여겨질 때, 다수 집단의 데이터를 줄여 균형을 맞추는 것이죠. 다만 언더 샘플링을 적용하면 다수 집단의 유의미한 정보를 손실할 수 있다는 단점이 있습니다. 

 

undersample = RandomUnderSampler(sampling_strategy='majority')
X_under, y_under = undersample.fit_resample(X, y)
print(Counter(y_under))
Counter({0: 100, 1: 100})

 

sampling_strategy 파라미터를 'majority'로 지정하면, 다수 집단에서 샘플링을 하여 소수 집단의 데이터수와 동일하게 맞추게 됩니다.

 

undersample = RandomUnderSampler(sampling_strategy=0.4) 
X_under, y_under = undersample.fit_resample(X, y)
print(Counter(y_under))
Counter({0: 250, 1: 100})

 

sampling_strategy 파라미터에 0과 1 사이의 숫자를 지정하면, (소수 집단 데이터수 / 다수 집단 데이터수)가 그 값이 되도록 다수 집단에서 샘플링을 수행합니다. 위 예시에서는 100/250=0.4로, 다수 집단에서 250개만 샘플링을 하였습니다.

 

 

Over Sampling - RandomOverSampler

 

적은 비율을 차지하는 소수 집단에서 복원 추출을 수행하는 방법입니다. 언더 샘플링처럼 데이터 중 일부를 취하는 것이 아니기 때문에 정보의 손실은 발생하지 않지만, 동일한 샘플이 여러번 학습 데이터에 포함되면서 학습 정확도는 높지만 테스트 정확도는 낮은 과적합(overfitting)이 발생할 수 있습니다.

 

oversample = RandomOverSampler(sampling_strategy='minority')
X_over, y_over = oversample.fit_resample(X, y)
print(Counter(y_over))
Counter({0: 9900, 1: 9900})

 

 sampling_strategy 파라미터를 'minority'라고 지정하면, 소수 집단에서 복원 추출을 수행하여 다수 집단 데이터수와 동일하게 맞추게 됩니다.

 

oversample = RandomOverSampler(sampling_strategy=0.4) 
X_over, y_over = oversample.fit_resample(X, y)
print(Counter(y_over))
Counter({0: 9900, 1: 3960})

 

sampling_strategy 파라미터에 0과 1 사이의 숫자를 지정하면, (소수 집단 데이터수 / 다수 집단 데이터수)가 그 값이 되도록 소수 집단에서 샘플링을 수행합니다. 위 예시에서는 3960/9900=0.4로, 소수 집단에서 3960개 데이터를 복원 추출하였습니다.

 

 

Over Sampling - SMOTE

 

SMOTE는 Synthetic Minority Over-sampling Technique으로, 소수 집단의 데이터를 바탕으로 새로운 데이터를 만들어 냅니다. 단순히 소수 집단에서 복원 추출을 하는 것이 아니라 소수 집단에 속한 데이터를 분석해 어떤 특징들이 있는지 살피고, 그와 유사한 패턴을 갖는 가짜 데이터를 만드는 것이죠. 

출처 : https://www.kaggle.com/rafjaa/dealing-with-very-small-datasets

 

smote_sample = SMOTE(sampling_strategy=0.4) 
X_sm, y_sm = smote_sample.fit_resample(X, y)
print(Counter(y_sm))
Counter({0: 9900, 1: 3960})

 

위 랜덤오버샘플링과 마찬가지로 비율을 설정하고 소수 집단으로부터 가짜 데이터를 만들었습니다.

 

 

마지막으로 오리지널 데이터와 RandomUnderSample, RandomOverSample, SMOTE를 적용하여 샘플링한 결과를 시각화하여 비교해보겠습니다.

 

fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(15, 15))
sns.scatterplot(X[:, 1], X[:, 2], hue=y, ax=axes[0][0])
axes[0][0].set_title('Original Data')
sns.scatterplot(X_under[:, 1], X_under[:,2], hue=y_under, ax=axes[0][1])
axes[0][1].set_title('Random Under Sampling')
sns.scatterplot(X_over[:, 1], X_over[:, 2], hue=y_over, ax=axes[1][0])
axes[1][0].set_title('Random Over Sampling')
sns.scatterplot(X_sm[:, 1], X_sm[:, 2], hue=y_sm, ax=axes[1][1])
axes[1][1].set_title('SMOTE')

 

원래 있던 데이터를 반복해서 뽑는 랜덤오버샘플링과는 다르게, SMOTE는 기존에 없었던 데이터를 새롭게 만들어낸 것을 시각적으로 확인할 수 있습니다. y=1인 데이터들(주황색 포인트) 근방에서 유사한 X값들을 갖는 새로운 y=1 데이터가 생성이 된 것이죠.

 

RandomUnderSample, RandomOverSample, SMOTE 이외에 다른 샘플링 방법들은 아래 참고 사이트를 통해 확인하실 수 있습니다. 샘플링은 데이터의 불균형을 해결하는 여러 방법 중 하나로 가장 쉽게 시도할 수 있습니다. 인공적인 데이터를 생성하여 머신러닝 학습에 도움을 줄 수도 있지만, 항상 모델 성능을 높여주는 것은 아닙니다. 데이터와 풀고자 하는 문제를 먼저 충분히 이해한 후, 상황에 따라 적절하게 선택적으로 사용하길 바랍니다.

 

 

참고

https://imbalanced-learn.org/stable/index.html

 

imbalanced-learn documentation — Version 0.8.1

User guide The user guide provides in-depth information on the key concepts of imbalanced-learn with useful background information and explanation.

imbalanced-learn.org

 

https://www.kaggle.com/rafjaa/dealing-with-very-small-datasets

 

Dealing with very small datasets

Explore and run machine learning code with Kaggle Notebooks | Using data from Don't Overfit! II

www.kaggle.com