Introducción y Procesamiento de Datos

Author

Juan Isaula

Introducción y Preprocesamiento de Datos

Este capítulo comienza con una introducción general a los modelos de riesgo crediticio. Exploraremos un conjunto de datos de la vida real y luego procesaremos previamente el conjunto de datos para que esté en el formato apropiado antes de aplicar los mdelos de riesgo crediticio.

¿Qué es el incumplimiento del Préstamo?

El área de modelado del riesgo crediticio tiene que ver con el caso de incumplimiento del préstamo. Ahora bien, ¿qué es incumplimiento de un préstamo? Cuando un banco concede un préstamo a un prestatario, que podría ser un individuo o una empresa, el banco normalmente transferirá el monto total del préstamo al prestatario.

Luego, el prestatario reembolsará esta cantidad en partes más pequeñas, incluidos algunos pagos de interes, con el tiempo. Por lo general, estos pagos se realizan mensualmente, trimestralmente o anualmente. Por supuesto, existe un cierto riesgo de que el prestatario no pueda reembolsar completamente este préstamo. Esto resulta en una pérdida para el banco.

Componentes de la pérdida esperada (EL)

La pérdida esperada en la que incurrá un banco se compone de tres elementos:

  • La probabilidad de incumplimiento (PI), que es la probabilidad de que el prestatario no pueda pagar la totalidad del préstamo.

  • Exposición en caso de incumplimiento (EXI), que es el valor esperado del préstamo en el momento de incumplimiento. También puede considerarse esto como el monto del préstamo que aún debe reembolsarse en el momento del incumplimiento.

  • La pérdida en caso de incumplimiento (PEI), expresado como porcentaje de la exposición en caso de incumplimiento.

Multiplicando estos tres elementos se obtiene la fórmula de pérdida esperada.

\[ EL = PI\times EXI\times PEI \]

En este curso nos centraremos en la probabilidad de incumplimiento.

Información utilizada por los Bancos

Los bancos mantiene información sobre el comportamiento de incumplimiento de clientes anteriores, que puede usarse para predecir el incumplimiento de nuevos clientes. A grandes rasgos, esta información se puede clasificar en dos tipos:

  • Información de la Aplicación

    • Ejemplos de información de la solicitud son los ingresos, el estado civil, etc.
  • Información de comportamiento

    • Este tipo de información rastrea el comportamiento pasado de los clientes, por ejemplo, el saldo de la cuenta actual y el historial de pagos atrasados.

Echemos un vistazo a las primeras diez lineas de nuestro conjunto de datos.

loan_data <- readRDS("C:/Users/juani/OneDrive/Documentos/2023/Ficohsa/libro_curso_ficohsa/loan_data_ch1.rds") 
head(loan_data,10)
   loan_status loan_amnt int_rate grade emp_length home_ownership annual_inc
1            0      5000    10.65     B         10           RENT      24000
2            0      2400       NA     C         25           RENT      12252
3            0     10000    13.49     C         13           RENT      49200
4            0      5000       NA     A          3           RENT      36000
5            0      3000       NA     E          9           RENT      48000
6            0     12000    12.69     B         11            OWN      75000
7            1      9000    13.49     C          0           RENT      30000
8            0      3000     9.91     B          3           RENT      15000
9            1     10000    10.65     B          3           RENT     100000
10           0      1000    16.29     D          0           RENT      28000
   age
1   33
2   31
3   24
4   39
5   24
6   28
7   22
8   22
9   28
10  22

Este conjunto de datos contiene información sobre préstamos anteriores. Cada fila representa un cliente y su información, junto con un indicador del estado del préstamo, que equivale a 1 si el cliente incumplió y 0 si el cliente no incumplió. El estado del préstamo se utilizará como variable de respuesta, y las variables explicativas son:

  • monto del préstamo (loan_amnt),

  • la tasa de interés (int_rate),

  • el grado (grade),

  • la duración del empleo (emp_length),

  • el estado de propiedad de la vivienda (home_ownership),

  • el ingreso anual (annual_inc) y

  • la edad (age). El grado es el puntaje del cliente, donde

    • A: indica la clase más alta de solvencia

    • G: la mas baja

