Silver bullet
IQR 기반 Outlier 탐지 및 제거 & SMOTE Over-sampling 본문
imbalanced-learn 라이브러리는 Scikit-learn을 비롯해 많은 라이브러리들의 버전에 영향을 줍니다.
→ Colab에서 실습을 진행하는 것을 권장합니다.
* Original source @ https://www.kaggle.com/dogdriip/iqr-outlier-smote-oversampling/notebook
본 실습에서 다뤄지는 신용카드 데이터셋의 경우 심한 class-imbalance 상태임
- class 0 == 정상적인 신용카드 거래 데이터
- class 1 == 사기 신용카드 거래 데이터
전체 데이터셋 중 0.1715% 만이 class 1 (사기거래) 데이터
일반적으로 Fraud detection & Anomaly detection 의 대상이 되는 데이터셋의 경우
이처럼 class-imbalanced data인 경우가 많음 (Fraud or Anomaly 자체가 극히 드물게 발생하기 때문)
!pip install lightgbm==3.3.2
# "액세스가 거부되었습니다" 에러 발생 시,
# cmd(명령프롬프트) 우클릭 & 관리자권한으로 실행 후,
# "pip install lightgbm==3.3.2"를 입력 및 실행하여 설치를 진행합니다.
2) Imbalanced-learn (imblearn) 설치
- (로컬 환경에서 진행 시) cmd(명령프롬프트) 우클릭 & 관리자권한 실행 후, 아래 명령어를 입력해 설치를 진행합니다.
- 에러가 발생할 경우 뒷 부분의 버전 정보("==0.7.0")를 제외해주세요.
conda install -c conda-forge imbalanced-learn==0.7.0
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
import warnings
warnings.filterwarnings('ignore')
# 데이터 출처 : Credit Card Fraud Detection @ https://www.kaggle.com/datasets/mlg-ulb/creditcardfraud
card_df = pd.read_csv('creditcard.csv')
card_df.shape
card_df = card_df.drop('Time', axis=1)
sns.distplot(card_df['Amount'])
# 로그변환과 np.log()가 아닌 np.log1p()를 하는 이유 @ https://suppppppp.github.io/posts/Why-Series-MDM-1/
sns.distplot(np.log1p(card_df['Amount']))
card_df['Amount'] = np.log1p(card_df['Amount'])
로그가 아닌 standardscaling을 써도 됨.
3. Outlier 탐지 및 제거
본 데이터셋과 같이 Feature의 수가 무척 많을 경우, Label(Target) 열과 가장 높은 상관관계를 갖고 있는 Feature들을 위주로 Outlier handling을 진행해주는 것이 좋음
- 모든 Feature를 대상으로 이상치 검출 & 제거를 하는 경우 많은 시간이 소모됨
- 모든 Feature를 대상으로 이상치 검출 & 제거를 하는 경우 과도하게 많은 행이 삭제될 수 있음
- Label(Target) 열과 낮은 상관관계를 갖고 있는 Feature들의 경우 이상치 제거를 하더라도 결과적인 모델 성능 향상이 미미함
card_df.corr
plt.figure(figsize=(10, 10))
sns.heatmap(card_df.corr(), cmap='RdBu', linewidths=.5)

