A continuacion presentamos el codigo para la construcción de un modelo de regresión logística binaria, arbol de decisiones y XGboost con y sin ponderación por clase, para predecir el riesgo de incumplimiento crediticio. Este análisis se basa en una base de datos previamente depurada y preparada, con un enfoque en la evaluación comparativa de ambos enfoques.

Librerias

Se cargan las librerías necesarias para la manipulación de datos, modelado y evaluación de modelos. Se establece una semilla para garantizar la reproducibilidad de los resultados.

library(tidyverse)   # Manipulación y visualización de datos
library(caret)       # Partición, preprocesamiento y métricas
library(readxl)      # Lectura de archivos Excel
library(pROC)        # Curvas ROC y AUC
library(rpart)       # Árbol de decisión
library(rpart.plot)  # Visualización del árbol
library(xgboost)     # Gradient Boosting

set.seed(2930)        # Semilla para reproducibilidad

Preparación y depuración de la base de datos

Carga y limpieza de la información

En esta etapa se realizó el carge de la base de datos desde un archivo en formato Excel. Posteriormente, se llevó a cabo un proceso de depuración orientado a eliminar variables de carácter administrativo o de identificacion, las cuales no aportan valor explicativo al modelo y podrían introducir ruido en la estimación.

Adicionalmente, todas las variables de tipo carácter fueron transformadas a formato categórico (factor), con el fin de ser correctamente interpretadas dentro de los modelos.

df <- read_excel("C:/JOHAN SEBASTIAN/MAESTRIA - CIENCIA DE DATOS/TERCER SEMESTRE/PROYECTO APLICADO III/df_limpio.xlsx")  # Carga base de datos desde Excel

df <- df %>%
  dplyr::select(
    -numero_banco, -fecha_prox_ven, -tipo_cartera,
    -fecha_inicio_op, -fecha_ven_op, -tipo_identificacion,
    -mo_nombre_cliente, -id
  ) %>%  # Elimina variables irrelevantes o identificadores
  mutate(across(where(is.character), as.factor))  # Convierte texto a factores

print(df)
## # A tibble: 55,454 × 34
##    zonal  nombre_oficina   Longitud Latitud dias_vencido rango             saldo
##    <fct>  <fct>               <dbl>   <dbl>        <dbl> <fct>             <dbl>
##  1 Nariño CHACHAGUI           -77.3    1.36            0 0 días          1.24 e7
##  2 Cauca  POPAYAN SUCURSAL    -76.6    2.46          107 Mayor a 90 días 1.18 e7
##  3 Cauca  PURACE              -76.5    2.34            0 0 días          2.40 e6
##  4 Nariño RICAURTE            -78.0    1.21            0 0 días          1.000e6
##  5 Nariño PASTO SUCURSAL      -77.3    1.21            0 0 días          1.07 e6
##  6 Cauca  BALBOA (CAUCA)      -77.2    2.04            0 0 días          5.09 e6
##  7 Cauca  SUAREZ (CAUCA)      -76.7    2.96            0 0 días          2.17 e6
##  8 Cauca  POPAYAN SUCURSAL    -76.6    2.46            0 0 días          6    e6
##  9 Cauca  POPAYAN SUCURSAL    -76.6    2.46            0 0 días          1.84 e7
## 10 Cauca  CAJIBIO             -76.6    2.62            0 0 días          3.57 e5
## # ℹ 55,444 more rows
## # ℹ 27 more variables: Banca_cliente <fct>, genero <fct>,
## #   ciudad_inversion <fct>, Departamento_Inversion <fct>, longitud_inver <fct>,
## #   latitud_inver <dbl>, monto_desembolso <dbl>, calificacion_obligacion <fct>,
## #   mo_modalidad <fct>, valor_vencido <dbl>, saldo_cuota_prox_venc <dbl>,
## #   etapa <fct>, estado_obligacion <fct>, cuotas_pagadas <dbl>,
## #   cuotas_pactadas <dbl>, cero_cuotas_pagadas <fct>, reestructurada <fct>, …

Recodificación de variables categóricas

Dado el alto número de categorías en algunas variables, se implementaron técnicas de recodificación para reducir la dimensionalidad y evitar problemas de sobreajuste.

Factor externo

# Reducimos cardinalidad de variables con muchos niveles, agrupando los menos frecuentes en "Otros"
df$`Tipo Factor Externo` <- fct_collapse(
  df$`Tipo Factor Externo`,
  Económico = c("Económico", "Orden Público"),
  Sequía    = c("Sequía", "Sequía y Heladas")
)

table(df$`Tipo Factor Externo`)
## 
##                   Económico Factores Naturales - Volcán 
##                       15088                         195 
##                Ola Invernal                      Sequía 
##                       39729                         442

Hecho victimizante

# Reducimos cardinalidad de variables con muchos niveles, agrupando los menos frecuentes en "Otros"
df$hecho_victimizante <- fct_lump_min(df$hecho_victimizante, min = 30)

table(df$`Tipo Factor Externo`)
## 
##                   Económico Factores Naturales - Volcán 
##                       15088                         195 
##                Ola Invernal                      Sequía 
##                       39729                         442

Tipo de producto

# Reducimos cardinalidad de variables con muchos niveles, agrupando los menos frecuentes en "Otros"

df$tipo_de_producto       <- fct_lump_min(df$tipo_de_producto, 50)
table(df$tipo_de_producto)
## 
##  CAP TRABAJO  MICROCREDITO MULTIDESTINO       CAP TRABAJO MUJER MICROEMPRESARIA 
##                                      81                                     364 
##      CAP. TRABAJO PROYECTO MICROCREDITO    CAPITAL DE TRABAJO ORDINARIA FINAGRO 
##                                      65                                    2626 
##   INV. VICTIMA CONFLICTO ARMADO INTERNO INVERSION - COMP. ANIM.Y RETEN.VIENTRES 
##                                    1702                                      90 
##  INVERSION - PLANTACION Y MANTENIMIENTO         INVERSION MUJER MICROEMPRESARIA 
##                                    2682                                     327 
##              INVERSIÓN MULTIDESTINO IBR            INVERSION MULTIDESTINO MICRO 
##                                     105                                     109 
##             INVERSION ORDINARIA FINAGRO         INVERSIÓN PROYECTO MICROCREDITO 
##                                   46859                                      77 
##        MICROCREDITO ECONOMIA POPULAR RP   NORMALIZACION DE RECURSOS FINAGRO IBR 
##                                     125                                      65 
##                                   Other 
##                                     177

Departamento de inversion

# Reducimos cardinalidad de variables con muchos niveles, agrupando los menos frecuentes en "Otros"
df$Departamento_Inversion <- fct_lump_min(df$Departamento_Inversion, 30)
table(df$Departamento_Inversion)
## 
##           Cauca          Nariño Valle del cauca Valle del Cauca           Other 
##           25524           27662            2172              35              61

Tasa de referencia bancaria

# Reducimos cardinalidad de variables con muchos niveles, agrupando los menos frecuentes en "Otros"
df$tasa_referencial       <- fct_lump_min(df$tasa_referencial, 30)
table(df$tasa_referencial)
## 
##    INDICADOR BANCARIO DE REFERENCIA MENSUAL 
##                                         251 
##  INDICADOR BANCARIO DE REFERENCIA SEMESTRAL 
##                                       44703 
## INDICADOR BANCARIO DE REFERENCIA TRIMESTRAL 
##                                        1722 
##                                   TASA Cero 
##                                        1151 
##                     Tasa DTF Efectivo Anual 
##                                        7612 
##                                       Other 
##                                          15

Selección de variables predictoras

Se definió un conjunto de variables explicativas basado en criterios teóricos como PCA, MCA y Factor Analysis of Mixed Data (FAMD), y empíricos relevantes para el análisis del riesgo crediticio

var_sele <- c(
  "tipo_de_producto", "tasa_referencial", "tipo_productor_pmg",
  "destino_agrupado", "Banca_cliente", "mo_modalidad",
  "Departamento_Inversion",
  "cuotas_pactadas", "Tipo Factor Externo",
  "monto_desembolso", "saldo",
  "COMPARATIVO_OCURRENCIA_HECHO",
  "genero", "hecho_victimizante",
  "rango", "dias_vencido"
)

df_modelo <- df[, var_sele]

Construcción de la variable objetivo de estudio

Se construyó una variable dependiente binaria denominada target_binario, donde:

“Al Día”: créditos sin mora (0 días) “En Mora”: créditos con algún nivel de incumplimiento

Esta transformación permite modelar el problema como una clasificación binaria, donde el interés principal es identificar el riesgo de incumplimiento.

Análisis de desbalance

# Verificar distribución del target (detectar desbalance)
cat("Distribución target_binario:\n")
## Distribución target_binario:
print(table(df_modelo$target_binario))
## 
##  Al Día En Mora 
##   48263    7191
cat("Proporción:\n")
## Proporción:
print(prop.table(table(df_modelo$target_binario)))
## 
##   Al Día  En Mora 
## 0.870325 0.129675

Partición y preprocesamiento de datos