Esta puntuación de la oficina refleja el historial de crédtio del individuo y es la única variable de comportamiento en el conjunton de datos.

Tabla Cruzada

Para obtener una descripción general de la estructura de datos de variables categóricas, puede utilizar la función CrossTable() perteneciente al paquete gmodels

library(gmodels) 
Warning: package 'gmodels' was built under R version 4.3.1

Aplicando esta función a la variable home_ ownership y se obtiene una tabla con cada una de las categorías de esta variable, con el número de casos y proporciones.

CrossTable(loan_data$home_ownership)

 
   Cell Contents
|-------------------------|
|                       N |
|         N / Table Total |
|-------------------------|

 
Total Observations in Table:  29092 

 
          |  MORTGAGE |     OTHER |       OWN |      RENT | 
          |-----------|-----------|-----------|-----------|
          |     12002 |        97 |      2301 |     14692 | 
          |     0.413 |     0.003 |     0.079 |     0.505 | 
          |-----------|-----------|-----------|-----------|



 

Utilizando el estado del préstamo como segundo argumento, se puede observar la relación entre esta varianle de factor y la respuesta. Al establecer la propiedad prop.r en TRUE y las demás proporciones enumeradas aquí en FALSE, se obtienen las proporciones por filas.

CrossTable(loan_data$home_ownership, loan_data$loan_status, 
           prop.r = TRUE,            
           prop.c = FALSE,
           prop.t = FALSE,
           prop.chisq = FALSE)

 
   Cell Contents
|-------------------------|
|                       N |
|           N / Row Total |
|-------------------------|

 
Total Observations in Table:  29092 

 
                         | loan_data$loan_status 
loan_data$home_ownership |         0 |         1 | Row Total | 
-------------------------|-----------|-----------|-----------|
                MORTGAGE |     10821 |      1181 |     12002 | 
                         |     0.902 |     0.098 |     0.413 | 
-------------------------|-----------|-----------|-----------|
                   OTHER |        80 |        17 |        97 | 
                         |     0.825 |     0.175 |     0.003 | 
-------------------------|-----------|-----------|-----------|
                     OWN |      2049 |       252 |      2301 | 
                         |     0.890 |     0.110 |     0.079 | 
-------------------------|-----------|-----------|-----------|
                    RENT |     12915 |      1777 |     14692 | 
                         |     0.879 |     0.121 |     0.505 | 
-------------------------|-----------|-----------|-----------|
            Column Total |     25865 |      3227 |     29092 | 
-------------------------|-----------|-----------|-----------|

 

Ahora bien, ¿qué te dice este resultado? Parece que la tasa de impago en el grupo de propietario de vivientas OTHER es bastante mayor que la tasa de impago en, por ejemplo, el grupo de propietarios de vivienda MORTAGE (hipoteca), con 17.5% frente a 9.8% de impagos en estos grupos respectivamente.

Histograma y Valores atípicos

Ahora veamos algunas variables continuas usando histogramas y gráficos.

Función hist()

Para un histograma básico, llamas a la función hist() con la variable de interés, en este caso, tasa de interés.

hist(loan_data$int_rate, main = "Histograma de tasas de interés", xlab = "Tasa interes")

Aquí puede ver que todos los préstamos tenían una tasa de interés superior al 5% y muy pocos préstamos tenían una tasa de interés superir al 20%.

Echemos un vistazo al histograma de ingresos anuales.

hist(loan_data$annual_inc, xlab = "Ingreso anual", main = "Histograma de ingresos anuales")

Notamos que aquí obtenemos un resultado extraño, aparentemente con solo una barra grande.

Al almacenar el histograma en hist_Income y utilizar las rupturas del signo del dólar, obtenemos información sobre la ubicación de las rupturas del histogram,a. Para tener una idea clara de la estructura de datos,

