Machine Learning

[Machine Learning] imblearn 라이브러리 undersampling

heedy 2022. 11. 21. 14:17
728x90

imblearn라이브러리의 under_sampling 비교

- Import

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import make_classification
from imblearn.under_sampling import *

- Data 생성

X, y = make_classification(n_samples=5000, n_features=2, n_informative=2,
                           n_redundant=0, n_repeated=0, n_classes=3,
                           n_clusters_per_class=1,
                           weights=[0.2, 0.3, 0.5],
                           class_sep=0.8, random_state=0)
print(X.shape , y.shape)
(5000, 2) (5000,)

Data Frame으로 변경

df = pd.DataFrame(X, columns = ['f1', 'f2'])
df['target'] = y
print(df.target.value_counts())
df.head()
>>>
2    2497
1    1501
0    1002

      f1			f2	target
0	-0.571967	1.247429	0
1	0.772671	0.395459	1
2	0.581133	0.420392	1
3	1.375456	0.974206	2
4	1.018848	1.119809	1

생성한 데이터의 분포

plt.figure(figsize = (12, 8))
sns.scatterplot(data = df, x = 'f1', y = 'f2', hue = 'target')


- RandomUnderSampler

메이저 클래스 샘플을 랜덤으로 제거

  • 'majority': resample only the majority class(메이저 클래스 샘플 리샘플링)
  • 'not minority': resample all classes but the minority class(마이너 클래스를 제외한 클래스 리샘플링)
  • 'not majority': resample all classes but the majority class(메이저 클래스를 제외한 클래스 리샘플링)
  • 'all': resample all classes(모든 클래스 리샘플링)
  • 'auto': equivalent to 'not minority'(마이너 클래스가 아닌 적절한 클래스 자동으로 선정)
rus = RandomUnderSampler(random_state = 10)
X_rus, y_rus = rus.fit_resample(X, y)
df1 = pd.DataFrame(X_rus, columns = ['rus1', 'rus2'])
df1['y_rus'] = y_rus
print(df1.y_rus.value_counts())

plt.figure(figsize = (12, 8))
sns.scatterplot(data = df1, x = 'rus1', y = 'rus2', hue = 'y_rus')
0    1002
2    1002
1    1002


- ClusterCentroids

KMeans 알고리즘을 이용하여 메이저 클래스의 샘플을 클러스터 중심을 기반으로 제거

cc = ClusterCentroids(random_state = 10)
X_cc, y_cc = cc.fit_resample(X, y)
df2 = pd.DataFrame(X_cc, columns = ['cc1', 'cc2'])
df2['y_cc'] = y_cc
print(df2.y_cc.value_counts())

plt.figure(figsize = (12, 8))
sns.scatterplot(data = df2, x = 'cc1', y = 'cc2', hue = 'y_cc')
0    1002
2    1002
1    1002


- CondensedNearestNeighbour

KNN 알고리즘을 사용하여 메이저 클래스의 샘플들 중 가까운 샘플들을 제거, 이상치에 민감

cnn = CondensedNearestNeighbour(random_state = 10)
X_cnn, y_cnn = cnn.fit_resample(X, y)
df3 = pd.DataFrame(X_cnn, columns = ['cnn1', 'cnn2'])
df3['y_cnn'] = y_cnn
print(df3.y_cnn.value_counts())

plt.figure(figsize = (12, 8))
sns.scatterplot(data = df3, x = 'cnn1', y = 'cnn2', hue = 'y_cnn')
0    1002
2      64
1      63


- EditedNearestNeighbours

Nearest-neighbors 알고리즘을 이용하여 근접한 샘플들과 유사하지 않은 샘플 제거

enn = EditedNearestNeighbours()
X_enn, y_enn = enn.fit_resample(X, y)
df4 = pd.DataFrame(X_enn, columns = ['enn1', 'enn2'])
df4['y_enn'] = y_enn
print(df4.y_enn.value_counts())

plt.figure(figsize = (12, 8))
sns.scatterplot(data = df4, x = 'enn1', y = 'enn2', hue = 'y_enn')
2    2389
1    1402
0    1002


- RepeatedEditedNearestNeighbours

ENN(EditedNearestNeighbours)알고리즘 여러 번 반복해서 진행하여 더 많은 샘플 제거

renn = RepeatedEditedNearestNeighbours()
X_renn, y_renn = renn.fit_resample(X, y)
df5 = pd.DataFrame(X_renn, columns = ['renn1', 'renn2'])
df5['y_renn'] = y_renn
print(df5.y_renn.value_counts())

plt.figure(figsize = (12, 8))
sns.scatterplot(data = df5, x = 'renn1', y = 'renn2', hue = 'y_renn')
2    2382
1    1399
0    1002


- AllKNN

RENN과 유사하게 ENN을 반복하여 진행하지만, 고려해야할 근접 샘플의 수를 증가시키면서 반복

allknn = AllKNN()
X_allknn, y_allknn = allknn.fit_resample(X, y)
df6 = pd.DataFrame(X_allknn, columns = ['allknn1', 'allknn2'])
df6['y_allknn'] = y_allknn
print(df6.y_allknn.value_counts())

