Mission


  • Kaggle 신용카드 데이터셋을 활용해 "신용카드 사기 검출" 분류
    • 고객이 구매하지 않은 상품에 대한 요금 청구를 방지

조건


  • 분류 알고리즘 사용
  • 예측 값: Class (0:정상, 1:사기)
  • 평가: ROC-AUC

🔗 프로젝트 링크



프로젝트 정리


데이터셋 준비

  • train data, test data, sample submission data

데이터 이해 및 탐색(EDA)

  • 기본 데이터 형태 확인

  • Train

    • id : 고유 숫자 부여
    • Time : 각 거래와 데이터셋의 첫 거래 사이의 경과 시간(초)
    • V1 ~ V28 : PCA로 얻은 주성분
    • Amount : 거래 금액
    • Class : 응답 변수(사기 거래인 경우 1, 그렇지 않은 경우 0) -> "Target" 데이터!
  • train의 경우, int형 데이터 및 float형 데이터 -> 즉, 수치형 데이터만 존재

    • (데이터셋 설명 파트에서 "이 데이터셋은 PCA 변환을 거친 수치형 변수들만 포함"이라는 근거가 있음)
  • 결측치는 없는 것으로 확인


  • Test
    • Train 데이터와 동일

  • Submission
    • 추후 제출할 데이터셋의 일부 형태
    • id, class

데이터셋 인포메이션

  • Dataset Description에서 확인해보자.
    • "클래스 불균형 비율을 고려하여, 정밀도-재현율 곡선 아래 영역(AUPRC)을 사용하여 정확도를 측정할 것을 권장합니다. 불균형 분류에서는 혼동 행렬 정확도가 큰 의미가 없습니다."
    • 해당 단락에서 유추할 수 있듯 Class 속성은 불균형 분포를 가지고 있음!
    • 정상 거래에 비해 사기 거래가 현저히 적은 것이 대부분이기 때문에 불균형 분포를 가지는 것이 당연
      • 'Class' : 응답 변수로, 사기 거래인 경우 1, 그렇지 않은 경우 0의 값
  • 데이터 특징
    • PCA 변환을 거친 수치형 변수만 포함
    • Vn형태의 컬럼: PCA로 얻은 주성분
    • 'Time', 'Amount'는 PCA 작업 X
      • 'Amount' : 예시 의존적 비용 민감 학습 등에 사용 가능

결측치 및 이상치

  • 결측치는 없는 데이터이기 때문에 불필요. 또한, 결측치를 특정 데이터로 대체한 흔적도 현재는 보이지 않는 것으로 판단
  • 이상치의 경우, 이상치 데이터가 있는 경우와 제거 후의 경우를 함께 확인하기 위해 현 단계에서 처리하지 않음.
    이상치는 IQR로 제거 예정

라이브러리 import

  • seaborn : 시각화에 필요
  • pyplot : 시각화에 필요
  • train_test_split : 테스트 데이터 생성을 위해 필요
  • StandardScaler : 빠르게 스탠다드 스케일링을 진행할 예정
  • LogisticRegression : 로지스틱 회귀 모델에 필요
  • RandomForestClassifier, GradientBoostingClassifier : 모델
  • roc_auc_score : 결과 수치를 보기 위해 필요

불균형 분포 데이터 Class 확인

  • 수치로 알 수 있듯, 정상 거래 데이터에 비해 사기 거래 데이터는 현저히 적음

  • 머신러닝 모델에서는 극도로 불균형한 레이블 값 분포는 좋은 성능을 내기 어려움 -> 오버 샘플링으로 보완

  • 왜?

    • 현재 중심을 두고 봐야 하는 데이터는 사기 거래 데이터인데, 이 데이터의 양이 매우 적기 때문에 학습을 위해서는 충분한 데이터를 확보해야한다는 의견이 있기 때문
    • SMOTE를 이용해 K nearest Neighbor를 찾아 -> 이 데이터와 K개 이웃 간 차이를 일정한 값으로 만들어 값을 증식할 예정
  • 정상 범주에 속하는 데이터 1의 경우 그 수가 많지만, 사기 거래 데이터인 0인 경우 적게 분포하고 있음을 확인 가능


데이터 스케일링 및 인코딩

  • StandardScaler로 데이터 평균을 0, 표준 편차를 1로 맞추기
  • 모델에 적용할 때 성능을 더 잘 올리기 위해서 간단히 적용
  • 인코딩의 경우, 주요 컬럼에서 굳이 필요하지 않다고 판단하여 진행하지 않음