# Correlation dataframe 기준 최하단 "Class" 행에서 가장 절대값이 큰 상관관계를 보이는 feature 찾기
card_df.corr().loc['Class'].sort_values()
V17 -0.326481
V14 -0.302544
V12 -0.260593
V10 -0.216883
V16 -0.196539
V3 -0.192961
V7 -0.187257
V18 -0.111485
V1 -0.101347
V9 -0.097733
V5 -0.094974
V6 -0.043643
Amount -0.008326
V24 -0.007221
V13 -0.004570
V15 -0.004223
V23 -0.002685
V22 0.000805
V25 0.003308
V26 0.004455
V28 0.009536
V27 0.017580
V8 0.019875
V20 0.020090
V19 0.034783
V21 0.040413
V2 0.091289
V4 0.133447
V11 0.154876
Class 1.000000
Name: Class, dtype: float64
outlier_index = []
for col in ['V14', 'V17']:
# 전체 데이터프레임을 대상으로 outlier 제거 시, class 1 기준 행의 수가 492개에서 47개로 줄어들어버립니다.
df_fraud = card_df[card_df['Class'] == 1]
quantile_25 = df_fraud[col].quantile(0.25)
quantile_75 = df_fraud[col].quantile(0.75)
iqr = quantile_75 - quantile_25
outlier_df = df_fraud[(df_fraud[col] < quantile_25 - iqr * 1.5) | (df_fraud[col] > quantile_75 + iqr * 1.5) ]
outlier_index = outlier_index + list(outlier_df.index)
print(outlier_index)
[8296, 8615, 9035, 9252]
card_df = card_df.drop(outlier_index)
SMOTE 실습
Class-imbalance가 심한 데이터셋을 활용할 시,
무조건 대다수 데이터가 포함된 class를 선택하는 방식으로 모델이 잘못 학습될 수 있습니다. (다수 데이터 class에 치우친 학습 진행)
이 경우, 적은 수의 데이터가 포함된 class의 데이터 양을 늘려주는 방법(over-sampling)을 적용해볼 수 있습니다.
기본적으로 Over-sampling 기법들은 원본 데이터의 값을 살짝씩 변경해 새로운 데이터를 생성하는 방식으로 작동합니다.
저희가 활용할 SMOTE(Synthetic Minority Over-sampling Technique) 기법은
- 적은 수의 데이터가 포함된 class의 개별 데이터들에 대하여 K-Nearest-Neighbor들을 찾아,
- 원본 데이터와 K개 최근접 이웃 사이의 차이를 일정 값으로 만들어,
- 기존 데이터와 약간 차이가 나는 새로운 데이터들을 생성하는 방식으로 작동합니다.
x_data = card_df.copy()
del x_data['Class']
y_data = card_df['Class']
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(x_data, y_data,
test_size=0.3,
stratify=y_data)
print('[ Train y ]')
print(y_train.value_counts())
print(y_train.value_counts() / y_train.shape[0] * 100)
print()
print('[ Test y ]')
print(y_test.value_counts())
print(y_test.value_counts() / y_test.shape[0] * 100)
[ Train y ]
0 199020
1 342
Name: Class, dtype: int64
0 99.828453
1 0.171547
Name: Class, dtype: float64
[ Test y ]
0 85295
1 146
Name: Class, dtype: int64
0 99.829122
1 0.170878
Name: Class, dtype: float64
2) SMOTE 기반 Over-sampling
from imblearn.over_sampling import SMOTE
smote = SMOTE(random_state=42)
X_train_over, y_train_over = smote.fit_sample(X_train, y_train)
print('SMOTE-sampling 적용 전 :', X_train.shape, y_train.shape)
print('SMOTE-sampling 적용 후 :', X_train_over.shape, y_train_over.shape)
print('SMOTE-sampling 적용 전 :')
print(y_train.value_counts())
print()
print('SMOTE-sampling 적용 후 :')
print(y_train_over.value_counts())
SMOTE-sampling 적용 전 : (199362, 29) (199362,)
SMOTE-sampling 적용 후 : (398040, 29) (398040,)
SMOTE-sampling 적용 전 :
Class
0 199020
1 342
Name: count, dtype: int64
SMOTE-sampling 적용 후 :
Class
0 199020
1 199020
Name: count, dtype: int64
5. Model training & evaluation (Light-GBM 활용)
conda install lightgbm
model_with_smote = LGBMClassifier(n_estimators=1000,
num_leaves=64,
boost_from_average=False)
model_with_smote.fit(X_train_over, y_train_over) # Over-sampling 적용 후
pred = model_with_smote.predict(X_test)
pred_proba = model_with_smote.predict_proba(X_test)[:, 1]
confusion = metrics.confusion_matrix(y_test, pred)
accuracy = metrics.accuracy_score(y_test, pred)
precision = metrics.precision_score(y_test, pred)
recall = metrics.recall_score(y_test, pred)
f1 = metrics.f1_score(y_test, pred)
roc_auc = metrics.roc_auc_score(y_test, pred_proba)
print('Confusion matrix:')
print(confusion)
print()
print('Accuracy :', accuracy)
print('Precision :', precision)
print('Recall :', recall)
print('F1 :', f1)
print('ROC_AUC :', roc_auc)
Confusion matrix:
[[85275 20]
[ 26 120]]
Accuracy : 0.999461616788193
Precision : 0.8571428571428571
Recall : 0.821917808219178
F1 : 0.8391608391608392
ROC_AUC : 0.9784783993023407
SMOTE 기반 Over-sampling 적용 결과,
-> Class 1 데이터 증대
-> 실제 Class 값이 1 인 데이터 중 model 이 class 1 으로 잘 맞춰낸 비율인 Recall 상승
※ 일반적으로 Recall & Precision은 Trade-off 관계가 있음
precision : 모델이 True로 예측한 후 실제 True인 예측 결과의 수
recall : 실제 True인 데이터 중 우리 모델이 True로 예측한 결과의 수
'AI > AI' 카테고리의 다른 글
| Pipeline for StandardScaler & OneHotEncoder (0) | 2024.07.12 |
|---|---|
| Model Saving & loading + Model Stacking (0) | 2024.07.12 |
| Dimensionality Reduction & PCA (0) | 2024.07.11 |
| Clustering & K-means Algorithm / 클러스터 수 결정 기법 - Elbow method & Silhouette score (0) | 2024.07.11 |
| K-Nearest Neighbor Algorithm (0) | 2024.07.11 |