INTRODUCCIÓN

Este proyecto documenta de manera ordenada y detallada todo el proceso realizado para el análisis y modelado de la deserción de clientes en el segmento evaluado.
El objetivo principal es predecir la probabilidad de que un cliente deserte en los próximos tres meses y, sobre todo, conocer las causas (variables) que influyen en esa decisión.
En este contexto, se define como “deserción” el hecho de que un cliente no mantenga saldo en los siguientes tres meses, siempre y cuando no haya existido variación en su saldo de colocaciones y contingentes durante ese período.

La página HTML generada contiene los pasos completos del proyecto, organizados en las siguientes secciones:

1. Limpieza de datos

  • Variables de colocaciones: fueron las primeras en evaluarse y depurarse.

  • Variables de contingentes: se incorporaron después de la primera limpieza para complementar el análisis.

2. Creación de factores

Debido al gran número de variables disponibles (114 variables independientes), se aplicó análisis de factores, con el propósito de reducir la dimensionalidad y facilitar la interpretación, sin perder información clave.

3. Selección y transformación de variables

Se seleccionaron las variables más representativas de cada factor. Luego se generó la variable objetivo (CHURN3) para cada registro, excluyendo aquellos casos donde no hubo variación en los saldos de colocaciones ni contingentes.
Además, se crearon nuevas variables derivadas y, dado que muchas variables numéricas tenían una distribución no normal y concentraban gran cantidad de valores pequeños, se procedió a categorizarlas para mejorar la interpretabilidad.

4. Modelado

Con la base de datos lista, se seleccionó el algoritmo LightGBM (Light Gradient Boosting Machine) por su capacidad de:

  • Manejar grandes volúmenes de datos de manera eficiente.

  • Capturar interacciones no lineales entre variables.

  • Mantener un buen equilibrio entre precisión y velocidad de entrenamiento.

El modelo se entrenó y evaluó mediante:

  • Métricas estadísticas para medir el desempeño global.

  • Matriz de confusión para interpretar los aciertos y errores en la predicción.

5. Interpretación de resultados

Para entender cómo cada variable influye en la predicción, se utilizó la librería SHAP (SHapley Additive exPlanations), que permite obtener una interpretación clara y visual del impacto de cada predictor sobre el resultado del modelo.

En resumen, este trabajo no solo presenta los resultados del modelo, sino que también detalla paso a paso el proceso de preparación, selección y análisis de datos, asegurando que las conclusiones sean técnicamente sólidas y fácilmente interpretables.

Limpieza de datos

Variables de colocaciones

En primer lugar, se presenta la base de datos completa para que el usuario pueda revisarla visualmente y conocer su estructura inicial.

data
## # A tibble: 6,793 × 97
##    periodo...1 NumeroDocumentoId codigoclientebanco  colo  conti NombreCliente  
##    <chr>       <chr>             <chr>              <dbl>  <dbl> <chr>          
##  1 202401      16405870          3772979                0 700000 CHAVEZ HURTADO…
##  2 202402      16405870          3772979                0 700000 CHAVEZ HURTADO…
##  3 202403      16405870          3772979                0 700000 CHAVEZ HURTADO…
##  4 202404      16405870          3772979                0 400000 CHAVEZ HURTADO…
##  5 202405      16405870          3772979                0 400000 CHAVEZ HURTADO…
##  6 202406      16405870          3772979                0 400000 CHAVEZ HURTADO…
##  7 202407      16405870          3772979                0 400000 CHAVEZ HURTADO…
##  8 202408      16405870          3772979                0 400000 CHAVEZ HURTADO…
##  9 202409      16405870          3772979                0 400000 CHAVEZ HURTADO…
## 10 202410      16405870          3772979                0 400000 CHAVEZ HURTADO…
## # ℹ 6,783 more rows
## # ℹ 91 more variables: deuda_tota_bp <dbl>, deuda_tot <dbl>, deuda_mpm <dbl>,
## #   deuda_corp_gran_med <dbl>, deuda_corp_gran <dbl>, deuda_total_bp <dbl>,
## #   deuda_corp_gran_bp <dbl>, deuda_corp_gran_med_bp <dbl>,
## #   deuda_emp_arren_bp <dbl>, deuda_total_bcp <dbl>, deuda_corp_gran_bcp <dbl>,
## #   deuda_corp_gran_med_bcp <dbl>, deuda_emp_arren_bcp <dbl>,
## #   deuda_total_bbva <dbl>, deuda_corp_gran_bbva <dbl>, …

Valores nulos

Se muestra un resumen de los valores nulos presentes en la base, representado mediante un heatmap. En este gráfico:

  • El eje X corresponde a las variables que tienen al menos un valor nulo.

  • El eje Y corresponde a las filas que contienen al menos un valor nulo.

  • El color negro indica valores no nulos.

  • El color amarillo indica valores nulos.

library(ggplot2)
library(reshape2)
library(stringr)

# Si no hay nulos
if(length(cols_with_nulls) == 0){
  plot.new()
  text(0.5, 0.5, "No hay valores nulos en las columnas", cex = 1.5)
} else {
  mat_na <- is.na(filas_con_nulos[, cols_with_nulls])
  df_long <- reshape2::melt(mat_na)
  colnames(df_long) <- c("Fila", "Columna", "EsNA")
  df_long$Fila <- factor(df_long$Fila, levels = rev(unique(df_long$Fila)))
  
  columnas_orden <- unique(df_long$Columna)
  
  # Wrap de etiquetas para que no se solapen
  labels_wrapped <- stringr::str_wrap(columnas_orden, width = 20)
  
  ggplot(df_long, aes(x = Columna, y = Fila, fill = EsNA)) +
    geom_tile(width = 1, height = 1) +
    scale_fill_manual(values = c("FALSE" = "#440154", "TRUE" = "#FDE725"),
                      labels = c("Completo", "Nulo"), name = "") +
    scale_x_discrete(breaks = columnas_orden, labels = labels_wrapped) +
    labs(title = "Heatmap de valores nulos\n(Solo filas y columnas con nulos)",
         x = "Columnas",
         y = NULL) +
    theme_minimal() +
    theme(
      axis.text.y = element_blank(),
      axis.ticks.y = element_blank(),
      axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1, size = 6),
      plot.title = element_text(size = 18),
      axis.title = element_text(size = 14),
      plot.margin = margin(30, 30, 30, 30)
    )
}

