Metodos de Clasificacion
library(tidyverse)
library(rpart)
library(rpart.plot)
library(caret)
library(readxl)
library(dplyr)
library(rsample)
library(ROSE)
library(rattle)
library(randomForest)
library(plotly)
library(vcd)
library(e1071)
library(ROCR)##grafica de la curva ROC
library(neuralnet) ## redes neuronales funcion "neuralnet"
library(nnet)##redes neuronales "nneyt"
library(e1071)
library(plyr)
library(ggplot2)
library(ggplotlyExtra)
library(PCAmixdata)
library(caTools)
library(data.table)
library(ROCit)
source("funDT.R")
set.seed(1727)
Tratamiento de la Base de Datos
Lectura de los Datos
En el presente trabajo se analizará la base de datos llamada BaseProd.xlsx, la cual consta con alrededor de 25 variables y 22965 individuos, en la que consta un registro detallado del uso de tarjetas de crédito, como también costa de información particular de los propietarios. La periodicidad de los datos es diaria, considerada desde el 01-01-2018 hasta el 31-03-2019.
La variable Tarjet sera, MarcaMora_Tarjeta, dicha variable describe si un solicitante de trajeta de credito presenta o no un retraso en sus pagos.
Es de considerar que se dispone de un evento raro, pues notemos que:
0 1
0.96233399 0.03766601
se cuenta solo con 0.03 % de observaciones de una de las categorias, se abordara este problema mas adelante al balancear los datos.
datos.02 <- datos.01 %>% mutate(MarcaMora_Tarjeta=factor(MarcaMora_Tarjeta),
ORIGEN_APROBACION=factor(ORIGEN_APROBACION),
FORMA_PAGO=factor(FORMA_PAGO),
MARCA_CUENTA_CORRIENTE=factor(MARCA_CUENTA_CORRIENTE),
MARCA_CUENTA_AHORROS=factor(MARCA_CUENTA_AHORROS),
SEGMENTO_RIESGO=factor(SEGMENTO_RIESGO),
SUCURSAL=factor(SUCURSAL),
GENERO=factor(GENERO),
INSTRUCCION = factor(INSTRUCCION))
Rows: 22,965
Columns: 23
$ MarcaMora_Tarjeta <fct> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ~
$ ORIGEN_APROBACION <fct> Proactivo, Demanda, Demanda, Proa~
$ FORMA_PAGO <fct> No, No, No, No, No, No, No, No, N~
$ SALDO_TOTAL_TARJETA <dbl> 1108.50, 601.56, 25.26, 12996.65,~
$ CUPO_PROMEDIO_TARJETA <dbl> 1400.0000, 3000.0000, 800.0000, 1~
$ SALDO_UTILIZ_PROM_CLIENTE <dbl> 1279.7483, 16.9700, 36.2250, 1759~
$ CANTIDAD_TOTAL_AVANCES <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ~
$ ANTIGUEDAD_TARJETA_ANIOS <dbl> 10, 7, 7, 7, 10, 10, 7, 7, 7, 7, ~
$ PROMEDIO_MENSUAL_CONSUMOS_LOCALES <dbl> 242.26, 0.00, 0.00, 404.59, 42.34~
$ MAXIMO_NUM_DIAS_VENCIDO <dbl> 21, 20, 31, 2, 2, 16, 7, 0, 19, 2~
$ NUMERO_OPERACIONES_TITULAR <dbl> 5, 2, 3, 7, 2, 2, 2, 2, 6, 7, 9, ~
$ PROMEDIO_DIAS_SOBREGIRO_CC <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0,~
$ PROMEDIO_MENSUAL_SALDO_CUENTA_PASIVO <dbl> 0.0000, 1627.4932, 4065.9979, 840~
$ MARCA_CUENTA_CORRIENTE <fct> No, Si, Si, Si, No, No, Si, Si, N~
$ MARCA_CUENTA_AHORROS <fct> No, Si, Si, Si, No, No, Si, Si, N~
$ RIESGO_CLIENTE_TOTAL_GFP <dbl> 1125.33, 601.56, 25.26, 16228.69,~
$ VALOR_DEPOSITO_A_PLAZO <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ~
$ SEGMENTO_RIESGO <fct> E, A, A, B, A, A, A, A, D, A, A, ~
$ SUCURSAL <fct> QUITO, QUITO, QUITO, AMBATO, QUIT~
$ EDAD <dbl> 27, 37, 46, 40, 29, 39, 44, 34, 3~
$ GENERO <fct> FEM, MAS, MAS, MAS, MAS, FEM, MAS~
$ INSTRUCCION <fct> PRI, UNI, SEC, UNI, UNI, UNI, SEC~
$ NUM_TC_SIST_FIM <dbl> 1, 0, 4, 2, 2, 3, 1, 0, 4, 5, 1, ~
Balanceo de los Datos.
Evento raro
En los modelos de elección binaria se presentan problemas cuando se trabaja con una bajo probabilidad de ocurrencia del suceso que se está estudiando, esto se conoce como evento raro. Formalmente, un evento raro se define como la probabilidad de ocurrencia de un evento, siempre y cuando esta sea inferior al \(5\%\).
La precencia de un evento raro puede originar que el poder predictivo del modelo se verá afectado pues podría predecir todos los casos como pertenecientes a la clase mayoritaria, lo que ocasiona problemas de clasificación en los grupos de riesgo homogéneos y en el mundo crediticio podría originar fraude con tarjetas de crédito que puede costar a las empresas e individuos mucho dinero.
Una alternativa para lidiar con este inconveniente es la recopilación de más datos (que casi siempre se pasa por alto) ya que con un conjunto de datos más grande podría exponerse una perspectiva diferente y tal vez más equilibrada de las clases. Esto puede resultar costoso, por lo que una opción bastante válida es realizar un remuestreo para aumentar las observaciones en la clase minoritaria o disminuir las de la clase mayoritaria con el objetivo de obtener una proporción justa en el número de instancias para las dos clases. Existen dos tipos principales de muestreo:
- Sub-muestreo aleatorio: elimina aleatoriamente instancias de la clase mayoritaria de un conjunto de datos desbalanceada. Entre las ventajas de este procedimiento se tiene que puede mejorar el tiempo de ejecución del modelo; grandes desventajas es que puede descartar información útil sobre los datos que podría ser utilizada para la creación de clasificadores basados en reglas como los bosques aleatorios y que la muestra no será una representación precisa de la población, lo que puede hacer que el clasificador se comporte mal en datos reales.
- Sobre-muestreo aleatorio: en este caso, no disminuye el número de instancias asignadas a la clase mayoritaria y se aumentan las instancias de la clase minoritaria replicándolas hasta un grado constante. Este método no conduce a la pérdida de información, pero aumenta el costo computacional del modelo.
set.seed(1727)
datos.02 <- ovun.sample(MarcaMora_Tarjeta ~ ., data = datos.02,
method = "both", p=0.5, N=5000, seed = 1)$data
0 1
0.5128 0.4872
Particionamiento de los Datos
Consiste en disponer de dos subconjuntos de datos procedentes del conjunto inicial (y ya tratado): un subconjunto de datos que se utiliza para construir el modelo y otro para validarlo.
A continuación se muestra la relación entre observaciones con mora y sin mora del subconjunto de entrenamiento(train) y de validacion (test), dado que estamos trabajando con datos balanceados, se espera tener dicha propiedad en los datos que ingresen al modelo.
### sets de entrenamiento y pueba
sample <- sample.split(setDF(datos.02), SplitRatio = 0.8)
train <- setDT(subset(setDF(datos.02), sample == TRUE))
test <- setDT(subset(setDF(datos.02), sample == FALSE))
0 1
0.5129057 0.4870943
0 1
0.5124195 0.4875805
Modelamiento
Arboles de Decision
n= 3913
node), split, n, loss, yval, (yprob)
* denotes terminal node
1) root 3913 1906 0 (0.5129057 0.4870943)
2) SEGMENTO_RIESGO=A 3057 1200 0 (0.6074583 0.3925417)
4) PROMEDIO_MENSUAL_SALDO_CUENTA_PASIVO>=232.7611 899 144 0 (0.8398220 0.1601780) *
5) PROMEDIO_MENSUAL_SALDO_CUENTA_PASIVO< 232.7611 2158 1056 0 (0.5106580 0.4893420)
10) ANTIGUEDAD_TARJETA_ANIOS>=2.5 768 229 0 (0.7018229 0.2981771) *
11) ANTIGUEDAD_TARJETA_ANIOS< 2.5 1390 563 1 (0.4050360 0.5949640)
22) CUPO_PROMEDIO_TARJETA>=275 1134 499 1 (0.4400353 0.5599647)
44) MAXIMO_NUM_DIAS_VENCIDO< 3.5 393 167 0 (0.5750636 0.4249364)
88) PROMEDIO_MENSUAL_CONSUMOS_LOCALES>=41.775 88 13 0 (0.8522727 0.1477273) *
89) PROMEDIO_MENSUAL_CONSUMOS_LOCALES< 41.775 305 151 1 (0.4950820 0.5049180)
178) RIESGO_CLIENTE_TOTAL_GFP< 2809.295 210 86 0 (0.5904762 0.4095238) *
179) RIESGO_CLIENTE_TOTAL_GFP>=2809.295 95 27 1 (0.2842105 0.7157895) *
45) MAXIMO_NUM_DIAS_VENCIDO>=3.5 741 273 1 (0.3684211 0.6315789)
90) PROMEDIO_MENSUAL_SALDO_CUENTA_PASIVO>=83.1287 48 9 0 (0.8125000 0.1875000) *
91) PROMEDIO_MENSUAL_SALDO_CUENTA_PASIVO< 83.1287 693 234 1 (0.3376623 0.6623377) *
23) CUPO_PROMEDIO_TARJETA< 275 256 64 1 (0.2500000 0.7500000) *
3) SEGMENTO_RIESGO=B,C,D,E 856 150 1 (0.1752336 0.8247664) *
Confusion Matrix and Statistics
Reference
Prediction 0 1
0 408 138
1 149 392
Accuracy : 0.736
95% CI : (0.7087, 0.762)
No Information Rate : 0.5124
P-Value [Acc > NIR] : <2e-16
Kappa : 0.4719
Mcnemar's Test P-Value : 0.555
Sensitivity : 0.7325
Specificity : 0.7396
Pos Pred Value : 0.7473
Neg Pred Value : 0.7246
Prevalence : 0.5124
Detection Rate : 0.3753
Detection Prevalence : 0.5023
Balanced Accuracy : 0.7361
'Positive' Class : 0
MarcaMora_Tarjeta
prediccion_1 0 1
0 408 138
1 149 392
[1] 73.59706
mosaic(cf.01$table, shade = T, colorize = T,
gp = gpar(fill = matrix(c("green3", "red2", "red2", "green3"), 2, 2)))
ROCit_obj.01 <- rocit(score=as.numeric(prediccion_1), class=test$MarcaMora_Tarjeta)
plot(ROCit_obj.01)
El AUC del modelo es 0.7360591
El índice GINI del modelo es 0.4721182
Random Forest
Call:
randomForest(formula = MarcaMora_Tarjeta ~ ., data = train)
Type of random forest: classification
Number of trees: 500
No. of variables tried at each split: 4
OOB estimate of error rate: 8.66%
Confusion matrix:
0 1 class.error
0 1758 249 0.12406577
1 90 1816 0.04721931
MeanDecreaseGini
ORIGEN_APROBACION 14.298045
FORMA_PAGO 17.025900
SALDO_TOTAL_TARJETA 145.577602
CUPO_PROMEDIO_TARJETA 139.213531
SALDO_UTILIZ_PROM_CLIENTE 129.821794
CANTIDAD_TOTAL_AVANCES 70.139098
ANTIGUEDAD_TARJETA_ANIOS 142.188382
PROMEDIO_MENSUAL_CONSUMOS_LOCALES 115.771469
MAXIMO_NUM_DIAS_VENCIDO 145.912529
NUMERO_OPERACIONES_TITULAR 81.090426
PROMEDIO_DIAS_SOBREGIRO_CC 17.455786
PROMEDIO_MENSUAL_SALDO_CUENTA_PASIVO 234.662335
MARCA_CUENTA_CORRIENTE 14.795181
MARCA_CUENTA_AHORROS 15.015276
RIESGO_CLIENTE_TOTAL_GFP 154.171591
VALOR_DEPOSITO_A_PLAZO 4.238032
SEGMENTO_RIESGO 164.468248
SUCURSAL 86.477572
EDAD 112.690436
GENERO 22.575611
INSTRUCCION 41.310308
NUM_TC_SIST_FIM 69.475159
MarcaMora_Tarjeta
predicciones 0 1
0 480 23
1 77 507
[1] 90.80037
mosaic(mc, shade = T, colorize = T,
gp = gpar(fill = matrix(c("green3", "red2", "red2", "green3"), 2, 2)))
ROCit_obj.02 <- rocit(score=as.numeric(predicciones), class=test$MarcaMora_Tarjeta)
plot(ROCit_obj.02)
El AUC del modelo es 0.9091816
El índice GINI del modelo es 0.8183632
Bayes
Naive Bayes Classifier for Discrete Predictors
Call:
naiveBayes.default(x = X, y = Y, laplace = laplace)
A-priori probabilities:
Y
0 1
0.5129057 0.4870943
Conditional probabilities:
ORIGEN_APROBACION
Y Demanda Proactivo
0 0.2321873 0.7678127
1 0.1757608 0.8242392
FORMA_PAGO
Y No Si
0 0.7354260 0.2645740
1 0.8357817 0.1642183
SALDO_TOTAL_TARJETA
Y [,1] [,2]
0 1478.380 1645.446
1 1610.525 1425.818
CUPO_PROMEDIO_TARJETA
Y [,1] [,2]
0 2737.954 2925.612
1 1817.026 1613.595
SALDO_UTILIZ_PROM_CLIENTE
Y [,1] [,2]
0 1271.248 1500.862
1 1217.765 1209.037
CANTIDAD_TOTAL_AVANCES
Y [,1] [,2]
0 0.9576482 2.721119
1 1.9134313 3.242007
ANTIGUEDAD_TARJETA_ANIOS
Y [,1] [,2]
0 4.274539 3.392541
1 2.389822 2.565198
PROMEDIO_MENSUAL_CONSUMOS_LOCALES
Y [,1] [,2]
0 207.01756 938.0952
1 70.34885 189.1060
MAXIMO_NUM_DIAS_VENCIDO
Y [,1] [,2]
0 10.26457 13.93852
1 15.90766 17.90042
NUMERO_OPERACIONES_TITULAR
Y [,1] [,2]
0 3.12855 1.699046
1 3.62382 1.852753
PROMEDIO_DIAS_SOBREGIRO_CC
Y [,1] [,2]
0 0.6008969 2.659406
1 0.5724029 4.008685
PROMEDIO_MENSUAL_SALDO_CUENTA_PASIVO
Y [,1] [,2]
0 2529.0169 13261.721
1 385.7062 4013.186
MARCA_CUENTA_CORRIENTE
Y No Si
0 0.4653712 0.5346288
1 0.5556139 0.4443861
MARCA_CUENTA_AHORROS
Y No Si
0 0.4653712 0.5346288
1 0.5556139 0.4443861
RIESGO_CLIENTE_TOTAL_GFP
Y [,1] [,2]
0 4542.725 17008.011
1 3555.475 6150.611
VALOR_DEPOSITO_A_PLAZO
Y [,1] [,2]
0 1667.433009 22437.6180
1 9.811931 345.8888
SEGMENTO_RIESGO
Y A B C D E
0 0.925261584 0.043348281 0.009466866 0.008968610 0.012954659
1 0.629590766 0.213011542 0.047219307 0.050367261 0.059811123
SUCURSAL
Y AMBATO CUENCA ESMERALDAS GUAYAQUIL IBARRA
0 0.0378674639 0.0378674639 0.0094668660 0.2800199302 0.0214250125
1 0.0278069255 0.0272822665 0.0204616999 0.3767051417 0.0267576076
SUCURSAL
Y LATACUNGA LOJA MACHALA MANTA QUEVEDO
0 0.0029895366 0.0089686099 0.0004982561 0.0204285002 0.0059790732
1 0.0031479538 0.0052465897 0.0026232949 0.0356768101 0.0083945435
SUCURSAL
Y QUITO RIOBAMBA SANTO DOMINGO
0 0.5560538117 0.0074738416 0.0109616343
1 0.4443861490 0.0068205666 0.0146904512
EDAD
Y [,1] [,2]
0 36.41604 8.099937
1 36.44806 8.266536
GENERO
Y FEM MAS
0 0.4225212 0.5774788
1 0.4029381 0.5970619
INSTRUCCION
Y PRI SEC TEC UNI
0 0.19133034 0.55605381 0.01943199 0.23318386
1 0.16107030 0.59548793 0.01731375 0.22612802
NUM_TC_SIST_FIM
Y [,1] [,2]
0 2.610862 1.702892
1 2.478489 1.709878
MarcaMora_Tarjeta
prediccionesBayes 0 1
0 84 16
1 473 514
[1] 55.0138
mosaic(mc, shade = T, colorize = T,
gp = gpar(fill = matrix(c("green3", "red2", "red2", "green3"), 2, 2)))
ROCit_obj.03 <- rocit(score=as.numeric(prediccionesBayes), class=test$MarcaMora_Tarjeta)
plot(ROCit_obj.03)
El AUC del modelo es 0.5603096
El índice GINI del modelo es 0.1206192
Redes Neuronales
# weights: 801
initial value 2898.542655
iter 10 value 2588.716808
iter 20 value 2491.184445
iter 30 value 2475.970614
iter 40 value 2443.173701
iter 50 value 2433.670950
iter 60 value 2404.259548
iter 70 value 2391.219363
iter 80 value 2372.967092
iter 90 value 2319.264066
iter 100 value 2307.851091
final value 2307.851091
stopped after 100 iterations
#A continuacion vamos a determinar la validez del modelo aplicando al grupo de datos test
# y revisar a los resultados de la predicci?n.
Confusion Matrix and Statistics
Reference
Prediction 0 1
0 373 177
1 184 353
Accuracy : 0.6679
95% CI : (0.639, 0.6959)
No Information Rate : 0.5124
P-Value [Acc > NIR] : <2e-16
Kappa : 0.3356
Mcnemar's Test P-Value : 0.7522
Sensitivity : 0.6697
Specificity : 0.6660
Pos Pred Value : 0.6782
Neg Pred Value : 0.6574
Prevalence : 0.5124
Detection Rate : 0.3431
Detection Prevalence : 0.5060
Balanced Accuracy : 0.6678
'Positive' Class : 0
MarcaMora_Tarjeta
predichos_red 0 1
0 373 177
1 184 353
[1] 66.78933
#*GRAFICO
mosaic(mcrd, shade = T, colorize = T,
gp = gpar(fill = matrix(c("green3", "red2", "red2", "green3"), 2, 2)))
ROCit_obj.04 <- rocit(score=as.numeric(predichos_red), class=test$MarcaMora_Tarjeta)
plot(ROCit_obj.04)
El AUC del modelo es 0.6678483
El índice GINI del modelo es 0.3356966
Comparacion de los Modelos
- El área bajo la curva AUC puede tomar valores entre \(0.5\) y \(1\). Un porcentaje del AUC del \(50\%\) implica que el modelo no es mejor que hacer una suposición aleatoria; y un valor de \(100\%\) indicaría la improbable aparición de predicciones perfectamente correctas. Sin embargo, para el caso de sistemas de clasificación lo ideal es tomar valores del AUC que sean mayores a \(0.7\), y entonces se dirá que esos modelos tienen una buena capacidad de clasificación.
Modelo <-c("Arbol de Decision","Random Forest","Bayes", "Redes Neuronales")
AUC_models <- c(AUC1, AUC2,AUC3,AUC4)
GINI_models <- c(GINI1, GINI2,GINI3,GINI4)
R2_regresion <- c(R2.01,R2.02,R2.03,R2.04)
data.frame(Modelo,'AUC'=AUC_models,'GINI'=GINI_models,
'% Correctamente' =R2_regresion)
Conclusion
- Estudiando los diferentes estadisticos, y graficos presentados a lo largo de este trabajo, se ha concluido que Random Forest ofrece los mejores resultados.
- El Balanceo de los Datos, es de suma importancia para los algoritmos de clasificacion, la existencia de evidencia de eventos raros, puede llevar a problemas de clasificacion.