martes, 27 de octubre de 2020

Machine Learning: Aprobación de Préstamos Hipotecarios con modelos de Árbol de Decisión (Decision Tree)

Machine Learning: Aprobación de Préstamos Hipotecarios automatizada con modelos de Árbol de Decisión (Decision Tree)

Descripción

Algoritmos de árbol de decisión.

Los árboles de decisión son ampliamente usados en el ámbito bancario debido a su alta precisión y la sencillez de presentar un modelo estadístico en un lenguaje básico, este tipo de problema generalmente tiene como objetivo crear un modelo para identificar factores que indiquen posibles riesgo de incumplimiento en pagos de préstamos o clasificar a los clientes en cuanto a su elegibilidad para un determinado préstamo. Los arboles de decisión son construidos usando un recursivo particionamiento, donde se dividen los datos en subconjuntos y los cuales una vez más son divididos repetidas veces en subconjuntos más pequeños continuando con el proceso hasta que el algoritmo determina que los datos del subconjunto son suficientemente homogéneo o parando por otro criterio establecido. El conjunto de reglas de divisiones usado para segmentar el espacio predictor puede ser resumido en un árbol, esto se conoce como método de árbol de decisión.

Aquí te muestro el proceso de construcción del modelo de árbol de decisión usando R y el algoritmo C5.0 así como herramientas del análisis exploratorio de los datos. Los datos train y test se obtuvieron de la plataforma de Datasciences Analytics Vidhya. El cliente primero solicita un préstamo hipotecario y luego la empresa valida la elegibilidad del cliente para el préstamo.Los datos son proporcionados por los clientes al llenar una forma en línea la cual contiene información como género, estado civil,dependientes, educación, ingresos entre otros. Se desea automatizar el proceso de elegibilidad del préstamo (en tiempo real) según la información que el cliente proporcionó al completar el formulario de solicitud.

Necesitaremos descargar el paquete C50.Además de los paquetes ya conocidos tydiverse,dplyr y gmodel, a continuación se muestra la estructura de los datos del conjunto train.

######data set train######################
head(datos_loan,3)
##    Loan_ID Gender Married Dependents Education Self_Employed ApplicantIncome
## 1 LP001002   Male      No          0  Graduate            No            5849
## 2 LP001003   Male     Yes          1  Graduate            No            4583
## 3 LP001005   Male     Yes          0  Graduate           Yes            3000
##   CoapplicantIncome LoanAmount Loan_Amount_Term Credit_History Property_Area
## 1                 0         NA              360              1         Urban
## 2              1508        128              360              1         Rural
## 3                 0         66              360              1         Urban
##   Loan_Status
## 1           Y
## 2           N
## 3           Y

Como parte de la estratégia en el tratamiento de los datos debemos en la etapa inicial conocer más sobre los datos, su estructura así como el comportamientos y posibles problemas en ellos, para procesarlos y preparalos con la inteción de que tengan un formato mas homogéneo lo cual nos permitirá establecer critérios de mayor calidad respecto de estos.

######data set train######################
skimr::skim(datos_loan)  
## Warning in sorted_count(x): Variable contains value(s) of "" that have been
## converted to "empty".

## Warning in sorted_count(x): Variable contains value(s) of "" that have been
## converted to "empty".

## Warning in sorted_count(x): Variable contains value(s) of "" that have been
## converted to "empty".

## Warning in sorted_count(x): Variable contains value(s) of "" that have been
## converted to "empty".
Data summary
Name datos_loan
Number of rows 614
Number of columns 13
_______________________
Column type frequency:
factor 8
numeric 5
________________________
Group variables None

Variable type: factor