cat("Variables con valores nulos:", length(cols_with_nulls), "\n")
## Variables con valores nulos: 76
cat("Filas con al menos un valor nulo:", nrow(filas_con_nulos), "\n")
## Filas con al menos un valor nulo: 247

Filas completamente nulas

De las filas identificadas anteriormente (aquellas que presentan valores nulos en las variables seleccionadas para el heatmap), se contabiliza cuántas tienen todas esas variables completamente nulas.

cat("Filas donde TODAS las columnas con nulos están vacías:", nrow(filas_todas_nulas_df), "\n")
## Filas donde TODAS las columnas con nulos están vacías: 171

Valores completamente 0

Se calcula la cantidad de filas que, además de tener valores nulos en todas las variables con al menos un nulo, presentan cero en el resto de variables (con excepción de periodo y ruc).

cat("Filas donde TODAS las columnas (excepto excluidas) son 0:", nrow(filas_todo_ceros), "\n")
## Filas donde TODAS las columnas (excepto excluidas) son 0: 142

Identificación de registros parcialmente completos

Se crea una copia de la base de datos llamada (data1) para continuar el análisis. En esta etapa, se filtran y muestran los registros que, a pesar de tener valores nulos en las variables con al menos un nulo, presentan valores distintos de cero en alguna de las siguientes variables: var_deuda_tot_m4, var_deuda_tot_m5 y var_deuda_tot_m6.

cat("Filas donde NO todas las columnas (excepto excluidas) son 0:", nrow(filas_no_todo_ceros), "\n")
## Filas donde NO todas las columnas (excepto excluidas) son 0: 29

Cantidad y porcentaje de ceros por variable

Se presenta un resumen con la cantidad y el porcentaje de ceros por cada variable.

ceros_df
##                                    Cantidad_Ceros Porcentaje_Ceros
## deuda_emp_arren_bp                           6428        94.626822
## deuda_emp_arren_sbk                          6053        89.106433
## deuda_emp_arren_bif                          5770        84.940380
## deuda_emp_arren_ibk                          5755        84.719564
## deuda_mpm                                    5465        80.450464
## CUOTA_deuda_mpm                              5354        78.816429
## deuda_emp_arren_bbva                         4817        70.911232
## deuda_emp_arren_bcp                          4656        68.541145
## conti                                        4448        65.479170
## deuda_corp_gran_sbk                          4040        59.472987
## deuda_corp_gran_med_sbk                      3918        57.677020
## PROM_deuda_corp_gran_sbk_3M                  3905        57.485647
## deuda_total_sbk                              3881        57.132342
## VAR_deuda_corp_gran_SBK_T1_T3                3876        57.058737
## PROM_deuda_corp_gran_med_sbk_3M              3762        55.380539
## R_DEUDA_TOTAL_SBK_3M_6M                      3732        54.938908
## PROM_DEUDA_TOTAL_sbk_3M                      3731        54.924187
## VAR_deuda_corp_gran_med_SBK_T1_T3            3729        54.894745
## VAR_DEUDA_TOTAL_SBK_T1_T3                    3699        54.453113
## deuda_corp_gran_bif                          3502        51.553069
## VAR_deuda_corp_gran_BIF_T1_T3                3304        48.638304
## deuda_corp_gran_med_bif                      3291        48.446931
## PROM_deuda_corp_gran_bif_3M                  3275        48.211394
## deuda_total_bif                              3221        47.416458
## deuda_corp_gran_ibk                          3094        45.546887
## VAR_deuda_corp_gran_med_BIF_T1_T3            3091        45.502723
## VAR_DEUDA_TOTAL_BIF_T1_T3                    3072        45.223024
## PROM_deuda_corp_gran_med_bif_3M              3038        44.722508
## R_DEUDA_TOTAL_BIF_3M_6M                      3030        44.604740
## PROM_DEUDA_TOTAL_bif_3M                      3015        44.383925
## VAR_deuda_corp_gran_IBK_T1_T3                2992        44.045341
## PROM_deuda_corp_gran_ibk_3M                  2959        43.559547
## deuda_corp_gran_med_ibk                      2882        42.426027
## deuda_total_ibk                              2865        42.175769
## VAR_deuda_corp_gran_med_IBK_T1_T3            2822        41.542765
## VAR_DEUDA_TOTAL_IBK_T1_T3                    2809        41.351391
## PROM_deuda_corp_gran_med_ibk_3M              2764        40.688945
## R_DEUDA_TOTAL_IBK_3M_6M                      2754        40.541734
## PROM_DEUDA_TOTAL_ibk_3M                      2751        40.497571
## var_SOW_COLOCACIONES_m6                      2623        38.613278
## var_SOW_COLOCACIONES_m5                      2572        37.862506
## var_SOW_COLOCACIONES_m4                      2496        36.743707
## var_SOW_COLOCACIONES_m3                      2413        35.521861
## var_SOW_COLOCACIONES_m2                      2300        33.858384
## deuda_corp_gran_bp                           2221        32.695422
## VAR_deuda_corp_gran_BBVA_T1_T3               2173        31.988812
## var_SOW_COLOCACIONES_m1                      2158        31.767996
## deuda_corp_gran_bbva                         2104        30.973061
## PROM_deuda_corp_gran_bbva_3M                 2035        29.957309
## VAR_deuda_corp_gran_BP_T1_T3                 1947        28.661858
## PROM_deuda_corp_gran_bp_3M                   1878        27.646106
## deuda_corp_gran_bcp                          1862        27.410570
## VAR_deuda_corp_gran_BCP_T1_T3                1824        26.851170
## PROM_deuda_corp_gran_bcp_3M                  1760        25.909024
## VAR_deuda_corp_gran_med_BBVA_T1_T3           1658        24.407478
## VAR_DEUDA_TOTAL_BBVA_T1_T3                   1637        24.098337
## deuda_corp_gran_med_bp                       1617        23.803916
## deuda_corp_gran_med_bbva                     1603        23.597821
## colo                                         1577        23.215074
## deuda_total_bbva                             1577        23.215074
## deuda_total_bp                               1529        22.508465
## deuda_corp_gran_med_bcp                      1478        21.757692
## PROM_deuda_corp_gran_med_bbva_3M             1474        21.698808
## R_DEUDA_TOTAL_BBVA_3M_6M                     1456        21.433829
## PROM_DEUDA_TOTAL_bbva_3M                     1451        21.360224
## VAR_deuda_corp_gran_med_BP_T1_T3             1388        20.432798
## deuda_total_bcp                              1379        20.300309
## VAR_DEUDA_TOTAL_BP_T1_T3                     1348        19.843957
## VAR_deuda_corp_gran_med_BCP_T1_T3            1338        19.696747
## PROM_deuda_corp_gran_med_bcp_3M              1302        19.166789
## VAR_DEUDA_TOTAL_BCP_T1_T3                    1287        18.945974
## PROM_deuda_corp_gran_med_bp_3M               1281        18.857648
## R_DEUDA_TOTAL_BCP_3M_6M                      1268        18.666274
## R_DEUDA_TOTAL_BP_3M_6M                       1247        18.357132
## PROM_DEUDA_TOTAL_bcp_3M                      1247        18.357132
## PROM_DEUDA_TOTAL_bp_3M                       1228        18.077433
## CUOTA_deuda_corp_gran                         789        11.614898
## deuda_corp_gran                               748        11.011335
## CUOTA_deuda_corp_gran_med                     304         4.475195
## deuda_corp_gran_med                           302         4.445753
## deuda_tota_bp                                 275         4.048285
## R_DEUDA_TOTAL_1M_MAX6M                        223         3.282791
## N_CRED                                        217         3.194465
## R_DEUDA_TOTAL_1M_6M                           215         3.165023
## deuda_tot                                     213         3.135581
## var_deuda_tot_m4                              210         3.091418
## var_deuda_tot_m2                              209         3.076697
## var_deuda_tot_m3                              208         3.061976
## var_deuda_tot_m1                              207         3.047255
## var_deuda_tot_m5                              207         3.047255
## var_deuda_tot_m6                              200         2.944207
## MIN6_var_deuda_tot                            167         2.458413
## periodo...1                                     0         0.000000
## NumeroDocumentoId                               0         0.000000
## codigoclientebanco                              0         0.000000
## NombreCliente                                   0         0.000000
## segmentacion_presupuesto                        0         0.000000

