-> 6조각 p262
-> 4, 5 p245
-> 4
-> 4
1. 정밀도: n->p 보면 큰일남. p155
2. 정밀도 = TP/(TP + FP) p라고 예측 p154
3. TPR = 민감도 = 재현율 = Recall p154
4. P:1 t:n -> n p151
5. p:1,n:0 -> 1 p151
캐글의 신용카드 dataset을 이용해 신용카드 사기 검출 분류 실습을 수행해 보겠다.
해당 dataset의 label인 Class 속성은 매우 불균형한 분포를 가지고 있다.
Class에서 0은 정상적인 신용카드 트랜잭션 데이터이고, 1은 신용카드 사기 트랜잭션을 의마하며, 전체 데이터의 약 0.172%만이 사기 트랜잭션이다.
일반적으로 사기 검출(Fraud Detection)이나 이상 검출(Anomaly Detection)과 같은 dataset은 label 값이 극도로 불균형한 분포를 가지기 쉽다.
필요한 모듈과 데이터를 로딩하고 데이터를 확인해보겠다.
pip install imbalanced-learn
import pandas as pd
import numpy as np
card_df = pd.read_csv('./creditcard.csv')
card.head(3)
card.info()
card.shape
V로 시작하는 feature는 의미를 알 수 없고,
Time feature는 데이터 생성과 관련한 작업용 속성으로서 큰 의미가 없어 제거하였다.
Amount feature는 신용카드 트랙잭션 금액을 의미하고,
card.info()로 확인해 보면 결측치(Missing Value) 값은 없다.
(1) time 칼럼을 삭제한다.
card.drop('Time', axis=1, inplace=True)
(2) 데이터셋 분리
from sklearn.model_selection import train_test_split
# DataFrame의 맨 마지막 컬럼이 레이블, 나머지는 피처들
features = card.iloc[:, :-1]
labels= card.iloc[:, -1]
# train_test_split( )으로 학습과 테스트 데이터 분할. stratify=labels 으로 Stratified 기반 분할
X_train, X_test, y_train, y_test = \
train_test_split(features, labels, test_size=0.3, stratify=labels)
# 학습 데이터 레이블 값 비율 p283
y_train.value_counts()/len(y_train)
# (3) 모델 생성, fit,predict,evaluate
from sklearn.linear_model import LogisticRegression
lr_clf = LogisticRegression(max_iter = 1000)
lr_clf.fit(X_train, y_train)
preds = lr_clf.predict(X_test)
preds_proba = lr_clf.predict_proba(X_test)[:,1]
get_clf_eval(y_test, preds ,preds_proba)
get_clf_eval 함수정의
from sklearn.metrics import roc_auc_score, confusion_matrix, accuracy_score, precision_score, recall_score, f1_score def get_clf_eval(y_test, pred=None, pred_proba=None): confusion = confusion_matrix( y_test, pred) accuracy = accuracy_score(y_test , pred) precision = precision_score(y_test , pred) recall = recall_score(y_test , pred) f1 = f1_score(y_test,pred) # ROC-AUC 추가 roc_auc = roc_auc_score(y_test, pred_proba) print('오차 행렬') print(confusion) # ROC-AUC print 추가 print('정확도: {0:.4f}, 정밀도: {1:.4f}, 재현율: {2:.4f},\ F1: {3:.4f}, AUC:{4:.4f}'.format(accuracy, precision, recall, f1, roc_auc))
# (3.1) 모델 생성, fit,predict,evaluate
from lightgbm import LGBMClassifier
lgbm_clf = LGBMClassifier(n_estimators= 1000, num_leaves= 64, n_jobs= -1, boost_from_average = False)
lgbm_clf.fit(X_train, y_train)
preds = lgbm_clf.predict(X_test)
preds_proba = lgbm_clf.predict_proba(X_test)[:,1]
get_clf_eval(y_test, preds ,preds_proba)
card["Amount"].describe()
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
card["Amount"] = scaler.fit_transform(card["Amount"].values.reshape(-1,1))
card["Amount"]
# (2) 데이터셋 분리
from sklearn.model_selection import train_test_split
# DataFrame의 맨 마지막 컬럼이 레이블, 나머지는 피처들
features = card.iloc[:, :-1]
labels= card.iloc[:, -1]
# train_test_split( )으로 학습과 테스트 데이터 분할. stratify=labels 으로 Stratified 기반 분할
X_train, X_test, y_train, y_test = \
train_test_split(features, labels, test_size=0.3, stratify=labels)
# (3) 모델 생성, fit,predict,evaluate
from sklearn.linear_model import LogisticRegression
lr_clf = LogisticRegression(max_iter = 1000)
lr_clf.fit(X_train, y_train)
preds = lr_clf.predict(X_test)
preds_proba = lr_clf.predict_proba(X_test)[:,1]
print(get_clf_eval(y_test, preds ,preds_proba))
print()
# (3.1) 모델 생성, fit,predict,evaluate
from lightgbm import LGBMClassifier
lgbm_clf = LGBMClassifier(n_estimators= 1000, num_leaves= 64, n_jobs= -1, boost_from_average = False)
lgbm_clf.fit(X_train, y_train)
preds = lgbm_clf.predict(X_test)
preds_proba = lgbm_clf.predict_proba(X_test)[:,1]
print(get_clf_eval(y_test, preds ,preds_proba))
import pandas as pd
import numpy as np
# 데이처 불러오기
card = pd.read_csv('/content/drive/MyDrive/book/creditcard.csv')
# (1) time 삭제
card.drop('Time', axis=1, inplace=True)
card["Amount"]
# 로그변환하기 (로그 사용 이유 : 숫자가 너무 커서)
card["Amount"] = np.log1p(card["Amount"])
card["Amount"]
# (2) 데이터셋 분리
from sklearn.model_selection import train_test_split
# DataFrame의 맨 마지막 컬럼이 레이블, 나머지는 피처들
features = card.iloc[:, :-1]
labels= card.iloc[:, -1]
# train_test_split( )으로 학습과 테스트 데이터 분할. stratify=labels 으로 Stratified 기반 분할
X_train, X_test, y_train, y_test = \
train_test_split(features, labels, test_size=0.3, stratify=labels)
# (3) 모델 생성, fit,predict,evaluate
from sklearn.linear_model import LogisticRegression
lr_clf = LogisticRegression(max_iter = 1000)
lr_clf.fit(X_train, y_train)
preds = lr_clf.predict(X_test)
preds_proba = lr_clf.predict_proba(X_test)[:,1]
print(get_clf_eval(y_test, preds ,preds_proba))
print()
# (3.1) 모델 생성, fit,predict,evaluate
from lightgbm import LGBMClassifier
lgbm_clf = LGBMClassifier(n_estimators= 1000, num_leaves= 64, n_jobs= -1, boost_from_average = False)
lgbm_clf.fit(X_train, y_train)
preds = lgbm_clf.predict(X_test)
preds_proba = lgbm_clf.predict_proba(X_test)[:,1]
print(get_clf_eval(y_test, preds ,preds_proba))
사분위는 전체 데이터를 값이 높은 순으로 정렬하고, 이를 25%씩으로 구간을 분할하는 것을 지칭한다.
IQR을 이용해 이상치 데이터를 검출하는 방식은 보통 IQR에 1.5를 곱해서 생성된 범위를 이용해 최대값과 최솟값을 결정한 뒤 최댓값을 초과하거나 최솟값에 미달하는 데이터를 이상치로 간주하는 것이다.
Q3에 IQR1.5를 더해서 일반적인 데이터가 가질 수 있는 최대값으로 가정하고, Q1에 IQR1.5를 빼서 일반적인 데이터가 가질 수 있는 최솟값으로 가정하였다.
경우에 따라 1.5가 아닌 값을 적용할 수도 있지만 일반적으로 1.5를 적용한다. 이렇게 결정된 최댓값보다 크거나, 최솟값보다 작은 값을 이상치 데이터로 간주한다.
이상치 데이터 IQR을 제거하기 위해 먼저 어떤 feature의 이상치 데이터를 검출할 것인지 선택이 필요하다. 매우 많은 feature가 있을 경우 이들 중 결정값(label)과 가장 상관성이 높은 feature들을 위주로 이상치를 검출하는 것이 좋다.
모든 feature들의 이상치를 검출하는 것은 시간이 많이 소모되며, 결정값과 상관성이 높지 않은 feature들의 경우는 이상치를 제거하더라도 크게 성능 향상에 기여하지 않기 때문이다.
DataFrame의 corr()을 이용해 각 feature 별로 상관도를 구한 뒤 시본의 heatmap을 통해 시각화해보았다.
# (1) 이상치 찾기, class가 1인것만 찾겠다.
fraud = card[card["Class"]==1]
fraud
fraud["V14"]
# IQR로 이상치 구하기
pct25 = np.percentile(fraud.V14, 25)
pct75 = np.percentile(fraud.V14, 75)
# IQR을 구하고, IQR에 1.5를 곱하여 최대값과 최소값 지점 구함.
IQR = pct75 - pct25
upper_out = pct75 + 1.5 * IQR
under_out = pct25 - 1.5 * IQR
# 최대값 보다 크거나, 최소값 보다 작은 값을 아웃라이어로 설정하고 DataFrame index 반환.
cond1 = fraud['V14'] >= upper_out
cond2 = fraud['V14'] <= under_out
cond3=fraud.V14[cond1 | cond2]
cond3.index
card.shape
#card에서 이상치를 빼주세요.
card = card.drop(labels = cond3.index, axis=0)
card.shape
# (2) 데이터셋 분리
from sklearn.model_selection import train_test_split
# DataFrame의 맨 마지막 컬럼이 레이블, 나머지는 피처들
features = card.iloc[:, :-1]
labels= card.iloc[:, -1]
# train_test_split( )으로 학습과 테스트 데이터 분할. stratify=labels 으로 Stratified 기반 분할
X_train, X_test, y_train, y_test = \
train_test_split(features, labels, test_size=0.3, stratify=labels)
# (3) 모델 생성, fit,predict,evaluate
from sklearn.linear_model import LogisticRegression
lr_clf = LogisticRegression(max_iter = 1000)
lr_clf.fit(X_train, y_train)
preds = lr_clf.predict(X_test)
preds_proba = lr_clf.predict_proba(X_test)[:,1]
print(get_clf_eval(y_test, preds ,preds_proba))
print()
# (3.1) 모델 생성, fit,predict,evaluate
from lightgbm import LGBMClassifier
lgbm_clf = LGBMClassifier(n_estimators= 1000, num_leaves= 64, n_jobs= -1, boost_from_average = False)
lgbm_clf.fit(X_train, y_train)
preds = lgbm_clf.predict(X_test)
preds_proba = lgbm_clf.predict_proba(X_test)[:,1]
print(get_clf_eval(y_test, preds ,preds_proba))
from imblearn.over_sampling import SMOTE
from sklearn.linear_model import LogisticRegression
from lightgbm import LGBMClassifier
# DataFrame의 맨 마지막 컬럼이 레이블, 나머지는 피처들
features = card.iloc[:, :-1]
labels= card.iloc[:, -1]
# train_test_split( )으로 학습과 테스트 데이터 분할. stratify=labels 으로 Stratified 기반 분할
X_train, X_test, y_train, y_test = \
train_test_split(features, labels, test_size=0.3, stratify=labels)
smote= SMOTE(random_state = 0)
X_train, y_train = smote.fit_resample(X_train, y_train)
# (3) 모델 생성, fit,predict,evaluate
lr_clf = LogisticRegression(max_iter = 1000)
lr_clf.fit(X_train, y_train)
preds = lr_clf.predict(X_test)
preds_proba = lr_clf.predict_proba(X_test)[:,1]
print(get_clf_eval(y_test, preds ,preds_proba))
print()
# (3.1)모델 생성, fit,predict,evaluate
lgbm_clf = LGBMClassifier(n_estimators= 1000, num_leaves= 64, n_jobs= -1, boost_from_average = False)
lgbm_clf.fit(X_train, y_train)
preds = lgbm_clf.predict(X_test)
preds_proba = lgbm_clf.predict_proba(X_test)[:,1]
print(get_clf_eval(y_test, preds ,preds_proba))
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] )
출처:
https://colab.research.google.com/drive/17jkzmhVqdvMx6tUpEVKAYFP5zokFF7UO#scrollTo=WB-QfCmtf44f -> 책 정리 잘하심.
https://m.blog.naver.com/wideeyed/221867273249 -> 베이직 판다스 보기 좋음.
오류모음: