262pg. 캐글 신용카드 사기검출
아래의 링크에서 creditcard.csv 파일을 다운받고 아나콘다에서 오픈한다.
https://www.kaggle.com/mlg-ulb/creditcardfraud?select=creditcard.csv
불균형한 레이블 값 분포로 인한 문제점을 해결하기 위해서 적절한 데이터를 확보하는 샘플링 방법이 다음과 같이 있다.
언더샘플링: 많은 데이터 샘플을 적은 데이터 세트 수준으로 감소. (정상 레이블 데이터를 이상 레이블 수준으로 감소)
오버샘플링: 적은 데이터 세트를 증식하여 학습을 위한 충분한 데이터를 확보. (원본 데이터의 피처값을 조금씩 변경하여 과적합을 예방해야함, SMOTE방법이 있음)
- 45줄: 'Time' column을 삭제한다. (신용카드사기 데이터에서 Time은 상관없는 자료이기 때문)
test의 DataFrame을 살펴보자.
Class의 lable값은 2개다. 이를 print(card_df['Class'].value_counts()) 를 해보면 다음과 같다. 극단적으로 1 lable에 해당되는 값이 적다고 볼 수 있다.
- 63줄: feature, target 데이터를 분리한다.
- 78줄: label의 종류에 따른 비율
straty=y 변수설정으로 통해 학습/테스트 데이터의 레이블 값 비율이 비슷하게 나왔다.
정확도는 높으나 재현율이 좋지 않다. (사기가 맞는데 사기가 아니라고 판단할 확률이 높음) 신용카드 사기검출 케이스에 있어서는 재현율이 높아야 한다. (사기를 잡아내야 금전적인 피해를 줄일 수 있기 때문이다)
- 145줄: XGBoost, LightGBM은 병렬처리가 가능하다. LightGBM의 n_jobs=-1 은 가용할 수 있는 모든 CPU를 사용해서 가동하라는 듯이다. (boost_from_average=False는 저자도 잘 모름. False가 퍼포먼스가 더 잘 나옴)
데이터 StandardScaler를 이용해서 Amount 피처를 변환 후 재현율이 높아졌다.
- 161줄: card_df의 amount(신용카드결제금액)에 대한 막대그래프이다(xticks는 0-30000까지 1000스텝으로 표기한다. rotation은 x축의 글자 각도를 말한다.) distoplot은 히스토그램(빈도수)을 나타낸다. kde을 설정하지 않으면 기본값이 True이다.
-174줄: 데이터를 통해 도출할 수 있는 것은 카드 피해금액기 1000불 이내인 경우가 압도적으로 많았다는 것이다. 그러나 위와 같이 한쪽으로 데이터가 쏠려있으면 문제가 생긴다. StandardScaler로 정규화를 시킨다.
참고) kde (Kernel density estimation, 랜덤 변수의 확률 밀도 함수를 추정하는 비모수적 방법)은 일정 단위(전체데이터 샘플 수N, 고정된 부피V)에 데이터K가 포함될 확률 P(x)로 기본값은 True이다. kde=True로 변경하고 bins=20으로 설정하면 다음과 같은 결과가 도출된다.
- 161줄: sns.distplot에 kde=False, bins=20 값을 설정해주면 kde분포가 사라지고 히스토그램만 남는다. bins=20은 영역을 20등분하라는 뜻이다.
이산형 데이터: 셀 수 있는 값을 취하는 데이터
- 이항분포 확률질량함수: p확률의 사건을 n번 수행했을 때 k번 성공할 확률
- 이항분포 누적확률질량함수: p확률의 사건을 n번 수행했을 때 k번 이상 성공할 확률 (시그마 사용)
(이산형 데이터의 이항 분포는 연속된 n번의 독립적 시행에서 각 시행이 확률 p를 가질 때의 이산 확률 분포이다. )
연속형 데이터: 연속인 어떤 구간에서 값을 취하는 자료
- 확률밀도함수를 사용하고 적분을 통한 특정 영역의 넓이로서 구할 수 있다.
데이터의 분포: 실제 데이터는 정규분포와 같은 예쁜 분포를 따르지 않고 어떤 분포를 따르는 지 알 수 없다. 이런 경우 데이터의 분포를 추정하여 확률밀도를 추정하는 방법에는 histogram(이산형), kernel density estimation(연속형), K-nerest neighbor 등 다양한 방법이 있다.
Kerneal Density Estimation 에는 두가지 방법이 있다.
- Parzen Window: kernel method의 대표적인 방법으로 일정한 부피(넓이) 안에 들어갈 데이터의 개수를 세는 방식.
- Gaussian Kernel: 파이썬 KDE에서 사용하는 kernel method
-191줄: StandardScaler로 정규화 한 뒤 LogisticRegression, LightBGM 예측성능을 다시 한 번 한다.
(데이터 차이가 극단적으로 많이 나기 때문에 log값을 이용해서 데이터 차이를 줄인다.)
-235줄: log1p, 즉 log(1+x) 를 취하는 이유는 log(0.5)와 같은 음수값이 나오지 않게 하기 위해서다.
-262줄. corr( )은 두 변수간의 상관계수를 의미한다 (얼마나 같은 경향성의 움직임을 가지는가).
이렇게 이상치를 제거하고 정규화로 극단적인 데이터 값의 차이를 log를 통해 줄여준 결과 예측 성능은 다음과 같이 달라졌다 >> 재현율이 낮아짐 (신용카드사기검출에서는 Positive를 Negative로 잘못 예측하지 않도록 재현율이 높아야한다)
- 이 그래프에서는 똑같은 데이터끼리의 상관관계를 나타낸다. Time-Time, V1-V1 ......Class-Class
- 히트맵에서 cmap을 'RdBu'로 설정하여 양의 상관관계일수록 진한파란색, 음의 상관관계일수록 진한빨간색으로 표현된다. 이를 이용해 검출된 이상치를 삭제한다. (아래 V14, V17이 상대적으로 더 큰 음의상관관계를 가진다. 이러한 outlier를 제거해주는 편이 좋다)
271pg. 이상치 데이터 제거 후 모델 학습/에측/평가
- IQR(InterQuantile Range): 사분위 값의 편차를 이용하는 기법으로 박스플롯(Box Plot) 방식으로 시각화가 가능하다. 보통 IQRx1.5로 생성된 범위를 이용해 최댓값, 최솟값을 결정한 뒤 이를 초과하거나 미달하는 데이터를 이상치로 간주한다. 위의 그래프는 DataFrame의 corr( )를 이용해 각 피처별로 상관도를 구한 뒤 시본의 heatmap을 통해 시각화 한 것이다.
- 276줄: quantile은 4분위값을 말한다. (참고: describe( )함수에서도 quantile값 설정이 가능하다.)
- 286줄: lowest_val미만, highest_val이상 조건을 만족하는 불린값의 인덱스 값을 넣어라
- 302줄: V14 Column에 1.5가중치를 부여해서 이상치를 뽑아내면 4개의 인덱스값이 도출된다. (아래에서 이를 제거함)
-312줄: get_preprocessed_df 함수를 보면, get_outlier(이상치 인덱스 V14)를 axis=0(row방향)으로 지운다.
이상치를 제거하자 재현율이 올라갔다. (이는 신용카드 사기가 Positive인데 Negative로 예측할 확률이 줄어들었기 때문이다) 즉, Positive 예측값이 상대적으로 많아져서 로지스틱 회귀와 LightGBM 모두 예측성능이 크게 향상되었다. (167pg참고)
참고) 278pg. 재현율의 변화 (신용카드 사기검출에서는 재현율이 높아지는 것이 좋다. Positive를 Negative로 예측할 확률이 줄어들어 Positive를 Positive로 예측할 확률이 상대적으로 더 많아져야 하기 때문이다)
초기 재현율 및 주요 데이터 분포도 변환 후 재현율
정규화 StandardScaler한 뒤 재현율
Log1p( )를 이용하여 극단적인 값의 차이를 최소화한 뒤 재현율
outlier (V14) 제거 후 재현율
275pg. SMOTE 오버 샘플링 적용 후 모델 학습/예측/평가
- 관리자 권한으로 prompt를 연 뒤 imbalanced-learn 패키지 다운로드
- 학습데이터세트만 오버샘플링 해야만 함
- 로지스틱 회귀모델의 경우 SMOTE로 오버샘플링 되면 재현율이 크게 증가하지만 정밀도가 급격히 저하된다.
- LightGBM의 경우 SMOTE로 오버샘플링 되면 재현율이 증가하고 정밀도도 낮아진다.
>> 결론적으로 오버샘플링을 하면 재현율은 높아지고 정밀도는 낮아지게 된다.
- 340줄: fit_sample을 fit_resemple로 변환시킨다 (코드가 시행이 안됨)
TrainData를 오버샘플링하여 전체 데이터를 증식시킨다. value_counts( )를 하면 개수를 확인할 수 있다.
(0: Nagative / 1: Positive)
LogeisticRegression 수행을 해서 재현율을 확인한다. (재현율은 높아지고 정밀도가 낮아졌다)
임계치의 변화에 따라 재현율과 정밀도의 값이 어떻게 달라지는 지 Matplotlib 그래프로 확인해본다.
LightGBM의 재현율과 정밀도를 확인해보자. (LogisticRegression보다 균형잡힌 좋은 수치이다. LogisticRegression의 정밀도가 너무 낮기 때문이다.)
278pg. 스태킹앙상블
- 개별적인 여러 알고리즘을 서로 결합해 예측 결과를 도출한다. (예측한 데이터를 기반으로 다시 학습/예측을 수행한다는 점에서 기존 Bagging, Boosting과의 차이가 있다)
- concatenate(기하학적으로 붙임), merge(특정 key값을 기준으로 합집합/교집합으로 붙임)방식이 있다.
동일한 train data를 서로다른 estimator로 predict 하면 114개의 1차원 데이터들이 도출된다.
pred에는 predict된 데이터가 함께 column방향으로 묶여진 형태이다. (2차원데이터의 concatenate와 비슷)
참고) pred=np.array([knn_pred, rf_pred, dt_pred, ada_pred]) 는 4x114 행렬로 도출된다. row 0,1,2,3은 위에 각각의 estimator를 말한다.
transpose를 통해 4x114였던 행렬이 114x4행렬로 변화된다. (=전치행렬)
초기에 설정한 5개의 estimator 중 4개(학습용분류기 용도)를 활용한 estimator로 예측값을 도출하고 그 결과를 모아 최종 메타 모델인 LogisticRegression이라는 마지막 estimator를 lr_final.fit(pred, y_test)로서 적용한다. pred는 각각의 estimator에 의한 예측값을 모은 것이며, y_test는 114개 실제 테스트데이터 정답값이다.
질문) pred는 이미 학습한 데이터인데 final=lr_final.predict(pred)에 다시 학습을 시키면 당연히 모델 예측 정확도가 높게 나오는건 당연한 것이 아닐까? >> 최종학습에서 테스트용 레이블 데이터 세트를 기반으로 학습하여 과적합 문제 발생.
이 때문에 좀 더 복잡한 get_stacking_base_datasets 를 적용한다.
282pg. CV세트 기반의스태킹
과적합을 개선하기위해 최종 메타 모델을 위한 데이터 세트를 만들 때 교차 검증 기반으로 예측된 결과 데이터 세트를 이용한다.
- 학습용 데이터를 N개의 폴드로 나눈 뒤 유사한 반복작업을 수행한다.
- 마지막 N번째 반복에서 개별 모델의 예측값으로 학습데이터/테스트 데이터를 생성한다.
- 이러한 로직을 N번 반복하여 이 예측값의 평균으로 최종 결과값을 생성하고 이를 메타 모델을 위한 테스트 데이터로 사용한다.
Ex) 학습 데이터 300개 (이를 3fold하면 각각 100개의 학습데이터로 나뉨), 테스트 데이터 50개라고 하자. 1,2,3 데이터중 1,2 트레인, 3 검증하고 (교차검증) 이로인한 모델을 통해 테스트 데이터를 집어넣어서 예측값을 도출한다. 이러한 과정을 2번 더 경험한 뒤 (1,3 트레인, 2 검증/ 2,3 트레인, 1검증하면 총 3번 검증하기 때문에 다시 300개의 교차검증된 학습데이터가 나온다.) 예측값이 3개가 나오면 이를 column방향으로 평균한다. 그럼 테스트 데이터는 50개가 나온다.
***아래 115줄 shuffle=True로 바꿔줘야 함
- 118줄: X_train_n.shape[0], 1 >> 455x1 형태배열을 리턴한다. np.zeros는 데이터를 0으로 초기화된 shape의 ndarray배열을 반환. (교차검증의 예측값을 넣는 틀을 만듦)
- 119줄: test_pred는 114개의 데이터를 7개의 fold로 나눔. 114x7 shape의 ndarray에 0 값을 넣는다. (추후 estimator에 의한 예측값을 집어넣고 평균화하는 틀)
- 122줄: for문과 enumerate문을 통해 7번의 루프동안(cv=7이므로) 학습할 2-7 데이터에 해당하는 인덱스(train_index), 검증할 1 데이터에 해당하는 인덱스(valid_index)을 넣어 교차검증을 수행한다.
- 125줄: x_tr는 1-7번까지 교차검증의 2-7 트레인데이터, y_tr은 교차검증의 1검증값, x_te는 2-7의 레이블값(정답값)
- 133줄: train_fold_pred는 교차검증을 수행 한 결과값인 (65, ) 1차원 데이터가 나오는데 reshape를 통해 (65,1)의 2차원 데이터로 변환 (455x1에 값을 넣기 위해)
- 136줄: test_pred[ : , folder_counter]에 test데이터를 predict하여 예측값을 도출함. (7회 반복해서 114x7에 데이터를 채워넣는다)
- 141줄: test_pred_mean에서 114x7 행렬의 column방향으로 평균값을 도출하면 (114, ) 1차원 데이터가 나온다. 최종적으로 (114, 1)이 나오기 위해 reshape를 한다. (최종적으로 만들어지는 estimator의 예측값은 455x1, 114x1의 데이터 두 개가 나온다>> train_fold_pred, test_pred_mean)
아래 148-151줄은 위의 for문에서 반복이 된다. (4개의 estimator의 적용)
concatenate로 4개의 estimator의 결과값(예측값)을 column방향으로 붙인다.
- 157줄: 455x4에 해당하는 데이터가 만들어짐 (65개로 7 fold된 데이터 묶음의 합)
- 158줄: 114x4에 대항하는 데이터가 만들어짐
-167줄: 교차검증의 예측 레이블 Stack_fianl_X_train에 feature 데이터로 들어감. y_train에는 실제 결과값인 레이블값. 메타모델에서는 이 둘을 fit학습시킨다.
- 168줄: meta모델 학습에는 stack_final_X_test가 (test데이터를 각각의 교차검증을 통해 나온 예측값의 평균) test feature 값으로 들어가서 fit학습된 최종 퍼포먼스를 predict를 통해 확인해서 예측값을 도출한다. 이 결과를 y_test (실제정답값)와 비교한다.
참고) 122줄 for문에 test.append, test1.append를 통해 train_index, valid_index의 데이터 형태를 본다.
결론) CV세트 기반의 스태킹을 하지 않으면 test데이터를 이용해서 뱉어낸 예측값을들 stacking한 값들을 다시 학습시켰다. 그 학습된 것으로 예측을 하면 과적합 문제가 발생한다. (객관적이지 않음. train과 test가 철저히 분리되지 않았기 때문) 따라서 CV세트 기반의 스태킹(교차검증포함)을 한다면 train기반으로 만들어진 데이터와 test기반으로 만들어진 데이터로 분리되어 좀 더 객관적인 예측정확도를 도출할 수 있다.
'살콤아내 자기계발 > 파이썬' 카테고리의 다른 글
파이썬 온라인 교육 플랫폼_코드스테이츠, 정보통신진흥원NIPA, POSTECH MOOC (0) | 2021.05.25 |
---|---|
파이썬 머신러닝 완벽가이드 6주차 정리 (경사하강법, 퍼셉트론/아달린) (0) | 2021.05.24 |
파이썬 머신러닝 완벽가이드 5주차 정리 (244pg. LightGBM) (0) | 2021.05.18 |
파이썬 머신러닝 완벽가이드 5주차 정리 (분류 214pg~, 보팅분류기, 랜덤포레스트, XGBoost) (0) | 2021.05.17 |
파이썬 머신러닝 완벽가이드 4주차 정리 (분류 211pg~, 앙상블학습) (2) | 2021.05.12 |