hist_income <- hist(loan_data$annual_inc, xlab = "Ingrso anual",          
                    main = "Histograma ingreso anual") 

hist_income$breaks
 [1]       0  500000 1000000 1500000 2000000 2500000 3000000 3500000 4000000
[10] 4500000 5000000 5500000 6000000

Argumento breaks

puede cambiar el número de pausas utilizando el argumento de pausas, de modo que obtenga un gráfico más intuitivo. Esto se puede hacer eligiendo un número que parezca más apropiado o utilizando una regla general, como la raíz cuadrada del número de observaciones en el conjunto de datos.

n_breaks <- sqrt(nrow(loan_data)) 
hist_income_n <- hist(loan_data$annual_inc,            
                      breaks = n_breaks,
                      xlab = "Ingreso anual",              
                      main = "Histograma de ingreso anual")

Esto da como resultado un vector de rupturas mucho más largo. Sin embargo, el resultado aquí todavia no se ve muy bien, con mucho espacio en blanco. el eje x del histograma oscila automáticamente desde el valor observado más pequeño hasta el más grande.

anual_inc

Veamos u histograma de dispersión para ver que esta pasando.

plot(loan_data$annual_inc, ylab = "Ingreso anual")

En este gráfico el ingreso anual se muestra en el eje y, y el número indice de la observación se muestra en el eje x.

Veamos que hay un salario enorme de 6 millones y ninguno de los otros supera los 2 millones. Entonces consideramos que este es un caso atípico.

Valores atípicos

En estadística, un valor atípico es una observación que está anormalmente distante de otros valores. Pero ¿cuándo una distancia es anormal? En general, los cientificos de datos utilizaran su criterio de experto, reglas generales o una combinación de ambos.

Juicio de Experto

Se podría utilizar el juicio de expertos si el cientifico de datos se considera un experto en el ámbito de la modelización del riesgo crediticio. Entonces puede juzgar que un salario anual superior a, digamos, 3 millones de dólares debe ser un error y debe eliminarse del conjunto de datos.

index_outlier_expert <- which(loan_data$annual_inc > 3000000) 
loan_data_expert <- loan_data[-index_outlier_expert,]

Si un cientifico de datos quiero confiar en una regla general, podría eliminar todos los valores que sean mayores o menores que 1.5 veces el rango intercuantil, que es el rango entre el primer y tercer cuartil de la distribución de la variable. Como aquí no se produjeron valores atípicos en el rango negativo, solo eliminamos los que se encuentran en el rango positivo.

\[ Q_3 + 1.5\times IQR \]

outlier_cutoff <- quantile(loan_data$annual_inc, 0.75) + 1.5*IQR(loan_data$annual_inc)  
index_outlier_ROT <- which(loan_data$annual_inc > outlier_cutoff)  
# Remove outliers
loan_data_ROT <- loan_data[-index_outlier_ROT,]

Histogramas

Después de eliminar los valores atípicos, obtiene los siguientes resultados.

hist(loan_data_expert$annual_inc,       
     sqrt(nrow(loan_data_expert)),      
     xlab = "Ingresos anuales")

hist(loan_data_ROT$annual_inc,    
     sqrt(nrow(loan_data_ROT)),   
     xlab = "Ingresos Anuales")

Estos resultados son más informativos que los iniciales, incluidos los valores atípicos, especialmente el histograma que se construyo utilizando la regla general. Tenga en cuenta que se eliminaron bastantes observaciones utilizando esta regla general. Incluso si no planea omitir estos valores atípicos en su análisis, podría resultar útil eliminarlos temporalmente al visualizar los datos.

Gráfico bivariado

Concluyamos mirando un gráfico bivariado. Cuando incluye una segunda variable en la función plot(), el primer argumento se trazará en el eje x y el segundo argumento en el eje y. Aquí se muestra un gráfico bivariado para la duración del empleo y los ingresos anuales.

plot(loan_data$emp_length, loan_data$annual_inc,    
     xlab = "Duración de empleo",
     ylab = "Ingresps anuales")