plt.figure(figsize = (12, 8))
sns.scatterplot(data = df6, x = 'allknn1', y = 'allknn2', hue = 'y_allknn')
2    2422
1    1429
0    1002


- InstanceHardnessThreshold

classification 모델로 훈련하여 확률이 낮은 샘플을 제거하는 방법
sklearn 라이브러리의 classification model을 활용하여 predict probability를 측정한 후 낮은 확률의 샘플을 제거

iht = InstanceHardnessThreshold(random_state = 10)
X_iht, y_iht = iht.fit_resample(X, y)
df7 = pd.DataFrame(X_iht, columns = ['iht1', 'iht2'])
df7['y_iht'] = y_iht
print(df7.y_iht.value_counts())

plt.figure(figsize = (12, 8))
sns.scatterplot(data = df7, x = 'iht1', y = 'iht2', hue = 'y_iht')
2    1580
1    1116
0    1002


- NearMiss

소수 클래스를 기준으로 메이저 클래스의 거리를 측정하여 제거할 샘플을 선택

nm = NearMiss()
X_nm, y_nm = nm.fit_resample(X, y)
df8 = pd.DataFrame(X_nm, columns = ['nm1', 'nm2'])
df8['y_nm'] = y_nm
print(df8.y_nm.value_counts())

plt.figure(figsize = (12, 8))
sns.scatterplot(data = df8, x = 'nm1', y = 'nm2', hue = 'y_nm')
0    1002
2    1002
1    1002


- NeighbourhoodCleaningRule

ENN, KNN 알고리즘을 사용하여 이상치 데이터 제거

ncr = NeighbourhoodCleaningRule()
X_ncr, y_ncr = ncr.fit_resample(X, y)
df9 = pd.DataFrame(X_ncr, columns = ['ncr1', 'ncr2'])
df9['y_ncr'] = y_ncr
print(df9.y_ncr.value_counts())

plt.figure(figsize = (12, 8))
sns.scatterplot(data = df9, x = 'ncr1', y = 'ncr2', hue = 'y_ncr')
2    2469
1    1473
0    1002


- OneSidedSelection

TomekLinks를 사용하여 이상치가 많은 샘플 제거

oss = OneSidedSelection(random_state = 10)
X_oss, y_oss = oss.fit_resample(X, y)
df10 = pd.DataFrame(X_oss, columns = ['oss1', 'oss2'])
df10['y_oss'] = y_oss
print(df10.y_oss.value_counts())

plt.figure(figsize = (12, 8))
sns.scatterplot(data = df10, x = 'oss1', y = 'oss2', hue = 'y_oss')
2    1839
1    1386
0    1002


- TomekLinks

  • 두 범주에서 하나씩 추출한 포인트를 각각 와 라 할 때,  또는 가 되는 관측치 가 없는 경우, 두 샘플 와 가 Tomek Link를 형성한다고 한다.
  • Tomek link를 형성하는 두 샘플 중 하나는 노이즈이거나 둘 다 경계선 근처에 있다.
  • Tomek link를 형성한 샘플 중 다수 범주에 속한 샘플을 제거한다.
  • [그림 4]는 Tomek link의 예제를 보여준다. 좌측과 같은 데이터 세트에 대하여 Tomek link를 형성하면 가운데 그림과 같이 된다. Tomek link를 형성한 파란색 샘플들을 제외하면 우측 그림과 같이 되는데 샘플을 제외하기 이전보다 두 범주의 구분이 보다 명확히 됨을 알 수 있다. 따라서 두 범주 간의 분류 경계면을 찾는데 도움이 된다.
  • Tomek link는 다수 범주의 데이터의 중심 분포는 거의 유지하면서 분류 경계를 조정하는 효과를 얻기 때문에 random undersampling에 비해 정보의 유실을 크게 줄일 수 있지만, 제거되는 샘플이 한정적이기 때문에 큰 언더 샘플링의 효과를 얻을 수는 없다.

tl = TomekLinks()
X_tl, y_tl = tl.fit_resample(X, y)
df11 = pd.DataFrame(X_tl, columns = ['tl1', 'tl2'])
df11['y_tl'] = y_tl
print(df11.y_tl.value_counts())

plt.figure(figsize = (12, 8))
sns.scatterplot(data = df11, x = 'tl1', y = 'tl2', hue = 'y_tl')
2    2470
1    1471
0    1002

 

- Tomek Link 출처: https://velog.io/@cleansky/%EC%9D%B8%EC%82%AC%EC%9D%B4%EB%93%9C-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EB%B6%88%EA%B7%A0%ED%98%95-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%83%98%ED%94%8C%EB%A7%81

 

[인사이드 머신러닝] 불균형 데이터 샘플링

모델을 학습시킴에 있어 클래스 간 샘플 수의 차이가 너무 크게 되면 분류기는 더 많은 샘플이 존재하는 클래스로 편향된다. 이 경우 전체적인 정확도는 높게 나올지라도 샘플 수가 적은 클래스

velog.io

- notebook ipynb file: https://github.com/heejvely/python-machine_learning-practice/blob/main/undersampling.ipynb

 

GitHub - heejvely/python-machine_learning-practice: practice for using python machine learning model

practice for using python machine learning model. Contribute to heejvely/python-machine_learning-practice development by creating an account on GitHub.

github.com

 

728x90