skim_variable n_missing complete_rate ordered n_unique top_counts
Loan_ID 0 1 FALSE 614 LP0: 1, LP0: 1, LP0: 1, LP0: 1
Gender 0 1 FALSE 3 Mal: 489, Fem: 112, emp: 13
Married 0 1 FALSE 3 Yes: 398, No: 213, emp: 3
Dependents 0 1 FALSE 5 0: 345, 1: 102, 2: 101, 3+: 51
Education 0 1 FALSE 2 Gra: 480, Not: 134
Self_Employed 0 1 FALSE 3 No: 500, Yes: 82, emp: 32
Property_Area 0 1 FALSE 3 Sem: 233, Urb: 202, Rur: 179
Loan_Status 0 1 FALSE 2 Y: 422, N: 192

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
ApplicantIncome 0 1.00 5403.46 6109.04 150 2877.5 3812.5 5795.00 81000 ▇▁▁▁▁
CoapplicantIncome 0 1.00 1621.25 2926.25 0 0.0 1188.5 2297.25 41667 ▇▁▁▁▁
LoanAmount 22 0.96 146.41 85.59 9 100.0 128.0 168.00 700 ▇▃▁▁▁
Loan_Amount_Term 14 0.98 342.00 65.12 12 360.0 360.0 360.00 480 ▁▁▁▇▁
Credit_History 50 0.92 0.84 0.36 0 1.0 1.0 1.00 1 ▂▁▁▁▇
table(datos_loan$Loan_Status)
## 
##   N   Y 
## 192 422
ggplot(data = datos_loan) + 
  geom_bar(mapping = aes(x = Loan_Status),fill="#69b3a2")

Podemos Notar que el conjunto train tiene 614 observaciones y 13 variables de las cuales 8 son tipo cualitativa y 5 numérica.La variable objetivo Loan_Status, nos dice cuales de los clientes tienen el prestamo aprobado, resultamdo 192 negados y 422 aprobados.

Entre los datos numéricos del conjunto train hay datos perdidos NA en las variables LoanAmount (22), Loan_Amount_Term (14) y Credit_History (50), en los cuales les imputamos el valor de las medias de los datos en cada una de las variables, excepto Credit_Hitory (50) que debió ser analizada con más detellates resultando que para nuestro modelo la mejor opción fué eliminar las filas con valores NA en esta variables.

###resulta FALSE para datos NA se muestra para los primeros 40###
head(complete.cases(datos_loan$LoanAmount),40)
##  [1] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
## [13]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
## [25]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE
## [37]  TRUE  TRUE  TRUE  TRUE

Por otro lado existen niveles de valores vacios (empty) en las variables cualitativas Gender(13), Married(3), Dependents(15) y Self_Employes(32), a estos valores vacions les imputaremos el valor de la moda respectiva.

table(datos_loan$Gender)
## 
##        Female   Male 
##     13    112    489
moda_Gender="Male"

table(datos_loan$Married)
## 
##      No Yes 
##   3 213 398
moda_Married="Yes"

table(datos_loan$Dependents)
## 
##       0   1   2  3+ 
##  15 345 102 101  51
moda_Dependents="0"

table(datos_loan$Self_Employed)
## 
##      No Yes 
##  32 500  82
moda_Self_Employes="No"

Observemos la situación en los sigiuentes gráficos:

Imputemos los valores de las modas respectivos a los datos vacios (empty) para cada varianle.

##ASIGNACIÖN (imputacion) de las modas respectivas a los valores vacios empty


levels(datos_loan$Gender)[1]="Male"

levels(datos_loan$Married)[1]="Yes"

levels(datos_loan$Dependents)[1]="0"

levels(datos_loan$Self_Employed)[1]="No"

Por último eliminemos las filas donde existen valores NA de la variable Credit_History. Esto no se hace a la ligera en realidad es el resultado de analizar varios escenarios y los resultados del modelo para cada uno de esos escenarios siendo esta la opción que genera el mejor modelo.

#Eliminemos las filas con valores NA de la variable Credit_History

datos_loan<-na.omit(datos_loan)

Veamos como nos quedan los datos luego del proceso de “limpiado” y estructurados.Al resolver este problema de consistencia mejora la calidad de los datos.