Echar un vistazo a los gráficos bivariados puede resultar interesante para realizar un seguimiento de los valores atípicos bivariados, que son valores atípicos en dos dimensiones de los datos.

Para la combinación trazada aquí, solo vemos un valor atípico en la escala de ingresos anuales y no en la duración del empleo.

Datos Faltantes y Clasificación Aproximada

Antes de entrar en materia eliminemos del conjunto de datos la observación que contiene un valor atípico bivariado para la edad y el ingreso anual.

index_highage <- which(loan_data$age>122)
new_data <- loan_data[-index_highage, ]

Entradas Faltantes

Lo que no hemos discutido antes es respecto a los datos faltantes (o NA, que significa no disponible) para dos variables: duración de empleo y tasa de interés. Mostraré algunos métodos para manejar datos faltantes sobre la variable de duración de empleo.

Lo primero que tiene que saber es cuántas entradas faltan, ya que esto afectará lo que haga con ellas. Una forma sencilla de averiguarlo es con la función summary().

summary(loan_data$emp_length)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
  0.000   2.000   4.000   6.145   8.000  62.000     809 

Note que existen 809 NA.

Estrategías: Insumos faltantes

Generalmente existen tres formas de tratar las entradas faltantes:

  • eliminarlas,

  • reemplazarlas

  • conservarlas

Ilustremos estos métodos sobre la variable de duración del empleo. Al eliminar, puede eliminar las observaciones en las que se detectan entradas faltantes o eliminar una variable completa. Por lo general, solo querrá eliminar observaciones si solo hay una pequeña cantidad de entradas y solo considerará eliminar una variable completa cuando falten muchos casos.

Eliminar filas

Para eliminar toda la variable duración del empleo, simplemente establezca la variable duración del empleo en los datos del préstamo en NULL. Aquí guardamos el resultado en una copia del conjunto de datos llamado loan_data_delete_employ. Hacer una copia de los datos originales antes de eliminarlos puede ser una buena forma de evitar la pérdida de información, pero puede resultar costoso si se trabaja con conjuntos de datos muy grandes.

index_NA <- which(is.na(loan_data$emp_length)) 
loan_data_no_NA <- loan_data[-c(index_NA),]

Reemplazar: imputación de mediana

En segundo lugar, al reemplazar una variable, la práctica común es reemplazar los valores faltantes.

index_NA <- which(is.na(loan_data$emp_length)) 
loan_data_replace <- loan_data
loan_data_replace$emp_length[index_NA] <- median(loan_data$emp_length, na.rm = TRUE)

como la mediana de los valores que realmente se observan. Esto se llama imputación de la mediana.

Conservar

Por último, puedes conservar los valores faltantes, ya que en algunos casos, el hecho de que falte un valor es información importante. Desafortunadamente, no siempre es posible mantener las NA como tales, ya que algunos métodos eliminarán automáticamente filas con NA porque no pueden manejarlas. Entonces, ¿cómo podeosm conservar las NA? Una solución popular es la clasificación aproximada. Con este método, básicamente colocas una variable continua en los llamados contenedores. Comencemos creando una nueva variable variable emp_cat, que será la variable que reemplazará a emp_length. La duración del empleo en nuestro conjunto de datos oscila entre 0 y 62 años. Pondremos la duración del empleo en grupos de aproximadamente 15 años, con grupos de 0 a 15, de 15 a 30, de 30 a 45, de 45 o más y un grupo faltante, que representa a los NA. Veamos cómo esto cambia nuestros datos.

loan_data$emp_cat <- rep(NA, length(loan_data$emp_length))  
loan_data$emp_cat[which(loan_data$emp_length <= 15)] <- "0-15"
loan_data$emp_cat[which(loan_data$emp_length > 15 & loan_data$emp_length <= 30)] <- "15-30" 
loan_data$emp_cat[which(loan_data$emp_length > 30 & loan_data$emp_length <= 45)] <- "30-45"
loan_data$emp_cat[which(loan_data$emp_length > 45)] <- "45+"
loan_data$emp_cat[which(is.na(loan_data$emp_length))] <- "Missing" 

