Motivations
Tiền xử lí số liệu (Pre-processing) là một khâu chiếm nhiều thời gian và công sức nhất. Một trong những vấn đề thường phải đối mặt ở bước này chính là xử lí số liệu trống (Missing Data Problem). Dữ liệu của cuộc thi Home Credit Default Risk cũng không ngoại lệ khi hầu hết các features đều có missing ở những mức độ khác nhau (có feature thì tỉ lệ missing có thể lên đến 70%). Hầu hết (nếu không nói là tất cả) các thuật toán Machine Learning đều đòi hỏi phải xử lí missing data bằng một quá trình gọi là data imputation.
Trong post này trình bày một cách tiếp cận đơn giản cho bước tiền xử lí số liệu cho missing data để đạt được AUC = 0.74081 trên test data (một kết quả không quá tồi nếu như các bạn để ý rằng top 1 có AUC 0.80570) với ba điểm đáng chú ý sau:
- Chỉ sử dụng các features ở application_train.csv để train mô hình chứ chưa sử dụng đến các dữ liệu / features khác.
- Missing data được xử lí bằng thuật toán Random Forest với hàm missRanger().
- Sử dụng Automated Machine Learning của thư viện h2o để train mô hình. Thư viện này có thể được chạy trên Python lẫn R (cũng như một số ngôn ngữ khác).
Dưới đây là R codes:
#============
# Load data
#============
# Clear workspace:
rm(list = ls())
# Import data:
library(tidyverse)
df_train <- read_csv("application_train.csv")
df_test <- read_csv("application_test.csv")
# Combine train and test data:
df_total <- bind_rows(df_train, df_test)
# Check missing rate:
lapply(df_total, function(x) {sum(is.na(x)) / length(x)})
# Replace space and - in character columns and convert to factor:
df_total %>%
select(-SK_ID_CURR) %>%
mutate_if(is.character, function(x) {x %>% str_to_upper()}) %>%
mutate_if(is.character, function(x) {x %>% str_replace_all(" ", "")}) %>%
mutate_if(is.character, function(x) {x %>% str_replace_all("\\,", "_")}) %>%
mutate_if(is.character, function(x) {x %>% str_replace_all("-", "_")}) %>%
mutate_if(is.character, as.factor) -> df_total
#====================================
# Data Imputation for Missing Data
#====================================
# Target variable:
target_var <- df_total$TARGET
# Input variables:
df_total %>% select(-TARGET) -> df_inputs
# Conduct data imputation:
library(missRanger)
missRanger(df_inputs, seed = 29) -> df_imputed
# Add targer variable and scale 0-1 for numeric features:
df_imputed %>%
mutate(TARGET = target_var) %>%
mutate_if(is.numeric, function(x) {(x - min(x)) / (max(x) - min(x))}) -> df_imputed
# Split data to train and test:
df_imputed %>%
filter(!is.na(TARGET)) %>%
mutate(TARGET = case_when(TARGET == 1 ~ "Bad", TRUE ~ "Good")) %>%
mutate(TARGET = as.factor(TARGET)) -> train_df
df_imputed %>% filter(is.na(TARGET)) -> test_df
#====================================
# Train Automated Machine Learning
#====================================
# Load h2o package and prepare data for training Auto ML:
library(h2o)
h2o.init(nthreads = 36, max_mem_size = "32g")
h2o.no_progress()
# Convert to h2o frame:
as.h2o(train_df) -> h2o_frame
as.h2o(test_df) -> test
# Split train data:
splits <- h2o.splitFrame(h2o_frame, ratios = c(0.7), seed = 29)
train <- splits[[1]]
valid <- splits[[2]]
# Define predictors and target:
y <- "TARGET"
x <- setdiff(names(train), y)
# Train Auto ML:
autoML <- h2o.automl(x = x,
y = y,
training_frame = train,
leaderboard_frame = valid,
stopping_metric = "AUC",
stopping_rounds = 15,
stopping_tolerance = 0.05,
max_models = 50,
max_runtime_secs = 60*60,
seed = 1,
sort_metric = "AUC")
# Use best model for predict probability of default:
predictions <- predict(autoML@leader, test)
predictions %>% as.data.frame() %>% pull(Bad) -> pd
# Save result for submission:
data.frame(SK_ID_CURR = df_test$SK_ID_CURR, TARGET = pd) -> df_submission
write_csv(df_submission, "submission.csv")
Brief Conclusion
Chỉ bằng cách tiếp cận đơn giản khi xử lí missing data (và cũng chỉ mới sử dụng các features trên train data) chúng ta đã có được Kết quả AUC = 0.74081 trên tập application_test.csv. Đây là một kết quả không quá thấp. Kết quả này có thể được nâng cao hơn nếu:
- Thực hiện tiền xử lí số liệu tinh vi hơn trước khi làm data imputation.
- Tạo thêm features mới từ các bảng dữ liệu được cung cấp. Lưu ý rằng ở đây chúng ta mới chỉ sử dụng các features từ application_train.csv chứ chưa tận dụng các features khác.
- Tinh chỉnh tham số cho mô hình hoặc sử dụng một cách tiếp cận nào khác như LightGBM, XGBoost chẳng hạn (đây là các Classifier mạnh thường đạt thứ hạng cao trong các cuộc thi).
Điều này cũng ngụ ý rằng AUC = 0.74081 nên đóng vai trò như là base line để so sánh/đánh giá các cách tiếp cận/mô hình khác. Nếu hì hục làm cả mấy tuần cho khâu Pre-processing + Feature Engineering mà kết quả thấp hơn 0.74081 coi như thất bại.
LS0tDQp0aXRsZTogJ0RhdGEgSW1wdXRhdGlvbjogQSBjYXNlIGZyb20gS2FnZ2xlIENvbXBldGl0aW9uIChQYXJ0IDEpJw0KYXV0aG9yOiAnQXV0aG9yOiBOZ3V5ZW4gQ2hpIER1bmcnDQpzdWJ0aXRsZTogIlIgTWFjaGluZSBMZWFybmluZyBTZXJpZXMiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICAjIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGhpZ2hsaWdodDogemVuYnVybg0KICAgICMgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0aGVtZTogImZsYXRseSINCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCi0tLQ0KDQpgYGB7ciBzZXR1cCxpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA2KQ0KYGBgDQoNCg0KIyBNb3RpdmF0aW9ucw0KDQpUaeG7gW4geOG7rSBsw60gc+G7kSBsaeG7h3UgKFByZS1wcm9jZXNzaW5nKSBsw6AgbeG7mXQga2jDonUgY2hp4bq/bSBuaGnhu4F1IHRo4budaSBnaWFuIHbDoCBjw7RuZyBz4bupYyBuaOG6pXQuIE3hu5l0IHRyb25nIG5o4buvbmcgduG6pW4gxJHhu4EgdGjGsOG7nW5nIHBo4bqjaSDEkeG7kWkgbeG6t3Qg4bufIGLGsOG7m2MgbsOgeSBjaMOtbmggbMOgIHjhu60gbMOtIHPhu5EgbGnhu4d1IHRy4buRbmcgKE1pc3NpbmcgRGF0YSBQcm9ibGVtKS4gROG7ryBsaeG7h3UgY+G7p2EgY3Xhu5ljIHRoaSBbSG9tZSBDcmVkaXQgRGVmYXVsdCBSaXNrXShodHRwczovL3d3dy5rYWdnbGUuY29tL2MvaG9tZS1jcmVkaXQtZGVmYXVsdC1yaXNrKSBjxaluZyBraMO0bmcgbmdv4bqhaSBs4buHIGtoaSBo4bqndSBo4bq/dCBjw6FjIGZlYXR1cmVzIMSR4buBdSBjw7MgbWlzc2luZyDhu58gbmjhu69uZyBt4bupYyDEkeG7mSBraMOhYyBuaGF1IChjw7MgZmVhdHVyZSB0aMOsIHThu4kgbOG7hyBtaXNzaW5nIGPDsyB0aOG7gyBsw6puIMSR4bq/biA3MCUpLiBI4bqndSBo4bq/dCAobuG6v3Uga2jDtG5nIG7Ds2kgbMOgIHThuqV0IGPhuqMpIGPDoWMgdGh14bqtdCB0b8OhbiBNYWNoaW5lIExlYXJuaW5nIMSR4buBdSDEkcOyaSBo4buPaSBwaOG6o2kgeOG7rSBsw60gbWlzc2luZyBkYXRhIGLhurFuZyBt4buZdCBxdcOhIHRyw6xuaCBn4buNaSBsw6AgZGF0YSBpbXB1dGF0aW9uLiANCg0KVHJvbmcgcG9zdCBuw6B5IHRyw6xuaCBiw6B5IG3hu5l0IGPDoWNoIHRp4bq/cCBj4bqtbiDEkcahbiBnaeG6o24gY2hvIGLGsOG7m2MgdGnhu4FuIHjhu60gbMOtIHPhu5EgbGnhu4d1IGNobyBtaXNzaW5nIGRhdGEgxJHhu4MgxJHhuqF0IMSRxrDhu6NjIEFVQyA9IDAuNzQwODEgdHLDqm4gdGVzdCBkYXRhICht4buZdCBr4bq/dCBxdeG6oyBraMO0bmcgcXXDoSB04buTaSBu4bq/dSBuaMawIGPDoWMgYuG6oW4gxJHhu4Mgw70gcuG6sW5nIHRvcCAxIGPDsyBBVUMgMC44MDU3MCkgduG7m2kgYmEgxJFp4buDbSDEkcOhbmcgY2jDuiDDvSBzYXU6DQoNCi0gQ2jhu4kgc+G7rSBk4bulbmcgY8OhYyBmZWF0dXJlcyDhu58gYXBwbGljYXRpb25fdHJhaW4uY3N2IMSR4buDIHRyYWluIG3DtCBow6xuaCBjaOG7qSBjaMawYSBz4butIGThu6VuZyDEkeG6v24gY8OhYyBk4buvIGxp4buHdSAvIGZlYXR1cmVzIGtow6FjLg0KLSBNaXNzaW5nIGRhdGEgxJHGsOG7o2MgeOG7rSBsw60gYuG6sW5nIHRodeG6rXQgdG/DoW4gKipSYW5kb20gRm9yZXN0KiogduG7m2kgaMOgbSBtaXNzUmFuZ2VyKCkuDQotIFPhu60gZOG7pW5nIEF1dG9tYXRlZCBNYWNoaW5lIExlYXJuaW5nIGPhu6dhIHRoxrAgdmnhu4duIGgybyDEkeG7gyB0cmFpbiBtw7QgaMOsbmguIFRoxrAgdmnhu4duIG7DoHkgY8OzIHRo4buDIMSRxrDhu6NjIGNo4bqheSB0csOqbiBQeXRob24gbOG6q24gUiAoY8WpbmcgbmjGsCBt4buZdCBz4buRIG5nw7RuIG5n4buvIGtow6FjKS4NCg0KRMaw4bubaSDEkcOieSBsw6AgUiBjb2RlczoNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQojPT09PT09PT09PT09DQojICBMb2FkIGRhdGEgDQojPT09PT09PT09PT09DQoNCiMgQ2xlYXIgd29ya3NwYWNlOiANCnJtKGxpc3QgPSBscygpKQ0KDQojIEltcG9ydCBkYXRhOiANCmxpYnJhcnkodGlkeXZlcnNlKQ0KZGZfdHJhaW4gPC0gcmVhZF9jc3YoImFwcGxpY2F0aW9uX3RyYWluLmNzdiIpDQpkZl90ZXN0IDwtIHJlYWRfY3N2KCJhcHBsaWNhdGlvbl90ZXN0LmNzdiIpDQoNCiMgQ29tYmluZSB0cmFpbiBhbmQgdGVzdCBkYXRhOiANCmRmX3RvdGFsIDwtIGJpbmRfcm93cyhkZl90cmFpbiwgZGZfdGVzdCkNCg0KIyBDaGVjayBtaXNzaW5nIHJhdGU6IA0KDQpsYXBwbHkoZGZfdG90YWwsIGZ1bmN0aW9uKHgpIHtzdW0oaXMubmEoeCkpIC8gbGVuZ3RoKHgpfSkNCg0KIyBSZXBsYWNlIHNwYWNlIGFuZCAtIGluIGNoYXJhY3RlciBjb2x1bW5zIGFuZCBjb252ZXJ0IHRvIGZhY3RvcjogDQoNCmRmX3RvdGFsICU+JSANCiAgc2VsZWN0KC1TS19JRF9DVVJSKSAlPiUgDQogIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsIGZ1bmN0aW9uKHgpIHt4ICU+JSBzdHJfdG9fdXBwZXIoKX0pICU+JSANCiAgbXV0YXRlX2lmKGlzLmNoYXJhY3RlciwgZnVuY3Rpb24oeCkge3ggJT4lIHN0cl9yZXBsYWNlX2FsbCgiICIsICIiKX0pICU+JSANCiAgbXV0YXRlX2lmKGlzLmNoYXJhY3RlciwgZnVuY3Rpb24oeCkge3ggJT4lIHN0cl9yZXBsYWNlX2FsbCgiXFwsIiwgIl8iKX0pICU+JSANCiAgbXV0YXRlX2lmKGlzLmNoYXJhY3RlciwgZnVuY3Rpb24oeCkge3ggJT4lIHN0cl9yZXBsYWNlX2FsbCgiLSIsICJfIil9KSAlPiUgDQogIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsIGFzLmZhY3RvcikgLT4gZGZfdG90YWwNCg0KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyAgRGF0YSBJbXB1dGF0aW9uIGZvciBNaXNzaW5nIERhdGENCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KIyBUYXJnZXQgdmFyaWFibGU6IA0KDQp0YXJnZXRfdmFyIDwtIGRmX3RvdGFsJFRBUkdFVA0KDQojIElucHV0IHZhcmlhYmxlczogDQpkZl90b3RhbCAlPiUgc2VsZWN0KC1UQVJHRVQpIC0+IGRmX2lucHV0cw0KDQoNCiMgQ29uZHVjdCBkYXRhIGltcHV0YXRpb246IA0KDQpsaWJyYXJ5KG1pc3NSYW5nZXIpDQptaXNzUmFuZ2VyKGRmX2lucHV0cywgc2VlZCA9IDI5KSAtPiBkZl9pbXB1dGVkDQoNCiMgQWRkIHRhcmdlciB2YXJpYWJsZSBhbmQgc2NhbGUgMC0xIGZvciBudW1lcmljIGZlYXR1cmVzOg0KDQpkZl9pbXB1dGVkICU+JQ0KICBtdXRhdGUoVEFSR0VUID0gdGFyZ2V0X3ZhcikgJT4lIA0KICBtdXRhdGVfaWYoaXMubnVtZXJpYywgZnVuY3Rpb24oeCkgeyh4IC0gbWluKHgpKSAvIChtYXgoeCkgLSBtaW4oeCkpfSkgLT4gZGZfaW1wdXRlZA0KDQojIFNwbGl0IGRhdGEgdG8gdHJhaW4gYW5kIHRlc3Q6IA0KDQpkZl9pbXB1dGVkICU+JQ0KICBmaWx0ZXIoIWlzLm5hKFRBUkdFVCkpICU+JQ0KICBtdXRhdGUoVEFSR0VUID0gY2FzZV93aGVuKFRBUkdFVCA9PSAxIH4gIkJhZCIsIFRSVUUgfiAiR29vZCIpKSAlPiUNCiAgbXV0YXRlKFRBUkdFVCA9IGFzLmZhY3RvcihUQVJHRVQpKSAtPiB0cmFpbl9kZg0KDQpkZl9pbXB1dGVkICU+JSBmaWx0ZXIoaXMubmEoVEFSR0VUKSkgLT4gdGVzdF9kZg0KDQoNCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgIFRyYWluIEF1dG9tYXRlZCBNYWNoaW5lIExlYXJuaW5nDQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCiMgTG9hZCBoMm8gcGFja2FnZSBhbmQgcHJlcGFyZSBkYXRhIGZvciB0cmFpbmluZyBBdXRvIE1MOiANCg0KbGlicmFyeShoMm8pDQpoMm8uaW5pdChudGhyZWFkcyA9IDM2LCBtYXhfbWVtX3NpemUgPSAiMzJnIikNCmgyby5ub19wcm9ncmVzcygpDQoNCiMgQ29udmVydCB0byBoMm8gZnJhbWU6IA0KDQphcy5oMm8odHJhaW5fZGYpIC0+IGgyb19mcmFtZQ0KYXMuaDJvKHRlc3RfZGYpIC0+IHRlc3QNCg0KIyBTcGxpdCB0cmFpbiBkYXRhOiANCg0Kc3BsaXRzIDwtIGgyby5zcGxpdEZyYW1lKGgyb19mcmFtZSwgcmF0aW9zID0gYygwLjcpLCBzZWVkID0gMjkpDQp0cmFpbiA8LSBzcGxpdHNbWzFdXQ0KdmFsaWQgPC0gc3BsaXRzW1syXV0NCg0KIyBEZWZpbmUgcHJlZGljdG9ycyBhbmQgdGFyZ2V0Og0KeSA8LSAiVEFSR0VUIg0KeCA8LSBzZXRkaWZmKG5hbWVzKHRyYWluKSwgeSkNCg0KIyBUcmFpbiBBdXRvIE1MOiANCg0KYXV0b01MIDwtIGgyby5hdXRvbWwoeCA9IHgsDQogICAgICAgICAgICAgICAgICAgICB5ID0geSwNCiAgICAgICAgICAgICAgICAgICAgIHRyYWluaW5nX2ZyYW1lID0gdHJhaW4sDQogICAgICAgICAgICAgICAgICAgICBsZWFkZXJib2FyZF9mcmFtZSA9IHZhbGlkLA0KICAgICAgICAgICAgICAgICAgICAgc3RvcHBpbmdfbWV0cmljID0gIkFVQyIsDQogICAgICAgICAgICAgICAgICAgICBzdG9wcGluZ19yb3VuZHMgPSAxNSwNCiAgICAgICAgICAgICAgICAgICAgIHN0b3BwaW5nX3RvbGVyYW5jZSA9IDAuMDUsDQogICAgICAgICAgICAgICAgICAgICBtYXhfbW9kZWxzID0gNTAsDQogICAgICAgICAgICAgICAgICAgICBtYXhfcnVudGltZV9zZWNzID0gNjAqNjAsDQogICAgICAgICAgICAgICAgICAgICBzZWVkID0gMSwNCiAgICAgICAgICAgICAgICAgICAgIHNvcnRfbWV0cmljID0gIkFVQyIpDQoNCiMgVXNlIGJlc3QgbW9kZWwgZm9yIHByZWRpY3QgcHJvYmFiaWxpdHkgb2YgZGVmYXVsdDogDQoNCnByZWRpY3Rpb25zIDwtIHByZWRpY3QoYXV0b01MQGxlYWRlciwgdGVzdCkNCnByZWRpY3Rpb25zICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIHB1bGwoQmFkKSAtPiBwZA0KDQojIFNhdmUgcmVzdWx0IGZvciBzdWJtaXNzaW9uOiANCmRhdGEuZnJhbWUoU0tfSURfQ1VSUiA9IGRmX3Rlc3QkU0tfSURfQ1VSUiwgVEFSR0VUID0gcGQpIC0+IGRmX3N1Ym1pc3Npb24NCndyaXRlX2NzdihkZl9zdWJtaXNzaW9uLCAic3VibWlzc2lvbi5jc3YiKQ0KDQpgYGANCg0KIyBCcmllZiBDb25jbHVzaW9uDQoNCkNo4buJIGLhurFuZyBjw6FjaCB0aeG6v3AgY+G6rW4gxJHGoW4gZ2nhuqNuIGtoaSB44butIGzDrSBtaXNzaW5nIGRhdGEgKHbDoCBjxaluZyBjaOG7iSBt4bubaSBz4butIGThu6VuZyBjw6FjIGZlYXR1cmVzIHRyw6puIHRyYWluIGRhdGEpIGNow7puZyB0YSDEkcOjIGPDsyDEkcaw4bujYyBL4bq/dCBxdeG6oyBBVUMgPSAwLjc0MDgxIHRyw6puIHThuq1wICphcHBsaWNhdGlvbl90ZXN0LmNzdiouIMSQw6J5IGzDoCBt4buZdCBr4bq/dCBxdeG6oyBraMO0bmcgcXXDoSB0aOG6pXAuIEvhur90IHF14bqjIG7DoHkgY8OzIHRo4buDIMSRxrDhu6NjIG7Dom5nIGNhbyBoxqFuIG7hur91Og0KDQotIFRo4buxYyBoaeG7h24gdGnhu4FuIHjhu60gbMOtIHPhu5EgbGnhu4d1IHRpbmggdmkgaMahbiB0csaw4bubYyBraGkgbMOgbSBkYXRhIGltcHV0YXRpb24uIA0KLSBU4bqhbyB0aMOqbSBmZWF0dXJlcyBt4bubaSB04burIGPDoWMgYuG6o25nIGThu68gbGnhu4d1IMSRxrDhu6NjIGN1bmcgY+G6pXAuIEzGsHUgw70gcuG6sW5nIOG7nyDEkcOieSBjaMO6bmcgdGEgKm3hu5tpIGNo4buJIHPhu60gZOG7pW5nIGPDoWMgZmVhdHVyZXMgdOG7qyBhcHBsaWNhdGlvbl90cmFpbi5jc3YqIGNo4bupIGNoxrBhIHThuq1uIGThu6VuZyBjw6FjIGZlYXR1cmVzIGtow6FjLiANCi0gVGluaCBjaOG7iW5oIHRoYW0gc+G7kSBjaG8gbcO0IGjDrG5oIGhv4bq3YyBz4butIGThu6VuZyBt4buZdCBjw6FjaCB0aeG6v3AgY+G6rW4gbsOgbyBraMOhYyBuaMawIExpZ2h0R0JNLCBYR0Jvb3N0IGNo4bqzbmcgaOG6oW4gKMSRw6J5IGzDoCBjw6FjIENsYXNzaWZpZXIgbeG6oW5oIHRoxrDhu51uZyDEkeG6oXQgdGjhu6kgaOG6oW5nIGNhbyB0cm9uZyBjw6FjIGN14buZYyB0aGkpLiANCg0KxJBp4buBdSBuw6B5IGPFqW5nIG5n4bulIMO9IHLhurFuZyBBVUMgPSAwLjc0MDgxIG7Dqm4gxJHDs25nIHZhaSB0csOyIG5oxrAgbMOgIGJhc2UgbGluZSDEkeG7gyBzbyBzw6FuaC/EkcOhbmggZ2nDoSBjw6FjIGPDoWNoIHRp4bq/cCBj4bqtbi9tw7QgaMOsbmgga2jDoWMuIE7hur91IGjDrCBo4bulYyBsw6BtIGPhuqMgbeG6pXkgdHXhuqduIGNobyANCmtow6J1IFByZS1wcm9jZXNzaW5nICsgRmVhdHVyZSBFbmdpbmVlcmluZyBtw6Aga+G6v3QgcXXhuqMgdGjhuqVwIGjGoW4gMC43NDA4MSBjb2kgbmjGsCB0aOG6pXQgYuG6oWkuIA0KDQoNCg==