피쳐 엔지니어링

  • 컬럼 자체가 많은 편이 아니기 때문에, 굳이 필요하지 않은 Time 컬럼을 제외하고 고려했을 때 Amount를 생각해볼 수 있음.
  • Amount 값의 스케일이 다른 컬럼에 비해 큰 편이기 때문에 -> 모델이 빠르게 학습하기 어려울 수 있음
  • 즉, Amount를 로그 값으로 변환해서 스케일을 줄이면 모델 학습에 있어 유리할 것으로 판단
  • 불필요한 컬럼인 Time은 삭제하기(사기 거래 예측에 필요하지 않은 데이터라 판단)
    • DataFrame을 복사해서 Time 피쳐만 삭제해서 복사한 DataFrame을 반환하기

학습 데이터 및 테스트 데이터 세트 분리

  • 본격적인 모델 학습을 위해 데이터 세트를 분리!

  • get_train_test_dataset()

    • 위의 Time 컬럼 삭제 함수 get_preprocessed_df()를 불러오기
    • split으로 학습 및 테스트 데이터 분할
      • 테스트 데이터 세트를 전체의 30%(Stratified) 방식으로 추출해 학습 데이터 세트 및 테스트 데이터 세트 레이블 값 분포도를 최대한 동일하게 만들기
      • 참고 : 교재에서는 레이블 값 분포도를 Stratified 방식으로 추출하여 유지하는데, y_target의 경우 현재 고유값도 2개 이상이며 결측치도 없지만 ValueError가 발생했었음.
        • Amout_log 컬럼을 맨 마지막에 파생 변수로 추가해서, 교재의 코드는 사용할 수 없기 때문에 X_features와 y_target을 Class 컬럼으로 정확히 명시하여 에러 삭제 완료.
  • 학습 데이터 세트 및 테스트 데이터 세트 레이블 값 비율 확인(백분율)

    • 학습 데이터의 1 비율 : 0.210671
    • 테스트 데이터 1 비율 : 0.21067

모델

  • 로지스틱 회귀 : 해당 데이터는 분포가 선형적이기 때문에 선형 모델에 적용하면 좋은 성능을 낼 수 있을 것으로 판단
  • 랜덤 포레스트 : 앙상블 학습, 해당 데이터에서의 상관관계가 일정한 특징을 띄지 않는 것으로 파악되어 복잡한 관계에서 유리한 모델도 사용해보는 것으로 판단
  • LightGBM : 현재 데이터의 가장 큰 특징인 "불균형 데이터"에 가장 적합한 모델이기 때문
    • 랜덤 포레스트도 사용해보려는 이유 : 상관 행렬 계산만으로, 현 단계에서는 피쳐 간의 명확한 상관과계 수치의 이유를 파악하기 어렵다고 판단했기 때문

  • 로지스틱 회귀

    • get_clf_eval 함수를 가져와 사용
    • 오차 행렬과 정확도, 정밀도, 재현율, F1, ROC-AUC를 보여주기 때문
  • 첫 로지스틱 회귀 결과

    • 정확도: 0.9990
    • 정밀도: 0.8452
    • 재현율: 0.6574
    • F1: 0.7396
    • ROC-AUC:0.9125

  • LightGBM
    • Estimator 객체 및, 학습 데이터 세트 입력을 통해 학습, 예측, 평가 수행
  • 첫 랜덤 포레스트 결과
    • 정확도: 0.9995
    • 정밀도: 0.9255
    • 재현율: 0.8056
    • F1: 0.8614
    • ROC-AUC: 0.9335

첫 모델 학습 결과 정리

  • 모든 지표가 LightGBM > 랜덤 포레스트 > 로지스틱 회귀 순!
  • LightGBM이 불균형 데이터에서 가장 사용하기 좋은 모델임을 증명함

첫 모델 학습 결과를 앙상블로 확인

  • Voting Classifier를 사용해서 앙상블을 구성하고, ROC-AUC를 출력
  • 앙상블 모델의 ROC-AUC : 0.9334

