SMOTE로 데이터 불균형 해결하기

John
8 min readApr 11, 2020

현실 세계의 데이터는 생각보다 이상적이지 않다.

데이터에서 각 클래스의 개수가 현저하게 차이가 난 상태로 모델을 학습하면, 다수의 범주로 패턴 분류를 많이하게 되는 문제가 생기고 이는 곧 모델의 성능에 영향을 끼치게 된다.

이번에는 불균형 데이터(imbalanced data)의 문제를 해결할 수 있는 SMOTE(synthetic minority oversampling technique)에 대해서 설명해보고자 한다.

1. SMOTE란

SMOTE의 동작 방식은 데이터의 개수가 적은 클래스의 표본을 가져온 뒤 임의의 값을 추가하여 새로운 샘플을 만들어 데이터에 추가하는 오버샘플링 방식이다.

2. 파이썬 예제 코드

데이터는 캐글의 Credit Card Fraud Detection의 creditcard.csv 을 활용했다.

import pandas as pd df = pd.read_csv('/Users/dreamus/Downloads/creditcard.csv')
df.Class.value_counts(normalize=True).plot(kind='bar')
print(df.Class.value_counts(normalize=True)*100)

보다시피 불균형하게 데이터가 분포되어 있는 것을 확인할 수 있고, 우선 현재 상태에서 아무 전처리 없이 모델링을 진행해보고자 한다.

from sklearn.model_selection import train_test_splitX = df.iloc[:,:-1]
y = df.iloc[:,-1]
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.25,random_state=10)#모델링
def modeling(model,x_train,x_test,y_train,y_test):
model.fit(x_train,y_train)
pred = model.predict(x_test)
metrics(y_test,pred)
#평가 지표
def metrics(y_test,pred):
accuracy = accuracy_score(y_test,pred)
precision = precision_score(y_test,pred)
recall = recall_score(y_test,pred)
f1 = f1_score(y_test,pred)
roc_score = roc_auc_score(y_test,pred,average='macro')
print('정확도 : {0:.2f}, 정밀도 : {1:.2f}, 재현율 : {2:.2f}'.format(accuracy,precision,recall))
print('f1-score : {0:.2f}, auc : {1:.2f}'.format(f1,roc_score,recall))

(1) 전처리 전 데이터로 모델 성능 평가

  • 로지스틱
from sklearn.linear_model import LogisticRegressionlr = LogisticRegression()
modeling(lr,X_train,X_test,y_train,y_test)
  • lightgbm
from lightgbm import LGBMClassifierlgb = LGBMClassifier(n_estimators=1000,num_leaves=64,n_jobs=-1,boost_from_average=False)
modeling(lgb,X_train,X_test,y_train,y_test)

SMOTE를 적용시키기 전, 모델링을 한 결과 다음과 같이 모델의 성능을 볼 수 있다.

기본적인 데이터로 모델 성능을 확인했으니 이제 데이터 정규화와 outlier를 제거하는 과정(본문 생략)을 거친 후 모델의 성능을 확인해보자.

(2) 전처리 후 모델 성능 평가

  • 로지스틱
lr = LogisticRegression()
modeling(lr,X_train,X_test,y_train,y_test)
  • lightgbm

-> 위에 제시한 파라미터와 다르게 is_unblance 파라미터를 True로 설정하여 진행했다.

lgb = LGBMClassifier(n_estimators=1000,num_leaves=64,n_jobs=-1,
is_unbalance = True,boost_from_average=False)
modeling(lgb,X_train,X_test,y_train,y_test)

전처리(정규화,아웃라이어 제거)만 해도 굉장히 성능이 좋아지는 것을 확인할 수 있다. 그럼 이 상태에서 imbalanced data의 문제를 해결할 수 있는 SMOTE 기법을 적용시켜보도록 한다.

(3) SMOTE 적용

from imblearn.over_sampling import SMOTEsmote = SMOTE(random_state=0)
X_train_over,y_train_over = smote.fit_sample(X_train,y_train)
print('SMOTE 적용 전 학습용 피처/레이블 데이터 세트: ', X_train.shape, y_train.shape)
print('SMOTE 적용 후 학습용 피처/레이블 데이터 세트: ', X_train_over.shape, y_train_over.shape)
print('SMOTE 적용 후 레이블 값 분포: \n', pd.Series(y_train_over).value_counts())
전체 학습 샘플 데이터의 양이 증가하면서 , 0/1의 클래스 분포가 동일해졌다.
  • 로지스틱
lr = LogisticRegression()
modeling(lr,X_train_over,X_test,y_train_over,y_test)
  • lightgbm
lgb = LGBMClassifier(n_estimators=1000,num_leaves=64,n_jobs=-1,boost_from_average=False)
modeling(lgb,X_train_over,X_test,y_train_over,y_test)

결론

로지스틱 회귀 모델 같은 경우는 전처리 후에 비하여 정확도,정밀도,f1-score가 급감한 반면에,
lightgbm같은 경우는 정밀도가 살짝 감소한 것을 제외하면 재현율과 AUC가 증가하는 것을 볼 수 있다.

물론 lightgbm 같은 경우는 “scale_pos_weight”과 “is_unbalance”의 파라미터 튜닝을 통해 어느 정도 성능을 높일 수 있으나 해당 데이터 셋으로 테스트 해본 결과 SMOTE를 통해 오버 샘플링한 모델의 성능이 가장 좋은 것을 확인할 수 있었다.

참고

--

--