Construyendo modelos de clasificación precisos y estables con R

Los árboles de decisión son un algoritmo de aprendizaje automático que permite clasificar o predecir una variable objetivo a partir de varias variables predictoras. Estos árboles se construyen mediante un proceso iterativo de selección de variables y partición de los datos en nodos y ramas. Los árboles de decisión son ampliamente utilizados en la industria para tareas de clasificación y regresión, como la segmentación de clientes, la detección de fraude y la diagnóstica médica.

Casos de uso de los árboles de decisión

Nota: Los casos de uso se enfocaran en el sector financiero, bancario y de seguros.

En la industria financiera:

  1. Segmentación de clientes: Los bancos pueden utilizar árboles de decisión para segmentar a sus clientes en base a sus características demográficas, historial de transacciones y comportamiento crediticio. Esto permite a los bancos personalizar sus productos y servicios para cada segmento de clientes y mejorar su rentabilidad.

  2. Detección de fraude: Los bancos también pueden utilizar árboles de decisión para detectar transacciones fraudulentas en tiempo real. Los árboles de decisión pueden ser entrenados con datos de transacciones legítimas y fraudulentas para identificar patrones y comportamientos sospechosos.

  3. Análisis de riesgo crediticio: Los bancos y las compañías financieras pueden utilizar árboles de decisión para evaluar el riesgo crediticio de sus clientes. Los árboles de decisión pueden ser entrenados con datos de historial crediticio, ingresos y garantías para determinar la probabilidad de impagos. Esto permite a las instituciones financieras tomar decisiones informadas sobre la concesión de créditos y los términos de los mismos.

En la industria de telecomunicaciones:

  1. Clasificación de llamadas: Las compañías de telecomunicaciones pueden utilizar árboles de decisión para clasificar las llamadas entrantes en diferentes categorías, como llamadas comerciales, llamadas de servicio al cliente y llamadas de emergencia. Esto permite a las compañías dirigir las llamadas a los departamentos y representantes adecuados, mejorando la eficiencia y la satisfacción del cliente.

  2. Análisis de uso de datos: Las compañías de telecomunicaciones también pueden utilizar árboles de decisión para analizar el uso de datos de sus clientes. Los árboles de decisión pueden ser entrenados con datos de uso de datos, ubicación y patrones de uso para identificar patrones de consumo y detectar posibles problemas de facturación. Esto permite a las compañías mejorar su oferta y servicio a los clientes.

En el coomercio minorista:

  1. Segmentación de clientes: Las empresas de comercio minorista pueden utilizar árboles de decisión para segmentar a sus clientes en base a sus comportamientos de compra, preferencias de productos y características demográficas. Esto permite a las empresas personalizar sus estrategias de marketing y mejorar la eficacia de sus campañas.

  2. Análisis de inventario: Las empresas de comercio minorista pueden utilizar árboles de decisión para analizar sus inventarios y tomar decisiones informadas sobre el nivel de inventario a mantener, cuándo reabastecer y qué productos pedir. Los árboles de decisión pueden ser entrenados con datos de ventas, tendencias de mercado y patrones de comportamiento del cliente para optimizar el inventario y reducir los costos.

¿Cómo funciona un árbol de decisión?

Los árboles de decisión utilizan una estrategia de divide y vencerás para representar una decisión y sus posibles consecuencias. El proceso comienza con una variable objetivo y un conjunto de variables predictoras, se utiliza un criterio para seleccionar la variable predictora que mejor divide los datos en relación a la variable objetivo.

Se repite el proceso en cada rama generada, creando nodos y ramas en el árbol. El proceso finaliza cuando se alcanzan ciertas condiciones, como un número máximo de niveles o un número mínimo de observaciones en un nodo. Los árboles de decisión son fáciles de interpretar y visualizar, pero pueden ser propensos a sobreajuste si no se realizan técnicas de poda para evitarlo.

¿Cómo construir un árbol de decisión con R?

R es un lenguaje de programación ampliamente utilizado en ciencia de datos y análisis estadístico, y tiene varios paquetes disponibles para construir árboles de decisión.

Uno de los paquetes más populares es “rpart” (Recursive Partitioning), que proporciona funciones para construir y visualizar árboles de decisión. El paquete también incluye funciones para realizar la poda de árboles y evaluar su precisión.