Se dividió la base de datos en:

  • 70% para entrenamiento
  • 30% para validación
# createDataPartition garantiza proporciones similares en train y test
train_idx <- createDataPartition(df_modelo$target_binario, p = 0.7, list = FALSE)
train_bin <- df_modelo[train_idx, ] # Datos de entrenamiento (70%)
test_bin  <- df_modelo[-train_idx, ] # Datos de validación (30%)

cat("\nTamaño train:", nrow(train_bin), "| test:", nrow(test_bin), "\n")
## 
## Tamaño train: 38819 | test: 16635

Escalado de variables numéricas

Las variables numéricas relevantes fueron estandarizadas (media cero y varianza uno) utilizando únicamente los datos de entrenamiento, evitando así problemas de data leakage.

# Seleccionamos las variables numericas para escalado 
vars_num <- c("cuotas_pactadas", "monto_desembolso", "saldo")

# Creamos objeto preProcess con parámetros de escalado basados solo en train
preproc_bin <- preProcess(train_bin[, vars_num], method = c("center", "scale"))

# Aplicamos la transformación a train y test usando el mismo preproc
train_bin[, vars_num] <- predict(preproc_bin, train_bin[, vars_num])
test_bin[, vars_num]  <- predict(preproc_bin, test_bin[, vars_num])

# Renombrar variable con espacios
train_bin <- train_bin %>% rename(Tipo_Factor_Externo = `Tipo Factor Externo`)
test_bin  <- test_bin  %>% rename(Tipo_Factor_Externo = `Tipo Factor Externo`)

Modelo Logit sin ponderación (modelo base)

Especificación del modelo logístico sin pesos,

Este modelo se realiza utilizando todas las variables seleccionadas como predictores, Ademas servirá como referencia para evaluar el impacto de la ponderación en el siguiente paso.

cat("\n====== MODELO LOGIT SIN PESOS ======\n")
## 
## ====== MODELO LOGIT SIN PESOS ======
model_logit <- glm(
  target_binario ~ tipo_de_producto + tasa_referencial + tipo_productor_pmg +
    destino_agrupado + Banca_cliente + mo_modalidad +
    Tipo_Factor_Externo + factor(Departamento_Inversion) + genero +
    cuotas_pactadas + monto_desembolso + saldo +          
    COMPARATIVO_OCURRENCIA_HECHO,          
  data   = train_bin,
  family = binomial(link = "logit")
)

