imbalanced-learn은 클래스 간 불균형을 보여주는 데이터 세트에서 일반적으로 사용되는 여러 리샘플링 기술을 제공하는 Python 패키지
import warnings
# hide warnings
warnings.filterwarnings("ignore")
from sklearn.datasets import make_classification
# 분류 문제 데이터 생성하는 함수 정의, 독립변수 2개, 범주 x개
def create_dataset(n_samples, weights):
return make_classification(
n_samples=n_samples,
n_features=2, n_informative=2, n_redundant=0,
n_classes=len(weights), n_clusters_per_class=1, weights=weights,
random_state=0)
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# 그래프 스타일 설정
sns.set_context("paper", font_scale=1)
# 분류기에 따른 결정영역을 표시하는 함수 정의
def plot_decision_results(X, y, clf, ax, title=None):
# 그리드 간격 설정
grid_step = 0.02
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 # X의 범위
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1 # y의 범위
# meshgrid 함수를 사용하여 그리드 포인트 생성
xx, yy = np.meshgrid(
np.arange(x_min, x_max, grid_step), np.arange(y_min, y_max, grid_step)
)
# 예측 모델에 그리드 포인트 데이터를 입력하여 결정 영역을 계산
# meshgrid 함수의 결과인 2차원 배열을 1차원 배열로 펼쳐서(.ravel()) 수평으로 쌓음(np.c_[])
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
# 예측 결과를 그리드 포인트의 데이터 형태로 재배열
Z = Z.reshape(xx.shape)
# 그리드 포인트의 등고선을 그림
ax.contourf(xx, yy, Z, alpha=0.4)
# 클래스의 산점도를 그림
ax.scatter(X[:, 0], X[:, 1], alpha=0.8, c=y, edgecolor="k")
if title is not None:
ax.set_title(title + f'\n({len(y[y==0])}, {len(y[y==1])}, {len(y[y==2])})', fontsize=12)
소수 클래스의 수를 고려하여 데이터 전체 표분의 크기를 축소시켜 균형을 맞추는 방법
무작위로 majority class의 인스턴스를 제거하여 균형을 맞춤
샘플링시마다 결과가 다름
서로 다른 클래스에 속하는 한 쌍의 인스턴스 중에서 가장 가까운 인스턴스(경계선에 있는 인스턴스)를 찾고, 그 중에서 majority class에 속하는 인스턴스를 제거
majority class에 속하는 인스턴스 중에서 minority class에 가까운 인스턴스를 보존
import numpy as np
from sklearn.linear_model import LogisticRegression
from imblearn.under_sampling import RandomUnderSampler, TomekLinks, EditedNearestNeighbours
from imblearn.under_sampling import CondensedNearestNeighbour, NearMiss, ClusterCentroids
# 시드 설정
np.random.seed(0)
# 데이터 생성
X, y = create_dataset(n_samples=200, weights=(0.05, 0.25, 0.7))
# 샘플러 설정
samplers = [RandomUnderSampler(),
TomekLinks(),
EditedNearestNeighbours(),
CondensedNearestNeighbour(n_neighbors=3),
NearMiss(version=1, n_neighbors=3),
NearMiss(version=2, n_neighbors=3),
NearMiss(version=3, n_neighbors=3),
ClusterCentroids()
]
# 서브 그래프 설정
fig, axs = plt.subplots(nrows=3, ncols=3, figsize=(10, 10))
# 분류기 생성
clf = LogisticRegression()
clf.fit(X, y)
plot_decision_results(X, y, clf, axs[0,0], title="Without resampling")
for i, sampler in enumerate(samplers):
X_resampled, y_resampled = sampler.fit_resample(X, y)
clf.fit(X_resampled, y_resampled)
plot_decision_results(X_resampled, y_resampled, clf, axs[(i+1)//3,(i+1)%3], f"Using {sampler.__class__.__name__}")
fig.suptitle(f"Decision function of {clf.__class__.__name__}")
fig.tight_layout()
소수 클래스의 수를 다수 클래스의 수에 맞춰 증가시키는 방법
무작위로 minority class의 인스턴스를 복제하여 균형을 맞춤
동일하게 복제되기 때문에 과적합 발생에 주의해야함
각 minority class 인스턴스의 K-최근접 이웃을 찾고 그 중 하나를 무작위로 선택한 다음 선형 보간을 계산하여 이웃에 새로운 minority class 인스턴스를 생성
모델의 과적합을 방지하는데에 유용함
모든 minority class 인스턴스에 대해 K-최근접 이웃을 측정한 다음 minority class 인스턴스와 majority class 인스턴스의 클래스 비율을 계산하여 새 인스턴스를 생성
경계선(borderline)에 있는 인스턴스만 SMOTE를 적용
경계선(borderline)에 있는 인스턴스만 SMOTE를 적용
SMOTE를 사용하여 minority class의 데이터를 생성하고, 그 중에서 majority class에 속하는 데이터를 Edited Nearest Neighbours를 이용하여 제거
import numpy as np
from sklearn.linear_model import LogisticRegression
from imblearn.over_sampling import RandomOverSampler, SMOTE, ADASYN, BorderlineSMOTE, SVMSMOTE, KMeansSMOTE
from imblearn.combine import SMOTETomek, SMOTEENN
# 시드 설정
np.random.seed(0)
# 데이터 생성
X, y = create_dataset(n_samples=200, weights=(0.05, 0.25, 0.7))
# 샘플러 설정
samplers = [RandomOverSampler(),
SMOTE(),
ADASYN(),
BorderlineSMOTE(),
SVMSMOTE(),
KMeansSMOTE(),
SMOTETomek(),
SMOTEENN()
]
# 서브 그래프 설정
fig, axs = plt.subplots(nrows=3, ncols=3, figsize=(10, 10))
# 분류기 생성
clf = LogisticRegression()
clf.fit(X, y)
plot_decision_results(X, y, clf, axs[0,0], title="Without resampling")
for i, sampler in enumerate(samplers):
X_resampled, y_resampled = sampler.fit_resample(X, y)
clf.fit(X_resampled, y_resampled)
plot_decision_results(X_resampled, y_resampled, clf, axs[(i+1)//3,(i+1)%3], f"Using {sampler.__class__.__name__}")
fig.suptitle(f"Decision function of {clf.__class__.__name__}")
fig.tight_layout(pad=1.5)
plt.show()
import numpy as np
from sklearn.linear_model import LogisticRegression
from imblearn.over_sampling import RandomOverSampler, SMOTE, ADASYN, BorderlineSMOTE, SVMSMOTE, KMeansSMOTE
from imblearn.combine import SMOTETomek, SMOTEENN
# 시드 설정
np.random.seed(0)
# 데이터 생성
X, y = create_dataset(n_samples=200, weights=(0.05, 0.25, 0.7))
# 샘플러 설정
samplers = [RandomOverSampler(),
SMOTE(),
ADASYN(),
BorderlineSMOTE(),
SVMSMOTE(),
KMeansSMOTE(),
SMOTETomek(),
SMOTEENN()
]
# 서브 그래프 설정
fig, axs = plt.subplots(nrows=3, ncols=3, figsize=(10, 10))
# 분류기 생성
clf = LogisticRegression()
clf.fit(X, y)
plot_decision_results(X, y, clf, axs[0,0], title="Without resampling")
for i, sampler in enumerate(samplers):
X_resampled, y_resampled = sampler.fit_resample(X, y)
clf.fit(X_resampled, y_resampled)
plot_decision_results(X_resampled, y_resampled, clf, axs[(i+1)//3,(i+1)%3], f"Using {sampler.__class__.__name__}")
fig.suptitle(f"Decision function of {clf.__class__.__name__}")
fig.tight_layout(pad=1.5)
plt.show()
import numpy as np
from sklearn.metrics import ConfusionMatrixDisplay
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from imblearn.under_sampling import RandomUnderSampler, TomekLinks, EditedNearestNeighbours, NearMiss, ClusterCentroids
from imblearn.over_sampling import RandomOverSampler, SMOTE, ADASYN, BorderlineSMOTE, SVMSMOTE, KMeansSMOTE
from imblearn.combine import SMOTETomek, SMOTEENN
from imblearn.metrics import geometric_mean_score
# 시드 설정
np.random.seed(0)
# 데이터 생성
X, y = create_dataset(n_samples=1000, weights=(0.1, 0.3, 0.6))
# 데이터셋 분리
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, test_size=0.3, random_state=0)
# 샘플러 설정
samplers = [RandomUnderSampler(),
EditedNearestNeighbours(),
ClusterCentroids(),
RandomOverSampler(),
SMOTE(),
ADASYN(),
BorderlineSMOTE(),
SVMSMOTE(),
KMeansSMOTE(),
SMOTETomek(),
SMOTEENN()
]
# 분류기 생성
clf = DecisionTreeClassifier()
# 서브 그래프 설정
fig, axs = plt.subplots(nrows=4, ncols=3, figsize=(10, 15))
clf.fit(X_train, y_train)
disp = ConfusionMatrixDisplay.from_estimator(clf, X_test, y_test, ax= axs[0,0], colorbar=False)
accuracy = clf.score(X_test, y_test)
geom_mean = geometric_mean_score(y_test, clf.predict(X_test))
disp.ax_.set_title(f"Without resampling\nAccuracy = {accuracy:.3f}\nGeom-Mean = {geom_mean:.3f}", fontsize=12)
for i, sampler in enumerate(samplers):
X_resampled, y_resampled = sampler.fit_resample(X_train, y_train)
clf.fit(X_resampled, y_resampled)
accuracy = clf.score(X_test, y_test)
geom_mean = geometric_mean_score(y_test, clf.predict(X_test))
disp = ConfusionMatrixDisplay.from_estimator(clf, X_test, y_test, ax=axs[(i+1)//3,(i+1)%3], colorbar=False)
disp.ax_.set_title(f"Using {sampler.__class__.__name__}\nAccuracy = {accuracy:.3f}\nGeom-Mean = {geom_mean:.3f}", fontsize=12)
fig.tight_layout(pad=2.0)
plt.show()
![](https://velog.velcdn.com/images/happycherry6/post/9438b5ce-878d-4d8b-98f3-4218791ca5f7/image.png)
import numpy as np
from sklearn.metrics import ConfusionMatrixDisplay
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import BaggingClassifier, RandomForestClassifier
from imblearn.ensemble import BalancedBaggingClassifier, BalancedRandomForestClassifier
from imblearn.under_sampling import RandomUnderSampler, TomekLinks, EditedNearestNeighbours, NearMiss, ClusterCentroids
from imblearn.over_sampling import RandomOverSampler, SMOTE, ADASYN, BorderlineSMOTE, SVMSMOTE, KMeansSMOTE
from imblearn.combine import SMOTETomek, SMOTEENN
from imblearn.metrics import geometric_mean_score
# 시드 설정
np.random.seed(0)
# 데이터 생성
X, y = create_dataset(n_samples=1000, weights=(0.1, 0.3, 0.6))
# 데이터셋 분리
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, test_size=0.3, random_state=0)
# 분류기 생성
clfs = [DecisionTreeClassifier(),
BaggingClassifier(n_estimators=50),
BalancedBaggingClassifier(n_estimators=50),
RandomForestClassifier(n_estimators=50)
]
# 서브 그래프 설정
fig, axs = plt.subplots(nrows=2, ncols=2, figsize=(8, 8))
for i, clf in enumerate(clfs):
clf.fit(X_train, y_train)
accuracy = clf.score(X_test, y_test)
geom_mean = geometric_mean_score(y_test, clf.predict(X_test))
disp = ConfusionMatrixDisplay.from_estimator(clf, X_test, y_test, ax=axs[i//2,i%2], colorbar=False)
disp.ax_.set_title(f"Using {clf.__class__.__name__}\nAccuracy = {accuracy:.3f}\nGeom-Mean = {geom_mean:.3f}", fontsize=12)
fig.tight_layout(pad=2.0)
plt.show()