Otro paquete popular es “party” (Conditional Inference Trees) que proporciona un enfoque alternativo para construir árboles de decisión basado en la inferencia estadística. Este paquete también incluye funciones para la poda de árboles y la evaluación de su precisión.

En éste post se proporcionarán ejemplos de código para construir y visualizar un árbol de decisión usando estos paquetes y se discutirán las diferencias entre ambos.

Nota: El conjunto de datos utilizado esta disponible publicamente en Kaggle en el siguiente link https://www.kaggle.com/datasets/teertha/personal-loan-modeling

Codigo para el análisis

El primer paso para iniciar, es la carga de las librerías necesarias para el análisis, cada una de ellas cuenta con un muy breve comentario indicando cual es su finalidad:

# Cargar las librerías necesarias 
library(tidyverse) # Procesamiento de datos
library(readxl) # Lectura de archivos de excel
library(rpart) # Creación de árboles de decision
library(rattle)# visualiza arbol de decision
library(caret) # Machine learning
library(ggplot2) # Visualización
library(corrplot) # Correlacion
library(knitr) # generacion de tablas

Seguidamente se realizará la carga del conjunto de datos sobre el que se realizará el análisis. Para este ejemplo se cargará un conjunto de datos en formato csv (almacenado en la variable “data”) ubicado en el disco duro, sin embargo, desde R podemos cargar datos desde diferentes fuentes, incluyendo: Servidores de bases de datos, captura directa desde la web, datos de software como SPSS o SAS, archivos como csv, txt, Excel, pdf, entre otros.

Al completarse la carga de los datos, se mostrará un breve resumen de la carga realizada, indicando el numero de filas y columnas que contiene el archivo.

# Cargar el conjunto de datos
data <- read_csv("~/Proyectos/AI/R/Bank_Personal_Loan_Modelling.csv")
## Rows: 5000 Columns: 14
## -- Column specification --------------------------------------------------------
## Delimiter: ","
## dbl (14): ID, Age, Experience, Income, ZIP Code, Family, CCAvg, Education, M...
## 
## i Use `spec()` to retrieve the full column specification for this data.
## i Specify the column types or set `show_col_types = FALSE` to quiet this message.

Exploración inicial

Para realizar un análisis inicial de los datos podemos usar las siguientes funciones core de R:

“dim()” indica el numero de filas y columnas:

# Ver las dimensiones del conjunto de datos
dim(data) # Filas / Columnas
## [1] 5000   14

El conjunto de datos (a partir de aquí dataframe o df), se compone de 5,000 filas y 14 columnas.

La función “head()” mostrará las primeras n filas que indiquemos:

# Visualizar las primeras 5 filas del conjunto de datos
head(data, 5) # conjunto de datos, numero de filas a mostrar
## # A tibble: 5 x 14
##      ID   Age Experience Income `ZIP Code` Family CCAvg Education Mortgage
##   <dbl> <dbl>      <dbl>  <dbl>      <dbl>  <dbl> <dbl>     <dbl>    <dbl>
## 1     1    25          1     49      91107      4   1.6         1        0
## 2     2    45         19     34      90089      3   1.5         1        0
## 3     3    39         15     11      94720      1   1           1        0
## 4     4    35          9    100      94112      1   2.7         2        0
## 5     5    35          8     45      91330      4   1           2        0
## # ... with 5 more variables: Personal Loan <dbl>, Securities Account <dbl>,
## #   CD Account <dbl>, Online <dbl>, CreditCard <dbl>

Se observan las primeras n columnas del conjunto de datos, con el fin de conocer como se muestran los datos.

Otra función mas detallada para el conocimiento del df es “str()”, que detalla el tipo de datos y muestra los primeros 10 datos de cada columna:

