Divide and conquer(I) : classification using desicion trees

En este post me gustaria desarrollar otros de los algoritmos necesarios para trabajar en problemas que impliquen clasificacion:  desicion trees y Rule Learners los cuales permiten transformar desiciones complejas en un set de opciones simples.

Desicion trees

Tal vez una de las tecnicas mas utilizada de machine learning, aplicable a casi cualquier tipo de datos (luego de realizar algunas transformaciones), y con un resultado – el modelo resultante – claramente interpretable por cualquier persona. Por estas caracteristicas, es un algoritmo que puede ser utilizado en los siguientes casos:

  • Modelos de puntaje de credito, donde por cuestiones legales sea necesario compartir el modelo.
  • Estudios de marketing acerca del comportamiento del cliente
  • Diagnostico de condiciones medicas.

Su mayor debilidad radica en los casos en los cuales se utiliza este algoritmo a pesar de no ser el mas optimo por ejemplo en aquellos casos donde existe una gran cantidad de casos features numericos o cuando existe una gran cantidad de features nominales con muchos niveles.

c5.0 decision tree algorithm

Si bien existen numerosas implementaciones de arboles de desicion, una de las mas conocidas y utilizadas es la que se encuentra en el C5.0 decision tree algorithm. Es considerado un estandar en la industria para producir arboles de desicion, tanto por su buena performance como porque mantiene dicho nivel de performance aun al aplicarlo a problemas directamente, sin ningun tipo de pre-procesamiento sobre los datos (out of the box).

Caso practico: Identificar el riesgo bancario

En este ejemplo vamos a trabajar con el dataset correspondiente a 1000 ejemplos sobre prestamos, el mismo esta en el paquete caret, bajo el nombre de GermanCredit. De forma de seguir nuestro ejercicio de una forma similar a como esta planteado en el libro “Machine Learning with R” necesitamos y crearemos una variable “default” con valores aleatorios entre 1 y 0, con rango de 70% y 30% para los dos casos respectivamente.

El objetivo de nuestra implementacion es llegar a determinar con el mayor grado de exactitud si un caso cualquiera terminara en default o no.

Analisis de la implementacion

Se van a implementar sucesivamente los siguientes algoritmos

  • Primer intento: El algoritmo C5.0 out of the box sin modificaciones.
  • Segundo intento: El algoritmo C5.0 sumando adaptative boosting. Que seria aplicar adaptative boosting? Es crear n-arboles de desicion y determinar entre los mismos cual es el mejor. En terminos generales se usa trials = 10, dado que varias investigaciones han mostrado que reduce el error sobre los datos a evaluar en un 25%
  • Tercer intento: El algoritmo C5.0 sumando una matriz de costo, que es una matriz de costo aquella que busca indicarle al algoritmo que hay errores mas costosos que otros, en este caso el error mas costoso es la no deteccion de aquellos usuarios que no van a pagar el credito.

Conclusiones

Luego de la aplicacion del algoritmo C5.0 out-of-the-box, C5.0 utilizando adaptative bootsting y C5.0 utilizando una matriz de costos, podemos elaborar las siguientes ideas:

  • El algoritmo C5.0 out of the box nos dio un porcentaje de exactitud del 56%, al analizar los errores encontramos que solo predijo el 13% de los errores por falta de pago.
  • El algoritmo C5.0 con boosting mejoro del 56% al 62%, y dentro de los errores de no deteccion de default paso de 13% a 20%.
  • Finalmente sumar la matriz de costo el porcentaje de exactitud del modelo bajo al 43%, pero mejoro notablemente la deteccion de casos de default donde pasamos del 20% al 70%.

Implementacion tecnica

Get the data

# Step 1: Get the data
require(caret)
data(GermanCredit)

# Step 2: Exploring and preparing the data
credit <- GermanCredit
credit$default <- sample(0:1, size=1000, replace= TRUE, prob=c(.70,.30))
credit$default <- as.factor(credit$default)
prop.table(table(credit$default))
  