skimr::skim(datos_loan)
Data summary
Name datos_loan
Number of rows 614
Number of columns 13
_______________________
Column type frequency:
factor 8
numeric 5
________________________
Group variables None

Variable type: factor

skim_variable n_missing complete_rate ordered n_unique top_counts
Loan_ID 0 1 FALSE 614 LP0: 1, LP0: 1, LP0: 1, LP0: 1
Gender 0 1 FALSE 2 Mal: 502, Fem: 112
Married 0 1 FALSE 2 Yes: 401, No: 213
Dependents 0 1 FALSE 4 0: 360, 1: 102, 2: 101, 3+: 51
Education 0 1 FALSE 2 Gra: 480, Not: 134
Self_Employed 0 1 FALSE 2 No: 532, Yes: 82
Property_Area 0 1 FALSE 3 Sem: 233, Urb: 202, Rur: 179
Loan_Status 0 1 FALSE 2 Y: 422, N: 192

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
ApplicantIncome 0 1.00 5403.46 6109.04 150 2877.50 3812.5 5795.00 81000 ▇▁▁▁▁
CoapplicantIncome 0 1.00 1621.25 2926.25 0 0.00 1188.5 2297.25 41667 ▇▁▁▁▁
LoanAmount 0 1.00 146.41 84.04 9 100.25 129.0 164.75 700 ▇▃▁▁▁
Loan_Amount_Term 0 1.00 342.00 64.37 12 360.00 360.0 360.00 480 ▁▁▁▇▁
Credit_History 50 0.92 0.84 0.36 0 1.00 1.0 1.00 1 ▂▁▁▁▇

Modelo de Árbol de Decisión

Una vez obtenidos los datos finales procedemos a entrenar nuestro modelo con este conjunto aquí usamos el algoritmo C5.0 en R

##modelo
loan_model<-C5.0(datos_modelo[-12],label_Loan )
loan_model
## 
## Call:
## C5.0.default(x = datos_modelo[-12], y = label_Loan)
## 
## Classification Tree
## Number of samples: 614 
## Number of predictors: 11 
## 
## Tree size: 5 
## 
## Non-standard options: attempt to group attributes
summary(loan_model)
## 
## Call:
## C5.0.default(x = datos_modelo[-12], y = label_Loan)
## 
## 
## C5.0 [Release 2.07 GPL Edition]      Tue Oct 27 12:34:29 2020
## -------------------------------
## 
## Class specified by attribute `outcome'
## 
## Read 614 cases (12 attributes) from undefined.data
## 
## Decision tree:
## 
## Credit_History <= 0: N (96.9/12.8)
## Credit_History > 0:
## :...Property_Area = Semiurban: Y (200.5/27.2)
##     Property_Area in {Rural,Urban}:
##     :...Married = Yes: Y (205.2/45.2)
##         Married = No:
##         :...LoanAmount <= 280: Y (105.7/30.7)
##             LoanAmount > 280: N (5.7/0.8)
## 
## 
## Evaluation on training data (614 cases):
## 
##      Decision Tree   
##    ----------------  
##    Size      Errors  
## 
##       5  113(18.4%)   <<
## 
## 
##     (a)   (b)    <-classified as
##    ----  ----
##      87   105    (a): class N
##       8   414    (b): class Y
## 
## 
##  Attribute usage:
## 
##   91.86% Credit_History
##   85.50% Property_Area
##   52.44% Married
##   18.40% LoanAmount
## 
## 
## Time: 0.0 secs

Resultados del modelo

Como resultado en la primera rama podríamos decir que los clientes chequeados con historial de crédito 0 son clasificadas como “posiblemente no otorgable”, mientras que los clientes con historial de crédito 1, son clasificada como “posiblemente si otorgable”. Los números entre paréntesis indican el número de observaciones que cumplen los criterios para esa decisión y el número clasificado incorrectamente por la decisión. Así en la primera línea, 96.9/12.8 indica, de los 96.9 observaciones que llegaron a la decisión de no otorgamiento, 12.8 se clasificaron incorrectamente como “no es otorgable”. Es decir, 12.8 solicitantes en realidad si tenían crédito aprobado a pesar de la predicción del modelo en contrario. Al final se tiene la evaluación del training data, un error de 113 en los 614 casos equivalente a un 18.4%.

