##### Rozdział 14: budowanie lepiej uczących się modeli -------------------

# wczytujemy zbiór danych kredytowych
credit <- read.csv("credit.csv")
library(caret)

## Tworzenie prostego dostrojonego modelu ----

# sprawdzamy parametry dostrajania C5.0
modelLookup("C5.0")

# zautomatyzowane dostrajanie parametrów drzewa decyzyjnego C5.0
set.seed(300)
m <- train(default ~ ., data = credit, method = "C5.0")

# podsumowanie wyników dostrajania
m

# dokonujemy prognoz za pomocą najlepszego modelu C5.0
p <- predict(m, credit)
table(p, credit$default)

# pozyskujemy przewidziane klasy
head(predict(m, credit))

# pozyskujemy przewidziane prawdopodobieństwa
head(predict(m, credit, type = "prob"))

## Dostosowywanie procesu dostrajania ----
# używamy trainControl(), aby zmienić strategię próbkowania
ctrl <- trainControl(method = "cv", number = 10,
                     selectionFunction = "oneSE")

# używamy funkcji expand.grid() do utworzenia siatki parametrów strojenia
grid <- expand.grid(model = "tree",
                    trials = c(1, 5, 10, 15, 20, 25, 30, 35),
                    winnow = FALSE)

# przyglądamy się wynikom expand.grid()
grid

# dostosowujemy funkcję train(), przekazując listę kontrolną i siatkę parametrów
set.seed(300)
m <- train(default ~ ., data = credit, method = "C5.0",
           metric = "Kappa",
           trControl = ctrl,
           tuneGrid = grid)

# wyświetlamy wyniki
m

## Bagging ----
# Używanie baggingu drzew decyzyjnych 
library(ipred)
credit <- read.csv("credit.csv", stringsAsFactors = TRUE)
set.seed(300)
mybag <- bagging(default ~ ., data = credit, nbagg = 25)
credit_pred <- predict(mybag, credit)
table(credit_pred, credit$default)

# szacujemy trafność drzew z baggingiem
library(caret)
credit <- read.csv("credit.csv", stringsAsFactors = TRUE)
set.seed(300)
ctrl <- trainControl(method = "cv", number = 10)
train(default ~ ., data = credit, method = "treebag",
      trControl = ctrl)

## Wzmacnianie ----

## Używanie drzewa decyzyjnego C5.0 (niepokazane w książce)
library(C50)
credit <- read.csv("credit.csv", stringsAsFactors = TRUE)
m_c50_bst <- C5.0(default ~ ., data = credit, trials = 100)

# tworzymy model Adaboost.M1
library(adabag)
credit <- read.csv("credit.csv", stringsAsFactors = TRUE)
set.seed(300)
m_adaboost <- boosting(default ~ ., data = credit)
p_adaboost <- predict(m_adaboost, credit)
head(p_adaboost$class)
p_adaboost$confusion

# tworzymy i oceniamy model Adaboost.M1 z wykorzystaniem 10-krotnej walidacji krzyżowej
set.seed(300)
adaboost_cv <- boosting.cv(default ~ ., data = credit)
adaboost_cv$confusion

# obliczamy statystykę kappa
library(vcd)
Kappa(adaboost_cv$confusion)

## Lasy losowe ----
# las losowy z ustawieniami domyślnymi
library(randomForest)
set.seed(300)
rf <- randomForest(default ~ ., data = credit)
rf

# obliczamy statystykę kappa dla prognoz out-of-bag
library(vcd)
Kappa(rf$confusion[1:2,1:2])

# ranger to szybsza implementacja algorytmu lasu losowego
library(ranger)
set.seed(300)
m_ranger <- ranger(default ~ ., data = credit)
m_ranger

# obliczamy statystykę kappa
Kappa(m_ranger$confusion.matrix)

## Maszyny wzmacniania gradientowego (GBM) ----

# przygotowujemy dane na użytek gbm()
credit <- read.csv("credit.csv", stringsAsFactors = TRUE)
credit$default <- ifelse(credit$default == "yes", 1, 0)

# tworzymy losowy podział na dane treningowe i testowe
set.seed(123)
train_sample <- sample(1000, 900)
credit_train <- credit[train_sample, ]
credit_test  <- credit[-train_sample, ]

# tworzymy model GBM z parametrami domyślnymi
library(gbm)
set.seed(300)
m_gbm <- gbm(default ~ ., data = credit_train)
m_gbm