데이터 분포도를 변환해서 다시 모델을 학습/예측/평가

  • Amount 피쳐

    • 1000불 이하의 데이터가 대부분
    • 26,000불까지 드물지만 많은 금액을 사용한 지표가 있음 -> 꼬리가 긴 분포 곡선을 가지고 있음
  • 로지스틱 회귀

    • 선형 모델이기 때문에 데이터가 정규 분포 형태를 띄는 것이 모델 성능에 좋음
    • Amount의 경우도 로지스틱 회귀에서 조금 더 데이터를 잘 받아들일 수 있도록 정규 분포 형태로 변환하기로 결정
  • standardScaler로 Amount를 정규분포 형태로 변환

    • 변환한 Amount는 Amount_Scaled로 컬럼명 변경
    • 또한, 맨 앞으로 이동
    • 기존의 컬럼인 Time과 Amount는 필요하지 않으므로 삭제
  • 로지스틱 회귀, 랜덤 포레스트, LightGBM 재수행

    • 로지스틱 회귀의 모든 수치는 동일
      • 이를 통해, 해당 모델은 Amount 컬럼의 값에 지대한 영향을 받지는 않는 것으로 판단
    • 랜덤 포레스트의 모든 수치는 상승
      • Amount의 로그 변환이 성능 향상에 영향을 미쳤다고 볼 수 있음
    • LightGBM의 모든 수치도 상승
      • 이 역시 이유 동일(가장 많이 상승)

이상치 데이터를 제거하고 다시 모델을 학습/예측/평가

  • Class와의 음의 상관관계 최고치 : V14, V17
  • 이전에 언급했듯, 이상치 제거는 IQR을 이용
    • V14에 대한 이상치 제거만 진행
  • 이상치 추출 및 제거하는 함수 get_processed_df()
    • 로그 변환 + V14 피쳐 이상치 데이터 삭제 로직으로 변경

  • 이상치 제거 이전과 이후의 성능 변화 살펴보기
    • 로지스틱 회귀 : 정확도 동일, 정밀도 하락, 재현율 상승, F1 하락, ROC-AUC 상승
    • 랜덤 포레스트 : 정확도 동일, 정밀도 상승, 재현율 상승, F1 상승, ROC-AUC 상승
    • LightGBM : 정확도 상승, 정밀도 상승, 재현율 상승, F1 상승, ROC-AUC 상승
  • 얻을 수 있는 인사이트
    • 불균형 데이터에 가장 적합하다고 알려진 LightGBM의 경우가 피쳐 데이터 가공 시에 눈에 띄는 성능 개선이 보임

SMOTE 오버 샘플링 적용 후 모델 학습/예측 평가

  • 주의 사항 : 학습 데이터 세트만 오버 샘플링 해야 함!

    • 검증 데이터 세트 또는 테스트 데이터 세트 오버 샘플링을 하게 되면, 결국 원본 데이터 세트가 아닌 데이터를 통해 검증이나 테스트가 수행되기 때문에 올바르게 검증하고 테스트했다고 보기 어려움
  • 데이터 증식 및 Class의 0과 1 값이 동일하게 설정

  • 로지스틱 회귀

    • 직전에 비해 정확도, 정밀도, F1이 하락했고, 재현율과 ROC-AUC는 상승
    • 재현율은 높을지언정 정밀도가 현저히 낮아졌기 때문에 이 결과는 신뢰도가 떨어질 수밖에 없음.
    • 이 모델이 실제 테스트 데이터 세트에서 예측을 Class=1에 지나치게 적용하면서 정밀도가 떨어진 것
  • 분류 결정 임곗값에 따른 정밀도와 재현율 곡선으로 문제 확인

    • precision_recall_curve_plot() 함수 사용
    • 지표 분석
      • 임계값 0.99 이하
      • 재현율 양호, 정밀도 낮음
      • 임계값 0.99 이상
      • 재현율 낮아짐 -> 정밀도 급상승
      • 즉, 로지스틱 회귀의 경우 SMOTE로 오버 샘플링하는 것은 적합하지 않음을 결론으로 내릴 수 있음
  • 랜덤 포레스트

    • 직전과 비교했을 경우 정확도 동일, 정밀도 및 재현율 상승, 또한 ROC-AUC 상승
    • F1 하락
      • 지표를 분석해보면 오버 샘플링을 통해 정확도가 낮아지는 문제가 생기지 않았고, 다른 모든 지표가 대부분 눈에 띌 정도로 상승했기 때문에 SMOTE를 적용하는 것에 의미가 있는 모델임을 알 수 있음
  • LightGBM

    • 첫 모델 학습 시기와 비교하면 이전의 앙상블 모델 ROC-AUC는 0.9334
    • 현재 모델은 ROC-AUC가 0.9483으로 상승했음을 확인할 수 있음
      • 큰 폭으로 상승했다고 보기에는 다소 어려울 수 있으나, 데이터의 분포도를 확인해서 Amount를 로그로 변환하고, 이상치 데이터를 처리했기 때문에 모델 성능이 상승했다고 판단해볼 수 있음