print(summary(model_logit))
## 
## Call:
## glm(formula = target_binario ~ tipo_de_producto + tasa_referencial + 
##     tipo_productor_pmg + destino_agrupado + Banca_cliente + mo_modalidad + 
##     Tipo_Factor_Externo + factor(Departamento_Inversion) + genero + 
##     cuotas_pactadas + monto_desembolso + saldo + COMPARATIVO_OCURRENCIA_HECHO, 
##     family = binomial(link = "logit"), data = train_bin)
## 
## Coefficients:
##                                                                 Estimate
## (Intercept)                                                    -12.47184
## tipo_de_productoCAP TRABAJO MUJER MICROEMPRESARIA               -0.77832
## tipo_de_productoCAP. TRABAJO PROYECTO MICROCREDITO               0.29182
## tipo_de_productoCAPITAL DE TRABAJO ORDINARIA FINAGRO             2.64366
## tipo_de_productoINV. VICTIMA CONFLICTO ARMADO INTERNO            3.43007
## tipo_de_productoINVERSION - COMP. ANIM.Y RETEN.VIENTRES          4.73300
## tipo_de_productoINVERSION - PLANTACION Y MANTENIMIENTO           3.90782
## tipo_de_productoINVERSION MUJER MICROEMPRESARIA                 -0.83688
## tipo_de_productoINVERSIÓN MULTIDESTINO IBR                       1.42929
## tipo_de_productoINVERSION MULTIDESTINO MICRO                    -0.42110
## tipo_de_productoINVERSION ORDINARIA FINAGRO                      3.57661
## tipo_de_productoINVERSIÓN PROYECTO MICROCREDITO                 -0.32129
## tipo_de_productoMICROCREDITO ECONOMIA POPULAR RP                -0.98645
## tipo_de_productoNORMALIZACION DE RECURSOS FINAGRO IBR            4.40109
## tipo_de_productoOther                                            2.53346
## tasa_referencialINDICADOR BANCARIO DE REFERENCIA SEMESTRAL      -4.28604
## tasa_referencialINDICADOR BANCARIO DE REFERENCIA TRIMESTRAL     -4.38210
## tasa_referencialTASA Cero                                       -0.05297
## tasa_referencialTasa DTF Efectivo Anual                         -3.73369
## tasa_referencialOther                                            2.60602
## tipo_productor_pmgGran Productor Finagro                         2.00461
## tipo_productor_pmgMediano Productor                             11.21681
## tipo_productor_pmgMicrofinanzas                                 11.97727
## tipo_productor_pmgNo Agropecuario                               10.93068
## tipo_productor_pmgPequeño Productor                             11.92805
## destino_agrupadoAgricultura - cultivos                          -1.42156
## destino_agrupadoComercializacion - transformacion agropecuaria  -2.12417
## destino_agrupadoFinancieros - capital de trabajo                -0.94813
## destino_agrupadoInfraestructura - equipamiento                  -1.93578
## destino_agrupadoPecuaria - pesca                                -1.35750
## destino_agrupadoServicio - apoyo agropecuario                   -1.53022
## Banca_clienteMICROFINANZAS                                       0.08470
## Banca_clientePERSONAL                                           -0.24445
## mo_modalidadMV                                                   0.84004
## mo_modalidadSV                                                   0.46197
## mo_modalidadTV                                                   1.72290
## Tipo_Factor_ExternoFactores Naturales - Volcán                   0.28545
## Tipo_Factor_ExternoOla Invernal                                  0.54353
## Tipo_Factor_ExternoSequía                                        0.15357
## factor(Departamento_Inversion)Nariño                            -0.33957
## factor(Departamento_Inversion)Valle del cauca                    0.33930
## factor(Departamento_Inversion)Valle del Cauca                   -0.39874
## factor(Departamento_Inversion)Other                             -0.46994
## generoMASCULINO                                                  0.11085
## cuotas_pactadas                                                 -0.55295
## monto_desembolso                                                -0.50926
## saldo                                                            0.54665
## COMPARATIVO_OCURRENCIA_HECHONo reporta                          -0.31539
## COMPARATIVO_OCURRENCIA_HECHOV-D                                 -0.01765
##                                                                Std. Error
## (Intercept)                                                     107.68920
## tipo_de_productoCAP TRABAJO MUJER MICROEMPRESARIA                 0.46667
## tipo_de_productoCAP. TRABAJO PROYECTO MICROCREDITO                0.56749
## tipo_de_productoCAPITAL DE TRABAJO ORDINARIA FINAGRO              1.35321
## tipo_de_productoINV. VICTIMA CONFLICTO ARMADO INTERNO             1.36858
## tipo_de_productoINVERSION - COMP. ANIM.Y RETEN.VIENTRES           1.40845
## tipo_de_productoINVERSION - PLANTACION Y MANTENIMIENTO            1.36787
## tipo_de_productoINVERSION MUJER MICROEMPRESARIA                   0.47953
## tipo_de_productoINVERSIÓN MULTIDESTINO IBR                        1.26220
## tipo_de_productoINVERSION MULTIDESTINO MICRO                      0.54916
## tipo_de_productoINVERSION ORDINARIA FINAGRO                       1.36599
## tipo_de_productoINVERSIÓN PROYECTO MICROCREDITO                   0.60528
## tipo_de_productoMICROCREDITO ECONOMIA POPULAR RP                  0.55929
## tipo_de_productoNORMALIZACION DE RECURSOS FINAGRO IBR             1.40349
## tipo_de_productoOther                                             1.32583
## tasa_referencialINDICADOR BANCARIO DE REFERENCIA SEMESTRAL        0.39971
## tasa_referencialINDICADOR BANCARIO DE REFERENCIA TRIMESTRAL       0.89431
## tasa_referencialTASA Cero                                         1.20222
## tasa_referencialTasa DTF Efectivo Anual                           0.41257
## tasa_referencialOther                                             1.05428
## tipo_productor_pmgGran Productor Finagro                        342.13131
## tipo_productor_pmgMediano Productor                             107.67884
## tipo_productor_pmgMicrofinanzas                                 107.67966
## tipo_productor_pmgNo Agropecuario                               107.68042
## tipo_productor_pmgPequeño Productor                             107.67860
## destino_agrupadoAgricultura - cultivos                            0.92497
## destino_agrupadoComercializacion - transformacion agropecuaria    1.01848
## destino_agrupadoFinancieros - capital de trabajo                  0.91037
## destino_agrupadoInfraestructura - equipamiento                    0.95354
## destino_agrupadoPecuaria - pesca                                  0.92645
## destino_agrupadoServicio - apoyo agropecuario                     0.92871
## Banca_clienteMICROFINANZAS                                        0.26858
## Banca_clientePERSONAL                                             0.43573
## mo_modalidadMV                                                    0.26166
## mo_modalidadSV                                                    0.13902
## mo_modalidadTV                                                    0.82170
## Tipo_Factor_ExternoFactores Naturales - Volcán                    0.27500
## Tipo_Factor_ExternoOla Invernal                                   0.07884
## Tipo_Factor_ExternoSequía                                         0.20750
## factor(Departamento_Inversion)Nariño                              0.03747
## factor(Departamento_Inversion)Valle del cauca                     0.06837
## factor(Departamento_Inversion)Valle del Cauca                     0.61247
## factor(Departamento_Inversion)Other                               0.61229
## generoMASCULINO                                                   0.03145
## cuotas_pactadas                                                   0.03085
## monto_desembolso                                                  0.05196
## saldo                                                             0.04158
## COMPARATIVO_OCURRENCIA_HECHONo reporta                            0.10746
## COMPARATIVO_OCURRENCIA_HECHOV-D                                   0.10798
##                                                                z value Pr(>|z|)
## (Intercept)                                                     -0.116 0.907801
## tipo_de_productoCAP TRABAJO MUJER MICROEMPRESARIA               -1.668 0.095354
## tipo_de_productoCAP. TRABAJO PROYECTO MICROCREDITO               0.514 0.607098
## tipo_de_productoCAPITAL DE TRABAJO ORDINARIA FINAGRO             1.954 0.050745
## tipo_de_productoINV. VICTIMA CONFLICTO ARMADO INTERNO            2.506 0.012200
## tipo_de_productoINVERSION - COMP. ANIM.Y RETEN.VIENTRES          3.360 0.000778
## tipo_de_productoINVERSION - PLANTACION Y MANTENIMIENTO           2.857 0.004279
## tipo_de_productoINVERSION MUJER MICROEMPRESARIA                 -1.745 0.080951
## tipo_de_productoINVERSIÓN MULTIDESTINO IBR                       1.132 0.257475
## tipo_de_productoINVERSION MULTIDESTINO MICRO                    -0.767 0.443195
## tipo_de_productoINVERSION ORDINARIA FINAGRO                      2.618 0.008836
## tipo_de_productoINVERSIÓN PROYECTO MICROCREDITO                 -0.531 0.595546
## tipo_de_productoMICROCREDITO ECONOMIA POPULAR RP                -1.764 0.077772
## tipo_de_productoNORMALIZACION DE RECURSOS FINAGRO IBR            3.136 0.001714
## tipo_de_productoOther                                            1.911 0.056024
## tasa_referencialINDICADOR BANCARIO DE REFERENCIA SEMESTRAL     -10.723  < 2e-16
## tasa_referencialINDICADOR BANCARIO DE REFERENCIA TRIMESTRAL     -4.900 9.58e-07
## tasa_referencialTASA Cero                                       -0.044 0.964854
## tasa_referencialTasa DTF Efectivo Anual                         -9.050  < 2e-16
## tasa_referencialOther                                            2.472 0.013442
## tipo_productor_pmgGran Productor Finagro                         0.006 0.995325
## tipo_productor_pmgMediano Productor                              0.104 0.917035
## tipo_productor_pmgMicrofinanzas                                  0.111 0.911434
## tipo_productor_pmgNo Agropecuario                                0.102 0.919145
## tipo_productor_pmgPequeño Productor                              0.111 0.911795
## destino_agrupadoAgricultura - cultivos                          -1.537 0.124323
## destino_agrupadoComercializacion - transformacion agropecuaria  -2.086 0.037013
## destino_agrupadoFinancieros - capital de trabajo                -1.041 0.297655
## destino_agrupadoInfraestructura - equipamiento                  -2.030 0.042346
## destino_agrupadoPecuaria - pesca                                -1.465 0.142846
## destino_agrupadoServicio - apoyo agropecuario                   -1.648 0.099417
## Banca_clienteMICROFINANZAS                                       0.315 0.752476
## Banca_clientePERSONAL                                           -0.561 0.574786
## mo_modalidadMV                                                   3.210 0.001325
## mo_modalidadSV                                                   3.323 0.000890
## mo_modalidadTV                                                   2.097 0.036015
## Tipo_Factor_ExternoFactores Naturales - Volcán                   1.038 0.299279
## Tipo_Factor_ExternoOla Invernal                                  6.894 5.41e-12
## Tipo_Factor_ExternoSequía                                        0.740 0.459249
## factor(Departamento_Inversion)Nariño                            -9.063  < 2e-16
## factor(Departamento_Inversion)Valle del cauca                    4.962 6.96e-07
## factor(Departamento_Inversion)Valle del Cauca                   -0.651 0.515022
## factor(Departamento_Inversion)Other                             -0.768 0.442769
## generoMASCULINO                                                  3.525 0.000424
## cuotas_pactadas                                                -17.923  < 2e-16
## monto_desembolso                                                -9.801  < 2e-16
## saldo                                                           13.148  < 2e-16
## COMPARATIVO_OCURRENCIA_HECHONo reporta                          -2.935 0.003336
## COMPARATIVO_OCURRENCIA_HECHOV-D                                 -0.163 0.870176
##                                                                   
## (Intercept)                                                       
## tipo_de_productoCAP TRABAJO MUJER MICROEMPRESARIA              .  
## tipo_de_productoCAP. TRABAJO PROYECTO MICROCREDITO                
## tipo_de_productoCAPITAL DE TRABAJO ORDINARIA FINAGRO           .  
## tipo_de_productoINV. VICTIMA CONFLICTO ARMADO INTERNO          *  
## tipo_de_productoINVERSION - COMP. ANIM.Y RETEN.VIENTRES        ***
## tipo_de_productoINVERSION - PLANTACION Y MANTENIMIENTO         ** 
## tipo_de_productoINVERSION MUJER MICROEMPRESARIA                .  
## tipo_de_productoINVERSIÓN MULTIDESTINO IBR                        
## tipo_de_productoINVERSION MULTIDESTINO MICRO                      
## tipo_de_productoINVERSION ORDINARIA FINAGRO                    ** 
## tipo_de_productoINVERSIÓN PROYECTO MICROCREDITO                   
## tipo_de_productoMICROCREDITO ECONOMIA POPULAR RP               .  
## tipo_de_productoNORMALIZACION DE RECURSOS FINAGRO IBR          ** 
## tipo_de_productoOther                                          .  
## tasa_referencialINDICADOR BANCARIO DE REFERENCIA SEMESTRAL     ***
## tasa_referencialINDICADOR BANCARIO DE REFERENCIA TRIMESTRAL    ***
## tasa_referencialTASA Cero                                         
## tasa_referencialTasa DTF Efectivo Anual                        ***
## tasa_referencialOther                                          *  
## tipo_productor_pmgGran Productor Finagro                          
## tipo_productor_pmgMediano Productor                               
## tipo_productor_pmgMicrofinanzas                                   
## tipo_productor_pmgNo Agropecuario                                 
## tipo_productor_pmgPequeño Productor                               
## destino_agrupadoAgricultura - cultivos                            
## destino_agrupadoComercializacion - transformacion agropecuaria *  
## destino_agrupadoFinancieros - capital de trabajo                  
## destino_agrupadoInfraestructura - equipamiento                 *  
## destino_agrupadoPecuaria - pesca                                  
## destino_agrupadoServicio - apoyo agropecuario                  .  
## Banca_clienteMICROFINANZAS                                        
## Banca_clientePERSONAL                                             
## mo_modalidadMV                                                 ** 
## mo_modalidadSV                                                 ***
## mo_modalidadTV                                                 *  
## Tipo_Factor_ExternoFactores Naturales - Volcán                    
## Tipo_Factor_ExternoOla Invernal                                ***
## Tipo_Factor_ExternoSequía                                         
## factor(Departamento_Inversion)Nariño                           ***
## factor(Departamento_Inversion)Valle del cauca                  ***
## factor(Departamento_Inversion)Valle del Cauca                     
## factor(Departamento_Inversion)Other                               
## generoMASCULINO                                                ***
## cuotas_pactadas                                                ***
## monto_desembolso                                               ***
## saldo                                                          ***
## COMPARATIVO_OCURRENCIA_HECHONo reporta                         ** 
## COMPARATIVO_OCURRENCIA_HECHOV-D                                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 29951  on 38818  degrees of freedom
## Residual deviance: 28682  on 38770  degrees of freedom
## AIC: 28780
## 
## Number of Fisher Scoring iterations: 11

Prediccion y calculo de umbral óptimo mediante criterio de Youden

# Predecir probabilidades en test
prob_logit <- predict(model_logit, newdata = test_bin, type = "response")

# Construir curva ROC y calcular AUC
roc_obj  <- roc(test_bin$target_binario, prob_logit,
                levels = c("Al Día", "En Mora"), quiet = TRUE)

# Umbral óptimo por criterio de Youden (maximiza Sensibilidad + Especificidad)
best_thr <- as.numeric(coords(roc_obj, "best", ret = "threshold",
                              best.method = "youden")[1])