loan_data$emp_cat <- as.factor(loan_data$emp_cat)

plot(loan_data$emp_cat)

loan_data$ir_cat <- rep(NA, length(loan_data$int_rate)) 
loan_data$ir_cat[which(loan_data$int_rate <= 8)] <- "0-8" 
loan_data$ir_cat[which(loan_data$int_rate > 8 & loan_data$int_rate <= 11)] <- "8-11" 
loan_data$ir_cat[which(loan_data$int_rate > 11 & loan_data$int_rate <= 13.5)] <- "11-13.5"
loan_data$ir_cat[which(loan_data$int_rate > 13.5)] <- "13.5+"
loan_data$ir_cat[which(is.na(loan_data$int_rate))] <- "Missing"  

loan_data$ir_cat <- as.factor(loan_data$ir_cat)  


plot(loan_data$ir_cat)

Observaciones Finales

Antes de probar todo esto en R, terminemos un par de comentarios.

  • Todos los métodos para el manejo de datos faltantes también se pueden aplicar a los valores atípicos. Si cree que un valor atípico es incorrecto puede tratarlo como NA y utilizar cualquiera de los métodos que hemos analizado en este capítulo.

  • Habrá notado que en este capítulo solo le hable de la falta de variables continuas ¿Qué pasa con las variables factoriales? Este es el enfoque básico. Para las variables categóricas, la eliminación funciona exactamente de la misma manera que para las variables continuas, eliminando observaciones o variables completas. Cuando deseamos reemplazar una variable de factor faltante, esto se hace asignándola a la clase modal, que es la clase con mayor frecuencia. Para mantener los NA de una variable categórica se incluye una categoría faltante.

Matrices de confusión y División de Datos

Hemos visto varias técnicas para procesar los datos. Cuando los datos estén completamente preprocesados, podrá continuar y comenzar el análisis.

iniciar análisis

Puede ejecutar el modelo en todo el conjunto de datos y utilizar el mismo conjunto de datos para evaluar el resultado, pero lo más probable es que esto conduzca a un resultado demasiado optimista.

Conjunto de entrenamiento (training set) y Prueba (test set)

Una alternativa es dividir los datos en dos partes. La primera parte de los datos, el llamado conjunto de entrenamiento, se puede usar para construir el modelo, y la segunda parte de los datos, el conjunto de prueba, se puede usar para probar los resultados.

Una forma común de hacerlo es utilizar dos tercios de los datos para un conjunto de entrenamiento y un tercio para el conjunto de prueba. Por supuesto, puede haber mucha variación en la estimación de rendimiento, dependiendo de qué dos tercios de los datos seleccione para el conjunto de entrenamiento. Una forma de reducir esta variación es mediante el uso de validación cruzada.

Validación cruzada (Cross - Validation)

Para el ejemplo del conjunto de entrenamiento de dos tercios y del conjunto de prueba de un tercio, una variable de validación cruzada se vería así.

Los datos se dividirían en tres partes iguales y, cada vez, dos de estas partes actuarían como un conjunto de entrenamiento y una parte actuaría como un conjunto de prueba. Por supuesto, podríamos usar tantas piezas como queramos, pero tendríamos que ejecutar el modelo muchas veces si usamos muchas piezas. Esto puede resultar computacionalmente pesado. En este curso, solo usaremos un conjunto de entrenamiento y un conjunto de prueba que contienen dos tercios versus un tercio de los datos, respectivamente. Imagine que acabamos de ejecutar un modelo y ahora lo aplicamos a nuestro conjunto de pruebas para ver qué tan buenos son los resultados.

Evaluar un modelo

Evaluar un modelo de riesgo crediticio signifca comparar los resultados observados de incumplimiento versus no incumplimiento, almacenados en la variable loan_status m del conjunto de prueba, con los resultados previstos según el modelo. Si se trata de una gran cantidad de predicciones, un método popular para resumir los resultados utiliza algo llamado matriz de confusión.