Se eliminan aquellas variables en las que el porcentaje de ceros es mayor al 70%.

cat("Lista de columnas a eliminar:\n")
## Lista de columnas a eliminar:
cat(paste0("- ", cols_eliminar, collapse = "\n"))
## - deuda_emp_arren_bp
## - deuda_emp_arren_sbk
## - deuda_emp_arren_bif
## - deuda_emp_arren_ibk
## - deuda_mpm
## - CUOTA_deuda_mpm
## - deuda_emp_arren_bbva
## - deuda_emp_arren_bcp

Todos los nulos a ceros

Los valores nulos restantes se reemplazan por ceros. Finalmente, se crea la variable tuvo_deuda_mes_anterior.

Variables de contingentes

En primer lugar, se presenta la base de datos filtrada para mostrar únicamente las columnas relacionadas con contingentes, de manera que el usuario pueda revisarlas de forma específica.

data_60
## # A tibble: 14,154 × 60
##    periodo...1 NumeroDocumentoId codigoclientebanco NombreCliente      DEUDA_VIG
##    <chr>       <chr>             <chr>              <chr>                  <dbl>
##  1 202301      16405870          3772979            CHAVEZ HURTADO AN…  5388925.
##  2 202302      16405870          3772979            CHAVEZ HURTADO AN…  5300098.
##  3 202303      16405870          3772979            CHAVEZ HURTADO AN…  5219866.
##  4 202304      16405870          3772979            CHAVEZ HURTADO AN…  5139545 
##  5 202305      16405870          3772979            CHAVEZ HURTADO AN…  5055563.
##  6 202306      16405870          3772979            CHAVEZ HURTADO AN…  4976125.
##  7 202307      16405870          3772979            CHAVEZ HURTADO AN…  4898167.
##  8 202308      16405870          3772979            CHAVEZ HURTADO AN…  4820827.
##  9 202309      16405870          3772979            CHAVEZ HURTADO AN…   821390.
## 10 202310      16405870          3772979            CHAVEZ HURTADO AN…   817963.
## # ℹ 14,144 more rows
## # ℹ 55 more variables: DEUDA_Reestructurado <dbl>, deuda_refinanciado <dbl>,
## #   deuda_vencido <dbl>, deuda_judicial <dbl>, deuda_tot_conting <dbl>,
## #   deuda_total_conting_bp <dbl>, deuda_total_conting_bcp <dbl>,
## #   deuda_total_conting_bbva <dbl>, deuda_total_conting_sbk <dbl>,
## #   deuda_total_conting_ibk <dbl>, deuda_total_conting_bif <dbl>,
## #   N_CRED_conting <dbl>, var_sow_contingentes_m1 <dbl>, …

Valores nulos

Se genera un resumen con la cantidad de valores nulos presentes en cada una de las variables relacionadas a contingentes.