# Creating Random test
set.seed(123)
train_sample <- sample(1000,900)

credit_train <- credit[train_sample,]
credit_test <- credit[-train_sample,]
prop.table(table(credit_test$default))
prop.table(table(credit_train$default))

Working with C5.0

# Step 4: Analyzing the model
credit_pred <- predict(credit_model,credit_test)
CrossTable(credit_test$default, credit_pred, prop.chisq = FALSE, prop.c = FALSE, prop.r = FALSE,
           dnn = c('actual default','predict default'))

#   Cell Contents
#   Total Observations in Table:  100 
# 
#                  | predict default 
#   actual default |         0 |         1 | Row Total | 
#   ---------------|-----------|-----------|-----------|
#                0 |        52 |        18 |        70 | 
#                  |     0.030 |     0.330 |           | 
#   ---------------|-----------|-----------|-----------|
#                1 |        26 |         4 |        30 | 
#                  |     0.180 |     0.460 |           | 
#   ---------------|-----------|-----------|-----------|
#     Column Total |        78 |        22 |       100 | 
#   ---------------|-----------|-----------|-----------|

Improving using boosters

#Step 5: Improving using boosters
credit_boost10 <- C5.0(x = credit_train[, -63], y = credit_train$default, trials = 10)

# Step 6: Analyzing the improved model
summary(credit_boost10)

# Evaluation on training data (900 cases):
#
# (a) (b) <-classified as
# ---- ----
# 627 (a): class 0
# 273 (b): class 1

credit_boots_pred10 <- predict(credit_boost10,credit_test)
CrossTable(credit_test$default, credit_boots_pred10, prop.chisq = FALSE, prop.c = FALSE, prop.r = FALSE,
dnn = c('actual default','predict default'))

# Cell Contents
# Total Observations in Table: 100
#
# | predict default 
# actual default | 0 | 1 | Row Total | 
# ---------------|-----------|-----------|-----------|
# 0 | 56 | 14 | 70 | 
# | 0.560 | 0.140 | | 
# ---------------|-----------|-----------|-----------|
# 1 | 24 | 6 | 30 | 
# | 0.240 | 0.060 | | 
# ---------------|-----------|-----------|-----------|
# Column Total | 80 | 20 | 100 | 
# ---------------|-----------|-----------|-----------|

Improving errors using cost matrix

#Step 7: Improving using matrix
matrix_dimensions <- list(c("0","1"),c("0","1"))
names(matrix_dimensions) <- c("predicted", "actual")
error_cost <- matrix(c(0,1,4,0),nrow =2, dimnames = matrix_dimensions)

credit_cost <- C5.0(credit_train[,-63], credit_train$default, costs = error_cost )

credit_cost_pred <- predict(credit_cost, credit_test)

# Step 8: Analyzing the improved model
CrossTable(credit_test$default, credit_cost_pred, prop.r = FALSE,
           dnn = c('actual default','predict default'))

#   Cell Contents
#   |-------------------------|
#   |                       N |
#   | Chi-square contribution |
#   |           N / Col Total |
#   |         N / Table Total |
#   |-------------------------|
#   
#   
#   Total Observations in Table:  100 
# 
# 
#                  | predict default 
#   actual default |         0 |         1 | Row Total | 
#   ---------------|-----------|-----------|-----------|
#                0 |        22 |        48 |        70 | 
#                  |     0.004 |     0.002 |           | 
#                  |     0.710 |     0.696 |           | 
#                  |     0.220 |     0.480 |           | 
#   ---------------|-----------|-----------|-----------|
#                1 |         9 |        21 |        30 | 
#                  |     0.010 |     0.004 |           | 
#                  |     0.290 |     0.304 |           | 
#                  |     0.090 |     0.210 |           | 
#   ---------------|-----------|-----------|-----------|
#     Column Total |        31 |        69 |       100 | 
#                  |     0.310 |     0.690 |           | 
#   ---------------|-----------|-----------|-----------|

Bibliografia

Machine Learning with R by Brett Lantz