Skip to content

bcaitech1/p2-tab-CoodingPenguin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 

Repository files navigation

Online Store Customer Purchase Prediction

logo Photo by Mike Petrucci on Unsplash

📌 모델 학습 코드에 관한 설명은 code 폴더를 참고해주세요!


📝 Table of Contents


📖 대회 개요

배경

  • 최근 온라인 거래를 이용하는 고객들이 많이 늘어나고 있으며, 그에 대한 로그 데이터도 많이 들어나고 있다.
  • 이 로그 데이터를 이용하여 고객별 미래 소비를 예측하여 12월 고객 대상으로 프로모션을 통해 성공적인 마케팅을 이끌고자 한다.
  • 즉, 어느 정도 소비를 할지 예측하고 프로모션 물량, 세부 계획을 정하고자 한다.

문제 정의

2009년 12월부터 2011년 11월까지의 온라인 상점의 거리 데이터를 가지고 2011년 12월 고객 구매액이 300을 초과하는지 예측하는 분류 모델

  • input : 2009년 12월부터 2011년 11월까지의 거래 로그 데이터
    • 고객에 대한 정보 : 고객 id, 고객 거주 국가
    • 상품 정보 : 상품 id, 상품 설명, 상품 가격
    • 거래 정보 : 주문 id(동일한 주문 id가 존재가능), 주문 일자, 상품 수량
    • 총 구매액 : 상품 가격과 상품 수량을 곱한 값
  • output : 각 고객별 2011년 12월 총 구매액이 300을 넘는지 여부
    • 5914명의 고객 id
    • 넘는 경우 (1), 넘지 않는 경우 (0)으로 표기

평가 지표: AUC

  • ROC는 TPR(긍정이라 예측했을 때 실제 긍정인 비율)과 FPR(실제로 부정인데 긍정이라 잘못 예측한 비율)으로 나타낸 임계값을 말한다.
  • ROC의 임계값의 아래 영역을 AUC라고 한다.

🏆 대회 결과

  • 등수 28등, AUC 0.8587
  • 제출 횟수 20회

🔎 EDA

시각화 보다는 데이터의 값(value)에 집중하여 값의 분포 혹은 종류를 살펴보았다. 시각화의 경우 대회 둘째 날 제공된 베이스코드을 많이 참고했다. 데이터를 보면서 다음과 같은 질문들이 생겼고 그에 대한 답변은 다음과 같다.

Q. product_id는 어떤 규칙으로 구성되어 있을까?

  • 크게 3가지로 나눌 수 있었다. 5자리 숫자로 되어 있는 경우, 5자리 숫자와 1자리 혹은 2자리의 알파벳이 결합되어 있는 경우, 문자열로 되어있는 경우가 있었다.
  • 문자열로 되어 있는 경우로는 'POST', 'D', 'M', 'C2', 'PADS', 'DOT', 'CRUK', 'BANK CHARGES', 'TEST001', 'TEST002', 'ADJUST', 'ADJUST2', 'SP1002'가 있었다.

Q. 문자열로 되어있는 경우의 문자열들은 어떤 의미를 가질까?

  • POST의 설명이 POSTAGE인 것을 보아 택배 금액으로 추측했다. 나라별로 가격이 다를 것이라 생각되 살펴본 결과 유럽 국가 외 국가의 가격이 다소 높은 것을 볼 수 있었다. C2는 CARRIAGE로 POST와 비슷하지만, 영국과 가까운 나라 위주로 있는 것을 보아 일일특급과 같은 비싼 운송 서비스로 생각된다. DOT는 DOTCOM POSTAGE로 DOTCOM DISTRIBUTION이라는 e-commerce 사이트에 추가로 지급하는 금액으로 보인다.
  • D의 설명이 Discount인 것을 보아 할인과 관련된 금액으로 생각했다. quantity가 대부분 음수인 것을 보아 total도 대부분 음수라고 추측했다. 다만 quantity가 1인 소수의 데이터가 존재했다. M은 Manual의 약자로 직원이 직접 입력한 금액으로 생각했다. 보통 그런 경우는 대량주문을 하는 케이스라 생각되어 quantity를 살펴보았는데, quantity가 높은 경우가 일부 존재하였다.
  • CRUK은 Cancer Research UK로 자선단체이다. 모든 주문 건이 환불로 처리된 것을 보아 기부 내역으로 추측했다. 그 외 BANK CHARGES는 은행 수수료로, TEST001, TEST002는 관리자에 의한 테스트 데이터로, ADJUST, ADJUST2는 금액 조정 데이터로 추측하였다. SP1002는 특정 상품에 대한 데이터였다. PADS는 추가 옵션 같은 상품으로 추측하였다.