resumen_nulos
##                                    Cantidad_Nulos Porcentaje_Nulos
## utilidad_ult_3                               9629            68.03
## pro_utilidad_ult_3                           9629            68.03
## utilidad_ult_6                               8730            61.68
## pro_utilidad_ult_6                           8730            61.68
## Util_ult_9                                   8144            57.54
## pro_Util_ult_9                               8144            57.54
## Util_ult_12                                  7835            55.36
## pro_Util_ult_12                              7835            55.36
## CUOTA_deuda_tot_conting                      4271            30.18
## VAR_deuda_total_conting_BP_T1_T3             4224            29.84
## VAR_deuda_total_conting_BCP_T1_T3            4224            29.84
## VAR_deuda_total_conting_BBVA_T1_T3           4224            29.84
## VAR_deuda_total_conting_SBK_T1_T3            4224            29.84
## VAR_deuda_total_conting_IBK_T1_T3            4224            29.84
## VAR_deuda_total_conting_BIF_T1_T3            4224            29.84
## deuda_tot_conting                            4216            29.79
## deuda_total_conting_bp                       4216            29.79
## deuda_total_conting_bcp                      4216            29.79
## deuda_total_conting_bbva                     4216            29.79
## deuda_total_conting_sbk                      4216            29.79
## deuda_total_conting_ibk                      4216            29.79
## deuda_total_conting_bif                      4216            29.79
## N_CRED_conting                               4216            29.79
## R_deuda_tot_conting_1M_6M                    4195            29.64
## R_deuda_tot_conting_1M_MAX6M                 4195            29.64
## R_deuda_total_conting_BP_3M_6M               4030            28.47
## R_deuda_total_conting_BCP_3M_6M              4030            28.47
## R_deuda_total_conting_BBVA_3M_6M             4030            28.47
## R_deuda_total_conting_SBK_3M_6M              4030            28.47
## R_deuda_total_conting_IBK_3M_6M              4030            28.47
## R_deuda_total_conting_BIF_3M_6M              4030            28.47
## PROM_deuda_total_conting_bp_3M               4030            28.47
## PROM_deuda_total_conting_bcp_3M              4030            28.47
## PROM_deuda_total_conting_bbva_3M             4030            28.47
## PROM_deuda_total_conting_sbk_3M              4030            28.47
## PROM_deuda_total_conting_ibk_3M              4030            28.47
## PROM_deuda_total_conting_bif_3M              4030            28.47
## DEUDA_VIG                                     343             2.42
## DEUDA_Reestructurado                          343             2.42
## deuda_refinanciado                            343             2.42
## deuda_vencido                                 343             2.42
## deuda_judicial                                343             2.42
## periodo...1                                     0             0.00
## NumeroDocumentoId                               0             0.00
## codigoclientebanco                              0             0.00
## NombreCliente                                   0             0.00
## var_sow_contingentes_m1                         0             0.00
## var_sow_contingentes_m2                         0             0.00
## var_sow_contingentes_m3                         0             0.00
## var_sow_contingentes_m4                         0             0.00
## var_sow_contingentes_m5                         0             0.00
## var_sow_contingentes_m6                         0             0.00
## var_deuda_tot_contingm1                         0             0.00
## var_deuda_tot_contingm2                         0             0.00
## var_deuda_tot_contingm3                         0             0.00
## var_deuda_tot_contingm4                         0             0.00
## var_deuda_tot_contingm5                         0             0.00
## var_deuda_tot_contingm6                         0             0.00
## MIN6_var_deuda_tot_conting                      0             0.00
## segmentacion_presupuesto                        0             0.00

Análisis de variables de utilidades

Se presta especial atención a las variables relacionadas con utilidades, ya que se sospecha que podrían tener un aporte significativo en el modelo. Al final, se decide eliminar las variables que representan promedios de utilidades (tanto a 3, 6, 9 como a 12 meses), conservando únicamente las variables de utilidades proyectadas a esos mismos periodos, pero sin promediar.

Para justificar esta decisión, se presenta un gráfico de cajas que evidencia que:

En las variables de utilidades (no promedio), la mayoría de valores son cercanos a cero, con pocos casos que alcanzan valores muy altos.

En las variables de promedios, la información se “desvía” debido a que los valores atípicos (muy altos) afectan considerablemente la media, reduciendo la capacidad de discriminar casos.

Como resultado, las variables promedio presentan menos dispersión, pero también aportan menos información útil para el modelo.

ggplot(data_box_long, aes(x = Valor, y = Variable)) +
  geom_boxplot() +
  theme_minimal() +
  labs(title = "Distribución de variables utilidad", x = "Valor", y = "") +
  theme(plot.title = element_text(hjust = 0.5))
## Warning: Removed 68676 rows containing non-finite outside the scale range
## (`stat_boxplot()`).

Análisis de variables con muchos ceros

Se identifican variables que contienen un porcentaje elevado de ceros, en particular: deuda_judicial, deuda_vencido, deuda_refinanciado, DEUDA_VIG y DEUDA_Reestructurado. De todas ellas, se decide conservar únicamente la variable DEUDA_VIG, por considerarse de posible alto aporte al modelo.

df_resumen
##               Variable Cantidad_Nulos Porcentaje_Nulos Cantidad_Ceros
## 1       deuda_judicial            343             2.42          13782
## 2        deuda_vencido            343             2.42          13177
## 3   deuda_refinanciado            343             2.42          13508
## 4            DEUDA_VIG            343             2.42              3
## 5 DEUDA_Reestructurado            343             2.42          13811
##   Porcentaje_Ceros Cantidad_Validos
## 1            97.37               29
## 2            93.10              634
## 3            95.44              303
## 4             0.02            13808
## 5            97.58                0

Creación de factores

Correlación

Para este análisis se optó por utilizar la matriz de correlación de Spearman en lugar de la de Pearson, debido a que las variables no cumplían con los supuestos de normalidad y linealidad necesarios para aplicar el coeficiente de Pearson de manera adecuada.

En primer lugar, se generó un gráfico de correlación entre todas las variables, y se filtraron aquellas que presentaban al menos un 30% de correlación con alguna otra variable.