str(data)
## spec_tbl_df [5,000 x 14] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ ID                : num [1:5000] 1 2 3 4 5 6 7 8 9 10 ...
##  $ Age               : num [1:5000] 25 45 39 35 35 37 53 50 35 34 ...
##  $ Experience        : num [1:5000] 1 19 15 9 8 13 27 24 10 9 ...
##  $ Income            : num [1:5000] 49 34 11 100 45 29 72 22 81 180 ...
##  $ ZIP Code          : num [1:5000] 91107 90089 94720 94112 91330 ...
##  $ Family            : num [1:5000] 4 3 1 1 4 4 2 1 3 1 ...
##  $ CCAvg             : num [1:5000] 1.6 1.5 1 2.7 1 0.4 1.5 0.3 0.6 8.9 ...
##  $ Education         : num [1:5000] 1 1 1 2 2 2 2 3 2 3 ...
##  $ Mortgage          : num [1:5000] 0 0 0 0 0 155 0 0 104 0 ...
##  $ Personal Loan     : num [1:5000] 0 0 0 0 0 0 0 0 0 1 ...
##  $ Securities Account: num [1:5000] 1 1 0 0 0 0 0 0 0 0 ...
##  $ CD Account        : num [1:5000] 0 0 0 0 0 0 0 0 0 0 ...
##  $ Online            : num [1:5000] 0 0 0 0 0 1 1 0 1 0 ...
##  $ CreditCard        : num [1:5000] 0 0 0 0 1 0 0 1 0 0 ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   ID = col_double(),
##   ..   Age = col_double(),
##   ..   Experience = col_double(),
##   ..   Income = col_double(),
##   ..   `ZIP Code` = col_double(),
##   ..   Family = col_double(),
##   ..   CCAvg = col_double(),
##   ..   Education = col_double(),
##   ..   Mortgage = col_double(),
##   ..   `Personal Loan` = col_double(),
##   ..   `Securities Account` = col_double(),
##   ..   `CD Account` = col_double(),
##   ..   Online = col_double(),
##   ..   CreditCard = col_double()
##   .. )
##  - attr(*, "problems")=<externalptr>

Para realizar un análisis descriptivo básico, puede utilizarse la función “summary()”, que devuelve las medidas de tendencia central esenciales para cada variable numerica en el df:

# Ver la información estadística básica de las variables numéricas
summary(data)
##        ID            Age          Experience       Income          ZIP Code    
##  Min.   :   1   Min.   :23.00   Min.   :-3.0   Min.   :  8.00   Min.   : 9307  
##  1st Qu.:1251   1st Qu.:35.00   1st Qu.:10.0   1st Qu.: 39.00   1st Qu.:91911  
##  Median :2500   Median :45.00   Median :20.0   Median : 64.00   Median :93437  
##  Mean   :2500   Mean   :45.34   Mean   :20.1   Mean   : 73.77   Mean   :93153  
##  3rd Qu.:3750   3rd Qu.:55.00   3rd Qu.:30.0   3rd Qu.: 98.00   3rd Qu.:94608  
##  Max.   :5000   Max.   :67.00   Max.   :43.0   Max.   :224.00   Max.   :96651  
##      Family          CCAvg          Education        Mortgage    
##  Min.   :1.000   Min.   : 0.000   Min.   :1.000   Min.   :  0.0  
##  1st Qu.:1.000   1st Qu.: 0.700   1st Qu.:1.000   1st Qu.:  0.0  
##  Median :2.000   Median : 1.500   Median :2.000   Median :  0.0  
##  Mean   :2.396   Mean   : 1.938   Mean   :1.881   Mean   : 56.5  
##  3rd Qu.:3.000   3rd Qu.: 2.500   3rd Qu.:3.000   3rd Qu.:101.0  
##  Max.   :4.000   Max.   :10.000   Max.   :3.000   Max.   :635.0  
##  Personal Loan   Securities Account   CD Account         Online      
##  Min.   :0.000   Min.   :0.0000     Min.   :0.0000   Min.   :0.0000  
##  1st Qu.:0.000   1st Qu.:0.0000     1st Qu.:0.0000   1st Qu.:0.0000  
##  Median :0.000   Median :0.0000     Median :0.0000   Median :1.0000  
##  Mean   :0.096   Mean   :0.1044     Mean   :0.0604   Mean   :0.5968  
##  3rd Qu.:0.000   3rd Qu.:0.0000     3rd Qu.:0.0000   3rd Qu.:1.0000  
##  Max.   :1.000   Max.   :1.0000     Max.   :1.0000   Max.   :1.0000  
##    CreditCard   
##  Min.   :0.000  
##  1st Qu.:0.000  
##  Median :0.000  
##  Mean   :0.294  
##  3rd Qu.:1.000  
##  Max.   :1.000

También puede aplicarse a nivel de variables individuales, por ejemplo para la variable “Age”:

# Ver la información estadística básica de la variable "Age"

