[Kalapa Credit Challenge] Giải nhất cá nhân (with Code)

machine-learning
data-science
kalapa

#1

Chào cả nhà,

Mình là Khánh Linh, học trò của thầy Harry Nguyễn.

Trước hết, mình xin gửi lời cảm ơn tới BTC Kalapa Challenge & AIviVN đã cho Linh và mọi người có cơ hội được trải nghiệm, thử sức một bài toán rất hay và thực tế.

Linh biết tới cuộc thi và tham gia hơi muộn so với các anh chị trong top 5, tuy vậy Linh hi vọng mọi người ủng hộ những chia sẻ của mình. Linh cũng may mắn vì đang tham gia một số dự án Fintech AI với thầy, và cuộc thi này là dịp tốt để mình áp dụng những kiến thức đã được tích luỹ. Được kết quả này, Linh quá là vui, vừa được thử sức vừa có ‘quà’, hihi.

Theo yêu cầu của BTC, Linh xin trình bày giải pháp tiếp cận như sau:

1. Khảo sát và phân tích dữ liệu

Qua việc khảo sát dữ liệu, mình có một vài nhận xét sau:

  • Imbalance data: 30k dữ liệu train mà có mỗi 486 nhãn ‘bad’ :frowning:
  • Missing data: Có tới hơn 40 trường dữ liệu thiếu > 30% :frowning:
  • Noisy data: Chưa được chuẩn hoá (vd: maCv), sai chính tả (vd: province), nhập nhằng vừa chữ cái/chuỗi vừa số (vd: FIELD_40), giá trị ‘None’ chiếm phần lớn…
  • Dữ liệu BTC cung cấp được tổng hợp từ ít nhất 2 nguồn dữ liệu thông qua một số indicator (FIELD_23), và trường tuổi (age_source1, age_source2). Mất kha khá thời gian xem xét, mình đoán rằng hai nguồn dữ liệu đó có thể là bảo hiểm xã hội (BHXH) và bảo hiểm y tế (BHYT).

Những observations này giúp cho Linh rất nhiều trong việc xử lý đặc trưng cho phù hợp. Mình có ghi lại các nhận xét cụ thể cho từng trường và cách xử lý, mọi người có thể tham khảo thêm trong file KalapaDataAnalysis.pdf

2. Tiền xử lý và chuyển đổi thuộc tính

Dựa trên các observations từ dữ liệu, mình chia các trường ra thành 3 loại: numerical, categorical và text tương ứng với các phương pháp tiền xử lý:

  • Numerical: Chuẩn hoá một số trường như ‘age’ (chọn đại diện, chia nhóm) và sinh thêm vài đặc trưng mới như FIELD_7_COUNT là chiều dài mảng mã hai ký tự.
  • Categorical: Đã thử một số cách như: ordinary encoding, target encoding, WOE. Tuy nhiên, WOE cho kết quả tốt nhất, variance nhỏ nhất trên tập validation.
  • Text (province, district, maCv): Đây là những trường có nhiều unique values, nếu tiếp cận theo hướng categorical thông thường sẽ làm tăng tính sparsity của dữ liệu. Mình quyết định encode các trường này sử dụng pre-trained embeddings (geolocation, fine-tuned) từ dự án của thầy.

Qua đây, mình xin cảm ơn anh Nguyen Chi Dung đã chia sẻ cách làm bằng ngôn ngữ R (https://rpubs.com/chidungkt/571838), đặc biệt phần WOE binning rất hiệu quả. Ban đầu, mình chỉ sử dụng cho các trường categorical, nhưng sau quyết định áp dụng thêm cho tất cả các trường numerical luôn và thấy có kết quả tốt hơn.

Tập đặc trưng cuối cùng là kết hợp của các giá trị WOE binning trên các trường categorical, numerical; và vector embeddings của các trường text. Tổng cộng mỗi người dùng sẽ được biểu diễn bằng một vector 67 chiều.

3. Xây dựng mô hình

Lúc bắt đầu, Linh có tham khảo một số notebooks [1, 2] cho cuộc thi Porto Seguro’s Safe Driver Prediction trên Kaggle. Hướng tiếp cận chia thành hai bước chính:

  • Phân chia dữ liệu: Sử dụng StratifiedKFold của scikit-learn
  • Mô hình: Mình đã thử một số mô hình tuy nhiên tập trung chính vào các thuật toán tree-based (LGBM, Random Forest) bởi tính phù hợp cho trường hợp dữ liệu lệch và nhiều missing data. Sau khi thử nghiệm, đánh giá mình quyết định phát triển mô hình theo thuật toán Random Forest.

Mô hình cho kết quả tốt nhất (Public: 0.34003, Private: 0.27812) của mình như sau:

  • StratifiedKFold (n_splits = 5)
  • Mô hình Random Forest

Toàn bộ source code mình chia sẻ tại https://github.com/klcute/kalapa

4. Hậu xử lý

Khi khảo sát thống kê, Linh nhận thấy một số thể hiện của đặc trưng tại một số trường hỗ trợ việc dự đoán xác suất đánh điểm tín dụng. Tuy nhiên, mô hình RF không học được những tính chất này có thể do tần xuất xuất hiện nhỏ. Vì vậy, Linh quyết định áp dụng thêm một số luật trong phần hậu xử lý nhằm tăng giá trị Gini. Cụ thể từ FIELD_50 đến FIELD_57 mình thấy khảo sát thấy quan trọng qua những nhận định ở phần phân tích dữ liệu nên mình viết một đoạn script nhỏ lọc ra những giá trị luôn GOOD trong tập train để gán GOOD trong tập test. Vì đây là cuộc thi nên Linh áp dụng phần này để tối ưu GINI vậy thôi ^^!

5. Kết luận

Trên đây, bài viết này sẽ giúp mọi người hiểu hơn về cách thức tiếp cận của Linh. Mặc dù cho kết quả xếp hạng tốt trên leaderboard, nhưng có thể hướng tiếp cận của mình vẫn còn hạn chế ở một vài bước, mong mọi người có gì góp ý để hoàn thiện hơn. Có gì sai sót mong anh chị thông cảm ạ, hihi

Thông qua cuộc thì này, Linh cũng mong muốn được giao lưu và học hỏi từ các anh chị trong cộng đồng machine learning.

Cảm ơn Công ty Kalapa & AIviVN và các anh chịrất nhiều.

Thân ái,

Khánh Linh :kissing_heart:


#2

Mình đợi mãi, cảm ơn bạn đã chia sẻ cách làm rất chi tiết


#3

Bạn explore data rất chi tiết, cảm ơn bạn đã chia sẻ, nhiều pattern mình cũng ko nhận ra khi xem dataset của bài này :slight_smile:


#4

Cảm ơn tác giả. Cách tiếp cận xử lý rất khoa học.


#5

Mình cũng loay hoay với FIELD7, FIELD9 ko ngờ bạn tìm ra được là mã bảo hiểm y tế - và 1 số thông tin mã nước thì tuyệt đó bạn.