짜리몽땅 매거진
[ML] 데이터 샘플링 본문
모델링을 할 때 데이터 '샘플링'을 해야한다는 말을 들어본 적 있을 것이다. 그렇다면 왜 샘플링을 해야할까?
통상적으로 예측하는 경우는 대부분 소수의 경우를 예측하는 경우가 많다. 예를 들어, 사기건, 비정상, 이탈 등등 기본적으로 소수의 이벤트를 예측하는 경우가 많다.
- 금융사기 > 98명 정상 , 2명 사기
- 우리는 그 2명을 예측
그렇다면 샘플링을 하지 않으면 어떤 문제로가 발생할까? 우선 머신이 제대로 학습을 하기 어렵고, 정확도에 이슈가 생긴다. 예를 들면, 타이타닉데이터 1이 생존 0이 생존하지 않음일 때, 어디에 가중치를 두지 않고 9:1 상관없이 다 학습하면 90% 이상의 정확도가 나올 수 있다. 하지만 이 수치가 과연 정말 높은 수치일까?
- A모델 90%의 비중을 80% 정확하게 분류하고, 10% 비중을 100% 정확하게 분류
- B모델 90%의 비중을 90% 정확하게 분류하고, 10% 비중을 50% 정확하게 분류
90%의 비중의 분류 성능이 조금 떨어지더라도 10% 비중을 100% 정확하게 분류(예측)하는 게 더 적합할 수 있다.
위와 같은 이유로 인해 우리는 데이터 샘플링이 요구되는 경우가 있다. 샘플링 기법에는 어떤게 있는지 클래스에 대해 가중치를 두는 가중치 밸런싱 기법들을 살펴보도록 하자.
1. Random Under-Sampling
비중이 큰 클래스를 작은 비중의 클래스만큼 추출해서 학습하는 기법으로 데이트의 패턴이 조금은 줄어들 수 있다.
- 1(사기)이 1,000개 , 0(정상)이 10,000개 > 1(사기)이 1,000개 , 0(정상) 1,000개
2. Random Over-Sampling
비중이 작은 클래스를 비중이 큰 클래스만큼 복제해서 학습하는 기법으로, 중북되는 데이터가 섞이게 된다. 데이터의 크기가 커지지만, 단순히 동일한 관측치가 복제되는 것이므로 정보의 양이 증가하거나 손실하진 않는다. 다만 과적합이 될 수 있고, 좋은 샘플링 방법이라 보기에는 아쉬운 점이 있다.
- 1(사기) 1,000개면 > 복제 샘플링 > 10,000개
- 1과 0이 10,000개 , 10,000씩 > 20,000개의 데이터로 학습
3. SMOTE (Synthetic Minority Over-Sampling Technique)
대표적인 oversampling 기법으로 KNN 방식을 활용해 샘플링을 진행한다.
비중이 작은 클래스(사기)의 K최근접 이웃을 찾아서 그 이웃의 관측치들 사이의 값들을 새로운 데이터 관측치로 생성하는 원리이다. 이웃들 사이의 선에서 가상의 합성 샘플을 생성하고, 이를 반복해 원하는 데이터셋까지 만드는 것이다. 클래스의 경계의 있는 관측치들만 이용하여 샘플링하는 borderline SMOTE 기법도 있다.
4. ADASYN (Adaptive Synthetic Sampling Approach)
SMOTE 방식을 조금 더 발전 시킨 기법으로 관측치의 양을 조절할 수 있는 점이 장점이다.
전체에서 소수가 10% 정도를 차지할 때, 소수의 클래스마다 k-최근접 이웃을 계산해 다수의 클래스 샘플이 얼마나 많이 포함 되어 있는지 확인한다. 샘플링에 대한 비율을 계산했다면 소수 샘플에 대한 생성할 샘플의 수를 결정하기 위해서 다수의 샘플 비율인 Ri 값을 사용한다.
- (1/n x Ri) = g
기존의 소수 클래스 샘플과 그 이웃 사이에서 새로운 샘플을 생성한다.
이제 앞서 살펴본 4가지 샘플링 기법을 직접 실습을 통해 확인해보자.
1. 라이브러리 호출 및 불균형 데이터셋 생성
from sklearn.datasets import make_classification
from imblearn.over_sampling import RandomOverSampler, SMOTE, ADASYN
import matplotlib.pyplot as plt
import seaborn as sns
from collections import Counter
# 불균형한 데이터셋 생성
X, y = make_classification(n_samples=1000, n_features=2, n_informative=2, n_redundant=0,
n_clusters_per_class=1, weights=[0.9], flip_y=0, random_state=1)
# 클래스 비율 시각화
plt.figure(figsize=(6, 4))
sns.scatterplot(x=X[:, 0], y=X[:, 1], hue=y, palette='coolwarm')
plt.title("Original Dataset")
plt.show()
print(f"Original class distribution: {Counter(y)}")
2. 샘플링 진행
# 랜덤 오버샘플링
ros = RandomOverSampler(random_state=111)
X_ros, y_ros =ros.fit_resample(X,y)
# SMOTE
smt =SMOTE(random_state=111)
X_smt, y_smt =smt.fit_resample(X,y)
# ADASYN
ads=ADASYN(random_state=111)
X_ads, y_ads=ads.fit_resample(X,y)
3. 샘플링 결과 시각화
fig, axes = plt.subplots(1,4, figsize=(24,8))
#원본 데이터
sns.scatterplot(x=X[:,0], y=X[:,1], hue=y, palette='coolwarm', ax=axes[0])
axes[0].set_title('Original Dataset')
#랜덤 오버 샘플링
sns.scatterplot(x=X_ros[:,0], y=X_ros[:,1], hue=y_ros, palette='coolwarm', ax=axes[1])
axes[1].set_title('Random OverSampling Dataset')
#SMOTE
sns.scatterplot(x=X_smt[:,0], y=X_smt[:,1], hue=y_smt, palette='coolwarm', ax=axes[2])
axes[2].set_title('SMOTE Dataset')
#ADASYN
sns.scatterplot(x=X_ads[:,0], y=X_ads[:,1], hue=y_ads, palette='coolwarm', ax=axes[3])
axes[3].set_title('ADASYN Dataset')
plt.show()
'Data > Machine Learning' 카테고리의 다른 글
[ML] AutoML_TPOT으로 최적 모델 찾기 (1) | 2024.10.29 |
---|---|
[ML] Sweetviz와 Pipeline으로 모델링하기 (0) | 2024.10.29 |
[ML] 데이터 변환 (1) | 2024.08.19 |
[ML] 머신러닝에서의 거리기반 측정 (1) | 2024.08.12 |
[ML] Kmeans 알고리즘 + DBSCAN (2) | 2024.08.11 |