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:
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.
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.
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.
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.
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.
En primer lugar, se presenta la base de datos completa para que el usuario pueda revisarla visualmente y conocer su estructura inicial.
## # 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)
)
}## Variables con valores nulos: 76
## 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.
## 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).
## 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.
## 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%.
## Lista de columnas a eliminar:
## - 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.
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.
## # 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.
## 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.
## 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
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.
## [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"
)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.
## KMO general del modelo: 0.791
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:
Criterio de Kaiser (λ > 1): Se retienen únicamente los factores cuyo valor propio (eigenvalor) es mayor que 1.
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:
##
## Método de Kaiser: 24 factores (λ > 1)
Segundo método:
## [1] 18
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.
## 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
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.
## Variables con valores nulos: 49
## 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.
## [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).
## # 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:
##
## 0 1
## 219 219
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.
Entrenamiento
En la fase de entrenamiento, se obtuvieron las métricas de
precision, recall, f1-score y
support.
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
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)")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:
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