목표 : 우선 기본적인 모델 학습을 해보고
데이터 전처리(피처 엔지니어링)를 통해서 모델 성능이 향상되는지 확인해보자.
1 1. 데이터 로드 및 확인
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings("ignore")
%matplotlib inline
card_df = pd.read_csv('./creditcard.csv')
print(card_df.shape)
card_df.head(3)
>>> (284807, 31)
원본 DataFrame은 유지하고 데이터 가공을 위한 DataFrame을 복사하여 반환
from sklearn.model_selection import train_test_split
# 전처리 함수 : df의 Time 컬럼 삭제
def get_preprocessed_df(df=None):
df_copy = df.copy()
df_copy.drop('Time', axis=1, inplace=True)
return df_copy
3 3. Amount 피처 변환 후 다시 학습
# Amount feature의 분포도 확인
import seaborn as sns
plt.figure(figsize=(8, 4))
plt.xticks(range(0, 30000, 1000), rotation=60)
sns.distplot(card_df['Amount'])
-> Amount 피처는 롱테일 구조임을 알 수 있다.
3.1 (1) Amount 피처에 StandardScaler 적용
from sklearn.preprocessing import StandardScaler
# Amount 피처값을 StandardScaler 적용하는 함수
def get_preprocessed_df(df=None):
df_copy = df.copy()
scaler = StandardScaler()
amount_n = scaler.fit_transform(df_copy['Amount'].values.reshape(-1, 1))
# 변환된 Amount를 Amount_Scaled로 피처명 변경후 DataFrame맨 앞 컬럼으로 입력
df_copy.insert(0, 'Amount_Scaled', amount_n)
# 기존 Time, Amount 피처 삭제
df_copy.drop(['Time', 'Amount'], axis=1, inplace=True)
return df_copy
StandardScaler 변환 후 로지스틱 회귀 및 LightGBM 학습/예측/평가
# Amount를 정규분포 형태로 변환 후 로지스틱 회귀 및 LightGBM 수행.
X_train, X_test, y_train, y_test = get_train_test_dataset(card_df)
print('### 로지스틱 회귀 예측 성능 ###')
lr_clf = LogisticRegression()
get_model_train_eval(lr_clf, ftr_train=X_train, ftr_test=X_test, tgt_train=y_train, tgt_test=y_test)
print('### LightGBM 예측 성능 ###')
lgbm_clf = LGBMClassifier(n_estimators=1000, num_leaves=64, n_jobs=-1, boost_from_average=False)
get_model_train_eval(lgbm_clf, ftr_train=X_train, ftr_test=X_test, tgt_train=y_train, tgt_test=y_test)
### 로지스틱 회귀 예측 성능 ###
오차 행렬
[[85281 14]
[ 58 90]]
정확도: 0.9992, 정밀도: 0.8654, 재현율: 0.6081, F1: 0.7143, AUC:0.9702
### LightGBM 예측 성능 ###
오차 행렬
[[85290 5]
[ 37 111]]
정확도: 0.9995, 정밀도: 0.9569, 재현율: 0.7500, F1: 0.8409, AUC:0.9779
-> StandardScaler를 적용해도 평가지표는 변화 없는 것을 알 수 있다.
정확도: 0.9992, 정밀도: 0.8762, 재현율: 0.6216, F1: 0.7273, AUC:0.9592
.
3.2 (2) Amount 피처를 로그 변환
def get_preprocessed_df(df=None):
df_copy = df.copy()
# 넘파이의 log1p( )를 이용하여 Amount를 로그 변환
amount_n = np.log1p(df_copy['Amount'])
df_copy.insert(0, 'Amount_Scaled', amount_n)
df_copy.drop(['Time','Amount'], axis=1, inplace=True)
return df_copy
# log1p 와 expm1 설명
import numpy as np
# 0.0001 == 0.0 으로 인식하게 된다.
print(1e-1000 == 0.0)
print(np.log(1e-1000)) # 10의 -1000승
-> 컴퓨터가 0으로 인식함 이런 상황이 발생하지 않도록 1을 더해준다.
print(np.log(1e-1000 + 1))
>>>
-inf
0.0
print(np.log1p(1e-1000))
>>> 0.0
# log1p를 통하여 이를 해결할 수 도 있다.
var_1 = np.log1p(100)
var_2 = np.expm1(var_1)
print(var_1, var_2)
# 로그와 지수는 서로 왔다갔다 하는 관계이다
>>> 4.61512051684126 100.00000000000003
# train, test 데이터 분리
X_train, X_test, y_train, y_test = get_train_test_dataset(card_df)
print('### 로지스틱 회귀 예측 성능 ###')
get_model_train_eval(lr_clf, ftr_train=X_train, ftr_test=X_test, tgt_train=y_train, tgt_test=y_test)
print('### LightGBM 예측 성능 ###')
get_model_train_eval(lgbm_clf, ftr_train=X_train, ftr_test=X_test, tgt_train=y_train, tgt_test=y_test
### 로지스틱 회귀 예측 성능 ###
오차 행렬
[[85283 12]
[ 59 89]]
정확도: 0.9992, 정밀도: 0.8812, 재현율: 0.6014, F1: 0.7149, AUC:0.9727
### LightGBM 예측 성능 ###
오차 행렬
[[85290 5]
[ 35 113]]
정확도: 0.9995, 정밀도: 0.9576, 재현율: 0.7635, F1: 0.8496, AUC:0.9796
-> Amount 피처를 log변환 해주었더니 전반적으로 모델 성능이 향상되었다.
LightGBM 정확도: 0.9995, 정밀도: 0.9573, 재현율: 0.7568, F1: 0.8453, AUC:0.9790
4 4. 이상치 데이터 제거 후 모델 학습/예측/평가
4.0.1 corr() : 각 피처들의 상관 관계. 결정 레이블인 class 값과 가장 상관도가 높은 피처 추출
import seaborn as sns
plt.figure(figsize=(9, 9))
corr = card_df.corr()
sns.heatmap(corr, cmap='RdBu')
-> class와 상관관계가 높은 피처는 V12, V14, V17이 있다.
이 중 V14의 이상치를 제거해보자
Dataframe에서 outlier에 해당하는 데이터를 필터링하기 위한 함수 생성. outlier 레코드의 index를 반환함
import numpy as np
# 이상치를 찾는 함수
def get_outlier(df=None, column=None, weight=1.5):
# fraud에 해당하는 column 데이터만 추출, 1/4 분위와 3/4 분위 지점을 np.percentile로 구함.
fraud = df[df['Class']==1][column]
quantile_25 = np.percentile(fraud.values, 25) # 1/4 분위
quantile_75 = np.percentile(fraud.values, 75) # 3/4 분위
# IQR을 구하고, IQR에 1.5를 곱하여 최대값과 최소값 지점 구함.
iqr = quantile_75 - quantile_25
iqr_weight = iqr * weight
lowest_val = quantile_25 - iqr_weight # 이상치 최소 기준
highest_val = quantile_75 + iqr_weight # 이상치 최대 기준
# 최대값 보다 크거나, 최소값 보다 작은 값을 아웃라이어로 설정하고 DataFrame index 반환.
outlier_index = fraud[(fraud < lowest_val) | (fraud > highest_val)].index
return outlier_index
print(np.percentile(card_df['V14'].values, 100))
print(np.max(card_df['V14']))
>>>
10.5267660517847
10.5267660517847
outlier_index = get_outlier(df=card_df, column='V14', weight=1.5)
print('이상치 데이터 인덱스:', outlier_index)
>>>
이상치 데이터 인덱스: Int64Index([8296, 8615, 9035, 9252], dtype='int64')
-> 이상치가 4개가 나왔다. 추후 삭제 예정
4.0.2 로그 변환 후 V14 피처의 이상치 데이터를 삭제한 뒤 모델들을 재 학습/예측/평가
# get_processed_df( )를 로그 변환 후 V14 피처의 이상치 데이터를 삭제하는 로직으로 변경.
def get_preprocessed_df(df=None):
df_copy = df.copy()
amount_n = np.log1p(df_copy['Amount'])
df_copy.insert(0, 'Amount_Scaled', amount_n)
df_copy.drop(['Time','Amount'], axis=1, inplace=True)
# 이상치 데이터 삭제하는 로직 추가
outlier_index = get_outlier(df=df_copy, column='V14', weight=1.5)
df_copy.drop(outlier_index, axis=0, inplace=True)
return df_copy
X_train, X_test, y_train, y_test = get_train_test_dataset(card_df)
print('### 로지스틱 회귀 예측 성능 ###')
get_model_train_eval(lr_clf, ftr_train=X_train, ftr_test=X_test, tgt_train=y_train, tgt_test=y_test)
print('### LightGBM 예측 성능 ###')
get_model_train_eval(lgbm_clf, ftr_train=X_train, ftr_test=X_test, tgt_train=y_train, tgt_test=y_test)
### 로지스틱 회귀 예측 성능 ###
오차 행렬
[[85281 14]
[ 48 98]]
정확도: 0.9993, 정밀도: 0.8750, 재현율: 0.6712, F1: 0.7597, AUC:0.9743
### LightGBM 예측 성능 ###
오차 행렬
[[85290 5]
[ 25 121]]
정확도: 0.9996, 정밀도: 0.9603, 재현율: 0.8288, F1: 0.8897, AUC:0.9780
-> 로지스틱 회귀의 재현율이 많이 높아졌다.
LightGBM의 재현율도 향상되었다.
5 5. "SMOTE 오버 샘플링" 적용 후 모델 학습/예측/평가
# imbalanced-learn 패키지 설치하기
conda install -c conda-forge imbalanced-learn
from imblearn.over_sampling import SMOTE
# 타겟값 분포에 맞춰서 피처 데이터를 오버 샘플링 해준다.
smote = SMOTE(random_state=0)
X_train_over, y_train_over = smote.fit_sample(X_train, y_train)
print("오버 샘플링 적용 시 학습 데이터의 피처/레이블 차이")
print('오버 샘플링 적용 전 학습용 피처/레이블 데이터 세트: ', X_train.shape, y_train.shape)
print('오버 샘플링 적용 후 학습용 피처/레이블 데이터 세트: ', X_train_over.shape, y_train_over.shape, '\n')
print('오버 샘플링 적용 후 레이블 값 분포: \n', pd.Series(y_train_over).value_counts())
>>>
오버 샘플링 적용 시 학습 데이터의 피처/레이블 차이
오버 샘플링 적용 전 학습용 피처/레이블 데이터 세트: (199362, 29) (199362,)
오버 샘플링 적용 후 학습용 피처/레이블 데이터 세트: (398040, 29) (398040,)
오버 샘플링 적용 후 레이블 값 분포:
1 199020
0 199020
Name: Class, dtype: int64
-> 오버 샘플링 했더니 레이블 분포가 균형이 맞춰졌다.
# 오버 샘플링 적용 전 레이블 값 분포 - 극심한 불균형 상태
y_train.value_counts()
>>>
0 199020
1 342
Name: Class, dtype: int64
5.1 로지스틱 회귀로 학습/예측/평가
lr_clf = LogisticRegression()
# ftr_train과 tgt_train 인자값이 SMOTE 증식된 X_train_over와 y_train_over로 변경됨에 유의
get_model_train_eval(lr_clf, ftr_train=X_train_over, ftr_test=X_test, tgt_train=y_train_over, tgt_test=y_test)
오차 행렬
[[82937 2358]
[ 11 135]]
정확도: 0.9723, 정밀도: 0.0542, 재현율: 0.9247, F1: 0.1023, AUC:0.9737
-> 재현율은 높아졌으나, 정밀도는 낮아졌다.
# Precision-Recall 곡선 시각화
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from sklearn.metrics import precision_recall_curve
%matplotlib inline
def precision_recall_curve_plot(y_test , pred_proba_c1):
# threshold ndarray와 이 threshold에 따른 정밀도, 재현율 ndarray 추출.
precisions, recalls, thresholds = precision_recall_curve( y_test, pred_proba_c1)
# X축을 threshold값으로, Y축은 정밀도, 재현율 값으로 각각 Plot 수행. 정밀도는 점선으로 표시
plt.figure(figsize=(8,6))
threshold_boundary = thresholds.shape[0]
plt.plot(thresholds, precisions[0:threshold_boundary], linestyle='--', label='precision')
plt.plot(thresholds, recalls[0:threshold_boundary],label='recall')
# threshold 값 X 축의 Scale을 0.1 단위로 변경
start, end = plt.xlim()
plt.xticks(np.round(np.arange(start, end, 0.1),2))
# x축, y축 label과 legend, 그리고 grid 설정
plt.xlabel('Threshold value'); plt.ylabel('Precision and Recall value')
plt.legend(); plt.grid()
plt.show()
precision_recall_curve_plot( y_test, lr_clf.predict_proba(X_test)[:, 1] )
5.1.1 LightGBM 모델 적용
lgbm_clf = LGBMClassifier(n_estimators=1000, num_leaves=64, n_jobs=-1, boost_from_average=False)
get_model_train_eval(lgbm_clf, ftr_train=X_train_over, ftr_test=X_test,
tgt_train=y_train_over, tgt_test=y_test)
오차 행렬
[[85283 12]
[ 22 124]]
정확도: 0.9996, 정밀도: 0.9118, 재현율: 0.8493, F1: 0.8794, AUC:0.9814
-> LightGBM 모델은 정밀도도 괜찮게 나왔다.
'Machine Learning > 머신러닝 완벽가이드 for Python' 카테고리의 다른 글
ch. 4.10 스태킹 앙상블 모델 (0) | 2022.10.12 |
---|---|
스마트폰 구매 요인 분석(Decision Tree) (실습) (0) | 2022.10.12 |
ch.4.09 분류 실습 2 : 신용카드 사기 예측 실습 (1) | 2022.10.11 |
ch4.08 분류실습 _ 산탄데르 고객 만족 예측 (1) | 2022.10.11 |
ch 4.07_01 LightGBM(실습) (0) | 2022.10.11 |