cat("\nUmbral óptimo (Youden):", round(best_thr, 4), "\n")
## 
## Umbral óptimo (Youden): 0.1479
# Clasificar según umbral óptimo
pred_logit <- factor(
  ifelse(prob_logit > best_thr, "En Mora", "Al Día"),
  levels = levels(test_bin$target_binario)
)

Evaluación del modelo

# Matriz de confusión y métricas
cm_logit <- confusionMatrix(pred_logit, test_bin$target_binario,
                            positive = "En Mora")
print(cm_logit)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction Al Día En Mora
##    Al Día   10260    1045
##    En Mora   4218    1112
##                                           
##                Accuracy : 0.6836          
##                  95% CI : (0.6765, 0.6907)
##     No Information Rate : 0.8703          
##     P-Value [Acc > NIR] : 1               
##                                           
##                   Kappa : 0.1379          
##                                           
##  Mcnemar's Test P-Value : <2e-16          
##                                           
##             Sensitivity : 0.51553         
##             Specificity : 0.70866         
##          Pos Pred Value : 0.20863         
##          Neg Pred Value : 0.90756         
##              Prevalence : 0.12967         
##          Detection Rate : 0.06685         
##    Detection Prevalence : 0.32041         
##       Balanced Accuracy : 0.61210         
##                                           
##        'Positive' Class : En Mora         
## 
# Imprimir métricas clave
cat("\nAUC-ROC:      ", round(auc(roc_obj), 4), "\n")
## 
## AUC-ROC:       0.6493
cat("Accuracy:     ", round(cm_logit$overall["Accuracy"],          4), "\n")
## Accuracy:      0.6836
cat("Sensitivity:  ", round(cm_logit$byClass["Sensitivity"],       4), "\n")
## Sensitivity:   0.5155
cat("Specificity:  ", round(cm_logit$byClass["Specificity"],       4), "\n")
## Specificity:   0.7087
cat("Precision:    ", round(cm_logit$byClass["Precision"],         4), "\n")
## Precision:     0.2086
cat("F1:           ", round(cm_logit$byClass["F1"],                4), "\n")
## F1:            0.297
cat("Balanced Acc.:", round(cm_logit$byClass["Balanced Accuracy"], 4), "\n")
## Balanced Acc.: 0.6121

Modelo Logit ponderado

Dado el desbalance en la variable dependiente, se implementó un esquema de ponderación de clases con el objetivo de incrementar la importancia relativa de la clase minoritaria (“En Mora”).

prop_real    <- prop.table(table(train_bin$target_binario))
cat("\nProporciones reales en train:\n")
## 
## Proporciones reales en train:
print(round(prop_real, 4))
## 
##  Al Día En Mora 
##  0.8703  0.1297
prop_objetivo  <- c("Al Día" = 0.55, "En Mora" = 0.45)
weights_class  <- prop_objetivo / prop_real
cat("\nPesos por clase:\n")
## 
## Pesos por clase:
print(round(weights_class, 4))
## 
##  Al Día En Mora 
##  0.6320  3.4701

Resultados del modelo ponderado

suppressWarnings(
  model_logit_w <- glm(
    target_binario ~ tipo_de_producto + tasa_referencial + tipo_productor_pmg +
      destino_agrupado + Banca_cliente + mo_modalidad +
      Tipo_Factor_Externo + Departamento_Inversion + genero +
      cuotas_pactadas + monto_desembolso + saldo +
      COMPARATIVO_OCURRENCIA_HECHO,
    data    = train_binw,           # Dataset CON pesos
    family  = binomial(link = "logit"),
    weights = w
  )
)