summary(data$Age) #el simbolo "$" se utiliza para llamar una variable dentro del df
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   23.00   35.00   45.00   45.34   55.00   67.00

Visualización de datos iniciales

Podemos crear un boxplot para poder visualizar la forma de una variable especifica con la función boxplot():

# crear boxplot con datos de una variable 
# para facilitar la comprensión del codigo, se comenta cada parametro

boxplot(data = data, # define el conjunto de datos a utilizar 
        Age ~ Family, # define las variables y (Age) y x (Family) respectivamente 
        main="Ejemplo de boxplot (R base)", # titulo del gráfico
        xlab="Variable x (Family)", # titulo del eje x
        ylab="Variable y (Age)", # titulo del eje y 
        col = "lightblue" # color por aplicar al gráfico
        )

El gráfico generado muestra en el eje x el numero de miembros de la familia y el eje y la edad de los clientes, pudiendo comparar la forma para cada grupo de clientes (definido por el tamaño de la familia).

Para visualizar un scatter plot podemos utilizar la función plot() y definir los parametros para visualización:

# crear Scatterplot con datos de una variable
plot(data$Age, # define la variable x
     data$Income, # define la variable y
     main = "Ejemplo de Scatterplot (R base)", # titulo del gráfico
     xlab = "Variable X (Age)",  # titulo del eje x
     ylab = "Variable Y (Income)", # titulo del eje y 
     col = "darkgreen" # color por aplicar al gráfico
     )

Para continuar con el análisis es necesario renombrar las variables al formato recomendado para los nombres de variables en R, para este fin utilizaremos la función “rename()”.

En este caso las variables a renombrar se observan a la derecha del signo “=” y el nuevo nombre al lado izquierdo de éste signo, como se muestra continuación:

# renombrar las variables a formato de R (nombre_variable o nombreVariable)

data <- rename(data, # nombre del df
               personal_loan = `Personal Loan`, # variables a renombrar separadas por comas 
               zip_code = `ZIP Code`,
               securities_account = `Securities Account`,
               cd_account = `CD Account`
               )

A partir de este punto el enfoque será la construcción del arbol de decisiones para determinar si un cliente tomaría un prestamo personal o no.

Partiendo de los valores de la variable, observamos que se trata de una variable binaria o dicotomica (pudiendo tomar uno de dos posibles valores de respuesta), ésta variable en el conjunto de datos actual indica si un cliente tomó (1) o no tomó (0) un prestamo personal, siendo la variable obejtivo que utilizaremos en los proximos pasos para entrenar al arbol de decisiones.

Continuamos analizando la distribución de la variable objetivo, en este caso la variable “personal_loan”:

# Ver la distribución de la variable objetivo "Personal Loan"
table(data$personal_loan)
## 
##    0    1 
## 4520  480

El resultado de la función “table()”, muestra la distribución de la variable “personal_loan”, observado que 4,520 (valor 0) clientes no tomaron un préstamo personal y 480 (valor 1) clientes tomaron un préstamo.

Para conocer la proporción de respuestas podemos realizarlo con un calculo simple, observado que el 9.6% de clientes son quienes tomaron un prestamo personal:

# Ver la distribución porcentual de la variable objetivo "Personal Loan"
table(data$personal_loan) * 100 / length(data$personal_loan)
## 
##    0    1 
## 90.4  9.6
# la función "length" devuelve el largo (numero de filas) de la variable seleccionada 

Con los datos anteriores se observa que el análisis se realizará sobre un cojunto de datos desbalanceado, ya que la clase minoritaría es menor al 10% del conjunto de datos, siendo esta clase los clientes que tomaron un préstamo personal. Los efectos de éste punto se ampliará posteriormente.

Continuando el análisis, podemos centrarnos en el efecto de las variables predictoras sobre la variable objetivo de éste caso. Iniciaremos explorando la variable de ingresos (Income):

# Ver la relación entre la variable objetivo "personal_loan" y la variable "Income"

boxplot(data = data, 
        Income ~ personal_loan, 
        main="Tomó prestamo personal - Income",
        xlab="Tomó prestamo personal", 
        ylab="Variable Income", 
        col = "lightblue" 
        )

Se observa que la mediana de ingresos (Income) de los clientes que tomaron prestamos es de 142.5 y la media de ingresos es de 144.75, valores que podemos comprobar con el siguiente código (con sintaxis de tidyverse):