Una matriz de confusión es una tabla de contingencia de clasificaciones correctas e incorrectas. Las clasificaciones correctas se encuentran en la diagonal de la matriz de confusión.

No default(0) Defaul(1)
No default (0) 8 2
Default (1) 1 3

Veamos, por ejemplo, que ocho no morosos fueron clasificados correctamente como no morosos, y tres morosos fueron clasificados correctamente como morosos. Sin embargo, vemos que dos no morosos fueron clasificados erróneamente como morosos, y un moroso fue clasificado erróneamente como no moroso.

Los elementos en las diagonales también se llaman verdaderos positivos y verdaderos negativos. Las diagonales fuera de la diagonal se denominan falsos positivos versus faltos negativos.

No default (0) Default (1)
No default (0) TN FP
Default (1) FN TP

Algunas medidas….

Se pueden derivar varias medidas de la matriz de confusión. Discutiremos la precisión de la clasificación, la sensibilidad y la especificidad.

  • La precisión de la clasificación (accuracy) es el porcentaje de instancias clasificadas correctamente, que equivale al 78.57% en este ejemplo.

    \[ \frac{8+3}{14} = 78.57\% \]

  • La sensibilidad (sensitivy) es el porcentaje de malos clientes que se clasifican correctamente o el 75% en este ejemplo.

    \[ \frac{3}{1+3} = 75\% \]

  • La especificidad es el porcentaje de buenos clientes que se clasifican correctamente o el 80% en este ejemplo.

    \[ \frac{8}{8+2} = 80\% \]

Ejercicios

Dividiendo el conjunto de datos

Para realizar sus conjuntos de entrenamiento y prueba, primero debe configurar una semilla usando set.seed(). Las semillas le permiten crear un punto de partida para números generados aleatoriamente, de modo que cada vez que se ejecute su código se genere la misma respuesta. La ventaja de hacer esto en su muestreo es que usted o cualquier otra persona puede recrear exactamente los mismo conjuntos de entrenamiento y prueba usando la misma semilla.

Con sample(), puede asignar observaciones aleatoriamente al conjunto de entrenamiento y prueba.

Para este ejercicio utilizará los dos primeros argumentos de la función sample():

  • El primer argumento es el vector del cual tomaremos muestras de valores. Seleccionaremos aleatoriamente números de fila como índices; puedes utilizar 1:nrow(loan_data) para crear el vector de números de fila.

  • El segundo argumento es el número de elementos a elegir. Entraremos 2/3*nrow(loan_data), ya que primero construimos el conjunto de entrenamiento.

# Establecemos una semilla de 567
set.seed(567) 
# index_train: almacena los indices del conjunto de entrenamiento 
index_train <- sample(1:nrow(loan_data), 2/3*nrow(loan_data)) 
# Creamos el conjunto de entrenamiento seleccionando los números de fila almacenados en index_train. y guardamos en training_set. 
training_set <- loan_data[index_train, ] 
# conjunto de prueba, son las filas que no estan en index_train 
test_set <- loan_data[-index_train, ]

Creando la matriz de confusión

En este ejemplo, supongamos que ejecutó un modelo y almacenó los resultados pronosticados en un vector llamado model_pred. Quiere ver cómo se desempeño el modelo, por lo que construirá una matriz de confusión. Comparará la columna de estado del préstamo real (loan_status) con los valores pronosticados (model_pred), utilizando la función table(), donde los argumentos y valores verdaderos y los valores pronosticados. Recuerde la estructura de la matriz de confusión y fórmulas.

\[ \begin{eqnarray*} accuracy &=& \frac{(TP + TN)}{(TP + FP + TN + FN)}\\[0.2cm] sensitivy &=& \frac{TP}{TP + FN}\\[0.2cm] specificity &=& \frac{TN}{TN + FP} \end{eqnarray*} \]

# Creamos la matriz de confusión 
conf_matrix <- table(test_set$loan_status,model_pred)

# cálculo del accuracy
(6092 + 349)/nrow(test_set)

# computo de sensitivy
349/1037