summary(model_logit_w)
## 
## Call:
## glm(formula = target_binario ~ tipo_de_producto + tasa_referencial + 
##     tipo_productor_pmg + destino_agrupado + Banca_cliente + mo_modalidad + 
##     Tipo_Factor_Externo + Departamento_Inversion + genero + cuotas_pactadas + 
##     monto_desembolso + saldo + COMPARATIVO_OCURRENCIA_HECHO, 
##     family = binomial(link = "logit"), data = train_binw, weights = w)
## 
## Coefficients:
##                                                                 Estimate
## (Intercept)                                                    -13.25924
## tipo_de_productoCAP TRABAJO MUJER MICROEMPRESARIA               -0.80721
## tipo_de_productoCAP. TRABAJO PROYECTO MICROCREDITO               0.19041
## tipo_de_productoCAPITAL DE TRABAJO ORDINARIA FINAGRO             3.81200
## tipo_de_productoINV. VICTIMA CONFLICTO ARMADO INTERNO            4.39589
## tipo_de_productoINVERSION - COMP. ANIM.Y RETEN.VIENTRES          5.64778
## tipo_de_productoINVERSION - PLANTACION Y MANTENIMIENTO           4.86298
## tipo_de_productoINVERSION MUJER MICROEMPRESARIA                 -0.94141
## tipo_de_productoINVERSIÓN MULTIDESTINO IBR                       2.47621
## tipo_de_productoINVERSION MULTIDESTINO MICRO                    -0.40570
## tipo_de_productoINVERSION ORDINARIA FINAGRO                      4.54943
## tipo_de_productoINVERSIÓN PROYECTO MICROCREDITO                 -0.57193
## tipo_de_productoMICROCREDITO ECONOMIA POPULAR RP                -1.04977
## tipo_de_productoNORMALIZACION DE RECURSOS FINAGRO IBR            5.63337
## tipo_de_productoOther                                            4.34595
## tasa_referencialINDICADOR BANCARIO DE REFERENCIA SEMESTRAL      -3.50300
## tasa_referencialINDICADOR BANCARIO DE REFERENCIA TRIMESTRAL     -3.79276
## tasa_referencialTASA Cero                                        1.49841
## tasa_referencialTasa DTF Efectivo Anual                         -2.98337
## tasa_referencialOther                                            3.31411
## tipo_productor_pmgGran Productor Finagro                         2.12569
## tipo_productor_pmgMediano Productor                             12.25295
## tipo_productor_pmgMicrofinanzas                                 12.96461
## tipo_productor_pmgNo Agropecuario                               12.22804
## tipo_productor_pmgPequeño Productor                             12.77747
## destino_agrupadoAgricultura - cultivos                          -1.34469
## destino_agrupadoComercializacion - transformacion agropecuaria  -2.00976
## destino_agrupadoFinancieros - capital de trabajo                -0.88631
## destino_agrupadoInfraestructura - equipamiento                  -1.83285
## destino_agrupadoPecuaria - pesca                                -1.32445
## destino_agrupadoServicio - apoyo agropecuario                   -1.51270
## Banca_clienteMICROFINANZAS                                       0.05828
## Banca_clientePERSONAL                                           -0.19703
## mo_modalidadMV                                                   0.88253
## mo_modalidadSV                                                   0.35155
## mo_modalidadTV                                                   1.54759
## Tipo_Factor_ExternoFactores Naturales - Volcán                   0.30368
## Tipo_Factor_ExternoOla Invernal                                  0.47705
## Tipo_Factor_ExternoSequía                                        0.03436
## Departamento_InversionNariño                                    -0.33311
## Departamento_InversionValle del cauca                            0.29355
## Departamento_InversionValle del Cauca                           -0.38815
## Departamento_InversionOther                                     -0.42025
## generoMASCULINO                                                  0.10574
## cuotas_pactadas                                                 -0.42037
## monto_desembolso                                                -0.41840
## saldo                                                            0.45948
## COMPARATIVO_OCURRENCIA_HECHONo reporta                          -0.33741
## COMPARATIVO_OCURRENCIA_HECHOV-D                                 -0.03718
##                                                                Std. Error
## (Intercept)                                                      65.67261
## tipo_de_productoCAP TRABAJO MUJER MICROEMPRESARIA                 0.32141
## tipo_de_productoCAP. TRABAJO PROYECTO MICROCREDITO                0.40380
## tipo_de_productoCAPITAL DE TRABAJO ORDINARIA FINAGRO              1.12092
## tipo_de_productoINV. VICTIMA CONFLICTO ARMADO INTERNO             1.12578
## tipo_de_productoINVERSION - COMP. ANIM.Y RETEN.VIENTRES           1.15383
## tipo_de_productoINVERSION - PLANTACION Y MANTENIMIENTO            1.12570
## tipo_de_productoINVERSION MUJER MICROEMPRESARIA                   0.32773
## tipo_de_productoINVERSIÓN MULTIDESTINO IBR                        0.98810
## tipo_de_productoINVERSION MULTIDESTINO MICRO                      0.37581
## tipo_de_productoINVERSION ORDINARIA FINAGRO                       1.12471
## tipo_de_productoINVERSIÓN PROYECTO MICROCREDITO                   0.41121
## tipo_de_productoMICROCREDITO ECONOMIA POPULAR RP                  0.37928
## tipo_de_productoNORMALIZACION DE RECURSOS FINAGRO IBR             1.15492
## tipo_de_productoOther                                             1.09773
## tasa_referencialINDICADOR BANCARIO DE REFERENCIA SEMESTRAL        0.30255
## tasa_referencialINDICADOR BANCARIO DE REFERENCIA TRIMESTRAL       0.64869
## tasa_referencialTASA Cero                                         0.91935
## tasa_referencialTasa DTF Efectivo Anual                           0.30830
## tasa_referencialOther                                             0.82953
## tipo_productor_pmgGran Productor Finagro                        239.19722
## tipo_productor_pmgMediano Productor                              65.66362
## tipo_productor_pmgMicrofinanzas                                  65.66540
## tipo_productor_pmgNo Agropecuario                                65.66624
## tipo_productor_pmgPequeño Productor                              65.66349
## destino_agrupadoAgricultura - cultivos                            0.77117
## destino_agrupadoComercializacion - transformacion agropecuaria    0.83869
## destino_agrupadoFinancieros - capital de trabajo                  0.76350
## destino_agrupadoInfraestructura - equipamiento                    0.78495
## destino_agrupadoPecuaria - pesca                                  0.77205
## destino_agrupadoServicio - apoyo agropecuario                     0.77144
## Banca_clienteMICROFINANZAS                                        0.18318
## Banca_clientePERSONAL                                             0.29843
## mo_modalidadMV                                                    0.16828
## mo_modalidadSV                                                    0.08984
## mo_modalidadTV                                                    0.58427
## Tipo_Factor_ExternoFactores Naturales - Volcán                    0.18767
## Tipo_Factor_ExternoOla Invernal                                   0.05380
## Tipo_Factor_ExternoSequía                                         0.13714
## Departamento_InversionNariño                                      0.02501
## Departamento_InversionValle del cauca                             0.05124
## Departamento_InversionValle del Cauca                             0.39904
## Departamento_InversionOther                                       0.39125
## generoMASCULINO                                                   0.02150
## cuotas_pactadas                                                   0.01896
## monto_desembolso                                                  0.03106
## saldo                                                             0.02554
## COMPARATIVO_OCURRENCIA_HECHONo reporta                            0.07708
## COMPARATIVO_OCURRENCIA_HECHOV-D                                   0.07750
##                                                                z value Pr(>|z|)
## (Intercept)                                                     -0.202 0.839996
## tipo_de_productoCAP TRABAJO MUJER MICROEMPRESARIA               -2.511 0.012024
## tipo_de_productoCAP. TRABAJO PROYECTO MICROCREDITO               0.472 0.637251
## tipo_de_productoCAPITAL DE TRABAJO ORDINARIA FINAGRO             3.401 0.000672
## tipo_de_productoINV. VICTIMA CONFLICTO ARMADO INTERNO            3.905 9.43e-05
## tipo_de_productoINVERSION - COMP. ANIM.Y RETEN.VIENTRES          4.895 9.84e-07
## tipo_de_productoINVERSION - PLANTACION Y MANTENIMIENTO           4.320 1.56e-05
## tipo_de_productoINVERSION MUJER MICROEMPRESARIA                 -2.873 0.004072
## tipo_de_productoINVERSIÓN MULTIDESTINO IBR                       2.506 0.012209
## tipo_de_productoINVERSION MULTIDESTINO MICRO                    -1.080 0.280350
## tipo_de_productoINVERSION ORDINARIA FINAGRO                      4.045 5.23e-05
## tipo_de_productoINVERSIÓN PROYECTO MICROCREDITO                 -1.391 0.164275
## tipo_de_productoMICROCREDITO ECONOMIA POPULAR RP                -2.768 0.005644
## tipo_de_productoNORMALIZACION DE RECURSOS FINAGRO IBR            4.878 1.07e-06
## tipo_de_productoOther                                            3.959 7.52e-05
## tasa_referencialINDICADOR BANCARIO DE REFERENCIA SEMESTRAL     -11.578  < 2e-16
## tasa_referencialINDICADOR BANCARIO DE REFERENCIA TRIMESTRAL     -5.847 5.01e-09
## tasa_referencialTASA Cero                                        1.630 0.103132
## tasa_referencialTasa DTF Efectivo Anual                         -9.677  < 2e-16
## tasa_referencialOther                                            3.995 6.46e-05
## tipo_productor_pmgGran Productor Finagro                         0.009 0.992909
## tipo_productor_pmgMediano Productor                              0.187 0.851973
## tipo_productor_pmgMicrofinanzas                                  0.197 0.843488
## tipo_productor_pmgNo Agropecuario                                0.186 0.852276
## tipo_productor_pmgPequeño Productor                              0.195 0.845714
## destino_agrupadoAgricultura - cultivos                          -1.744 0.081213
## destino_agrupadoComercializacion - transformacion agropecuaria  -2.396 0.016561
## destino_agrupadoFinancieros - capital de trabajo                -1.161 0.245704
## destino_agrupadoInfraestructura - equipamiento                  -2.335 0.019544
## destino_agrupadoPecuaria - pesca                                -1.715 0.086254
## destino_agrupadoServicio - apoyo agropecuario                   -1.961 0.049893
## Banca_clienteMICROFINANZAS                                       0.318 0.750356
## Banca_clientePERSONAL                                           -0.660 0.509101
## mo_modalidadMV                                                   5.244 1.57e-07
## mo_modalidadSV                                                   3.913 9.11e-05
## mo_modalidadTV                                                   2.649 0.008078
## Tipo_Factor_ExternoFactores Naturales - Volcán                   1.618 0.105620
## Tipo_Factor_ExternoOla Invernal                                  8.867  < 2e-16
## Tipo_Factor_ExternoSequía                                        0.251 0.802181
## Departamento_InversionNariño                                   -13.317  < 2e-16
## Departamento_InversionValle del cauca                            5.729 1.01e-08
## Departamento_InversionValle del Cauca                           -0.973 0.330704
## Departamento_InversionOther                                     -1.074 0.282768
## generoMASCULINO                                                  4.918 8.76e-07
## cuotas_pactadas                                                -22.171  < 2e-16
## monto_desembolso                                               -13.469  < 2e-16
## saldo                                                           17.992  < 2e-16
## COMPARATIVO_OCURRENCIA_HECHONo reporta                          -4.377 1.20e-05
## COMPARATIVO_OCURRENCIA_HECHOV-D                                 -0.480 0.631378
##                                                                   
## (Intercept)                                                       
## tipo_de_productoCAP TRABAJO MUJER MICROEMPRESARIA              *  
## tipo_de_productoCAP. TRABAJO PROYECTO MICROCREDITO                
## tipo_de_productoCAPITAL DE TRABAJO ORDINARIA FINAGRO           ***
## tipo_de_productoINV. VICTIMA CONFLICTO ARMADO INTERNO          ***
## tipo_de_productoINVERSION - COMP. ANIM.Y RETEN.VIENTRES        ***
## tipo_de_productoINVERSION - PLANTACION Y MANTENIMIENTO         ***
## tipo_de_productoINVERSION MUJER MICROEMPRESARIA                ** 
## tipo_de_productoINVERSIÓN MULTIDESTINO IBR                     *  
## tipo_de_productoINVERSION MULTIDESTINO MICRO                      
## tipo_de_productoINVERSION ORDINARIA FINAGRO                    ***
## tipo_de_productoINVERSIÓN PROYECTO MICROCREDITO                   
## tipo_de_productoMICROCREDITO ECONOMIA POPULAR RP               ** 
## tipo_de_productoNORMALIZACION DE RECURSOS FINAGRO IBR          ***
## tipo_de_productoOther                                          ***
## tasa_referencialINDICADOR BANCARIO DE REFERENCIA SEMESTRAL     ***
## tasa_referencialINDICADOR BANCARIO DE REFERENCIA TRIMESTRAL    ***
## tasa_referencialTASA Cero                                         
## tasa_referencialTasa DTF Efectivo Anual                        ***
## tasa_referencialOther                                          ***
## tipo_productor_pmgGran Productor Finagro                          
## tipo_productor_pmgMediano Productor                               
## tipo_productor_pmgMicrofinanzas                                   
## tipo_productor_pmgNo Agropecuario                                 
## tipo_productor_pmgPequeño Productor                               
## destino_agrupadoAgricultura - cultivos                         .  
## destino_agrupadoComercializacion - transformacion agropecuaria *  
## destino_agrupadoFinancieros - capital de trabajo                  
## destino_agrupadoInfraestructura - equipamiento                 *  
## destino_agrupadoPecuaria - pesca                               .  
## destino_agrupadoServicio - apoyo agropecuario                  *  
## Banca_clienteMICROFINANZAS                                        
## Banca_clientePERSONAL                                             
## mo_modalidadMV                                                 ***
## mo_modalidadSV                                                 ***
## mo_modalidadTV                                                 ** 
## Tipo_Factor_ExternoFactores Naturales - Volcán                    
## Tipo_Factor_ExternoOla Invernal                                ***
## Tipo_Factor_ExternoSequía                                         
## Departamento_InversionNariño                                   ***
## Departamento_InversionValle del cauca                          ***
## Departamento_InversionValle del Cauca                             
## Departamento_InversionOther                                       
## generoMASCULINO                                                ***
## cuotas_pactadas                                                ***
## monto_desembolso                                               ***
## saldo                                                          ***
## COMPARATIVO_OCURRENCIA_HECHONo reporta                         ***
## COMPARATIVO_OCURRENCIA_HECHOV-D                                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 53426  on 38818  degrees of freedom
## Residual deviance: 50907  on 38770  degrees of freedom
## AIC: 61530
## 
## Number of Fisher Scoring iterations: 10