# oceniamy prosty model GBM
p_gbm <- predict(m_gbm, credit_test, type = "response")
p_gbm_c <- ifelse(p_gbm > 0.50, 1, 0)
table(credit_test$default, p_gbm_c)

# obliczamy statystykę kappa 
library(vcd)
Kappa(table(credit_test$default, p_gbm_c))

# tworzymy dostrojony model gbm() z wykorzystaniem pakietu caret
# zaczynamy od utworzenia siatki strojenia
grid_gbm <- expand.grid(
  n.trees = c(100, 150, 200),
  interaction.depth = c(1, 2, 3),
  shrinkage = c(0.01, 0.1, 0.3),
  n.minobsinnode = 10
)

# definiujemy parametry eksperymentu
library(caret)
ctrl <- trainControl(method = "cv", number = 10,
                     selectionFunction = "best")

# przeprowadzamy eksperyment caret
credit <- read.csv("credit.csv", stringsAsFactors = TRUE)
set.seed(300)
m_gbm_c <- train(default ~ ., data = credit, method = "gbm",
                 trControl = ctrl, tuneGrid = grid_gbm,
                 metric = "Kappa",
                 verbose = FALSE)

# wypisujemy wyniki
m_gbm_c

## Extreme Gradient Boosting (XGB) ----

# Formatujemy dane kredytowe jako macierz rozrzedzoną
credit <- read.csv("credit.csv", stringsAsFactors = TRUE)
library(Matrix)
credit_matrix <- sparse.model.matrix(~ . -default, data = credit)

# badamy rozrzedzoną macierz credit_matrix
dim(credit_matrix)
print(credit_matrix[1:5, 1:15])

# usuwamy wyraz wolny
credit_matrix <- credit_matrix[, -1] 

# dzielimy macierz na przykłady treningowe i testowe
set.seed(12345)
train_ids <- sample(1000, 900)
credit_train <- credit_matrix[train_ids, ]
credit_test <- credit_matrix[-train_ids, ]

# sprawdzamy, czy zbiory mają odpowiednio 900 i 100 wierszy oraz po 35 kolumn
dim(credit_train)
dim(credit_test)

# tworzymy dla danych treningowych i testowych wektory 1/0 wskazujące status spłaty pożyczki
credit_train_labels <-
  ifelse(credit[train_ids, c("default")] == "yes", 1, 0)
credit_test_labels <-
  ifelse(credit[-train_ids, c("default")] == "yes", 1, 0)

# budujemy model xgboost
library(xgboost)

# ustawiamy hiperparametry XGB
params.xgb <- list(objective   = "binary:logistic",
                   max_depth   = 6,
                   eta         = 0.3,
                   gamma       = 0,
                   colsample_bytree = 1,
                   min_child_weight = 1,
                   subsample = 1)

set.seed(555)
xgb_credit <- xgboost(params  = params.xgb,
                      data    = credit_train,
                      label   = credit_train_labels, 
                      nrounds = 100,
                      print_every_n = 10,
                      verbose = 1)

# dokonujemy prognoz
prob_default <- predict(xgb_credit, credit_test)
pred_default <- ifelse(prob_default > 0.50, 1, 0)

# tworzymy macierz błędów
table(pred_default, credit_test_labels)

# obliczamy statystykę kappa
library(vcd)
Kappa(table(pred_default, credit_test_labels))

# tworzymy dostrojony modelk xgboost() z wykorzystaniem pakietu caret
# zaczynamy od utworzenia siatki strojenia
grid_xgb <- expand.grid(
  eta = c(0.3, 0.4),
  max_depth = c(1, 2, 3),
  colsample_bytree = c(0.6, 0.8),
  subsample = c(0.50, 0.75, 1.00),
  nrounds = c(50, 100, 150),
  gamma = c(0, 1),
  min_child_weight = 1
)

# definiujemy obiekt kontrolny
library(caret)
ctrl <- trainControl(method = "cv", number = 10,
                     selectionFunction = "best")

# przeprowadzamy eksperyment caret
set.seed(300)
m_xgb <- train(default ~ ., data = credit, method = "xgbTree",
                    trControl = ctrl, tuneGrid = grid_xgb,
                    metric = "Kappa", verbosity = 0)

# wyświetlamy wyniki dla wszystkich modeli (niepokazane w książce ze względu na ich rozmiar)
m_xgb

# wypisujemy hiperparametry najlepszego modelu
m_xgb$bestTune

# wypisujemy najlepszą wartość kappa spośród 216 przetestowanych modeli
max(m_xgb$results["Kappa"])