variables_eliminadas
##  [1] "deuda_emp_arren_bp"                 "var_SOW_COLOCACIONES_m1"           
##  [3] "var_SOW_COLOCACIONES_m2"            "var_SOW_COLOCACIONES_m4"           
##  [5] "var_SOW_COLOCACIONES_m5"            "var_SOW_COLOCACIONES_m6"           
##  [7] "CUOTA_deuda_mpm"                    "var_deuda_tot_m4"                  
##  [9] "var_deuda_tot_m5"                   "var_deuda_tot_m6"                  
## [11] "var_sow_contingentes_m1"            "var_sow_contingentes_m2"           
## [13] "var_sow_contingentes_m3"            "var_sow_contingentes_m4"           
## [15] "var_sow_contingentes_m5"            "var_sow_contingentes_m6"           
## [17] "var_deuda_tot_contingm2"            "var_deuda_tot_contingm3"           
## [19] "var_deuda_tot_contingm4"            "var_deuda_tot_contingm5"           
## [21] "var_deuda_tot_contingm6"            "VAR_deuda_total_conting_BBVA_T1_T3"
## [23] "VAR_deuda_total_conting_SBK_T1_T3"  "VAR_deuda_total_conting_IBK_T1_T3" 
## [25] "VAR_deuda_total_conting_BIF_T1_T3"

Matriz de correlación de Spearman y matriz de distancia

Posteriormente, con las variables que superaron este umbral, se volvió a calcular la matriz de correlación de Spearman. Se verificó si esta matriz era definida positiva mediante el análisis de sus valores propios (eigenvalores), confirmando que así era.

Finalmente, se ordenó la matriz utilizando una matriz de distancias y un agrupamiento jerárquico (clustering), lo que permitió obtener una visualización más clara y ordenada. De esta forma, se pudo tener una idea preliminar de cómo podrían conformarse los factores en las etapas posteriores del análisis.

library(pheatmap)

# Generar la matriz de correlación ordenada como heatmap
pheatmap::pheatmap(
  matriz_corr_ordenada,
  fontsize = 6,       # tamaño de letras
  fontsize_row = 6,
  fontsize_col = 6,
  cellwidth = 8,
  cellheight = 8,
  main = "Matriz de correlación (Spearman) ordenada"
)

Análisis Factorial

Supuestos

Con la base de datos previamente depurada, se procedió a verificar que estuviera en condiciones de aplicar un análisis factorial, lo que implica comprobar ciertos supuestos estadísticos.

En particular, se utilizó la prueba KMO (Kaiser-Meyer-Olkin Measure of Sampling Adequacy), la cual evalúa si los datos son adecuados para este tipo de análisis.

  • Hipótesis nula (H₀): La matriz de correlaciones no es adecuada para aplicar un análisis factorial.

  • Hipótesis alternativa (H₁): La matriz de correlaciones sí es adecuada para aplicar un análisis factorial.

El resultado obtenido para el KMO general indicó que sí es posible aplicar el análisis factorial sobre la base de datos.

cat(sprintf("KMO general del modelo: %.3f\n", kmo_model))
## KMO general del modelo: 0.791

FAP (Analisis de factor principal)

Se optó por utilizar el Análisis de Factor Principal (FAP), una técnica que permite identificar un conjunto reducido de factores que explican la mayor parte de la varianza observada en los datos originales. Este método es especialmente útil cuando se busca simplificar la estructura de las variables manteniendo la máxima información posible.

Numero de factores

Antes de proceder con la extracción, fue necesario determinar la cantidad óptima de factores.
Para ello, se aplicaron dos criterios:

  1. Criterio de Kaiser (λ > 1): Se retienen únicamente los factores cuyo valor propio (eigenvalor) es mayor que 1.

  2. Criterio de porcentaje de varianza explicada: Se seleccionan los factores que, en conjunto, explican al menos el 80% de la varianza total.

Primero método:

cat("\nMétodo de Kaiser: ", kaiser_factors, " factores (λ > 1)\n")
## 
## Método de Kaiser:  24  factores (λ > 1)

Segundo método:

num_factors_80
## [1] 18

Factores obtenidos

En resumen, el proceso consistió en obtener los factores y sus respectivos pesos.
Dado que cada factor está compuesto por todas las variables, se procedió a ordenar —en valor absoluto— las 10 variables con mayor aporte a cada factor.

Posteriormente, se realizó un reordenamiento de factores aplicando criterio propio: no siempre se seleccionaron exactamente las 10 variables con mayor peso, pero este ajuste permitió una mejor definición e interpretación de cada factor.

Finalmente, se generó una gráfica tipo “llaves” que facilita la comprensión visual.
En esta representación, para cada factor se muestran:
- El nombre del factor.
- Las variables que lo componen.
- Los pesos asociados a cada variable dentro del factor.

