Imbalanced Class
Contents
Imbalanced Class#
데이터 준비 과정인 EDA(Exploratory Data Analysis) 에서는 분석에 맞는 데이터를 만들기 위해 많은 기법들을 통해 데이터를 정제합니다. 지도 학습을 통해 Classification 을 위한 데이터 준비 과정에서 일반적으로 발생하는 문제 중에 하나는 예측하고자 하는 Class 에 해당하는 데이터 수의 불균형을 들 수 있습니다.
예를 들어 공장에서 불량품을 분류하는 문제에 대한 모델을 만들 경우, 불량율이 1% 라고 한다면 양품과 불량품 Class 내의 데이터 비율은 99:1 로 불균형을 이루게 됩니다. 이는 모델 학습 및 평가에 많은 영향을 주게 됩니다. 학습 후 모델이 모든 예측을 양품으로 하더라도 단순히 정확도는 99% 가 되기 때문입니다. 물론 이 부분을 평가하는 다른 함수들이 존재하긴 하지만, 학습을 통해 좋은 모델을 얻기 위해서라도 Class내의 데이터 불균형 문제는 해결하는 것이 좋습니다.
Package: https://imbalanced-learn.org/stable/index.html
Over-sampling & Under-sampling#
Over-sampling 은 Class 내의 데이터 비율이 낮은 데이터를 여러 방법으로 샘플링하여 높은쪽 비율로 맞추는 방법이고, Under-sampling 은 Class 내의 데이터 비율이 높은 데이터를 여러 방법으로 샘플링하여 낮은쪽 비율로 맞추는 방법입니다.
Over-sampling#
Class 내의 데이터 비율이 [0.01, 0.05, 0.94] 인 가상의 데이터를 만들고, 불균형 데이터를 통해 SVM 모델을 학습하여 평가한 결과와 Over-sampling 을 통해 균형 데이터로 만들고 학습한 결과입니다.
Random Sampling (RandomOverSampler)
The Synthetic Minority Oversampling Technique (SMOTE) CBHK2002
The Adaptive Synthetic (ADASYN) HBGL2008
%matplotlib inline
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings("ignore")
import numpy as np
from sklearn import datasets, svm, metrics
from imblearn import over_sampling
from collections import Counter
# 데이터
n_samples = 10000
np_data_xs, np_data_ys = datasets.make_classification(n_samples=n_samples,
n_features=2, n_informative=2,
n_redundant=0, n_repeated=0,
n_classes=3, n_clusters_per_class=1,
weights=[0.01, 0.05, 0.94],
class_sep=0.8, random_state=0)
print("np_data_ys={}".format(sorted(Counter(np_data_ys).items())))
idx = int(n_samples * 0.7)
np_train_xs = np_data_xs[:idx]
np_train_ys = np_data_ys[:idx]
np_test_xs = np_data_xs[idx:]
np_test_ys = np_data_ys[idx:]
print("np_train_ys={}".format(sorted(Counter(np_train_ys).items())))
print("np_test_ys={}".format(sorted(Counter(np_test_ys).items())))
# 불균형 데이터 학습
model = svm.LinearSVC()
model.fit(np_train_xs, np_train_ys)
# 평가
np_pred_ys = model.predict(np_test_xs)
cr = metrics.classification_report(np_test_ys, np_pred_ys)
print("classification_report\n", cr)
# Over-sampling
samplers = [
over_sampling.RandomOverSampler(random_state=0),
over_sampling.SMOTE(random_state=0),
over_sampling.ADASYN(random_state=0)
]
for sampler in samplers:
np_train_resampled_xs, np_train_resampled_ys = sampler.fit_resample(np_train_xs, np_train_ys)
print("np_train_resampled_ys={}".format(sorted(Counter(np_train_resampled_ys).items())))
print("np_test_ys={}".format(sorted(Counter(np_test_ys).items())))
# 균형 데이터 학습
model = svm.LinearSVC()
model.fit(np_train_resampled_xs, np_train_resampled_ys)
# 평가
np_pred_ys = model.predict(np_test_xs)
cr = metrics.classification_report(np_test_ys, np_pred_ys)
print("classification_report\n", cr)
np_data_ys=[(0, 132), (1, 523), (2, 9345)]
np_train_ys=[(0, 89), (1, 380), (2, 6531)]
np_test_ys=[(0, 43), (1, 143), (2, 2814)]
classification_report
precision recall f1-score support
0 0.00 0.00 0.00 43
1 0.73 0.66 0.69 143
2 0.98 1.00 0.99 2814
micro avg 0.97 0.97 0.97 3000
macro avg 0.57 0.55 0.56 3000
weighted avg 0.95 0.97 0.96 3000
np_train_resampled_ys=[(0, 6531), (1, 6531), (2, 6531)]
np_test_ys=[(0, 43), (1, 143), (2, 2814)]
classification_report
precision recall f1-score support
0 0.46 0.63 0.53 43
1 0.34 0.62 0.44 143
2 0.99 0.94 0.96 2814
micro avg 0.92 0.92 0.92 3000
macro avg 0.60 0.73 0.65 3000
weighted avg 0.95 0.92 0.93 3000
np_train_resampled_ys=[(0, 6531), (1, 6531), (2, 6531)]
np_test_ys=[(0, 43), (1, 143), (2, 2814)]
classification_report
precision recall f1-score support
0 0.46 0.63 0.53 43
1 0.36 0.66 0.47 143
2 0.99 0.94 0.96 2814
micro avg 0.92 0.92 0.92 3000
macro avg 0.60 0.74 0.65 3000
weighted avg 0.95 0.92 0.93 3000
np_train_resampled_ys=[(0, 6529), (1, 6527), (2, 6531)]
np_test_ys=[(0, 43), (1, 143), (2, 2814)]
classification_report
precision recall f1-score support
0 0.30 0.79 0.44 43
1 0.08 0.41 0.14 143
2 0.99 0.78 0.87 2814
micro avg 0.76 0.76 0.76 3000
macro avg 0.46 0.66 0.48 3000
weighted avg 0.94 0.76 0.83 3000
단순히 정확도 면에서는 불균형 데이터가 더 정확하다고 나오지만, Class 0 의 예측 성능은 매우 안좋게 나오게 됩니다. 모델의 균형적 측면에서 정확도는 조금 낮지만 균형 데이터로 학습한 모델이 더욱 안정적인 성능을 나타냄을 알 수 있습니다.
Under-sampling#
Class 내의 데이터 비율이 [0.01, 0.05, 0.94] 인 가상의 데이터를 만들고, 불균형 데이터를 통해 SVM 모델을 학습하여 평가한 결과와 Under-sampling 을 통해 균형 데이터로 만들고 학습한 결과입니다.
Random Sampling (RandomUnderSampler)
K-means 알고리즘을 이용하여 sampling(ClusterCentroids)
%matplotlib inline
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings("ignore")
import numpy as np
from sklearn import datasets, svm, metrics
from imblearn import under_sampling
from collections import Counter
# 데이터
n_samples = 10000
np_data_xs, np_data_ys = datasets.make_classification(n_samples=n_samples,
n_features=2, n_informative=2,
n_redundant=0, n_repeated=0,
n_classes=3, n_clusters_per_class=1,
weights=[0.01, 0.05, 0.94],
class_sep=0.8, random_state=0)
print("np_data_ys={}".format(sorted(Counter(np_data_ys).items())))
idx = int(n_samples * 0.7)
np_train_xs = np_data_xs[:idx]
np_train_ys = np_data_ys[:idx]
np_test_xs = np_data_xs[idx:]
np_test_ys = np_data_ys[idx:]
print("np_train_ys={}".format(sorted(Counter(np_train_ys).items())))
print("np_test_ys={}".format(sorted(Counter(np_test_ys).items())))
# 불균형 데이터 학습
model = svm.LinearSVC()
model.fit(np_train_xs, np_train_ys)
# 평가
np_pred_ys = model.predict(np_test_xs)
cr = metrics.classification_report(np_test_ys, np_pred_ys)
print("classification_report\n", cr)
# Under-sampling
samplers = [
under_sampling.RandomUnderSampler(random_state=0),
under_sampling.ClusterCentroids(random_state=0)
]
for sampler in samplers:
np_train_resampled_xs, np_train_resampled_ys = sampler.fit_resample(np_train_xs, np_train_ys)
print("np_train_resampled_ys={}".format(sorted(Counter(np_train_resampled_ys).items())))
print("np_test_ys={}".format(sorted(Counter(np_test_ys).items())))
# 균형 데이터 학습
model = svm.LinearSVC()
model.fit(np_train_resampled_xs, np_train_resampled_ys)
# 평가
np_pred_ys = model.predict(np_test_xs)
cr = metrics.classification_report(np_test_ys, np_pred_ys)
print("classification_report\n", cr)
np_data_ys=[(0, 132), (1, 523), (2, 9345)]
np_train_ys=[(0, 89), (1, 380), (2, 6531)]
np_test_ys=[(0, 43), (1, 143), (2, 2814)]
classification_report
precision recall f1-score support
0 0.00 0.00 0.00 43
1 0.73 0.66 0.69 143
2 0.98 1.00 0.99 2814
micro avg 0.97 0.97 0.97 3000
macro avg 0.57 0.55 0.56 3000
weighted avg 0.95 0.97 0.96 3000
np_train_resampled_ys=[(0, 89), (1, 89), (2, 89)]
np_test_ys=[(0, 43), (1, 143), (2, 2814)]
classification_report
precision recall f1-score support
0 0.32 0.63 0.43 43
1 0.52 0.64 0.57 143
2 0.99 0.96 0.97 2814
micro avg 0.94 0.94 0.94 3000
macro avg 0.61 0.74 0.66 3000
weighted avg 0.96 0.94 0.95 3000
np_train_resampled_ys=[(0, 89), (1, 89), (2, 89)]
np_test_ys=[(0, 43), (1, 143), (2, 2814)]
classification_report
precision recall f1-score support
0 0.47 0.63 0.53 43
1 0.38 0.61 0.47 143
2 0.99 0.95 0.97 2814
micro avg 0.93 0.93 0.93 3000
macro avg 0.61 0.73 0.66 3000
weighted avg 0.95 0.93 0.94 3000
단순히 정확도 면에서는 불균형 데이터가 더 정확하다고 나오지만, Class 0 의 예측 성능은 매우 안좋게 나오게 됩니다. 모델의 균형적 측면에서 정확도는 조금 낮지만 균형 데이터로 학습한 모델이 더욱 안정적인 성능을 나타냄을 알 수 있습니다.