T########################################################################### # Handout 2 # # Machin Learning and Public Policy # # Universidad de los Andes # # 2018 # ########################################################################### #Name: Lukas Sanz Ramirez #Code: 201529628 ############################################################################ # ¿Qué puede decir acerca de la solvencia de los clientes a partir de los # # datos de uso del teléfono disponibles? ¿Qué sugiere su análisis mediante # # herramientas de aprendizaje automático sobre el diseño de productos para # # la inclusión financiera de los pobres? Su análisis debe mostrar # #claramente que tiene # ############################################################################ #instalar paquetes install.packages(c(“ggplot2”,“rpart”, “rpart.plot”, “MASS”, “randomForest”, “tree”,“glmnet”,“dummies”,“Mlmetrics”,“dplyr”,“arules”, “factoextra”, “NbClust”))
setwd("~/handout")
base<-read.csv("~/handout/momo_z.csv")
dt <- read.csv("~/handout/momo_z.csv")
library("ggplot2")
summary(dt)
## send_amt send_qty send_dgr received_amt
## Min. :-0.33732 Min. :-0.6407 Min. :-0.7832 Min. :-0.42023
## 1st Qu.:-0.29962 1st Qu.:-0.5012 1st Qu.:-0.5143 1st Qu.:-0.35224
## Median :-0.23625 Median :-0.3020 Median :-0.2992 Median :-0.25383
## Mean : 0.00000 Mean : 0.0000 Mean : 0.0000 Mean : 0.00000
## 3rd Qu.:-0.06165 3rd Qu.: 0.0765 3rd Qu.: 0.1848 3rd Qu.:-0.02446
## Max. :41.58243 Max. :23.3243 Max. :29.5477 Max. :36.13196
## received_qty received_dgr deposit_amt deposit_qty
## Min. :-0.8062 Min. :-0.9927 Min. :-0.33486 Min. :-0.7089
## 1st Qu.:-0.5568 1st Qu.:-0.6120 1st Qu.:-0.28696 1st Qu.:-0.5043
## Median :-0.2717 Median :-0.2313 Median :-0.21928 Median :-0.2705
## Mean : 0.0000 Mean : 0.0000 Mean : 0.00000 Mean : 0.0000
## 3rd Qu.: 0.2271 3rd Qu.: 0.2445 3rd Qu.:-0.05462 3rd Qu.: 0.1094
## Max. :58.5592 Max. :38.8827 Max. :39.80240 Max. :28.5453
## deposity_dgr withdraw_amt withdraw_qty withdraw_dgr
## Min. :-1.1330 Min. :-0.35510 Min. :-0.8215 Min. :-0.9545
## 1st Qu.:-0.6693 1st Qu.:-0.31032 1st Qu.:-0.6443 1st Qu.:-0.6758
## Median :-0.3216 Median :-0.22060 Median :-0.2901 Median :-0.2577
## Mean : 0.0000 Mean : 0.00000 Mean : 0.0000 Mean : 0.0000
## 3rd Qu.: 0.2580 3rd Qu.:-0.01633 3rd Qu.: 0.2413 3rd Qu.: 0.2997
## Max. :11.3854 Max. :36.88574 Max. :18.7217 Max. :16.0477
## bill_amt bill_qty bill_dgr
## Min. : -0.00724 Min. :-0.32578 Min. :-0.3679
## 1st Qu.: -0.00724 1st Qu.:-0.32578 1st Qu.:-0.3679
## Median : -0.00724 Median :-0.32578 Median :-0.3679
## Mean : 0.00000 Mean : 0.00000 Mean : 0.0000
## 3rd Qu.: -0.00642 3rd Qu.:-0.06983 3rd Qu.:-0.3679
## Max. :223.46174 Max. :50.47888 Max. :12.6897
## airtime topup days_no_balance age
## Min. :-1.1974 Min. :-1.3327 Min. :-2.10806 Min. :-1.5562
## 1st Qu.:-0.6405 1st Qu.:-0.6615 1st Qu.:-0.81861 1st Qu.:-0.7743
## Median :-0.2901 Median :-0.2900 Median : 0.07612 Median :-0.1905
## Mean : 0.0000 Mean : 0.0000 Mean : 0.00000 Mean : 0.0000
## 3rd Qu.: 0.3078 3rd Qu.: 0.3510 3rd Qu.: 0.78663 3rd Qu.: 0.5648
## Max. :12.4662 Max. :11.5195 Max. : 2.47082 Max. : 7.1109
## gender default
## FEMALE:16288 Default:11999
## MALE :33331 Paid :38001
## OTHER : 381
##
##
##
head(dt)
str(dt)
## 'data.frame': 50000 obs. of 21 variables:
## $ send_amt : num -0.276 -0.204 -0.122 0.499 0.794 ...
## $ send_qty : num -0.282 -0.302 -0.143 0.176 1.192 ...
## $ send_dgr : num -0.192 -0.138 0.131 0.346 1.422 ...
## $ received_amt : num -0.219 -0.24 -0.354 0.384 0.443 ...
## $ received_qty : num -0.1648 -0.3074 -0.5568 -0.0579 -0.0223 ...
## $ received_dgr : num -0.136 -0.422 -0.422 -0.231 -0.136 ...
## $ deposit_amt : num -0.3002 -0.1736 0.0129 0.1834 0.4428 ...
## $ deposit_qty : num -0.475 -0.271 0.139 -0.329 0.197 ...
## $ deposity_dgr : num -0.5534 -0.5534 0.0261 -0.4375 0.6057 ...
## $ withdraw_amt : num -0.0786 -0.1621 -0.2749 0.3322 -0.2621 ...
## $ withdraw_qty : num 0.123 -0.349 -0.585 0.123 -0.644 ...
## $ withdraw_dgr : num 0.3 -0.258 -0.815 0.3 -0.676 ...
## $ bill_amt : num -0.007237 -0.002772 0.000621 0.005557 0.006142 ...
## $ bill_qty : num -0.326 0.442 1.21 1.21 0.698 ...
## $ bill_dgr : num -0.368 3.549 3.549 6.161 2.244 ...
## $ airtime : num -0.4 0.248 0.567 3.86 0.433 ...
## $ topup : num -0.275 0.692 0.978 -1.333 -0.243 ...
## $ days_no_balance: num -0.398 -1.582 -1.766 -2.108 -1.476 ...
## $ age : num -0.711 -0.323 0.337 -0.408 0.365 ...
## $ gender : Factor w/ 3 levels "FEMALE","MALE",..: 1 1 2 2 2 2 1 1 1 2 ...
## $ default : Factor w/ 2 levels "Default","Paid": 2 2 2 2 2 2 2 2 2 2 ...
table(dt$gender)
##
## FEMALE MALE OTHER
## 16288 33331 381
prop.table(table(dt$gender))
##
## FEMALE MALE OTHER
## 0.32576 0.66662 0.00762
Como se observó en las tablas presentadas arriba el 66% de la poblacion son de género masculino, el 32% de genero femenino y el 0,7% de la población se consideran de otro genero. Por otra parte como se puede ver mas adelante el 76% de la población total pagan sus deudas relacionadas con créditos de las plataformas de dinero móvil, por otra parte el grueso de la población se encuentra entre las -1.9 y 1.9 deviaciones estándar de la media como se muestra el histograma de frecuencia presentado a continuación.
prop.table(table(dt$default))
##
## Default Paid
## 0.23998 0.76002
barplot(table(dt$default), col=heat.colors(2))
title("Estado de pago de creditos mobiles")
hist(dt$age, main="Histograma de la Edad", xlab="Edad")
library(scatterplot3d)
scatterplot3d(dt$age,dt$default,dt$airtime,color=(3))
names(dt)
## [1] "send_amt" "send_qty" "send_dgr"
## [4] "received_amt" "received_qty" "received_dgr"
## [7] "deposit_amt" "deposit_qty" "deposity_dgr"
## [10] "withdraw_amt" "withdraw_qty" "withdraw_dgr"
## [13] "bill_amt" "bill_qty" "bill_dgr"
## [16] "airtime" "topup" "days_no_balance"
## [19] "age" "gender" "default"
scatterplot3d(dt$send_amt,dt$default,dt$received_amt,color=(3))
Por otra parte parece existir una relación positiva entre la proporción de personas que pagan sus créditos otorgados por las plataformas móviles y el tiempo que pasan usando sus teléfonos, de manera analoga aquellas personas que envían y reciben dinero por encima del promedio tienden a pagar sus deudas móviles. Por el contrario aquellas personas que envían y reciben menos dinero por medio de sus celulares tienden a no estar al día en sus deudas móviles.
library(dummies)
## dummies-1.5.6 provided by Decision Patterns
dt = dummy.data.frame(dt)
dt <-dt[ ,!colnames(dt)=="defaultDefault"]
str(dt)
## 'data.frame': 50000 obs. of 23 variables:
## $ send_amt : num -0.276 -0.204 -0.122 0.499 0.794 ...
## $ send_qty : num -0.282 -0.302 -0.143 0.176 1.192 ...
## $ send_dgr : num -0.192 -0.138 0.131 0.346 1.422 ...
## $ received_amt : num -0.219 -0.24 -0.354 0.384 0.443 ...
## $ received_qty : num -0.1648 -0.3074 -0.5568 -0.0579 -0.0223 ...
## $ received_dgr : num -0.136 -0.422 -0.422 -0.231 -0.136 ...
## $ deposit_amt : num -0.3002 -0.1736 0.0129 0.1834 0.4428 ...
## $ deposit_qty : num -0.475 -0.271 0.139 -0.329 0.197 ...
## $ deposity_dgr : num -0.5534 -0.5534 0.0261 -0.4375 0.6057 ...
## $ withdraw_amt : num -0.0786 -0.1621 -0.2749 0.3322 -0.2621 ...
## $ withdraw_qty : num 0.123 -0.349 -0.585 0.123 -0.644 ...
## $ withdraw_dgr : num 0.3 -0.258 -0.815 0.3 -0.676 ...
## $ bill_amt : num -0.007237 -0.002772 0.000621 0.005557 0.006142 ...
## $ bill_qty : num -0.326 0.442 1.21 1.21 0.698 ...
## $ bill_dgr : num -0.368 3.549 3.549 6.161 2.244 ...
## $ airtime : num -0.4 0.248 0.567 3.86 0.433 ...
## $ topup : num -0.275 0.692 0.978 -1.333 -0.243 ...
## $ days_no_balance: num -0.398 -1.582 -1.766 -2.108 -1.476 ...
## $ age : num -0.711 -0.323 0.337 -0.408 0.365 ...
## $ genderFEMALE : int 1 1 0 0 0 0 1 1 1 0 ...
## $ genderMALE : int 0 0 1 1 1 1 0 0 0 1 ...
## $ genderOTHER : int 0 0 0 0 0 0 0 0 0 0 ...
## $ defaultPaid : int 1 1 1 1 1 1 1 1 1 1 ...
install.packages(c(“arules”, “factoextra”, “NbClust”))
library("ggplot2")
library("factoextra")
## Welcome! Related Books: `Practical Guide To Cluster Analysis in R` at https://goo.gl/13EFCZ
set.seed(123)
grupos <- kmeans(dt,centers=4)
dt$clusters=grupos$cluster
fviz_cluster(grupos, data = dt,
palette = c("#00AFBB","#2E9FDF", "#E7B800", "#FC4E07"),
main = "Partitioning Clustering Plot")
# Initialize total within sum of squares error: wss
wss <- 0
for (i in 1:15) {
grupos.out <- kmeans(scale(dt), centers = i, nstart = 20)
# Save total within sum of squares to wss variable
wss[i] <- grupos.out$tot.withinss
}
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 2500000)
## Warning: did not converge in 10 iterations
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 2500000)
## Warning: did not converge in 10 iterations
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 2500000)
## Warning: did not converge in 10 iterations
## Warning: did not converge in 10 iterations
## Warning: did not converge in 10 iterations
## Warning: did not converge in 10 iterations
## Warning: did not converge in 10 iterations
## Warning: did not converge in 10 iterations
plot(1:15, wss, type = "b",
xlab = "Number of Clusters",
ylab = "Within groups sum of squares")
grupos.best <- kmeans(dt,centers=7)
dt$clusters=grupos.best$cluster
fviz_cluster(grupos.best, data = dt,
palette = c("#00AFBB","#2E9FDF", "#E7B800", "#FC4E07","#006633","#330066","#0000c1"),
main = "Partitioning Clustering Plot"
)
barplot(table(grupos.best$cluster), col=heat.colors(7))
dt$clusters=as.factor(dt$clusters)
dt = dummy.data.frame(dt)
str(dt)
## 'data.frame': 50000 obs. of 30 variables:
## $ send_amt : num -0.276 -0.204 -0.122 0.499 0.794 ...
## $ send_qty : num -0.282 -0.302 -0.143 0.176 1.192 ...
## $ send_dgr : num -0.192 -0.138 0.131 0.346 1.422 ...
## $ received_amt : num -0.219 -0.24 -0.354 0.384 0.443 ...
## $ received_qty : num -0.1648 -0.3074 -0.5568 -0.0579 -0.0223 ...
## $ received_dgr : num -0.136 -0.422 -0.422 -0.231 -0.136 ...
## $ deposit_amt : num -0.3002 -0.1736 0.0129 0.1834 0.4428 ...
## $ deposit_qty : num -0.475 -0.271 0.139 -0.329 0.197 ...
## $ deposity_dgr : num -0.5534 -0.5534 0.0261 -0.4375 0.6057 ...
## $ withdraw_amt : num -0.0786 -0.1621 -0.2749 0.3322 -0.2621 ...
## $ withdraw_qty : num 0.123 -0.349 -0.585 0.123 -0.644 ...
## $ withdraw_dgr : num 0.3 -0.258 -0.815 0.3 -0.676 ...
## $ bill_amt : num -0.007237 -0.002772 0.000621 0.005557 0.006142 ...
## $ bill_qty : num -0.326 0.442 1.21 1.21 0.698 ...
## $ bill_dgr : num -0.368 3.549 3.549 6.161 2.244 ...
## $ airtime : num -0.4 0.248 0.567 3.86 0.433 ...
## $ topup : num -0.275 0.692 0.978 -1.333 -0.243 ...
## $ days_no_balance: num -0.398 -1.582 -1.766 -2.108 -1.476 ...
## $ age : num -0.711 -0.323 0.337 -0.408 0.365 ...
## $ genderFEMALE : int 1 1 0 0 0 0 1 1 1 0 ...
## $ genderMALE : int 0 0 1 1 1 1 0 0 0 1 ...
## $ genderOTHER : int 0 0 0 0 0 0 0 0 0 0 ...
## $ defaultPaid : int 1 1 1 1 1 1 1 1 1 1 ...
## $ clusters1 : int 0 0 0 0 0 0 0 0 0 0 ...
## $ clusters2 : int 0 0 0 0 0 0 0 0 0 0 ...
## $ clusters3 : int 0 0 0 0 0 0 0 0 0 0 ...
## $ clusters4 : int 0 0 0 0 0 1 0 0 0 0 ...
## $ clusters5 : int 0 1 1 1 1 0 0 0 0 1 ...
## $ clusters6 : int 0 0 0 0 0 0 0 0 0 0 ...
## $ clusters7 : int 1 0 0 0 0 0 1 1 1 0 ...
## - attr(*, "dummies")=List of 1
## ..$ clusters: int 24 25 26 27 28 29 30
Como se pudo observar anteriormente las variables relacionadas con las interacciones económicas en marco de la plataformas móviles capturan en cierta medida la riqueza y la capacidad de pago de la personas en la economía de una nación, de esta manera aquella porción de la población más pobre si bien no cuenta con activos que puedan ofertar como hipoteca o respaldo a la hora de solicitar un producto financiero, estas cuentan con un historial de transacciones económicas bajo el uso de plataformas móviles de intercambio de dinero y comunicaciones.
En ese orden de ideas, el uso de esta información puede ser de gran ayuda para el diseño de políticas públicas que busquen garantizar el acceso al crédito de aquellas poblaciones más pobres, reduciendo el riesgo que asumen las entidades financieras de perder sus recursos fruto del no pago de los créditos otorgados a este tipo de clientes sin respaldo económico en activos físicos.
Así las cosas, el emprender un programa de acceso al crédito para las poblaciones más pobres podrá permitir a estos hogares superar las barreras sociales que les impiden salir de la su estado de pobreza o incluso pobreza extrema.
Habiendo dicho lo anterior resulta relevante predecir con efectividad cuales de estas personas tienen una mayor probabilidad de pago con base a la información disponible de sus transacciones realizadas mediante el uso de la plataforma dinero móvil controlando por su edad y género, adicionalmente se tienen en cuenta luego de la implementación del algoritmo de k-medias el pertenecer a uno de los clúster asociados con el fin de controlar los modelos por aquellas variables que son comunes entre individuos y no se encuentran disponibles en la base de datos inicial.
Así mismo, se presentaran algunos modelos a ser tenidos en cuenta para la predicción de pago de la población con base en los datos disponibles en la base de datos de la plataforma dinero móvil
base<-base[,-22]
id=sample(1:nrow(dt),size=nrow(dt)*0.7)
train=dt[id,] #Selecciona el 70% de las filas
test=dt[-id,] #Selecciona el 30% restante de filas
names(train)
## [1] "send_amt" "send_qty" "send_dgr"
## [4] "received_amt" "received_qty" "received_dgr"
## [7] "deposit_amt" "deposit_qty" "deposity_dgr"
## [10] "withdraw_amt" "withdraw_qty" "withdraw_dgr"
## [13] "bill_amt" "bill_qty" "bill_dgr"
## [16] "airtime" "topup" "days_no_balance"
## [19] "age" "genderFEMALE" "genderMALE"
## [22] "genderOTHER" "defaultPaid" "clusters1"
## [25] "clusters2" "clusters3" "clusters4"
## [28] "clusters5" "clusters6" "clusters7"
x_train= data.matrix(train[, -23]) # Variables indep de base de entrenamiento.
x_test= data.matrix(test[, -23]) # Variables indep de la base de prueba
y_train = train$defaultPaid # Variable dependiente
y_test = test$defaultPaid # Variable dependiente
id=sample(1:nrow(base),size=nrow(base)*0.7)
trainb=base[id,] #Selecciona el 70% de las filas
testb=base[-id,] #Selecciona el 30% restante de filas
names(trainb)
## [1] "send_amt" "send_qty" "send_dgr"
## [4] "received_amt" "received_qty" "received_dgr"
## [7] "deposit_amt" "deposit_qty" "deposity_dgr"
## [10] "withdraw_amt" "withdraw_qty" "withdraw_dgr"
## [13] "bill_amt" "bill_qty" "bill_dgr"
## [16] "airtime" "topup" "days_no_balance"
## [19] "age" "gender" "default"
Partiendo del modelo mas sencillo a continuacion se estima un modelo minimos cuadrados ponderados. #Ordinary least scuares
lm.fit=lm(y_train~x_train, data=train) #Regresion Simple
step= step(lm.fit, direction="both") # Stepwise
## Start: AIC=-61621.47
## y_train ~ x_train
##
## Df Sum of Sq RSS AIC
## <none> 6008.3 -61621
## - x_train 27 348.63 6356.9 -59701
back= step(lm.fit, direction = "backward", trace=FALSE) # Backward
forw= step(lm.fit, direction="forward", trace=FALSE) #Forward
summary(step)
##
## Call:
## lm(formula = y_train ~ x_train, data = train)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.20480 0.00493 0.18834 0.26898 1.10488
##
## Coefficients: (2 not defined because of singularities)
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.7531270 0.0291442 25.841 < 2e-16 ***
## x_trainsend_amt 0.0162062 0.0062067 2.611 0.009030 **
## x_trainsend_qty 0.0115846 0.0082078 1.411 0.158134
## x_trainsend_dgr 0.0169251 0.0059098 2.864 0.004187 **
## x_trainreceived_amt 0.0049387 0.0058237 0.848 0.396430
## x_trainreceived_qty -0.0565386 0.0058556 -9.656 < 2e-16 ***
## x_trainreceived_dgr 0.0348800 0.0049636 7.027 2.15e-12 ***
## x_traindeposit_amt 0.0003401 0.0050867 0.067 0.946695
## x_traindeposit_qty 0.0018918 0.0048382 0.391 0.695788
## x_traindeposity_dgr -0.0254079 0.0038724 -6.561 5.41e-11 ***
## x_trainwithdraw_amt 0.0077656 0.0046912 1.655 0.097859 .
## x_trainwithdraw_qty 0.0173480 0.0058887 2.946 0.003221 **
## x_trainwithdraw_dgr 0.0539351 0.0049412 10.915 < 2e-16 ***
## x_trainbill_amt 0.0051375 0.0808885 0.064 0.949358
## x_trainbill_qty 0.0094925 0.0033985 2.793 0.005223 **
## x_trainbill_dgr 0.0104923 0.0031862 3.293 0.000992 ***
## x_trainairtime -0.0240480 0.0100846 -2.385 0.017102 *
## x_traintopup -0.0419827 0.0080457 -5.218 1.82e-07 ***
## x_traindays_no_balance -0.0501650 0.0028406 -17.660 < 2e-16 ***
## x_trainage 0.0149660 0.0029820 5.019 5.23e-07 ***
## x_traingenderFEMALE 0.0373395 0.0287633 1.298 0.194240
## x_traingenderMALE -0.0164205 0.0283253 -0.580 0.562113
## x_traingenderOTHER NA NA NA NA
## x_trainclusters1 0.0293019 0.0109905 2.666 0.007677 **
## x_trainclusters2 -0.0035978 0.0097006 -0.371 0.710728
## x_trainclusters3 -0.0181470 0.0114630 -1.583 0.113409
## x_trainclusters4 0.0018604 0.0182419 0.102 0.918770
## x_trainclusters5 0.0364394 0.0111459 3.269 0.001079 **
## x_trainclusters6 -0.0813771 0.0422379 -1.927 0.054033 .
## x_trainclusters7 NA NA NA NA
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.4145 on 34972 degrees of freedom
## Multiple R-squared: 0.05484, Adjusted R-squared: 0.05411
## F-statistic: 75.16 on 27 and 34972 DF, p-value: < 2.2e-16
plm= predict(lm.fit, test)
## Warning: 'newdata' had 15000 rows but variables found have 35000 rows
## Warning in predict.lm(lm.fit, test): prediction from a rank-deficient fit
## may be misleading
plm_step= predict(step, test)
## Warning: 'newdata' had 15000 rows but variables found have 35000 rows
## Warning in predict.lm(step, test): prediction from a rank-deficient fit may
## be misleading
plm_back= predict(back, test)
## Warning: 'newdata' had 15000 rows but variables found have 35000 rows
## Warning in predict.lm(back, test): prediction from a rank-deficient fit may
## be misleading
plm_forw= predict(forw, test)
## Warning: 'newdata' had 15000 rows but variables found have 35000 rows
## Warning in predict.lm(forw, test): prediction from a rank-deficient fit may
## be misleading
Como se puede se puede observar para un nivel de confianza del 95% las variables clúster 6 y 1, edad, tiempo al aire, el pago de facturas, el dinero retirado, enviado y recibido tienen un efecto positivo en la probabilidad de pago de las personas en la economía. Con el fin de reducir la sobre especificación del modelo, a continuación se presentan los modelos de Ridge y Lasso de penalización para identificar las variables más importantes para construir un modelo adecuado de predicción #Ridge
library(glmnet)
## Loading required package: Matrix
## Loading required package: foreach
## Loaded glmnet 2.0-16
grilla=seq(from=0.0001, to=5,length=1000)
set.seed(123)
ridge= cv.glmnet(x_train, y_train, alpha=0, family="gaussian" ,
type.measure = "mse", nfold=5, lambda = grilla)
coef(ridge)
## 30 x 1 sparse Matrix of class "dgCMatrix"
## 1
## (Intercept) 0.7677255236
## send_amt 0.0067697274
## send_qty 0.0052579818
## send_dgr 0.0115970852
## received_amt 0.0004835315
## received_qty -0.0162488223
## received_dgr 0.0068961409
## deposit_amt 0.0031658112
## deposit_qty 0.0027538661
## deposity_dgr -0.0116762885
## withdraw_amt 0.0058063155
## withdraw_qty 0.0148602521
## withdraw_dgr 0.0306752865
## bill_amt 0.0152482381
## bill_qty 0.0064987900
## bill_dgr 0.0115182034
## airtime -0.0197204459
## topup -0.0307443649
## days_no_balance -0.0386394376
## age 0.0139171543
## genderFEMALE 0.0176185874
## genderMALE -0.0171431861
## genderOTHER -0.0051883654
## clusters1 0.0223030761
## clusters2 -0.0218981469
## clusters3 -0.0063064138
## clusters4 0.0066140496
## clusters5 0.0186422549
## clusters6 -0.0291766367
## clusters7 -0.0037529626
ridge$lambda.min # lambda con el minimo error de validación cruzada
## [1] 0.005104905
plot(ridge) # Resultados de la validación
pridge= predict(ridge, newx=x_test, s="lambda.min") #Predecir con el lambda de minimo error
install.packages(“ROCR”)
library(ROCR)
## Loading required package: gplots
##
## Attaching package: 'gplots'
## The following object is masked from 'package:stats':
##
## lowess
set.seed(123)
lasso= cv.glmnet(x_train, y_train, alpha=1, family="gaussian" ,
type.measure = "mse", nfold=5, lambda=grilla)
coef(lasso)
## 30 x 1 sparse Matrix of class "dgCMatrix"
## 1
## (Intercept) 7.900916e-01
## send_amt 1.594543e-02
## send_qty 1.200933e-02
## send_dgr 1.635478e-02
## received_amt 3.856306e-03
## received_qty -5.504031e-02
## received_dgr 3.387924e-02
## deposit_amt 2.694812e-05
## deposit_qty 1.832729e-03
## deposity_dgr -2.523571e-02
## withdraw_amt 8.115575e-03
## withdraw_qty 1.663505e-02
## withdraw_dgr 5.395641e-02
## bill_amt 2.398800e-03
## bill_qty 9.425810e-03
## bill_dgr 1.053563e-02
## airtime -2.229458e-02
## topup -4.306817e-02
## days_no_balance -5.000728e-02
## age 1.498047e-02
## genderFEMALE 1.315084e-04
## genderMALE -5.286332e-02
## genderOTHER -3.418072e-02
## clusters1 2.865279e-02
## clusters2 -4.145922e-03
## clusters3 -1.774200e-02
## clusters4 1.651621e-03
## clusters5 3.571473e-02
## clusters6 -7.751759e-02
## clusters7 .
lasso$lambda.min
## [1] 1e-04
plot(lasso)
plasso= predict(lasso, newx=x_test, s="lambda.min")
classo= glmnet(x_train, y_train, alpha=1)
plot(classo,xvar="lambda",label=TRUE)
predr4 <- prediction(plasso, test$defaultPaid)
perf4 <- performance(predr4, measure = "tpr", x.measure = "fpr")
plot(perf4,col=rainbow(3), main="ROC curve defaultPaid", xlab="Specificity",
ylab="Sensitivity")
abline(0, 1)
Luego de correr los modelo de penalización se encuentra que la variable relacionada con pertenecer al clúster 7 deja de ser importante para predecir la probabilidad de pago. Por otra parte la cantidad de dinero recibido deja de ser una variable positiva sobre la probabilidad de pago.
A continuación se presentan las versiones de los modelos anteriores a manera de un modelo logit con el fin de estimar el mejor modelo posible dados los supuestos sobre la distribución de los modelos binomiales de regresión. #viendo el modelo comoun logit #logit
glm.fit=glm(y_test ~x_test, data=train, family=binomial(link = "logit")) #logit
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
step= step(glm.fit, direction="both") # Stepwise
## Start: AIC=15785.75
## y_test ~ x_test
##
## Df Deviance AIC
## <none> 15730 15786
## - x_test 27 16649 16651
back= step(glm.fit, direction = "backward", trace=FALSE) # Backward
forw= step(glm.fit, direction="forward", trace=FALSE) #Forward
summary(step)
##
## Call:
## glm(formula = y_test ~ x_test, family = binomial(link = "logit"),
## data = train)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -3.0412 0.2390 0.6273 0.7823 2.7037
##
## Coefficients: (2 not defined because of singularities)
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 1.61038 0.35848 4.492 7.05e-06 ***
## x_testsend_amt 0.62044 0.13968 4.442 8.92e-06 ***
## x_testsend_qty -0.14494 0.09458 -1.532 0.125407
## x_testsend_dgr 0.35480 0.08848 4.010 6.07e-05 ***
## x_testreceived_amt -0.21695 0.09595 -2.261 0.023750 *
## x_testreceived_qty -0.30375 0.06878 -4.416 1.01e-05 ***
## x_testreceived_dgr 0.17558 0.05046 3.479 0.000503 ***
## x_testdeposit_amt -0.40780 0.13265 -3.074 0.002111 **
## x_testdeposit_qty 0.19476 0.06094 3.196 0.001395 **
## x_testdeposity_dgr -0.20193 0.03805 -5.307 1.11e-07 ***
## x_testwithdraw_amt 0.25315 0.08576 2.952 0.003160 **
## x_testwithdraw_qty 0.13961 0.06872 2.032 0.042195 *
## x_testwithdraw_dgr 0.34853 0.05125 6.800 1.04e-11 ***
## x_testbill_amt 3.94500 2.29878 1.716 0.086139 .
## x_testbill_qty 0.06631 0.03988 1.663 0.096399 .
## x_testbill_dgr 0.07692 0.03393 2.267 0.023397 *
## x_testairtime -0.20722 0.09657 -2.146 0.031885 *
## x_testtopup -0.16918 0.07460 -2.268 0.023344 *
## x_testdays_no_balance -0.32293 0.02595 -12.444 < 2e-16 ***
## x_testage 0.10767 0.02780 3.873 0.000107 ***
## x_testgenderFEMALE -0.06782 0.35725 -0.190 0.849425
## x_testgenderMALE -0.32454 0.35355 -0.918 0.358655
## x_testgenderOTHER NA NA NA NA
## x_testclusters1 0.03716 0.10375 0.358 0.720209
## x_testclusters2 -0.03149 0.08818 -0.357 0.720973
## x_testclusters3 -0.42117 0.10908 -3.861 0.000113 ***
## x_testclusters4 -0.40064 0.18269 -2.193 0.028311 *
## x_testclusters5 -0.05745 0.10315 -0.557 0.577581
## x_testclusters6 -0.95530 0.48849 -1.956 0.050511 .
## x_testclusters7 NA NA NA NA
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 16649 on 14999 degrees of freedom
## Residual deviance: 15730 on 14972 degrees of freedom
## AIC: 15786
##
## Number of Fisher Scoring iterations: 10
plmlog= predict(glm.fit, test)
## Warning in predict.lm(object, newdata, se.fit, scale = 1, type =
## ifelse(type == : prediction from a rank-deficient fit may be misleading
plm_steplog= predict(step, test)
## Warning in predict.lm(object, newdata, se.fit, scale = 1, type =
## ifelse(type == : prediction from a rank-deficient fit may be misleading
plm_backlog= predict(back, test)
## Warning in predict.lm(object, newdata, se.fit, scale = 1, type =
## ifelse(type == : prediction from a rank-deficient fit may be misleading
plm_forwlog= predict(forw, test)
## Warning in predict.lm(object, newdata, se.fit, scale = 1, type =
## ifelse(type == : prediction from a rank-deficient fit may be misleading
library("ROCR")
predr3 <- prediction(plmlog, test$defaultPaid)
perf3 <- performance(predr3, measure = "tpr", x.measure = "fpr")
plot(perf3, col=rainbow(7), main="ROC curve defaultPaid", xlab="Specificity",
ylab="Sensitivity")
abline(0, 1)
Así mismo, como en el modelo de regresión lineal las variables relacionadas con el envío, la recepción y la conversión de dinero vía plataforma movil, y aquellas variables relacionadas con el pago de facturas, tiempo al aire, días de mora y edad; son estadísticamente significativas para un nivel de confianza del 95% para explicar las variaciones en la probabilidad de pagar un credito.
Con el fin de reducir el problema de sobrespecificación del modelo se corren a continuación las versiones de lasso y ridge para un modelo logit. #ridege logit
library(glmnet)
set.seed(123)
grilla=seq(from=0.0001, to=10,length=1000)
set.seed(123)
ridgelog= cv.glmnet(x_train, y_train, alpha=0, family="binomial" ,
type.measure = "auc", nfold=3, lambda = grilla)
coef(ridgelog) # Coeficientes
## 30 x 1 sparse Matrix of class "dgCMatrix"
## 1
## (Intercept) 1.274825894
## send_amt 0.056232875
## send_qty 0.041434941
## send_dgr 0.142582453
## received_amt -0.015796600
## received_qty -0.168829976
## received_dgr 0.069173508
## deposit_amt 0.024546715
## deposit_qty 0.038791008
## deposity_dgr -0.122344821
## withdraw_amt 0.075028399
## withdraw_qty 0.101811342
## withdraw_dgr 0.244711168
## bill_amt 0.306408832
## bill_qty 0.052023450
## bill_dgr 0.086225502
## airtime -0.142153343
## topup -0.187502079
## days_no_balance -0.251268301
## age 0.089230633
## genderFEMALE 0.127295614
## genderMALE -0.124668291
## genderOTHER 0.006525196
## clusters1 0.139848857
## clusters2 -0.068655539
## clusters3 -0.112829535
## clusters4 -0.004857019
## clusters5 0.125014306
## clusters6 -0.234695675
## clusters7 -0.041575453
ridgelog$lambda.min # lambda con el minimo error de validación cruzada
## [1] 1e-04
plot(ridgelog) # Resultados de la validación
pridgelog= predict(ridgelog, newx=x_test, s="lambda.min")
library("ROCR")
predr2 <- prediction(pridgelog, test$defaultPaid)
perf2 <- performance(predr2, measure = "tpr", x.measure = "fpr")
plot(perf2, col=rainbow(7), main="ROC curve defaultPaid", xlab="Specificity",
ylab="Sensitivity")
abline(0, 1)
#Lasso Logit
install.packages("weatherData",repos = "http://cran.us.r-project.org")
## Installing package into 'C:/Users/anroj/Documents/R/win-library/3.5'
## (as 'lib' is unspecified)
## Warning: package 'weatherData' is not available (for R version 3.5.1)
options(repos="https://cran.rstudio.com" )
lassolog= cv.glmnet(x_train, y_train, alpha=1, family="binomial",
type.measure = "auc", nfold=3, lambda=grilla)
coef(lassolog)
## 30 x 1 sparse Matrix of class "dgCMatrix"
## 1
## (Intercept) 1.24219385
## send_amt 0.13543492
## send_qty .
## send_dgr 0.31908751
## received_amt -0.03055818
## received_qty -0.38323369
## received_dgr 0.19459310
## deposit_amt -0.01495177
## deposit_qty 0.07079716
## deposity_dgr -0.20635734
## withdraw_amt 0.12763235
## withdraw_qty 0.12361649
## withdraw_dgr 0.34539179
## bill_amt 0.34815100
## bill_qty 0.06689925
## bill_dgr 0.08252905
## airtime -0.22585594
## topup -0.17262281
## days_no_balance -0.28841083
## age 0.09484132
## genderFEMALE 0.24653296
## genderMALE -0.09818810
## genderOTHER 0.08078784
## clusters1 0.15773281
## clusters2 .
## clusters3 -0.20430058
## clusters4 -0.08963106
## clusters5 0.15032017
## clusters6 -0.49051163
## clusters7 -0.04868583
lassolog$lambda.min
## [1] 1e-04
plot(lassolog)
plassolog= predict(lassolog, newx=x_test, s="lambda.min")
classolog= glmnet(x_train, y_train, alpha=1)
plot(classolog,xvar="lambda",label=TRUE)
install.packages("RocR")
## Installing package into 'C:/Users/anroj/Documents/R/win-library/3.5'
## (as 'lib' is unspecified)
## Warning: package 'RocR' is not available (for R version 3.5.1)
## Warning: Perhaps you meant 'ROCR' ?
library("ROCR")
predr <- prediction(plassolog, test$defaultPaid)
perf <- performance(predr, measure = "tpr", x.measure = "fpr")
plot(perf, col=rainbow(7), main="ROC curve defaultPaid", xlab="Specificity",
ylab="Sensitivity")
abline(0, 1)
Como se pudo ver en las curvas ROC estimadas en el apartado anterior la capacidad del modelo sigue siendo aún muy limitada, es por esta razón que a continuación se presenta el modelo desde el punto de vista de un Árbol de Calificación.
install.packages(c(“rpart”, “rpart.plot”, “MASS”, “randomForest”, “tree”))
library(rpart.plot) #Gráficos
## Loading required package: rpart
set.seed(123)
tree <- rpart(y_train ~ x_train, data = train, method="class", control=rpart.control(xval=10, cp=1e-04))
printcp(tree) # Resultado de CV
##
## Classification tree:
## rpart(formula = y_train ~ x_train, data = train, method = "class",
## control = rpart.control(xval = 10, cp = 1e-04))
##
## Variables actually used in tree construction:
## [1] x_trainage x_trainairtime x_trainbill_amt
## [4] x_trainbill_dgr x_trainbill_qty x_trainclusters1
## [7] x_trainclusters2 x_trainclusters5 x_traindays_no_balance
## [10] x_traindeposit_amt x_traindeposit_qty x_traindeposity_dgr
## [13] x_traingenderFEMALE x_traingenderMALE x_trainreceived_amt
## [16] x_trainreceived_dgr x_trainreceived_qty x_trainsend_amt
## [19] x_trainsend_dgr x_trainsend_qty x_traintopup
## [22] x_trainwithdraw_amt x_trainwithdraw_dgr x_trainwithdraw_qty
##
## Root node error: 8348/35000 = 0.23851
##
## n= 35000
##
## CP nsplit rel error xerror xstd
## 1 0.00862482 0 1.00000 1.00000 0.0095508
## 2 0.00722728 3 0.97413 0.97892 0.0094807
## 3 0.00263536 6 0.95244 0.96287 0.0094261
## 4 0.00203642 7 0.94981 0.96095 0.0094195
## 5 0.00199649 11 0.94166 0.96011 0.0094167
## 6 0.00167705 14 0.93567 0.95927 0.0094138
## 7 0.00155726 16 0.93232 0.95580 0.0094017
## 8 0.00137758 17 0.93076 0.95556 0.0094009
## 9 0.00131768 19 0.92801 0.95424 0.0093963
## 10 0.00099824 20 0.92669 0.95340 0.0093934
## 11 0.00095831 23 0.92369 0.95161 0.0093872
## 12 0.00083852 31 0.91507 0.95256 0.0093905
## 13 0.00077863 38 0.90896 0.95496 0.0093988
## 14 0.00075866 42 0.90585 0.95424 0.0093963
## 15 0.00071874 45 0.90357 0.95604 0.0094026
## 16 0.00065884 51 0.89914 0.95747 0.0094076
## 17 0.00062889 53 0.89782 0.95999 0.0094162
## 18 0.00062290 57 0.89530 0.95987 0.0094158
## 19 0.00059895 62 0.89219 0.95999 0.0094162
## 20 0.00056900 76 0.88321 0.95963 0.0094150
## 21 0.00055902 81 0.87949 0.95879 0.0094121
## 22 0.00053905 84 0.87782 0.95855 0.0094113
## 23 0.00049912 92 0.87350 0.96011 0.0094167
## 24 0.00047916 99 0.86991 0.96059 0.0094183
## 25 0.00043923 117 0.86104 0.96334 0.0094278
## 26 0.00041926 152 0.84104 0.96682 0.0094397
## 27 0.00039930 175 0.82966 0.97017 0.0094511
## 28 0.00038931 181 0.82726 0.97664 0.0094731
## 29 0.00035937 190 0.82355 0.97832 0.0094787
## 30 0.00031944 232 0.80834 0.98347 0.0094960
## 31 0.00029947 247 0.80247 1.00084 0.0095535
## 32 0.00028749 318 0.77659 1.00419 0.0095645
## 33 0.00027951 328 0.77300 1.01198 0.0095898
## 34 0.00026953 387 0.75180 1.01390 0.0095960
## 35 0.00023958 391 0.75072 1.03234 0.0096547
## 36 0.00020963 486 0.72544 1.03965 0.0096776
## 37 0.00019965 500 0.72149 1.05247 0.0097173
## 38 0.00019166 530 0.71394 1.07379 0.0097819
## 39 0.00017968 558 0.70664 1.07822 0.0097951
## 40 0.00015972 634 0.68675 1.09104 0.0098328
## 41 0.00015573 674 0.67897 1.10529 0.0098741
## 42 0.00014974 691 0.67549 1.10697 0.0098789
## 43 0.00014375 719 0.67058 1.11021 0.0098881
## 44 0.00013975 747 0.66447 1.11272 0.0098953
## 45 0.00013690 759 0.66279 1.11272 0.0098953
## 46 0.00011979 792 0.65632 1.14974 0.0099979
## 47 0.00010268 994 0.62482 1.15549 0.0100134
## 48 0.00010000 1001 0.62410 1.15932 0.0100236
prp(tree) # Gráfico 2
## Warning: labs do not fit even at cex 0.15, there may be some overplotting
Así las cosas este primer árbol resulta muy profundo y difícil de leer por lo que a continuación se podan las ramas del árbol que están de más con base en el número de nodos óptimos para hacer del árbol el mejor modelo de predicción posible.
bestcp=tree$cptable[which.min(tree$cptable[,"xerror"]),"CP"]
set.seed(123)
ptree<- prune(tree,cp= bestcp)
prp(ptree)
Como se observa en el árbol presentado anteriormente, solo por dar un ejemplo, aquellas personas que han cambiado menos de -0.75 desviaciones estándar de dinero móvil a dinero real, que han pasado más de -0.36 desviaciones de días sin pagar, que no han recibido más de -0.36 desviaciones estándar de dinero vía mobil money y que han cambiado más de -0.33 desviaciones estándar de dinero movil a dinero físico pagan su crédito.
predtree <- predict(ptree, test, type = "class")
## Warning: 'newdata' had 15000 rows but variables found have 35000 rows
con el fin de afinar el poder predictivo de la maquina de aprendizaje se procede a la adecuación del modelo al algoritmo de bosques aleatorios que por causa de la carga computacional que requiere la implementación del algoritmo, se seleciona un universo de 100 arboles de clasificación.
library(randomForest)
## randomForest 4.6-14
## Type rfNews() to see new features/changes/bug fixes.
##
## Attaching package: 'randomForest'
## The following object is masked from 'package:ggplot2':
##
## margin
# Default m: sqrt(p):mtry, ntree= número de árboles para construir
fitrf = randomForest(trainb$default ~.,
data=train,
importance=TRUE, ntree=100)
fitrf$ntree
## [1] 100
varImpPlot(fitrf, type=2)
# Error cv
plot(fitrf)
pred_rf=predict(fitrf, test, type = "class")
CM = table( testb$default, pred_rf)
CM
## pred_rf
## Default Paid
## Default 24 3511
## Paid 100 11365
Como se pudo observar en la gráfica de barras estimada a manera de ranking de importancia para predecir la capacidad de pago de las personas en la economía las variables de la edad, cantidad de dinero recibido vía plataforma dinero móvil, la cantidad de dinero convertido de dinero móvil a dinero físico, la cantidad de dinero depositado en plataformas móvil, el tiempo que tiene las personas al aire en la plataforma mobil money, la cantidad de dinero enviado por este tipo de plataformas y los días en mora son aquellas variables de mayor peso a ser tenidas en cuenta a la hora de predecir la capacidad de pago de un individuo en la economía.
Finalmente, se presenta un modelo bosting siendo este el mejor modelo predictor de capacidad de pago por parte de los agentes en la economía a partir de la información disponible en la base de datos de la plataforma dinero móvil.
install.packages(c(“gbm”, “ggplot2”,“survival”, “prodlim”))
library(survival)
##
## Attaching package: 'survival'
## The following object is masked from 'package:rpart':
##
## solder
library(gbm)
## Loading required package: lattice
## Loading required package: splines
## Loading required package: parallel
## Loaded gbm 2.1.3
gbmf=gbm(defaultPaid~.,data=train,distribution="bernoulli",n.trees=100,interaction.depth=10, cv.folds = 10)
print(gbmf)
## gbm(formula = defaultPaid ~ ., distribution = "bernoulli", data = train,
## n.trees = 100, interaction.depth = 10, cv.folds = 10)
## A gradient boosted model with bernoulli loss function.
## 100 iterations were performed.
## The best cross-validation iteration was 100.
## There were 29 predictors of which 19 had non-zero influence.
summary(gbmf)
mejor = gbm.perf(gbmf, method="cv")
gbmf=gbm(defaultPaid~.,data=train,distribution="bernoulli",n.trees=mejor,interaction.depth=10)
summary(gbmf)
importancia_pred <- summary(gbmf, plotit = FALSE, n.trees=mejor)
ggplot(data = importancia_pred, aes(x = reorder(var, rel.inf), y = rel.inf,
fill = rel.inf)) +
labs(x = "variable", title = "Reducción de MSE") +
geom_col() +
coord_flip() +
theme_bw() +
theme(legend.position = "bottom")
predict<-predict(gbmf,newdata=test,n.trees=100)
mean((predict-test$defaultPaid)^2)
## [1] 0.3370699
Luego de haber corrido el modelo mediante el algoritmo de boosting, se consolida un modelo de predicción con un 33% de error, mejor que los modelos anteriores que terminan por predecir con un error del 44%. Finalmente, dentro de las variables más importantes a ser tenidas en cuenta para la predicción de la capacidad de pago de los agentes en la economía se encontró que la variable más importante es el cambio de dinero de la plataforma móvil a dinero físico, seguido por los días en mora que presentan los individuos en sus deudas el topup y la cantidad de dinero recibido mediante la plataforma móvil.
Por otra parte, en lo que respecta al diseño de una política pública que busque garantizar el acceso de al crédito de la poblaciones más pobres de la economía, resulta útil el uso de este modelo predictivo con el fin de aumentar la cantidad de personas que a pesar de no tener algún activo que de soporte a la deuda adquirida con el banco, estos tengan la capacidad de pago de las mismas, así de esta manera conseguir la reducción de las barreras sociales que impiden la superación de la pobreza en los países menos desarrollados.
Si bien los modelos presentados al inicio del ejercicio presentan estimaciones más consistentes su varianza es muy amplia lo cual termina perjudicando la capacidad de predicción de estos modelos, los modelos de bosques aleatorios y boosting resuelven el problema de predicción reduciendo la varianza de las estimaciones asumiendo un costo en término de sesgo estos resultaran más útiles a la hora de predecir el comportamiento de los individuos sujetos a un programa o una intervención de política pública.
Para el caso puntual del ejercicio resulta clara la necesidad de minimizar el riesgo que puede asumir una banca de desarrollo al afrontarse a la decisión de brindar crédito a los menos favorecidos dada la incertidumbre y el no sustento de la deuda que hacen ver los individuos beneficiarios del programa de crédito