data %>% # df de origen
  select(c(Income, personal_loan)) %>% # selecciona las columnas a utilizar
  group_by(personal_loan) %>%  # agrupa por las etiquetas de personal_loan
  summarise(median(Income), # calcula la mediana de ingresos para cada grupo
            mean(Income)) # calcula la media de ingresos para cada grupo
## # A tibble: 2 x 3
##   personal_loan `median(Income)` `mean(Income)`
##           <dbl>            <dbl>          <dbl>
## 1             0              59            66.2
## 2             1             142.          145.

Seguimos con el resto de variables que componen el conjunto de datos:

# Ver la relación entre la variable objetivo "personal_loan" y la variable "Age"

boxplot(data = data, 
        Age ~ personal_loan, 
        main="Tomó prestamo personal - Age",
        xlab="Tomó prestamo personal", 
        ylab="Variable Age", 
        col = "lightblue" 
        )

# Ver la relación entre la variable objetivo "personal_loan" y la variable "Experience"

boxplot(data = data, 
        Experience ~ personal_loan, 
        main="Tomó prestamo personal - Experience",
        xlab="Tomó prestamo personal", 
        ylab="Variable Experience", 
        col = "lightblue" 
        )

# Ver la relación entre la variable objetivo "personal_loan" y la variable "Family"

boxplot(data = data, 
        Family ~ personal_loan, 
        main="Tomó prestamo personal - Family",
        xlab="Tomó prestamo personal", 
        ylab="Variable Family", 
        col = "lightblue" 
        )

# Ver la relación entre la variable objetivo "personal_loan" y la variable "CCAvg"

boxplot(data = data, 
        CCAvg ~ personal_loan, 
        main="Tomó prestamo personal - CCAvg",
        xlab="Tomó prestamo personal", 
        ylab="Variable CCAvg", 
        col = "lightblue" 
        )

# Ver la relación entre la variable objetivo "personal_loan" y la variable "Mortgage"

boxplot(data = data, 
        Mortgage  ~ personal_loan, 
        main="Tomóprestamo personal - Mortgage ",
        xlab="Tomó prestamo personal", 
        ylab="Variable Mortgage ", 
        col = "lightblue" 
        )

Con los datos obtenidos observamos, para los clientes que tomaron un prestamo personal que:

  1. La media de ingresos anuales es de 144.75K
  2. La media de edad de los clientes es de 45.07 años
  3. La experiencia profesional media es de 19.84 años
  4. El tamaño medio de la familia es de 2.61 miembros
  5. La media del consumo mensual medio con tarjeta de crédito es de 3.91K
  6. El valor medio de la hipoteca es de 100.85K

Analisis de correlaciones

Seguidamente podemos revisar las posibles correlaciones entre las variables del df con el siguiente codigo:

# Calcular las correlaciones entre las variables numéricas
cor_matrix <- cor(data[ ,sapply(data,is.numeric)]) # toma unicmaente variables numericas

# Crear el mapa de calor
corrplot(cor(cor_matrix),        # matiz de correlación
         method = "number", # Metodo del grafico de correlación
         type = "upper",    # Estilo de la matriz de correlación
         diag = TRUE,      # si es TRUE (default) agrega la diagonal
         tl.col = "black", # color de las etiquetas
         tl.cex=0.5, # tamaño de las etiquetas
         tl.srt=70, # grados de rotación
         number.cex = 0.6, # tamaño de los coeficientes
         bg = "white",     # color de fondo
         title = "Matriz de correlación", # titulo del grafico
         col = NULL)       # paleta de color

Del grafico de calor generado con la matriz de correlación observamos que:

  1. Existe correlación positiva perfecta entre las variables Edad y Experiencia.
  2. Existe correlación positiva fuerte entre las variables Ingresos y consumo medio mensual con tarjeta de crédito.
  3. Existe correlación positiva fuerte entre las variables Ingresos y Toma prestamo.
  4. Existe correlación positiva fuerte entre las variables consumo medio mensual con tarjeta de crédito y Toma prestamo.

Entrenamiento del modelo de ML

Procedemos a preparar los datos para crear el modelo de aprendizaje automatico. Iniciamos transformando la variable objetivo, convirtiendo de numerico a factor (categoría).

Nota: Los factores son un tipo de datos en R, esencialmente vectores de valores categoricos.