Aquí se observa que el modelo acierta para los para los que no otorgable 87 veces y acierta para los que si otorgable 414 veces, es decir el modelo acierta 501 veces para un 81.6%.

Hagamos pronóstico con nuestro modelo.

Apliquemos nuestro modelo de árbol de decisión al de prueba.

Predicción:

loan_predict<-predict(loan_model,datos32_test)
loan_predict
##   [1] Y Y Y Y Y Y Y N Y Y Y Y Y N Y Y Y Y Y Y Y Y Y Y Y N Y Y Y Y Y Y Y Y Y N Y
##  [38] Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y N Y Y N Y Y Y Y N Y Y N N Y N Y Y Y Y
##  [75] Y Y Y Y Y Y N Y N Y N Y Y Y Y Y Y Y Y Y N Y Y Y Y Y Y N Y Y Y Y N Y Y Y Y
## [112] Y Y Y Y Y Y N N N Y Y Y N N Y N Y Y Y Y Y Y Y Y Y Y Y Y Y N Y N Y Y Y Y N
## [149] Y Y Y Y Y N Y Y Y Y Y Y Y N Y Y Y N N Y N Y Y Y Y N N Y Y Y Y Y Y Y Y Y Y
## [186] Y Y Y Y Y Y Y N N Y Y N Y N Y Y Y Y Y Y Y Y Y Y Y Y N Y Y Y Y Y Y Y Y Y Y
## [223] Y Y N Y Y Y Y N Y Y Y Y Y N N Y Y Y Y N Y N Y N Y Y Y Y N Y Y Y Y N Y Y Y
## [260] Y Y Y Y Y Y Y N Y N Y Y Y Y N N Y Y Y N Y Y Y Y Y Y Y Y Y Y Y Y Y Y N Y Y
## [297] Y Y Y Y Y N Y Y Y Y Y Y Y Y Y N Y Y Y Y Y N Y Y Y Y Y Y Y N Y Y Y Y Y Y Y
## [334] Y Y Y Y Y Y N Y Y Y Y Y Y N Y Y Y Y Y Y Y N Y Y Y Y Y Y Y Y Y Y Y Y
## Levels: N Y
table(loan_predict)
## loan_predict
##   N   Y 
##  59 308
final22<-mutate(loan_test,Loan_Status=loan_predict)
Resulfinal22<- dplyr::select(final22,Loan_ID,Loan_Status)
head(Resulfinal22,10)
##     Loan_ID Loan_Status
## 1  LP001015           Y
## 2  LP001022           Y
## 3  LP001031           Y
## 4  LP001035           Y
## 5  LP001051           Y
## 6  LP001054           Y
## 7  LP001055           Y
## 8  LP001056           N
## 9  LP001059           Y
## 10 LP001067           Y

La última tabla muestra el pronóstico de la aprobacion de créditos para los clientes en el conjunto de datos de prueba, al hacer la comprobacion en la página de Analitic Vidhya se obtuvo una evaluación positiva del 77% de la predicción.

Mejoremos el performance del modelo.

A continuación mostramos como podríamos aumentar la precisión del algoritmo C5.0, mejorando el performance del modelo. El método usado es conocido como Boosting, el cual básicamente consiste en combinar varios modelos con débil performance, así trabajando estos en equipo serán mas fuerte que los modelos solos. Para tal fin solo agregamos un parámetro de prueba a nuestra función C5.0 ( ), para indicar el número máximo de árboles de decisión a usar en el boosting team. Usaremos 10 pruebas, que es un número que está establecido como un estándar.

###mejorando el performance del modelo con bossting