Q. customer_id가 12346인 고객은 쇼핑몰 관리자로 보인다. 그 외에 다른 관리자 계정이 존재할까?

  • 12346 고객의 경우 TEST001, TEST002, M과 같은 주문 건이 많았으며, 일반 상품에 대한 주문건의 경우에도 다른 상품임에도 가격이 동일한 것으로 보아 관리자 계정임을 확신하였다.
  • 그 외에 관리자 계정으로 추측된 14103, 14827, 16454, 16446의 주문 건을 살펴보았는데 14103, 14807은 TEST로그가 있는 것을 보아 테스트 계정으로 의심하였으며 16454, 16446은 테스트를 위한 일회용 계정으로 생각하였다.

🚀 접근 방법

Feature Engineering

제공된 베이스라인 코드의 feature_engineering 함수를 수정하여 나만의 피처를 만들거나 토의 게시판에 캠퍼들이 올려주신 여러 피처들을 참고하였다. 최종적으로 사용한 피처는 ✅으로 표시하였다.

시계열 ✅

  • 7강에 제공된 time-series관련 피처를 추가했다. order_date를 int형으로 바꾸어 구매 첫날과 최근 구매일을 피처로 생성했다. 그 외 주문 시간 차이, 수량 차이, 총 구매액 차이에 관한 피처를 생성하여 aggregation function을 적용하였다.
  • LightGBM 모델의 feature importance를 보면 order_ts가 가장 높은 중요도를 가지는 것을 볼 수 있었다. 그 외의 피처도 꽤 높은 중요도를 보여 최종 피처로 사용하였다.

환불

  • 환불과 관련된 데이터의 경우 order_id에 C가 있다는 점을 활용하여 환불 관련 피처를 생성하였다. is_refund는 환불 여부를, refund_total은 총 환불액이다. is_refund에는 sum을 적용하여 고객별 환불 건수를 계산했으며, refund_total에는 sum과 skew를 적용하여 고객별 총 환불액과 그에 대한 왜도를 피처로 생성하였다.
  • 모델 학습 시 매우 작은 중요도를 가졌으며, total값에 이미 환불관련 내용이 반영되어있다는 생각이 들어 최종 피처에서 제외하였다.

문자열 상품

  • product_id에서 보여준 문자열로 된 상품을 얼마나 구매했는지를 피처로 만들었다. 하지만 관련 데이터가 매우 적어 모델 성능에 큰 영향을 미치지 않을 것이라 생각되어 최종 피처에서 제외하였다.

가장 많이 구매한 달 ✅

  • order_date에서 월, 연월을 추출하여 만들었다. aggregation function으로 mode(최빈값)을 적용하였고 꽤 준수한 중요도를 보여주었고 최종 피처로 채택하였다.

트렌드와 계절성 ✅

  • 강민용 캠퍼님이 토의 게시판에 제공해주신 코드를 사용하여 월별, quarter 단위의 구매액, 수량, 가격관련 피처를 생성하였다. 기준 월은 강민용 캠퍼님의 값을 그대로 사용하였다.
  • 적용 결과 AUC가 0.8560에서 0.8579로 상승하는 매우 좋은 결과를 보여주었다. 또한 중요도도 높게 나와 최종 피처로 채택하였다.

Modeling

LightGBM

첫 번째 모델로 베이스코드에서 제공된 LightGBM 모델을 사용하였으며, 하이퍼파라미터는 그대로 사용하였고 검증 방법은 Stratified K-Fold기법을 사용하였고 예측시 Out of Fold Validation을 사용하였다. 위의 피처로 학습을 진행하면 Fold 별 validation score는 0.81과 0.82 사이를 왔다갔다 했으며, ouf of fold validation의 AUC는 0.81 정도의 값이 나왔다. 리더보드에 제출한 결과 AUC 0.8587로 가장 높은 성능을 보여주었다.