# convertir la variable objetivo de numerico a factor 

data$personal_loan <- as.factor(data$personal_loan) # función para transformar a factor los valores de la variable dada

levels(data$personal_loan) = c("No", "Yes") # asigna los nuevos niveles (valores): 0 = No, 1 = Si

levels(data$personal_loan) # muestra los nuevos valores de la variable
## [1] "No"  "Yes"
# convertir la variable education de numerico a factor 

data$Education <- as.factor(data$Education) # función para transformar a factor 
levels(data$Education) = c("Basico", "Medio", "Alto") # asigna los nuevos niveles 

Dividimos el conjunto de datos, para el modelado es necesario definir el conjunto de datos de entrenamiento (datos sobre los que se realiza el analisis inicial) y datos de prueba (datos que el modelo no conoce y utilizaremos para probar el modelo entrenado y evaluar su rendimiento).

# eliminar la variable "ID" ya que no es predictora
data <- data %>% select(-c(ID))

# establecemos la semillla aleatoria para poder replicar el proceso (no requerido en producción)
set.seed(22)

# dividir datos en entrenamiento y prueba
index <- createDataPartition(data$personal_loan, # df de origen
                             p = 0.8,  # tamaño del df de entrenamiento (80%)
                             list = FALSE) # no se genera como lista

# asigna los datos a los nuevos df 
train_data <- data[index, ] # asigna el conjunto de entrenamiento
test_data <- data[-index, ] # asigna el conjunto de prueba

Creamos una malla de parametros de prueba, estos parametros crearan multiples escenarios para el entrenamiento de modelos con el objetivo de encontrar el que genere el mejor rendimiento.

# especificar control de entrenamiento y grid de búsqueda
fitControl <- trainControl(method = "cv", # metodo a usar: cross validation
                           number = 10,  # numero de validaciones 
                           classProbs = TRUE) # devuelve la probabiilidad para cada clase (compra o no compra)

grid_search <- expand.grid(cp = c(0.001, 0.01, 0.1, 0.2)) # el argumento cp especifica el criterio de poda

Creamos el modelo de arbol de decisión con los parametros previamente establecidos para iniciar su entrenamiento:

# entrenar modelo y buscar mejores parametros
rpart_model <- train(personal_loan ~ ., # variable objetivo dado (~) todas las variables (.)
                     data = train_data, # df que contiene los datos de entrenamiento
                     method = "rpart",  # librería a utilizar
                     metric = "Accuracy", # metrica para seleccinar el mejor rendimiento
                     trControl = fitControl, # parametros de control
                     tuneGrid = grid_search) # parametros de mejora

Una vez entrenado el modelo, ejecutamos predicciones sobre el df de prueba para validar las metricas del modelo:

# hace predicciones en el conjunto de prueba y almacenar en la variable predictions

predictions <- predict(rpart_model, # modelo entrenado
                       newdata = test_data, # df donde se ejecutaran las predicciones
                       method = "class") # metodo: class para modelos de clasificación

Evaluación del modelo entrenado

Creamos la matriz de confusión (informe de clasificación) para ver las metricas del modelo sobre los datos de prueba:

# crear matriz de confusión
confusionMatrix(predictions, # df con resultados de predicciones
                test_data$personal_loan # variable del df que contiene los datos reales (tomó o no el prestamo)
                )
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction  No Yes
##        No  900  10
##        Yes   4  86
##                                           
##                Accuracy : 0.986           
##                  95% CI : (0.9766, 0.9923)
##     No Information Rate : 0.904           
##     P-Value [Acc > NIR] : <2e-16          
##                                           
##                   Kappa : 0.917           
##                                           
##  Mcnemar's Test P-Value : 0.1814          
##                                           
##             Sensitivity : 0.9956          
##             Specificity : 0.8958          
##          Pos Pred Value : 0.9890          
##          Neg Pred Value : 0.9556          
##              Prevalence : 0.9040          
##          Detection Rate : 0.9000          
##    Detection Prevalence : 0.9100          
##       Balanced Accuracy : 0.9457          
##                                           
##        'Positive' Class : No              
## 

Del informe mostrado observamos que el modelo tiene:

  1. Accuracy de 98.6%
  2. Recall o Sensitivity de 99.56% siendo este indicador importante al tratarse de un df desbalanceado, mide que tan bien se detecta la probabilidad de tomar el prestamo (prediccion de que si toma y que en realidad tomó el prestamo).
  3. Specificity o Precision de 89.58%
  4. Detection Prevalence o F1 Score de 91.0% siendo importante al tratarse de un df desbalanceado.