Prediccion y calculo de umbral óptimo mediante criterio de Youden

# 9e. Predicción sobre test real sin modificaciones ---
prob_logit_w <- predict(model_logit_w, newdata = test_bin, type = "response")

# 9f. Curva ROC ---
roc_obj_w <- roc(test_bin$target_binario, prob_logit_w,
                 levels = c("Al Día", "En Mora"), quiet = TRUE)

# 9g. Umbral óptimo por criterio de Youden ---
best_thr_w <- as.numeric(coords(roc_obj_w, "best", ret = "threshold",
                                best.method = "youden")[1])
cat("\nUmbral óptimo ponderado (Youden):", round(best_thr_w, 4), "\n")
## 
## Umbral óptimo ponderado (Youden): 0.4927
# 9h. Clasificación final ---
pred_logit_w <- factor(
  ifelse(prob_logit_w > best_thr_w, "En Mora", "Al Día"),
  levels = levels(test_bin$target_binario)
)

Evaluación del modelo ponderado

# 9i. Evaluación ---
cm_logit_w <- confusionMatrix(pred_logit_w, test_bin$target_binario,
                              positive = "En Mora")
print(cm_logit_w)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction Al Día En Mora
##    Al Día   10572    1084
##    En Mora   3906    1073
##                                         
##                Accuracy : 0.7           
##                  95% CI : (0.693, 0.707)
##     No Information Rate : 0.8703        
##     P-Value [Acc > NIR] : 1             
##                                         
##                   Kappa : 0.1462        
##                                         
##  Mcnemar's Test P-Value : <2e-16        
##                                         
##             Sensitivity : 0.4975        
##             Specificity : 0.7302        
##          Pos Pred Value : 0.2155        
##          Neg Pred Value : 0.9070        
##              Prevalence : 0.1297        
##          Detection Rate : 0.0645        
##    Detection Prevalence : 0.2993        
##       Balanced Accuracy : 0.6138        
##                                         
##        'Positive' Class : En Mora       
## 
cat("\nAUC-ROC:      ", round(auc(roc_obj_w), 4), "\n")
## 
## AUC-ROC:       0.6493
cat("Accuracy:     ", round(cm_logit_w$overall["Accuracy"],          4), "\n")
## Accuracy:      0.7
cat("Sensitivity:  ", round(cm_logit_w$byClass["Sensitivity"],       4), "\n")
## Sensitivity:   0.4975
cat("Specificity:  ", round(cm_logit_w$byClass["Specificity"],       4), "\n")
## Specificity:   0.7302
cat("Precision:    ", round(cm_logit_w$byClass["Precision"],         4), "\n")
## Precision:     0.2155
cat("F1:           ", round(cm_logit_w$byClass["F1"],                4), "\n")
## F1:            0.3007
cat("Balanced Acc.:", round(cm_logit_w$byClass["Balanced Accuracy"], 4), "\n")
## Balanced Acc.: 0.6138

Arboles de decision

Es un modelo de clasificación que utiliza una estructura de árbol para tomar decisiones basadas en las características de los datos. Cada nodo del árbol representa una característica, cada rama representa un valor de esa característica y cada hoja representa una clase o resultado final. El árbol se construye dividiendo el conjunto de datos en subconjuntos basados en la característica que mejor separa las clases en cada paso. Es fácil de interpretar y visualizar, lo que lo hace popular para tareas de clasificación y regresión.

Arbol de decision sin ponderación

# Modelo de árbol de decisión sin ponderación
tree_model <- rpart(
  target_binario ~ tipo_de_producto + tasa_referencial + tipo_productor_pmg +
    destino_agrupado + Banca_cliente + mo_modalidad +
    Tipo_Factor_Externo + Departamento_Inversion + genero +
    cuotas_pactadas + monto_desembolso + saldo +
    COMPARATIVO_OCURRENCIA_HECHO,
  data    = train_bin,           # Dataset SIN pesos
  method  = "class",
  control = rpart.control(cp = 0.01)
)

Imagen del árbol de decisión sin ponderación

rpart.plot(tree_model, main = "Árbol de Decisión — Sin Pesos")

El árbol de decisión muestra que la variable más determinante para clasificar el riesgo crediticio es el saldo, ya que realiza la primera división separando a los clientes con mayor probabilidad de mora de aquellos con menor riesgo. En particular, valores bajos de saldo se asocian con una alta probabilidad de incumplimiento, formando un segmento pequeño pero crítico. Para el resto de la población, el modelo utiliza variables como el número de cuotas pactadas y el tipo de producto para refinar la clasificación, identificando subgrupos mayoritariamente “Al Día” pero también algunos nichos específicos con riesgo elevado. En conjunto, el árbol evidencia que el riesgo no es uniforme, sino que depende de combinaciones específicas de variables, permitiendo detectar tanto grupos masivos de bajo riesgo como segmentos reducidos con alta probabilidad de mora.

Predicción y cálculo de umbral óptimo mediante criterio de Youden

prob_tree     <- predict(tree_model, newdata = test_bin, type = "prob")[, "En Mora"]
roc_tree      <- roc(test_bin$target_binario, prob_tree,
                     levels = c("Al Día", "En Mora"), quiet = TRUE)
best_thr_tree <- as.numeric(coords(roc_tree, "best", ret = "threshold",
                                   best.method = "youden")[1])
cat("\nUmbral óptimo árbol sin pesos (Youden):", round(best_thr_tree, 4), "\n")
## 
## Umbral óptimo árbol sin pesos (Youden): 0.1546
pred_tree <- factor(
  ifelse(prob_tree > best_thr_tree, "En Mora", "Al Día"),
  levels = levels(test_bin$target_binario)
)

Matriz de confusion

cm_tree <- confusionMatrix(pred_tree, test_bin$target_binario, positive = "En Mora")
print(cm_tree)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction Al Día En Mora
##    Al Día   14222    1885
##    En Mora    256     272
##                                           
##                Accuracy : 0.8713          
##                  95% CI : (0.8661, 0.8763)
##     No Information Rate : 0.8703          
##     P-Value [Acc > NIR] : 0.3612          
##                                           
##                   Kappa : 0.1598          
##                                           
##  Mcnemar's Test P-Value : <2e-16          
##                                           
##             Sensitivity : 0.12610         
##             Specificity : 0.98232         
##          Pos Pred Value : 0.51515         
##          Neg Pred Value : 0.88297         
##              Prevalence : 0.12967         
##          Detection Rate : 0.01635         
##    Detection Prevalence : 0.03174         
##       Balanced Accuracy : 0.55421         
##                                           
##        'Positive' Class : En Mora         
## 
cat("\nAUC-ROC:      ", round(auc(roc_tree), 4), "\n")
## 
## AUC-ROC:       0.555
cat("Accuracy:     ", round(cm_tree$overall["Accuracy"],          4), "\n")
## Accuracy:      0.8713
cat("Sensitivity:  ", round(cm_tree$byClass["Sensitivity"],       4), "\n")
## Sensitivity:   0.1261
cat("Specificity:  ", round(cm_tree$byClass["Specificity"],       4), "\n")
## Specificity:   0.9823
cat("Precision:    ", round(cm_tree$byClass["Precision"],         4), "\n")
## Precision:     0.5152
cat("F1:           ", round(cm_tree$byClass["F1"],                4), "\n")
## F1:            0.2026
cat("Balanced Acc.:", round(cm_tree$byClass["Balanced Accuracy"], 4), "\n")
## Balanced Acc.: 0.5542

Árbol de decision ponderado por clase

tree_model_w <- rpart(
  target_binario ~ tipo_de_producto + tasa_referencial + tipo_productor_pmg +
    destino_agrupado + Banca_cliente + mo_modalidad +
    Tipo_Factor_Externo + Departamento_Inversion + genero +
    cuotas_pactadas + monto_desembolso + saldo +
    COMPARATIVO_OCURRENCIA_HECHO,
  data    = train_binw,          # Dataset CON pesos
  method  = "class",
  weights = w,                   # Vector de pesos por observación
  control = rpart.control(cp = 0.01)
)

Imagen del árbol de decisión sin ponderación

rpart.plot(tree_model_w, main = "Árbol de Decisión — Ponderado")

Predicción y cálculo de umbral óptimo mediante criterio de Youden

prob_tree_w     <- predict(tree_model_w, newdata = test_bin, type = "prob")[, "En Mora"]
roc_tree_w      <- roc(test_bin$target_binario, prob_tree_w,
                       levels = c("Al Día", "En Mora"), quiet = TRUE)
best_thr_tree_w <- as.numeric(coords(roc_tree_w, "best", ret = "threshold",
                                     best.method = "youden")[1])