하이퍼파라미터 튜닝

  • 로지스틱 회귀

    • C를 이용해서 -> 정규화 강도를 높여가고
    • liblinear와 saga 2가지의 최적화 알고리즘을 써서(데이터셋의 크고 작음에 따름) 튜닝 시도
    • K-폴드 교차 검증으로 진행(5개)
      • CV를 5개로 지정해서 이전과 어떻게 달라지는지 확인하기
  • 랜덤 포레스트

    • 시간이 오래걸리는 문제가 있기 때문에 RandomizedSearchCV를 이용해 탐색
  • 트리 개수, 트리의 max_depth, min_samples_split를 이용한 튜닝 진행

  • 이렇게 했음에도 불구하고 시간이 과도하게 오래 소요되는 문제가 있어 임의의 값으로 진행

    • Best parameters for Random Forest: {'n_estimators': 100, 'max_depth': 10, 'min_samples_split': 2}로 임의 설정
  • LightGBM

  • 시간이 오래걸리는 문제가 있기 때문에 RandomizedSearchCV를 이용해 탐색!

  • 리프 노드의 경우, 너무 많으면 과적합이 발생할 수 있으니, 적당하게 설정!

  • 학습률도 비슷.

  • 트리 개수와 max_depth도 지정


최적 파라미터로 재학습

  • 로지스틱 회귀

    • 하이퍼 파라미터 튜닝 이전 vs 이후
      • 정확도 : 0.9582 -> 0.9986 ⬆️
      • 정밀도 : 0.0427 -> 0.7846 ⬆️
      • 재현율 : 0.8879 -> 0.4766 ⬇️
      • F1 : 0.0815 -> 0.5930 ⬆️
      • ROC-AUC : 0.9627 -> 0.9051 ⬇️
  • 랜덤 포레스트

    • 하이퍼 파라미터 튜닝 이전 vs 이후
      • 정확도 : 0.9995 -> 0.9995 -
      • 정밀도 : 0.9100 -> 0.9368 ⬆️
      • 재현율 : 0.8505 -> 0.8318 ⬇️
      • F1 : 0.8792 -> 0.8812 ⬆️
      • ROC-AUC : 0.9657 -> 0.9847 ⬆️
  • LightGBM

    • 하이퍼 파라미터 튜닝 이전 vs 이후
      • 정확도 : 0.9995 -> 0.9995 -
      • 정밀도 : 0.8911 -> 0.9175 ⬆️
      • 재현율 : 0.8411 -> 0.8318 ⬇️
      • F1 : 0.8654 -> 0.8725 ⬆️
      • ROC-AUC : 0.9793 -> 0.9819 ⬆️
  • 결과 분석

    • ROC-AUC를 기준으로 봤을 경우, 랜덤 포레스트 > LightGBM > 로지스틱 회귀 순
      • 해당 데이터는 불균형 데이터이기 때문에 그 형태에 조금 더 적합한 LightGBM을 사용하거나, 수치상으로 Best인 랜덤 포레스트를 사용할 수도 있을 것으로 결론
      • 다만, 랜덤 포레스트의 경우, 설정값에 따라 아주 오랜 시간이 소요될 수 있어 주의 요망

앙상블로 최종 ROC-AUC 확인

  • 앙상블 결과 비교(ROC-AUC)

    • First : 0.9334
    • Second : 0.9483
    • Final : 0.9431
  • 대체적으로 약 0.93에서 약 0.94까지 성능 지표를 올린 것으로 결론

  • 최종 결과 분석

    • 하이퍼 파라미터 튜닝 전 : LightGBM > 랜덤 포레스트 > 로지스틱 회귀
    • 하이퍼 파리미터 튜닝 후 : 랜덤 포레스트 > LightGBM > 로직스틱 회귀
    • 즉, 이번 신용카드 사기 검출 데이터에서 가장 적합한 모델은 랜덤 포레스트 또는 LightGBM
    • 불균형 데이터이기 때문에 LightGBM으로 선정
profile
언젠가 내 코드로 세상에 기여할 수 있도록, Data Science&BE 개발 기록 노트☘️

0개의 댓글

관련 채용 정보