Conceptos de metricas de rendimiento del modelo

Para entender de mejor manera estos indicadores, se describen brevemente a continuación:

  • Accuracy: Es la proporción de predicciones correctas en relación a todas las predicciones realizadas. Es una medida común de rendimiento en problemas de clasificación, pero puede ser engañosa en casos donde las clases están desequilibradas.

  • Sensitivity (también conocida como tasa de verdaderos positivos): Es la proporción de verdaderos positivos (es decir, casos positivos correctamente identificados) en relación a todos los casos positivos.

  • Specificity (también conocida como tasa de verdaderos negativos): Es la proporción de verdaderos negativos (es decir, casos negativos correctamente identificados) en relación a todos los casos negativos.

  • Detection Rate (también conocida como tasa de detección): Es la proporción de casos positivos correctamente identificados en relación a todos los casos positivos verdaderos (incluyendo aquellos correctamente e incorrectamente identificados).

  • Detection Prevalence (también conocida como prevalencia de detección): Es la proporción de casos positivos verdaderos (incluyendo aquellos correctamente e incorrectamente identificados) en relación a todos los casos.

  • Balanced Accuracy: Es la media aritmética de la sensibilidad y la especificidad. Es una medida de rendimiento que tiene en cuenta tanto la capacidad de detectar casos positivos como la capacidad de excluir casos negativos.

  • Kappa: Es una medida de rendimiento que tiene en cuenta tanto la precisión global del modelo como el nivel de desequilibrio entre las clases. Es útil para evaluar el rendimiento de un modelo en problemas con desequilibrio de clase.

El rendimiento del modelo puede considerarse adecuado una vez observado su rendimiento.

Visualización del arbol de decisión entrenado

Seguidamente podemos visualizar el arbol de decisión entrenado para conocer el proceso de decisiones aplicado:

# Visualizar el árbol de decisión
fancyRpartPlot(rpart_model$finalModel)

Importancia de las variables predictivas o feature importances

Para un detalle mas especifico de las variables predictoras consideradas por el modelo entreando, podemos generar un resumen de la importancia (peso) de cada variable:

# Obtener las importancias de las variables
x <- varImp(rpart_model, # modelo a analizar
            scale = F) #scale: Falso: pesos netos, Verdadero: pesos acumulados

# generamos visualización de las 10 principales variables
plot(x, top = 10)

Partiendo del grafico anterior observamos que las principales variables predictivas son:

  1. Nivel de educación Medio
  2. Ingresos (Income)
  3. Nivel de educación Alto
  4. Posee un certificado de deposito (cd_account)
  5. El consumo medio mensual con tarjeta de crédito

Los pesos predictivos acumulados de cada variable se observan a continuación:

x1 <- varImp(rpart_model, # modelo a analizar
            scale = T)

x1 <- data.frame(x1[1:1])
x1 <- x1 %>% arrange(desc(Overall)) 

kable(x1, 
      caption = "Importancia de variables",
      format = "html") 
Importancia de variables
Overall
EducationMedio 100.0000000
Income 88.3737299
EducationAlto 81.5985804
cd_account 63.1325808
CCAvg 58.3181036
Family 58.0022246
Mortgage 11.1016823
Age 4.7443106
Experience 3.3878982
Online 2.4198093
zip_code 1.7550433
securities_account 0.0990808
CreditCard 0.0000000

Guardado y carga posterior del modelo

Por ultimo guardamos el modelo entrenado para su uso posterior:

# Guardar el modelo de árbol de decisión
save(rpart_model, # nombre del modelo entrenado
     file = "arbol_dec_prestamo.rda"  # nombre con el que se guarda el modelo
     ) 

# el modelo se guardará en la carpeta donde se encuentra el script de R, excepto que se defina una ruta diferente

Para un uso posterior, cargamos el modelo entrenado con el siguiente codigo:

# Cargar el modelo de árbol de decisión
load("arbol_dec_prestamo.rda")

Predicción sobre nuevos datos

Cargamos datos nuevos para ejecutar predicciones (en caso de producción):