root
##                                              levelName
## 1   Modelo                                            
## 2    ¦--Deudas_bp                                     
## 3    ¦   ¦--deuda_total_bp (0.941)                    
## 4    ¦   ¦--deuda_corp_gran_med_bp (0.943)            
## 5    ¦   ¦--PROM_DEUDA_TOTAL_bp_3M (0.941)            
## 6    ¦   ¦--PROM_deuda_corp_gran_med_bp_3M (0.944)    
## 7    ¦   ¦--PROM_deuda_corp_gran_bp_3M (0.906)        
## 8    ¦   °--deuda_corp_gran_bp (0.917)                
## 9    ¦--Deudas_sbk                                    
## 10   ¦   ¦--deuda_total_sbk (0.979)                   
## 11   ¦   ¦--deuda_corp_gran_med_sbk (0.98)            
## 12   ¦   ¦--PROM_DEUDA_TOTAL_sbk_3M (0.979)           
## 13   ¦   ¦--PROM_deuda_corp_gran_med_sbk_3M (0.981)   
## 14   ¦   ¦--PROM_deuda_corp_gran_sbk_3M (0.969)       
## 15   ¦   °--deuda_corp_gran_sbk (0.972)               
## 16   ¦--Deudas_bcp                                    
## 17   ¦   ¦--deuda_total_bcp (0.986)                   
## 18   ¦   ¦--deuda_corp_gran_med_bcp (0.986)           
## 19   ¦   ¦--PROM_DEUDA_TOTAL_bcp_3M (0.983)           
## 20   ¦   ¦--PROM_deuda_corp_gran_med_bcp_3M (0.985)   
## 21   ¦   ¦--PROM_deuda_corp_gran_bcp_3M (0.966)       
## 22   ¦   °--deuda_corp_gran_bcp (0.97)                
## 23   ¦--Deudas_ibk                                    
## 24   ¦   ¦--deuda_total_ibk (0.98)                    
## 25   ¦   ¦--deuda_corp_gran_med_ibk (0.981)           
## 26   ¦   ¦--PROM_DEUDA_TOTAL_ibk_3M (0.982)           
## 27   ¦   ¦--PROM_deuda_corp_gran_med_ibk_3M (0.982)   
## 28   ¦   ¦--PROM_deuda_corp_gran_ibk_3M (0.968)       
## 29   ¦   °--deuda_corp_gran_ibk (0.971)               
## 30   ¦--Deudas_bbva                                   
## 31   ¦   ¦--deuda_total_bbva (0.977)                  
## 32   ¦   ¦--deuda_corp_gran_med_bbva (0.98)           
## 33   ¦   ¦--PROM_DEUDA_TOTAL_bbva_3M (0.976)          
## 34   ¦   ¦--PROM_deuda_corp_gran_med_bbva_3M (0.982)  
## 35   ¦   ¦--PROM_deuda_corp_gran_bbva_3M (0.937)      
## 36   ¦   °--deuda_corp_gran_bbva (0.938)              
## 37   ¦--Deudas_bif                                    
## 38   ¦   ¦--deuda_total_bif (0.977)                   
## 39   ¦   ¦--deuda_corp_gran_med_bif (0.979)           
## 40   ¦   ¦--PROM_DEUDA_TOTAL_bif_3M (0.974)           
## 41   ¦   ¦--PROM_deuda_corp_gran_med_bif_3M (0.979)   
## 42   ¦   ¦--PROM_deuda_corp_gran_bif_3M (0.959)       
## 43   ¦   °--deuda_corp_gran_bif (0.964)               
## 44   ¦--Conti_bcp                                     
## 45   ¦   ¦--PROM_deuda_total_conting_bcp_3M (0.994)   
## 46   ¦   ¦--R_deuda_total_conting_BCP_3M_6M (0.925)   
## 47   ¦   °--deuda_total_conting_bcp (0.961)           
## 48   ¦--Conti_bbva                                    
## 49   ¦   ¦--PROM_deuda_total_conting_bbva_3M (0.995)  
## 50   ¦   ¦--R_deuda_total_conting_BBVA_3M_6M (0.93)   
## 51   ¦   °--deuda_total_conting_bbva (0.966)          
## 52   ¦--Conti_bif                                     
## 53   ¦   ¦--PROM_deuda_total_conting_bif_3M (0.998)   
## 54   ¦   ¦--R_deuda_total_conting_BIF_3M_6M (0.987)   
## 55   ¦   °--deuda_total_conting_bif (0.955)           
## 56   ¦--Conti_bp                                      
## 57   ¦   ¦--PROM_deuda_total_conting_bp_3M (0.991)    
## 58   ¦   ¦--deuda_total_conting_bp (0.951)            
## 59   ¦   °--R_deuda_total_conting_BP_3M_6M (0.951)    
## 60   ¦--Conti_ibk                                     
## 61   ¦   ¦--R_deuda_total_conting_IBK_3M_6M (0.988)   
## 62   ¦   ¦--PROM_deuda_total_conting_ibk_3M (0.998)   
## 63   ¦   °--deuda_total_conting_ibk (0.946)           
## 64   ¦--Conti_sbk                                     
## 65   ¦   ¦--R_deuda_total_conting_SBK_3M_6M (0.994)   
## 66   ¦   ¦--PROM_deuda_total_conting_sbk_3M (0.998)   
## 67   ¦   °--deuda_total_conting_sbk (0.95)            
## 68   ¦--Var_bp                                        
## 69   ¦   ¦--VAR_DEUDA_TOTAL_BP_T1_T3 (0.997)          
## 70   ¦   ¦--VAR_deuda_corp_gran_med_BP_T1_T3 (0.997)  
## 71   ¦   ¦--VAR_deuda_corp_gran_BP_T1_T3 (0.899)      
## 72   ¦   °--R_DEUDA_TOTAL_BP_3M_6M (0.779)            
## 73   ¦--Var_bcp                                       
## 74   ¦   ¦--VAR_DEUDA_TOTAL_BCP_T1_T3 (0.997)         
## 75   ¦   ¦--VAR_deuda_corp_gran_med_BCP_T1_T3 (0.996) 
## 76   ¦   ¦--VAR_deuda_corp_gran_BCP_T1_T3 (0.887)     
## 77   ¦   °--R_DEUDA_TOTAL_BCP_3M_6M (0.751)           
## 78   ¦--Var_bbva                                      
## 79   ¦   ¦--VAR_DEUDA_TOTAL_BBVA_T1_T3 (0.998)        
## 80   ¦   ¦--VAR_deuda_corp_gran_med_BBVA_T1_T3 (0.999)
## 81   ¦   ¦--VAR_deuda_corp_gran_BBVA_T1_T3 (0.888)    
## 82   ¦   °--R_DEUDA_TOTAL_BBVA_3M_6M (0.681)          
## 83   ¦--Var_ibk                                       
## 84   ¦   ¦--VAR_DEUDA_TOTAL_IBK_T1_T3 (0.998)         
## 85   ¦   ¦--VAR_deuda_corp_gran_med_IBK_T1_T3 (0.999) 
## 86   ¦   ¦--VAR_deuda_corp_gran_IBK_T1_T3 (0.952)     
## 87   ¦   °--R_DEUDA_TOTAL_IBK_3M_6M (0.532)           
## 88   ¦--Var_bif                                       
## 89   ¦   ¦--VAR_DEUDA_TOTAL_BIF_T1_T3 (0.996)         
## 90   ¦   ¦--VAR_deuda_corp_gran_med_BIF_T1_T3 (0.998) 
## 91   ¦   ¦--VAR_deuda_corp_gran_BIF_T1_T3 (0.937)     
## 92   ¦   °--R_DEUDA_TOTAL_BIF_3M_6M (0.47)            
## 93   ¦--Var_sbk                                       
## 94   ¦   ¦--VAR_DEUDA_TOTAL_SBK_T1_T3 (0.996)         
## 95   ¦   ¦--VAR_deuda_corp_gran_med_SBK_T1_T3 (0.998) 
## 96   ¦   ¦--VAR_deuda_corp_gran_SBK_T1_T3 (0.94)      
## 97   ¦   °--R_DEUDA_TOTAL_SBK_3M_6M (0.272)           
## 98   ¦--var_conti                                     
## 99   ¦   ¦--var_deuda_tot_contingm1 (0.61)            
## 100  ¦   °--... 4 nodes w/ 0 sub                      
## 101  °--... 4 nodes w/ 22 sub