cat("\nUmbral óptimo árbol ponderado (Youden):", round(best_thr_tree_w, 4), "\n")
## 
## Umbral óptimo árbol ponderado (Youden): 0.5233
pred_tree_w <- factor(
  ifelse(prob_tree_w > best_thr_tree_w, "En Mora", "Al Día"),
  levels = levels(test_bin$target_binario)
)

Matriz de confusion

cm_tree_w <- confusionMatrix(pred_tree_w, test_bin$target_binario, positive = "En Mora")
print(cm_tree_w)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction Al Día En Mora
##    Al Día   12781    1573
##    En Mora   1697     584
##                                           
##                Accuracy : 0.8034          
##                  95% CI : (0.7973, 0.8094)
##     No Information Rate : 0.8703          
##     P-Value [Acc > NIR] : 1.00000         
##                                           
##                   Kappa : 0.1499          
##                                           
##  Mcnemar's Test P-Value : 0.03148         
##                                           
##             Sensitivity : 0.27075         
##             Specificity : 0.88279         
##          Pos Pred Value : 0.25603         
##          Neg Pred Value : 0.89041         
##              Prevalence : 0.12967         
##          Detection Rate : 0.03511         
##    Detection Prevalence : 0.13712         
##       Balanced Accuracy : 0.57677         
##                                           
##        'Positive' Class : En Mora         
## 
cat("\nAUC-ROC:      ", round(auc(roc_tree_w), 4), "\n")
## 
## AUC-ROC:       0.5779
cat("Accuracy:     ", round(cm_tree_w$overall["Accuracy"],          4), "\n")
## Accuracy:      0.8034
cat("Sensitivity:  ", round(cm_tree_w$byClass["Sensitivity"],       4), "\n")
## Sensitivity:   0.2707
cat("Specificity:  ", round(cm_tree_w$byClass["Specificity"],       4), "\n")
## Specificity:   0.8828
cat("Precision:    ", round(cm_tree_w$byClass["Precision"],         4), "\n")
## Precision:     0.256
cat("F1:           ", round(cm_tree_w$byClass["F1"],                4), "\n")
## F1:            0.2632
cat("Balanced Acc.:", round(cm_tree_w$byClass["Balanced Accuracy"], 4), "\n")
## Balanced Acc.: 0.5768
# ── ELIMINAR VARIABLES CON LEAKAGE DE LAS BASES DE ENTRENAMIENTO Y TEST ──────
# dias_vencido ES el target en forma numérica — su presencia causa AUC = 1.0
# rango es la categorización directa de dias_vencido — también leakage

vars_leakage <- c("dias_vencido", "rango")

train_bin  <- train_bin[,  !names(train_bin)  %in% vars_leakage]
test_bin   <- test_bin[,   !names(test_bin)   %in% vars_leakage]
train_binw <- train_binw[, !names(train_binw) %in% vars_leakage]

Modelo XGBOOST

XGBoost es un algoritmo de aprendizaje automático basado en árboles de decisión que utiliza el método de boosting para mejorar la precisión de las predicciones. Es especialmente efectivo para problemas de clasificación y regresión, y es conocido por su eficiencia computacional y capacidad para manejar grandes conjuntos de datos con características mixtas (numéricas y categóricas). XGBoost construye modelos secuenciales donde cada nuevo árbol corrige los errores del anterior, lo que resulta en un modelo final robusto y preciso.

Preparación de matrices para XGBoost

# Variables predictoras sin target, rango ni w
vars_xgb <- setdiff(names(train_bin), c("target_binario", "rango"))

# Matrices de features
X_train <- model.matrix(~ . - 1, data = train_bin[, vars_xgb])
X_test  <- model.matrix(~ . - 1, data = test_bin[, vars_xgb])

# Alinear columnas: test puede no tener todos los niveles de train
cols_comunes <- intersect(colnames(X_train), colnames(X_test))
X_train <- X_train[, cols_comunes]
X_test  <- X_test[,  cols_comunes]

# Targets numéricos: "En Mora" = 1, "Al Día" = 0
y_train <- as.numeric(train_bin$target_binario == "En Mora")
y_test  <- as.numeric(test_bin$target_binario  == "En Mora")

Parámetros para XGBoost

params_xgb <- list(
  objective        = "binary:logistic",
  eval_metric      = "auc",
  eta              = 0.05,
  max_depth        = 4,
  subsample        = 0.6,
  colsample_bytree = 0.6,
  alpha            = 1.0, 
  lambda           = 5.0,
  min_child_weight = 15,
  gamma            = 0.3
)

XGBoost sin ponderación

dtrain <- xgb.DMatrix(data = X_train, label = y_train)
dtest  <- xgb.DMatrix(data = X_test,  label = y_test)

xgb_model <- xgb.train(
  params                = params_xgb,
  data                  = dtrain,
  nrounds               = 800,
  watchlist             = list(train = dtrain, test = dtest),
  early_stopping_rounds = 20,
  verbose               = 0
)
## Warning in throw_err_or_depr_msg("Parameter '", match_old, "' has been renamed
## to '", : Parameter 'watchlist' has been renamed to 'evals'. This warning will
## become an error in a future version.

Predicción y cálculo de umbral óptimo mediante criterio de Youden

prob_xgb     <- predict(xgb_model, newdata = dtest)
roc_xgb      <- roc(test_bin$target_binario, prob_xgb,
                    levels = c("Al Día", "En Mora"), quiet = TRUE)
best_thr_xgb <- as.numeric(coords(roc_xgb, "best", ret = "threshold",
                                  best.method = "youden")[1])
cat("Umbral óptimo XGBoost sin pesos (Youden):", round(best_thr_xgb, 4), "\n")
## Umbral óptimo XGBoost sin pesos (Youden): 0.1311
pred_xgb <- factor(
  ifelse(prob_xgb > best_thr_xgb, "En Mora", "Al Día"),
  levels = levels(test_bin$target_binario)
)

Matriz de confusión

cm_xgb <- confusionMatrix(pred_xgb, test_bin$target_binario, positive = "En Mora")
print(cm_xgb)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction Al Día En Mora
##    Al Día   11465     800
##    En Mora   3013    1357
##                                           
##                Accuracy : 0.7708          
##                  95% CI : (0.7643, 0.7772)
##     No Information Rate : 0.8703          
##     P-Value [Acc > NIR] : 1               
##                                           
##                   Kappa : 0.2931          
##                                           
##  Mcnemar's Test P-Value : <2e-16          
##                                           
##             Sensitivity : 0.62911         
##             Specificity : 0.79189         
##          Pos Pred Value : 0.31053         
##          Neg Pred Value : 0.93477         
##              Prevalence : 0.12967         
##          Detection Rate : 0.08157         
##    Detection Prevalence : 0.26270         
##       Balanced Accuracy : 0.71050         
##                                           
##        'Positive' Class : En Mora         
## 
cat("\nAUC-ROC:      ", round(auc(roc_xgb), 4), "\n")
## 
## AUC-ROC:       0.7689
cat("Accuracy:     ", round(cm_xgb$overall["Accuracy"],          4), "\n")
## Accuracy:      0.7708
cat("Sensitivity:  ", round(cm_xgb$byClass["Sensitivity"],       4), "\n")
## Sensitivity:   0.6291
cat("Specificity:  ", round(cm_xgb$byClass["Specificity"],       4), "\n")
## Specificity:   0.7919
cat("Precision:    ", round(cm_xgb$byClass["Precision"],         4), "\n")
## Precision:     0.3105
cat("F1:           ", round(cm_xgb$byClass["F1"],                4), "\n")
## F1:            0.4158
cat("Balanced Acc.:", round(cm_xgb$byClass["Balanced Accuracy"], 4), "\n")
## Balanced Acc.: 0.7105

Importancia de las variables

xgb.importance(model = xgb_model) |>
  head(15) |>
  xgb.plot.importance(main = "Importancia de variables — XGBoost sin pesos")

XGBoost ponderado por clase

# Preparar matriz desde train_binw (excluir target, rango y w)
vars_xgb_w <- setdiff(names(train_binw), c("target_binario", "rango", "w"))
X_train_w  <- model.matrix(~ . - 1, data = train_binw[, vars_xgb_w])

# Alinear columnas con X_test
cols_comunes_w <- intersect(colnames(X_train_w), colnames(X_test))
X_train_w <- X_train_w[, cols_comunes_w]
X_test_w  <- X_test[,   cols_comunes_w]

y_train_w <- as.numeric(train_binw$target_binario == "En Mora")

# DMatrix CON pesos por observación
dtrain_w <- xgb.DMatrix(data   = X_train_w,
                        label  = y_train_w,
                        weight = train_binw$w)   # <-- pesos explícitos
dtest_w  <- xgb.DMatrix(data = X_test_w, label = y_test)

Xgboost ponderado por clase

xgb_model_w <- xgb.train(
  params                = params_xgb,
  data                  = dtrain_w,
  nrounds               = 800,
  watchlist             = list(train = dtrain_w, test = dtest_w),
  early_stopping_rounds = 20,
  verbose               = 0
)
## Warning in throw_err_or_depr_msg("Parameter '", match_old, "' has been renamed
## to '", : Parameter 'watchlist' has been renamed to 'evals'. This warning will
## become an error in a future version.