# Aplicar el modelo a nuevos datos
new_data <- read.csv("nuevos_datos_pred.csv", sep = ";")

# guarda variable ID en df aparte
ids <- new_data$ID

# Elimina variable ID (no requerida)
new_data <- new_data %>% select(-c(ID))

# transforma variables a factor
new_data$Education <- as.factor(new_data$Education) # función para transformar a factor 
levels(new_data$Education) = c("Basico", "Medio", "Alto") # asigna los nuevos niveles 

# ejecuta predicciones
new_predictions <- predict(rpart_model, # nombre del modelo
                           new_data,  # df con datos a predecir
                           type = "prob") # raw: si/no, prob: prob si/no

# pegar probabilidad de Si tomar el prestamo
new_data$Prob_yes <- new_predictions$Yes  

# agregamos los ID al df
new_data$ID <- ids

# tomar solo ID y probabildiad
new_data <- new_data %>% 
  select(ID, Prob_yes) %>% 
  round(3)


# Visualizamos los primeros 10 clientes y su probabildiad de tomar prestamo
kable(head(new_data), 
      caption = "Predicciones de tomar prestamo",
      format = "html") 
Predicciones de tomar prestamo
ID Prob_yes
3131 0.004
2360 0.952
1852 0.004
3710 0.004
1318 0.004
4151 0.004

Con esto conluye el proceso de entrenamiento, prueba, evalución, guardado y carga del modelo de machine learning con arbol de decisiñon en R.

Ventajas y desventajas de los arboles de decisión

Los árboles de decisión son un algoritmo de aprendizaje automático ampliamente utilizado en la industria debido a sus ventajas y facilidad de uso. Algunas de las principales ventajas son:

  • Fácil de entender y explicar: Los árboles de decisión son fáciles de entender y explicar, ya que representan las decisiones y las reglas utilizadas para clasificar los datos de forma gráfica y sencilla. Esto los hace ideales para tomar decisiones en aplicaciones críticas, como el riesgo crediticio, la atención médica y la seguridad.

  • No requieren una gran cantidad de datos para entrenar: Los árboles de decisión pueden ser entrenados con una pequeña cantidad de datos y son capaces de manejar datos de alta dimensión, lo que los hace ideales para problemas con pocos datos.

  • No requieren una gran cantidad de preparación de datos: Los árboles de decisión son menos sensibles a los cambios de escala y no requieren una gran cantidad de preprocesamiento de datos, lo que los hace ideales para problemas con datos no estandarizados.

Sin embargo, también existen algunas desventajas al utilizar árboles de decisión:

  • Sensibles a ruido en los datos: Los árboles de decisión son sensibles al ruido en los datos y pueden generar soluciones complejas y difíciles de interpretar.

  • Sobreajuste: Los árboles de decisión tienen un alto riesgo de sobreajuste, especialmente cuando se utilizan muchas variables y se permite una profundidad muy grande.

  • Problemas con datos continuos: Los árboles de decisión no manejan bien los datos continuos y requieren discretizar los datos para poder utilizarlos.

En resumen, los árboles de decisión son una herramienta poderosa para la clasificación y la toma de decisiones, pero también tienen limitaciones y pueden requerir técnicas adicionales para prevenir el sobreajuste y mejorar la interpretabilidad.

Conclusiones

En este post se ha discutido el uso de árboles de decisión en R para clasificar si un cliente pagará o no un préstamo. Se ha presentado un ejemplo de código utilizando el paquete rpart para entrenar un modelo y hacer predicciones. Además, se han discutido técnicas para optimizar el rendimiento del modelo, como la poda, el ajuste de parámetros, la selección de variables, bagging y Random Forest, y la evaluación del modelo.

Es importante mencionar que los arboles de decision son una herramienta muy util en la toma de decisiones y para la clasificación de datos, pero también tienen sus limitaciones y pueden requerir técnicas adicionales para prevenir el sobreajuste y mejorar la interpretabilidad. Para obtener más información sobre árboles de decisión en R, se recomienda revisar la documentación de los paquetes rpart, caret y tidyverse, así como tutoriales en línea sobre el tema.

Algunos datos de contacto para obtener más información sobre árboles de decisión y R podrían consutar:

Además, si usted desea contactarme directamente, puede hacerlo a través de mi correo electrónico rafmesal@gmail.com

Saludos!

Rafael Mejía

email: rafmesal@gmail.com