Selección y tranformación de variables

En esta etapa se presenta el resultado final de todo el trabajo previo.
Con la base de datos ya depurada y los factores obtenidos, el primer paso es escoger variables representativas de cada factor, priorizando la interpretabilidad.

A estas variables se añaden algunas adicionales que no fueron incluidas en ningún factor, ya que no mostraban correlación con otras variables pero sí con la variable objetivo CHURN3.
Esta variable (CHURN3) es binaria e indica si un cliente deserta (valor 1) o no deserta (valor 0) en los próximos tres meses. En el conjunto de datos, existe un número reducido de casos con valor 1 y una gran mayoría con valor 0.

Con las variables seleccionadas, se realiza una breve limpieza adicional y la transformación a variables ordinales. Posteriormente, se entrena el modelo utilizando LightGBM (Light Gradient Boosting Machine), un algoritmo de alto rendimiento que destaca por:
- Manejar eficientemente grandes volúmenes de datos.
- Capturar relaciones no lineales entre variables.
- Ofrecer una excelente velocidad de entrenamiento y predicción.

Los resultados incluyen métricas estadísticas generales y, de forma especial, la matriz de confusión. Además, para comprender las causas detrás de las predicciones, se calcula la importancia de variables y se emplea la librería SHAP para mejorar la interpretabilidad.

Variables seleccionadas]

Se presenta un breve resumen de las variables utilizadas:
(aquí variables)

Nulos

Se identifican las variables con valores nulos y se muestra la cantidad de filas donde todas esas variables son nulas, únicamente con fines de visualización.

cat("Variables con valores nulos:", length(cols_with_nulls_model2), "\n")
## Variables con valores nulos: 49
cat("Filas donde TODAS las variables objetivo son nulas:", nrow(filas_todas_nulas_objetivo), "\n")
## Filas donde TODAS las variables objetivo son nulas: 13

Exclusión de registros sin variación de saldo en el último trimestre

Se excluyen los clientes que no presentaron variación en el saldo de colocaciones ni contingentes durante el último trimestre.
Para ello, se genera un heatmap donde el color negro representa valores no nulos y el color amarillo representa nulos.

# Ajuste dinámico de altura
altura_por_fila <- 5
altura_total <- max(20, nrow(filas_todas_nulas_objetivo) * altura_por_fila)

ggplot(heatmap_data, aes(x = variable, y = row_id, fill = es_nulo)) +
  geom_tile() +
  scale_fill_viridis(
    discrete = TRUE,
    option = "magma",
    name = "Es NA"
  ) +
  labs(
    title = "Heatmap de valores nulos\n(Filas con TODAS las variables objetivo nulas)",
    x = "Variable",
    y = "Fila"
  ) +
  theme_minimal() +
  theme(
    axis.text.y = element_text(size = 5),
    axis.text.x = element_text(size = 5, angle = 90, vjust = 0.5, hjust = 1)
  ) +
  coord_fixed(ratio = 1.2)

Dado que esta exclusión podría alterar la distribución de la variable CHURN3, se realiza con precaución. Se verifica que ninguno de los registros eliminados corresponde a clientes con CHURN3 = 1, lo que significa que todos tenían CHURN3 = 0. En total, se eliminaron 13 clientes.

print(valores_unicos)
## [1] "20377832699" "20602872476" "20604303029" "20606926643" "20609339439"
## [6] "20611248866"

Creación de nuevas variables

Se generan variables binarias y de conteo para identificar distintas combinaciones y tipos de deuda, tales como:
- colo_bp, colo_conti_corp_gran_bp, colo_conti_med_bp, colo_conti_corp_gran_otros_bp, conti_bp.
- deuda_otros_bancos_colo, cantidad_bancos_con_deuda_colo.
- deuda_otros_bancos_conti, cantidad_bancos_con_deuda_conti.

Estas variables permiten capturar información relevante sobre la presencia y distribución de deuda en diferentes productos y entidades financieras.

Balanceo de datos

Debido a que la variable CHURN3 presenta una proporción muy desigual (muchos 0 y pocos 1), se aplica un muestreo aleatorio balanceado:
- Se conservan todos los registros con CHURN3 = 1.
- Se selecciona aleatoriamente un número equivalente de registros con CHURN3 = 0.

De esta manera, se evita que el modelo aprenda de forma desbalanceada y se favorece el aprendizaje de patrones asociados a los casos de deserción (valor 1).

data1_seleccionada_model
## # A tibble: 438 × 30
##    periodo...1 NumeroDocumentoId cliente_periodo   colo_corp_gran_bp colo_med_bp
##    <chr>       <chr>             <chr>                         <int>       <int>
##  1 202310      20517274527       20517274527-2023…                 1           0
##  2 202407      20523273265       20523273265-2024…                 1           0
##  3 202406      20101904874       20101904874-2024…                 0           0
##  4 202407      20510713363       20510713363-2024…                 0           0
##  5 202409      20516530686       20516530686-2024…                 1           0
##  6 202408      20397180817       20397180817-2024…                 1           0
##  7 202310      20477683810       20477683810-2023…                 0           0
##  8 202407      20394862704       20394862704-2024…                 1           0
##  9 202409      20557679392       20557679392-2024…                 0           0
## 10 202310      20553167672       20553167672-2023…                 1           0
## # ℹ 428 more rows
## # ℹ 25 more variables: colo_corp_gran_otros_bp <int>, conti_bp <int>,
## #   deuda_otros_bancos_colo <int>, cantidad_bancos_con_deuda_colo <dbl>,
## #   deuda_otros_bancos_conti <int>, cantidad_bancos_con_deuda_conti <dbl>,
## #   R_deuda_total_conting_BCP_3M_6M <dbl>,
## #   R_deuda_total_conting_BBVA_3M_6M <dbl>,
## #   R_deuda_total_conting_BIF_3M_6M <dbl>, …

