1 R2D3

R2D3 웹사이트에 기계학습에 대한 시각적 소개가 잘 정리되어 있다. 뉴욕과 샌프란시스코 두 도시의 부동산을 분류하는 데이터를 바탕으로 의사결정나무(Decision Tree) 기계학습 알고리즘이 동작하는 방식을 마우스 스크롤을 아래로 내리게 되면 시각적으로 확인할 수 있다.

FAQ 웹사이트에서 CSV 파일을 다운로드 받아 직접 기계학습 예측모형을 제작해보자.

2 caret + DALEX 예측모형

A Short Introduction to the caret Package 팩키지를 주된 예측모형 엔진으로 사용하고 블랙박스 예측모형을 이해하고 해석하는데 DALEX: Descriptive mAchine Learning EXplanations를 사용한다. 즉, 데이터프레임을 받아 caret 예측모형을 생성하고 이를 DALEX를 통해 블랙박스 모형을 해석하고 이해하는 작업방식이 된다.

DALEX + caet 예측모형

2.1 데이터

R2D3 뉴욕, 샌프란시스코 부동산 분류 데이터를 다운로드 받아 예측모형 적합을 위한 형태로 가공한다.

# 0. 환경설정 -----
library(tidyverse)
library(caret)
library(recipes)
library(skimr)
library(DALEX)
library(randomForest)
library(e1071)
library(xgboost)
library(cowplot)

# 1. 데이터 -----
## 1.1. 데이터 가져오기
r2d3_df <- read_csv("https://raw.githubusercontent.com/jadeyee/r2d3-part-1-data/master/part_1_data.csv", skip=2)

## 1.2. X/Y 데이터 분할
x_train_tbl <- r2d3_df %>% select(-in_sf)
y_train_tbl <- r2d3_df %>% select(in_sf)   

## 1.3. X/Y 데이터 요리
rec_obj <- recipe(~ ., data = x_train_tbl) %>%
    # step_scale(all_numeric()) %>%
    prep(stringsAsFactors = FALSE)

x_train_processed_tbl <- bake(rec_obj, x_train_tbl) 

y_train_processed_tbl <- y_train_tbl

xy_train <- bind_cols(y_train_processed_tbl, x_train_processed_tbl) %>% 
    mutate(in_sf = as.factor(in_sf))

## 1.4. 훈련/시험 데이터 분할

train_idx <- createDataPartition(xy_train$in_sf, p = 0.7, list = FALSE, times = 1)
xy_train_df <- xy_train[ train_idx,]
xy_test_df  <- xy_train[-train_idx,]

2.2 모형적합

GLM, RandomForest, SVM, xgBoost 예측모형으로 부동산을 예측해본다.

# 2. 예측 모형 -----

tune_grid <- expand.grid(nrounds = 200,
                         max_depth = 5,
                         eta = 0.05,
                         gamma = 0.01,
                         colsample_bytree = 0.75,
                         min_child_weight = 0,
                         subsample = 0.5)

## 2.1. 모형 3종 세트 (GLM, Random Forest, SVM)

model_glm <- train(in_sf ~., data = xy_train_df, 
                   method="glm", family="binomial")

model_rf  <- train(in_sf ~., data = xy_train_df, 
                  method="rf", ntree = 100, tuneLength = 1)

model_svm <- train(in_sf ~., data = xy_train_df, 
                   method="svmRadial", prob.model = TRUE, tuneLength = 1)

model_xgb  <- train(in_sf ~., data = xy_train_df, 
                   method="xgbTree", tuneGrid = tune_grid)

2.3 explainer 객체 생성

모형 이해와 해석을 위해서 DALEX 팩키지 explain() 함수를 통해 explainer 객체를 생성한다. 다음 그림에 정리된 것처럼 예측함수(predict_function), 라벨(label), 경우에 따라서 연결함수(link_function)을 적시해야 한다.

explain() 함수

# 3. DALEX 설정 -----
## 3.1. explainer 사전 설정
prob_fun <- function(object, newdata) { 
    predict(object, newdata=newdata, type="prob")[,2]
}

y_test_v <- as.numeric(as.character(xy_test_df$in_sf))

## 3.2. explainer 실행
explainer_glm <- DALEX::explain(model_glm, label = "GLM", 
                                data = xy_test_df, y = y_test_v,
                                predict_function = prob_fun)

explainer_rf <- DALEX::explain(model_rf, label = "RF",
                               data = xy_test_df, y = y_test_v,
                               predict_function = prob_fun)


explainer_svm <- DALEX::explain(model_svm,  label = "SVM", 
                                data = xy_test_df, y = y_test_v,
                                predict_function = prob_fun)

explainer_xgb <- DALEX::explain(model_xgb,  label = "xgBoost", 
                                data = xy_test_df, y = y_test_v,
                                predict_function = prob_fun)

2.4 예측모형 이해와 설명

2.4.1 모형 성능평가

GLM, RandomForest, SVM, xgBoost 예측모형의 성능 비교를 위해서 model_performance() 함수를 사용한다. ECDF와 Boxplot을 활용하여 상대적인 모형의 성능을 비교할 수 있다.

# 4. 예측 모형 이해와 설명 -----
## 4.1. 모형 성능
mp_glm <- model_performance(explainer_glm)
mp_rf  <- model_performance(explainer_rf)
mp_svm <- model_performance(explainer_svm)
mp_xgb <- model_performance(explainer_xgb)

ecdf_g <- plot(mp_rf, mp_glm, mp_svm, mp_xgb) +
    theme(legend.position = "top")

boxplot_g <- plot(mp_rf, mp_glm, mp_svm, mp_xgb, geom = "boxplot", show_outliers = 3) +
    theme(legend.position = "none")

plot_grid(ecdf_g, boxplot_g)

2.4.2 중요변수

각 예측모형에서 중요한 역할을 수행하는 변수를 5개 뽑아 비교한다. n_sample = -1은 모든 관측점을 사용한다는 의미가 된다.

## 4.2. 중요 변수 
vi_glm <- variable_importance(explainer_glm, n_sample = -1, loss_function = loss_root_mean_square, type = "raw")
vi_rf  <- variable_importance(explainer_rf,  n_sample = -1, loss_function = loss_root_mean_square, type = "raw")
vi_svm <- variable_importance(explainer_svm, n_sample = -1, loss_function = loss_root_mean_square, type = "raw")
vi_xgb <- variable_importance(explainer_xgb, n_sample = -1, loss_function = loss_root_mean_square, type = "raw")

plot(vi_glm, vi_rf, vi_svm, vi_xgb, max_vars = 6)

2.4.3 반응 변수 연관

특정변수(elevation)가 각 예측모형에서 중요한 변수로 식별되어서 이변수가 부동산 분류에 어떤 관련이 있는 pdp로 살펴본다.

## 4.3. 변수 반응도

pdp_glm <- variable_response(explainer_glm, variable = "elevation", type = "pdp")
pdp_rf  <- variable_response(explainer_rf,  variable = "elevation", type = "pdp")
pdp_svm <- variable_response(explainer_svm, variable = "elevation", type = "pdp")
pdp_xgb <- variable_response(explainer_xgb, variable = "elevation", type = "pdp")

plot(pdp_glm, pdp_rf, pdp_svm, pdp_xgb) +
    scale_x_log10(labels=scales::comma) +
    scale_y_continuous(labels = scales::percent)