TabNet

두 번째 모델로 TabNet을 사용하였고 오피스 아워에 제공된 모델 스팩을 사용했으며 learning rate만 0.002로 변경하였다. TabNet의 경우 LightGBM에 비해 AUC값이 0.7 초반 대로 좋지 않은 성능을 보여주었다. 또한 예측 값이 LightGBM의 예측값에 비해 높게 형성되었다. 예측 방법에 문제가 있다 생각해 TabNet은 모든 학습 후에 예측을 하도록 구현했고 예측값이 LightGBM과 비슷한 분포를 보여주었다. 그래도 값이 높게 분포가 되어있었기 때문에 리더보드에 제출은 하지 않았다.

Soft Voting

마지막으로 LightGBM과 TabNet을 Soft Voting을 하였다. 이 때 TabNet의 성능이 좋지 않아 TabNet을 한 번 학습시키지 않고 3번 반복하여 학습시켰다. 그 결과를 LightGBM 결과값과 앙상블 시켰으나 리더보드에서 0.8498값을 얻었다.

그 외

어떤 피처는 값의 범위가 크고 어떤 피처는 작아서 Quantile Transform을 적용시켜보았다. 적용 결과 값이 전체적으로 작아지면서 학습 시간이 매우 빨라졌다. 하지만 가장 높은 성능을 보여준 경우에서 Quantile Transform을 적용하여 리더보드에 제출한 결과 AUC 0.8581로 성능이 조금 떨어졌다.


👀 회고

  • EDA는 딱 둘째 날까지! 저번 대회와 마찬가지로 이번 데회에서도 데이터에 대한 지식이 부족하다고 생각해 한 주를 EDA로 보냈지만 공개된 데이터의 특징 외에 더 특별한 것을 찾을 수 없었다. 또한 EDA를 하느라 첫 주의 제출횟수를 대부분 날려버렸다. 그 시간에 검증 전략을 새우고 어떤 피처를 만들지부터 고민하는 것이 더 중요하다는 생각이 들었다.
  • 검증 전략을 잘 세우자! 세 번째 피어세션 때 김기민 캠퍼님이 자신이 어떻게 리더보드 스코어를 올렸는지에 대한 많은 이야기를 들려주셨다. 그 중 가장 기억에 남는 것이 검증 전략이었는데, 여러 피처를 생각해서 적용해보고 나온 결과를 가지고 몇 시간 동안 분석을 한다고 하셨다. 특히 이번 대회의 제출횟수가 많이 부족하다고 생각해 검증을 하는데 시간을 꽤 들이셨다고 했다. 이번 대회를 급하게 마무리하느라 Mean AUC나 OOF AUC가 잘 나오면 제출을 했는데, 다음에는 왜 이런 결과가 나왔는지 분석하는 시간을 가지는 것이 좋을 것 같다.
  • 실험 환경은 미리미리! 이번 대회에서는 단순 수기로 평가 지표를 기록하였다. 이렇게 하니 정확히 어떤 모델인지 헷갈렸고 마지막에는 기억에 의존해야만 했다. 토의 게시판에 제출왕님이 mlflow 사용법을 올려주셨는데 "나중에 써야지"하고 바로 적용을 안해서 결국 마지막까지도 사용을 하지 못했다. 다음에는 실험 환경부터 적용을 해야겠다.
  • 고민보다 GO! 특히 이번 대회에서 피처를 생성하는데 주저함이 있었다. "이 피처는 이런 점 때문에 오히려 모델 성능을 떨어뜨리지 않을까" 생각을 많이 하였고 이로 인해 많은 피처를 생성해내지 못했다. 그러던 중 김기민 캠퍼님이 "그렇게 반례를 찾는 것보다 모델에 넣어 돌려보고 결과를 확인해보는 것이 더 낫다"고 조언을 해주셨다. 이 피처가 성능을 떨어뜨릴지 올릴지 모르는데 지레짐작 겁부터 먹었다. 다음 대회부터는 일단 만들어보고 그 결과를 바탕으로 결정을 해야겠다.

About

p2-tab-CoodingPenguin created by GitHub Classroom

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published