loan_model_boosting2<-C5.0(datos_modelo[-12],label_Loan, trials = 10 )
loan_model_boosting2
## 
## Call:
## C5.0.default(x = datos_modelo[-12], y = label_Loan, trials = 10)
## 
## Classification Tree
## Number of samples: 614 
## Number of predictors: 11 
## 
## Number of boosting iterations: 10 
## Average tree size: 4.6 
## 
## Non-standard options: attempt to group attributes
#Apliquemos nuestro nuevo modelo boosting al conjunto test, para evaluar el performance
#modelo:
loan_predict_boosting2<-predict(loan_model_boosting2,datos32_test)
loan_predict_boosting2
##   [1] Y Y Y Y Y Y Y N Y Y Y Y Y N Y Y Y Y Y Y Y Y Y Y Y N Y Y Y Y Y Y Y Y Y N Y
##  [38] Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y N Y Y N Y Y Y Y N Y Y N N Y N Y Y Y Y
##  [75] Y Y Y Y Y Y N Y N Y N Y Y Y Y Y Y Y Y Y N Y Y Y Y Y Y N Y Y Y Y N Y Y Y Y
## [112] Y Y Y Y Y Y N N N Y Y Y N N Y N Y Y Y Y Y Y Y Y Y Y Y Y Y N Y N Y Y Y Y N
## [149] Y Y Y Y Y N Y Y Y Y Y Y Y N Y Y Y N N Y N Y Y Y Y N N Y Y Y Y Y Y Y Y Y Y
## [186] Y Y Y Y Y Y Y N N Y Y N Y N Y Y Y Y Y Y Y Y Y Y Y Y N Y Y Y Y Y Y Y Y Y Y
## [223] Y Y N Y Y Y Y N Y Y Y Y Y N N Y Y Y Y N Y N Y N Y Y Y Y N Y Y Y Y N Y Y Y
## [260] Y Y Y Y Y Y Y N Y N Y Y Y Y N N Y Y Y N Y Y Y Y Y Y Y Y Y Y Y Y Y Y N Y Y
## [297] Y Y Y Y Y N Y Y Y Y Y Y Y Y Y N Y Y Y Y Y N Y Y Y N Y Y Y N Y Y Y Y Y Y Y
## [334] Y Y Y Y Y Y N Y Y Y Y Y Y N Y Y Y Y Y Y Y N Y Y Y Y Y Y Y Y Y Y Y Y
## Levels: N Y
table(loan_predict_boosting2)
## loan_predict_boosting2
##   N   Y 
##  60 307
final263<-mutate(loan_test,Loan_Status=loan_predict_boosting2)
Resulfinal263<- dplyr::select(final263,Loan_ID,Loan_Status)
head(Resulfinal263,10)
##     Loan_ID Loan_Status
## 1  LP001015           Y
## 2  LP001022           Y
## 3  LP001031           Y
## 4  LP001035           Y
## 5  LP001051           Y
## 6  LP001054           Y
## 7  LP001055           Y
## 8  LP001056           N
## 9  LP001059           Y
## 10 LP001067           Y

El pronóstico obtenido al final resultó con una precisión de 75%, el cúal no mejora la precisión del modelo inicial, esto es posible al realizar este proceso de Boosting. Con la función summary () podemos ver los 10 árboles de decisión y observar algunos resultados respecto a a la precisión en el conjunto train usando el modelo Boosting.

Los árboles también se pueden usar para predicción numérica haciendo solo unos pocos ajustes en el algoritmo de crecimiento. Árboles para predicción numérica caen en dos categorías. La primera conocida como regresión de árbol, y cuyo nombre no significa que sea regresión lineal. El segundo tipo de árbol para predicción numérica es conocido como modelo de árbol, estos crece en la misma forma como lo hace un árbol de regresión pero en cada hoja un modelo múltiple es creado.

Los modelos de árboles son una gran herramienta en el estudio de Machine Learning para problemas de pronóstico o clasificación, en consecuencia estudiarlos y conocer su utilización para los que nos dedicamos a este estudio de la Ciencia de datos (Datascience) es parte de los objetivos.