Resumen de la variable target para la data balanceada:

table(data1_seleccionada_model$CHURN3)
## 
##   0   1 
## 219 219

Modelado

Con la data previamente procesada y lista para el análisis, se procedió al entrenamiento del modelo utilizando LightGBM, un algoritmo de gradient boosting optimizado para velocidad y eficiencia en problemas de clasificación. A continuación, se presentan las principales métricas y resultados obtenidos.

Métricas de rendimiento

Entrenamiento
En la fase de entrenamiento, se obtuvieron las métricas de precision, recall, f1-score y support.

  • Precision: mide la proporción de predicciones positivas correctas sobre el total de predicciones positivas.
  • Recall: indica la capacidad del modelo para identificar correctamente todos los casos positivos reales.
  • F1-score: balance entre precision y recall.
  • Support: cantidad de observaciones reales en cada clase.

En general, los resultados del conjunto de entrenamiento fueron bastante sólidos, mostrando que el modelo logra una alta capacidad de predicción sin indicios de sobreajuste extremo.

results_fmt <- format(results, digits = 2, nsmall = 2)
rownames(results_fmt) <- NULL
print(noquote(results_fmt), row.names = FALSE)
##  Class Precision Recall F1_Score Support
##      0      1.00   1.00     1.00  176.00
##      1      1.00   1.00     1.00  176.00

Prueba
En el conjunto de prueba, las métricas se mantienen en valores elevados, aunque con ligeras disminuciones respecto al entrenamiento. Esto es un comportamiento esperado, ya que el modelo enfrenta datos que no ha visto antes, lo que demuestra su capacidad de generalización.

results_fmt <- format(results_test, digits = 2, nsmall = 2)
rownames(results_fmt) <- NULL
print(noquote(results_fmt), row.names = FALSE)
##  Class Precision Recall F1_Score Support
##      0      0.95   0.95     0.95   43.00
##      1      0.95   0.95     0.95   43.00

Matriz de confusión

Para una interpretación más visual, se presenta la matriz de confusión, que permite observar cómo se distribuyen las predicciones entre verdaderos positivos, verdaderos negativos, falsos positivos y falsos negativos. En este caso, se aprecia que el modelo logra identificar de forma precisa los casos de deserción, manteniendo un bajo número de errores.

# Convertir a matriz si el modelo lo requiere
X_test_df <- as.matrix(X_test)
y_proba_test <- predict(model, X_test_df)
y_pred_test <- ifelse(y_proba_test > 0.5, 1, 0)

# Graficar matriz
plot_confusion_matrix(y_test, y_pred_test, "Matriz de Confusión (Test)")

Interpretación de resultados

Para comprender la importancia de las variables y su impacto en la predicción, se utilizó el método SHAP (SHapley Additive exPlanations).

  • En primer lugar, se muestra un gráfico de barras con las variables más relevantes seleccionadas por LightGBM, entre las que destacan: [aquí incluirás tus variables]. Este gráfico refleja la contribución promedio de cada variable al resultado del modelo.

  • Posteriormente, se presenta el gráfico de resumen de SHAP (shap.summary_plot(shap_values, X)), que combina la magnitud y la dirección del impacto. En el eje X se observa el efecto de cada variable en la probabilidad de deserción:

    • Valores positivos indican mayor propensión a desertar.
    • Valores negativos indican menor probabilidad de deserción.
    • El color azul representa valores bajos de la variable y el color fucsia/rojo intenso representa valores altos.

Este análisis permite no solo identificar las variables más influyentes, sino también entender cómo afectan la decisión final del modelo.

ggplot(importance_df, aes(x = reorder(Variable, Mean_SHAP), y = Mean_SHAP)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  coord_flip() +
  labs(title = "Importancia de variables (SHAP)",
       x = "Variable",
       y = "SHAP medio absoluto") +
  theme_minimal()

ggplot(shap_long, aes(x = SHAP, y = Variable, color = value)) +
  geom_jitter(height = 0.15, width = 0, size = 1.2, alpha = 0.8) +
 scale_color_gradientn(
  colors = c("blue", "magenta", "red"),
  values = scales::rescale(c(
    min(shap_long$value, na.rm = TRUE),
    quantile(shap_long$value, 0.49, na.rm = TRUE),  # casi medio
    quantile(shap_long$value, 0.51, na.rm = TRUE),  # casi medio
    max(shap_long$value, na.rm = TRUE)
  )),
  name = "Valor de la variable"
) +
  geom_vline(xintercept = 0, linetype = "dashed") +
  theme_minimal(base_size = 10) +
  labs(
    title = "Impacto de las variables en la predicción (SHAP)",
    x = "Valor SHAP (izquierda: reduce churn, derecha: aumenta churn)",
    y = "Variable"
  ) +
  theme(
    axis.text = element_text(size = 8),
    axis.title = element_text(size = 10),
    legend.text = element_text(size = 8),
    legend.title = element_text(size = 9),
    plot.title = element_text(size = 12)
  )
## Warning in regularize.values(x, y, ties, missing(ties), na.rm = na.rm):
## collapsing to unique 'x' values
## Warning in regularize.values(x, y, ties, missing(ties), na.rm = na.rm):
## collapsing to unique 'x' values
## Warning in regularize.values(x, y, ties, missing(ties), na.rm = na.rm):
## collapsing to unique 'x' values