Predicción y cálculo de umbral óptimo mediante criterio de Youden

prob_xgb_w     <- predict(xgb_model_w, newdata = dtest_w)
roc_xgb_w      <- roc(test_bin$target_binario, prob_xgb_w,
                      levels = c("Al Día", "En Mora"), quiet = TRUE)
best_thr_xgb_w <- as.numeric(coords(roc_xgb_w, "best", ret = "threshold",
                                    best.method = "youden")[1])
cat("Umbral óptimo XGBoost ponderado (Youden):", round(best_thr_xgb_w, 4), "\n")
## Umbral óptimo XGBoost ponderado (Youden): 0.4509
pred_xgb_w <- factor(
  ifelse(prob_xgb_w > best_thr_xgb_w, "En Mora", "Al Día"),
  levels = levels(test_bin$target_binario)
)

Matriz de confusión

cm_xgb_w <- confusionMatrix(pred_xgb_w, test_bin$target_binario, positive = "En Mora")
print(cm_xgb_w)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction Al Día En Mora
##    Al Día   11753     780
##    En Mora   2725    1377
##                                          
##                Accuracy : 0.7893         
##                  95% CI : (0.783, 0.7955)
##     No Information Rate : 0.8703         
##     P-Value [Acc > NIR] : 1              
##                                          
##                   Kappa : 0.3253         
##                                          
##  Mcnemar's Test P-Value : <2e-16         
##                                          
##             Sensitivity : 0.63839        
##             Specificity : 0.81178        
##          Pos Pred Value : 0.33569        
##          Neg Pred Value : 0.93776        
##              Prevalence : 0.12967        
##          Detection Rate : 0.08278        
##    Detection Prevalence : 0.24659        
##       Balanced Accuracy : 0.72509        
##                                          
##        'Positive' Class : En Mora        
## 
cat("\nAUC-ROC:      ", round(auc(roc_xgb_w), 4), "\n")
## 
## AUC-ROC:       0.7921
cat("Accuracy:     ", round(cm_xgb_w$overall["Accuracy"],          4), "\n")
## Accuracy:      0.7893
cat("Sensitivity:  ", round(cm_xgb_w$byClass["Sensitivity"],       4), "\n")
## Sensitivity:   0.6384
cat("Specificity:  ", round(cm_xgb_w$byClass["Specificity"],       4), "\n")
## Specificity:   0.8118
cat("Precision:    ", round(cm_xgb_w$byClass["Precision"],         4), "\n")
## Precision:     0.3357
cat("F1:           ", round(cm_xgb_w$byClass["F1"],                4), "\n")
## F1:            0.44
cat("Balanced Acc.:", round(cm_xgb_w$byClass["Balanced Accuracy"], 4), "\n")
## Balanced Acc.: 0.7251

Importancia de las variables

xgb.importance(model = xgb_model_w) |>
  head(15) |>
  xgb.plot.importance(main = "Importancia de variables — XGBoost ponderado")

Tabla comparativa

En este apartado se presenta una tabla comparativa que resume las métricas clave de desempeño para cada uno de los modelos evaluados: Logit sin pesos, Logit ponderado, Árbol sin pesos, Árbol ponderado, XGBoost sin pesos y XGBoost ponderado. Las métricas incluidas son AUC-ROC, Accuracy, Sensitivity, Specificity, Precision, F1 Score y Balanced Accuracy. Esta tabla permite una comparación directa entre los modelos para identificar cuál ofrece el mejor rendimiento en la predicción del riesgo de incumplimiento crediticio.

Metricas clave de desempeño para cada modelo

tabla_completa <- data.frame(
  Modelo = c(
    "Logit sin pesos",
    "Logit ponderado",
    "Árbol sin pesos",
    "Árbol ponderado",
    "XGBoost sin pesos",
    "XGBoost ponderado"
  ),
  AUC = c(
    round(auc(roc_obj),     4),
    round(auc(roc_obj_w),   4),
    round(auc(roc_tree),    4),
    round(auc(roc_tree_w),  4),
    round(auc(roc_xgb),     4),
    round(auc(roc_xgb_w),   4)
  ),
  Accuracy = c(
    round(cm_logit$overall["Accuracy"],   4),
    round(cm_logit_w$overall["Accuracy"], 4),
    round(cm_tree$overall["Accuracy"],    4),
    round(cm_tree_w$overall["Accuracy"],  4),
    round(cm_xgb$overall["Accuracy"],     4),
    round(cm_xgb_w$overall["Accuracy"],   4)
  ),
  Sensitivity = c(
    round(cm_logit$byClass["Sensitivity"],   4),
    round(cm_logit_w$byClass["Sensitivity"], 4),
    round(cm_tree$byClass["Sensitivity"],    4),
    round(cm_tree_w$byClass["Sensitivity"],  4),
    round(cm_xgb$byClass["Sensitivity"],     4),
    round(cm_xgb_w$byClass["Sensitivity"],   4)
  ),
  Specificity = c(
    round(cm_logit$byClass["Specificity"],   4),
    round(cm_logit_w$byClass["Specificity"], 4),
    round(cm_tree$byClass["Specificity"],    4),
    round(cm_tree_w$byClass["Specificity"],  4),
    round(cm_xgb$byClass["Specificity"],     4),
    round(cm_xgb_w$byClass["Specificity"],   4)
  ),
  Precision = c(
    round(cm_logit$byClass["Precision"],   4),
    round(cm_logit_w$byClass["Precision"], 4),
    round(cm_tree$byClass["Precision"],    4),
    round(cm_tree_w$byClass["Precision"],  4),
    round(cm_xgb$byClass["Precision"],     4),
    round(cm_xgb_w$byClass["Precision"],   4)
  ),
  F1 = c(
    round(cm_logit$byClass["F1"],   4),
    round(cm_logit_w$byClass["F1"], 4),
    round(cm_tree$byClass["F1"],    4),
    round(cm_tree_w$byClass["F1"],  4),
    round(cm_xgb$byClass["F1"],     4),
    round(cm_xgb_w$byClass["F1"],   4)
  ),
  Balanced_Acc = c(
    round(cm_logit$byClass["Balanced Accuracy"],   4),
    round(cm_logit_w$byClass["Balanced Accuracy"], 4),
    round(cm_tree$byClass["Balanced Accuracy"],    4),
    round(cm_tree_w$byClass["Balanced Accuracy"],  4),
    round(cm_xgb$byClass["Balanced Accuracy"],     4),
    round(cm_xgb_w$byClass["Balanced Accuracy"],   4)
  )
)

print(tabla_completa)
##              Modelo    AUC Accuracy Sensitivity Specificity Precision     F1
## 1   Logit sin pesos 0.6493   0.6836      0.5155      0.7087    0.2086 0.2970
## 2   Logit ponderado 0.6493   0.7000      0.4975      0.7302    0.2155 0.3007
## 3   Árbol sin pesos 0.5550   0.8713      0.1261      0.9823    0.5152 0.2026
## 4   Árbol ponderado 0.5779   0.8034      0.2707      0.8828    0.2560 0.2632
## 5 XGBoost sin pesos 0.7689   0.7708      0.6291      0.7919    0.3105 0.4158
## 6 XGBoost ponderado 0.7921   0.7893      0.6384      0.8118    0.3357 0.4400
##   Balanced_Acc
## 1       0.6121
## 2       0.6138
## 3       0.5542
## 4       0.5768
## 5       0.7105
## 6       0.7251

Curva ROC

plot(roc_obj,    col = "steelblue",   lwd = 2,
     main = "Curvas ROC — Comparativa General")
plot(roc_obj_w,  col = "steelblue",   lwd = 2, lty = 2, add = TRUE)
plot(roc_tree,   col = "forestgreen", lwd = 2,           add = TRUE)
plot(roc_tree_w, col = "forestgreen", lwd = 2, lty = 2, add = TRUE)
plot(roc_xgb,    col = "tomato",      lwd = 2,           add = TRUE)
plot(roc_xgb_w,  col = "tomato",      lwd = 2, lty = 2, add = TRUE)
abline(a = 0, b = 1, lty = 3, col = "gray60")

legend("bottomright",
       legend = c(
         paste0("Logit sin pesos   (AUC = ", round(auc(roc_obj),    3), ")"),
         paste0("Logit ponderado   (AUC = ", round(auc(roc_obj_w),  3), ")"),
         paste0("Árbol sin pesos   (AUC = ", round(auc(roc_tree),   3), ")"),
         paste0("Árbol ponderado   (AUC = ", round(auc(roc_tree_w), 3), ")"),
         paste0("XGBoost sin pesos (AUC = ", round(auc(roc_xgb),    3), ")"),
         paste0("XGBoost ponderado (AUC = ", round(auc(roc_xgb_w),  3), ")")
       ),
       col = c("steelblue","steelblue","forestgreen","forestgreen","tomato","tomato"),
       lty = c(1, 2, 1, 2, 1, 2),
       lwd = 2, bty = "n", cex = 0.82)