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_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.
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")
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.
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.
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.
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.
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.
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 567set.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.
# 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 sensitivy349/1037
Regresión Logística
Estructura de datos final
Echemos un vistazo a la estructura del conjunto de entrenamiento. Recuerde que loan_status es nuestra variable de respuesta y ahora tenemos variables de cuatro y tres factores continuas como variables explicativas.
Es similar en muchos aspectos a la regresión lineal, excepto que el resultado del modelo es un valor entre cero y uno. Esto es necesario ya que estamos interesados en predecir la probabilidad de incumplimiento, que, por definición, está entre cero y uno. En un modelo de regresión logística, la probabilidad de incumplimiento también se puede escribir como la probabilidad de que el estado del préstamo sea igual a uno, condicionado a las variables \(x_1, . . . , x_m\), que en el caso de nuestro conjunto de datos son monto del préstamo,. grado, antiguedad, etc.
Además se estiman algunos parámetros \(\beta_0, . . . , \beta_m\). La combinación de los parámetros y las variables se denominan predictor lineal.
Ajustar un modelo logístico en R
Puede ajustar un modelo de regresión logística y obtener las estimaciones de los parámetros en R usando la función glm(), que significa modelo lineal generalizado, con el argumento de familia igual a binomial. Veamos un ejemplo en el que solo incluimos la variable edad como predictor. Al observar el resultado, obtenemos algunos coeficientes y diagnósticos del modelo. Por ahora, nos centraremos en los coeficientes. La intersección es la estimación de \(\beta_0\) y el valor debajo de la edad es la estimación de \(\beta_1\).
Call: glm(formula = loan_status ~ age, family = "binomial", data = training_set)
Coefficients:
(Intercept) age
-1.885449 -0.007342
Degrees of Freedom: 19393 Total (i.e. Null); 19392 Residual
Null Deviance: 13460
Residual Deviance: 13460 AIC: 13460
Entonces, ¿cómo interpretamos estos números ? Para responder a esta pregunta, primero damos un paso atrás y hacemos algunos cálculos básicos.
Probabilidades de incumplimiento
Has visto la expresión de la probabilidad de incumplimiento. Al multiplicar esta expresión por la función exponencial del predictor lineal tanto en el numerador como en el denominador, obtenemos este resultado.
La probabilidad de que el estado del préstamo sea igual a 0. o la probabilidad de no incumplimiento, viene dada por uno menos la probabilidad de incumplimiento.
Ahora bien, si dividimos la probabilidad de incumplimiento por la probabilidad de no incumplimiento, obtenemos las probabilidades a favor del incumplimiento. Convenientemente, esto es simplemente igual a la función exponencial de nuestro predictor lineal. Veamos,
Supongamos que el valor de la variable \(x_j\) aumenta en 1, mientras que todas las demas variables permanecen iguales. Si esto sucede, las probabilidades de incumplimiento se multiplicarán por la exponencial de \(e^{\beta_j}\). Tenga en cuenta lo siguiente:
Las probabilidades DISMINUIRAN si aumenta \(x_j\) cuando \(\beta_j < 0\), \(e^{\beta_j} <1\)y
las probabilidades AUMENTARÁN si aumenta \(x_j\) cuando \(\beta_j > 0\), \(e^{\beta_j}>1\).
Volviendo al modelo de regresión logística que construimos, vemos que el coeficiente de edad es \(e^{-0.007342}\). Si la edad aumenta en uno, las probabilidades de incumplimiento se multiplicarán por aproximadamente \(-0.734\). Esto significa que un año más de edad reduce la probabilidad de impago en casi un 80%.
Ejercicios
Construyamos un modelo glm con variable ir_cat como predictor
log_model_cat <-glm(formula = loan_status ~ ir_cat, family ="binomial", data = training_set)
Imprimamos las estimaciones de los parámetros
log_model_cat
Call: glm(formula = loan_status ~ ir_cat, family = "binomial", data = training_set)
Coefficients:
(Intercept) ir_cat11-13.5 ir_cat13.5+ ir_cat8-11 ir_catMissing
-2.9091 1.0071 1.3874 0.5933 0.7937
Degrees of Freedom: 19393 Total (i.e. Null); 19389 Residual
Null Deviance: 13460
Residual Deviance: 13050 AIC: 13060
Ahora, veamos las diferentes categorías en ir_cat usando la table()
Múltiples variables en un modelo de regresión logística
La interpretación de un solo parámetro sigue siendo válidad cuando se incluyen varias variables en un modelo. Cuando incluye varias variables y solicita la interpretación cuando una determinada variable cambia, se supone que las otras variables permanecen constantes o sin cambios. Hay una elegante frase latina para esto, ceterís paribus, que literalmente significa mantener a todos los demás iguales.
Para construir un modelo de regresión logística con múltiples variables, puede usar el signo + para agregar variables.
Para evaluar el modelo hay una serie de cosas a tener en cuenta. Ya miraste los valores de los parámetros, pero eso no es lo único importante. También es importante la importancia estadística de la estimación de un determinado parámetro. La importancia de un parámetro a menudo se denomina valor p; sin embargo, en la salida de un modelo lo verá indicado como p(>|t|). En glm, el significado leve se indica con un “.” a un significado muy fuerte denotado por “**”. Cuando un parámetro no es significativo, significa que no se puede asegurar que este parámetro sea significativamente diferente de 0. La significancia estadística es importante. En general, sólo tiene sentido interpretar el efecto sobre el incumplimiento para parámetros significativos.
Ahora, constuyamos el mdoelo de regresión logística
log_model_multi <-glm(loan_status ~ age + ir_cat + grade + loan_amnt + annual_inc , family ="binomial", data = training_set)
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
Obtener los niveles de significancia usando summary()
summary(log_model_multi)
Call:
glm(formula = loan_status ~ age + ir_cat + grade + loan_amnt +
annual_inc, family = "binomial", data = training_set)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -2.428e+00 1.284e-01 -18.920 < 2e-16 ***
age -3.980e-03 3.863e-03 -1.030 0.3029
ir_cat11-13.5 7.018e-01 1.313e-01 5.344 9.08e-08 ***
ir_cat13.5+ 6.556e-01 1.462e-01 4.485 7.31e-06 ***
ir_cat8-11 4.867e-01 1.160e-01 4.196 2.71e-05 ***
ir_catMissing 5.067e-01 1.275e-01 3.973 7.09e-05 ***
gradeB 1.427e-01 1.041e-01 1.370 0.1707
gradeC 4.806e-01 1.200e-01 4.006 6.18e-05 ***
gradeD 8.033e-01 1.365e-01 5.887 3.93e-09 ***
gradeE 9.689e-01 1.643e-01 5.896 3.73e-09 ***
gradeF 1.512e+00 2.296e-01 6.584 4.58e-11 ***
gradeG 2.072e+00 3.443e-01 6.019 1.76e-09 ***
loan_amnt -8.438e-06 4.208e-06 -2.005 0.0449 *
annual_inc -4.788e-06 7.365e-07 -6.502 7.95e-11 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 13460 on 19393 degrees of freedom
Residual deviance: 12892 on 19380 degrees of freedom
AIC: 12920
Number of Fisher Scoring iterations: 5
Predecir la probabilidad de Incumplimiento
Ya aprendio cómo construir un modelo de regresión logística. Pero, por supuesto, le gustaria saber cómo utilizar el modelo obtenido y sus estimaciones de parámetros para calcular estimaciones de probabilidad de incumplimiento para los cados del conjunto de prueba. Las predicciones del conjunto de prueba se pueden comparar con sus resultados reales, lo cual es necesario para validar el modelo.
Un ejemplo con edad y propiedad de la vivienda
Para guiarlo a través de este principio, veamos un ejemplo bastante simple, que contiene las variables edad (age) y propiedad de casa (home_ownership). Las estimaciones de los parámetros se obtuvieron utilizando el conjunto de entrenamiento de nuestros datos de préstamo.
y las estimaciones de parámetros, ahora podemos calcular una probabilidad de incumplimiento usando los valores de covariables de los casos que están en el conjunto de prueba. Nuievamente, tenga en cuenta que tenemos una estimación de parámetros para cada una de las categorías en la variable categórica, excepto una para la categoría de referencia, que es la categoría de propiedad de vivienda HIPOTECA en este modelo.
Ejemplo de conjunto de prueba
Veamos un ejemplo específico. El cliente de la primera línea del conjunto de prueba tiene 45 años hy es inquilino. Utilizando el modelo que tenemos a mano, puede calcular la probabilidad de incumplimiento de esta manera.
Note que se llego a una probabilidad de incumplimiento del 10.97% para este cliente en específico.
Hacer predicciones en R
Vamos a utilizar la función predict para predecir la probabilidad de incumplimiento para uno o varios casos de conjunto de pruebas. Comencemos seleccionando el primer caso del conjunto de prueba.
test_case <-as.data.frame(test_set[1,])test_case
loan_status loan_amnt int_rate grade emp_length home_ownership annual_inc age
2 0 2400 NA C 25 RENT 12252 31
emp_cat ir_cat
2 15-30 Missing
Ya se a que esté utilizando uno o varios casos, siempre debe asegurarse de que los casos de prueba estén almacenados en un marco de datos. Exploremos este caso de prueba. La edad es de 31 años y la categoría de propiedad de vivienda es alquiler. Usando la función predict(), el primer argumento contiene el modelo ajustado. El segundo argumento, proporciona los nuevos datos en test_case.
predict(log_model_small, newdata = test_case)
2
-2.012814
Al hacer esto nota que obtienes un resultado de -2.010561. Esta aún no es la probabilidad de incumplimiento sino el predictor lineal. Al cambiar el argumento de respuesta, obtiene la probabilidad de incumplimiento predicha real para este cliente.
predict(log_model_small, newdata = test_case, type ="response")
2
0.117864
Ejercicio
Hagamos predicciones para todos los elementos del conjunto de prueba usando el modelo log_model_small.
predictions_all_small <-predict(log_model_small, newdata = test_set, type ="response")
Miremos el rango del objeto predictions_all_small
range(predictions_all_small)
[1] 0.0740231 0.1818599
Evaluación del resultado del model de regresión logística
Utilizando las probabilidades predichas, le gustaría hacer una matriz de confusión. Como vio en secciones anteriores, puede crear una matriz de confusión comparando la columna loan_status en el conjunto de pruena con las predicciones del modelo para el estado del préstamo.
El problema es que la probabilidad predicha de incumplimiento se situa entre cero y uno. ¿Cómo haremos ahora una matriz de confusión?
La respuesta está en la especificación de un valor umbral o de corte. Necesitamos determinar un valor entre 0 y 1, y si el valor predicho está por encima de este valor, la predicción se establece en ; si no, la predicción se establece en 0.
Limite = 0.5.
Un valor de corte lógico podría ser el 0.5: si las probabilidades son mayores a favor del incumplimiento, o mayores que el 0.5, la predicción se establece en 1; si no, se establece en 0.
Echemos un vistazo a la matriz de confusión para el subconjunto de estos 9698 casos.
library(tidyverse)
Warning: package 'tidyverse' was built under R version 4.3.1
Warning: package 'ggplot2' was built under R version 4.3.1
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.2 ✔ readr 2.1.4
✔ forcats 1.0.0 ✔ stringr 1.5.0
✔ ggplot2 3.4.2 ✔ tibble 3.2.1
✔ lubridate 1.9.2 ✔ tidyr 1.3.0
✔ purrr 1.0.1
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
Queda claro que este límite no conducirá a ningún cumplimiento previsto, lo que dará una columna de ceros, por lo tanto, tenemos una sensivilidad del 0%, sin que ninguno de los incumplimientos reales se clasifique correctamente. Como ha visto en los ejercicios anteriores, no es raro tener probabilidades de incumplimiento predichas bastante bajas, ya que el incumplimiento de los préstamos es un evento poco común. Por lo tanto, se debe tener cuidado al decidir un valor de corte, no simplemente establecerlo en el 0.5.
Este resultado conduce a una sensibilidad significativamente mejor, mientras que la precisión de la clasificación mejora también.
Árboles de decisión
Los árboles de clasificación son otro método popular en el mundo de la modelización del riesgo crediticio. En este capítulo aprenderá cómo crear árboles de clasificación utilizando datos crediticios en R.
¿Qué es un árbol de decisión?
Otra forma de clasificar a los clinetes en grupos de incumplimientos y no incumplimientos en mediante árboles de decisión. Una razón importante de la popularidad de los árboles de decisión es su interpretabilidad.
Ejemplo de árbol de decisión
Aquí hay un árbol de ejemplo. Al responder las preguntas desde la parte superior (o la Raíz) del árbol hasta la parte inferior (o los nodos de la hoja), se toma una decisión sobre si clasificar una determinada instancia como un caso predeterminado o no predeterminado. Existen varios paquetes en R para construir árboles de decisión automáticamente.
¿Cómo tomar una decisión dividida?
Antes de hacerlo, me gustaría explicar cómo se toma la llamada decisión dividida. Para cada nodo del árbol, la decisión de división afectará la estructura final del árbol. Veamos dos posibles decisiones de división para la variable categórica. ¿Cómo decidimos si la pregunta que se debe hacer es si alguien, digamos alquila una casa o no, O si alguien alquila una casa o pertenece a la categoría “otros”, o no?
Para una variable continua (digamos edad), ¿cómo definimos el valor límite para la edad que define el límite entre un valor predeterminado o no? La respuesta se puede encontrar en la definición de una medida para la impureza. En resumen, le gustaría minimizar las impurezas en cada nodo del árbol. Una medida popular (y la medida por defecto para la impureza en el popular paquete de reparto) es la medida Gini. Veamos un ejemplo.
Ejemplo
Suponga que tiene un conjunto de capacitación con 500 casos, 250 valores predeterminados y 250 casos no predeterminados. A menudo verá la cantidad de casos en cada nodo representados así:
con el número real de incumplimientos en el lado izquierdo, y el número real de valores predeterminados en el lado derecho.
Por supuesto, el escenario ideal, aunque poco realista, conducirá a una división perfecta entre incumplimiento y no incumplimientos a la edad de 40 años. Como este no es el caso, calculemos la impureza usando la medida Gini.
La impureza en un determinado nodo según la medida de Gini viene dada por dos veces la proporción de no incumplimientos en un nodo, multiplicada por la proporción de incumplimientos en este nodo.
\[
Gini = 2*prop(default)*prop(non-default)
\]
Al aplicar está fórmula al nodo raíz, esto conduce a una impuerza de 0.5 (que es la cantidad máxima posible, con exactamente tantos valores predeterminados como no predeterminados). Ya que
\[
Gini_R = 2*(250/500)*(250/500) = 0.5
\]
una impureza del 0.4536 en el nodo inzquierdo,
\[
Gini\_N2 = 2*(80/230)*(150/230) = 0.4536
\]
y una impuerza del 0.4664 en el nodo derecho,
\[
Gini\_N1 = 2*(170/270)*(100/270) = 0.4664
\]
Una métrica importantes es la ganancia en pureza que se logra desde el nodo raíz hasta los dos nodos N1 y N2.
Esta ganancia se puede calcular restando las medidas de Gini ponderadas en los nodos N1 y N2 de la medida de Gini en la raíz.
En nuestro ejemplo, esto conduce a una ganancia de casi 0.04. El algoritmo selecciona la división que conduce a la mayor ganancia.
Ejercicio
# La medida de Gini del nodo raíz se da a continuación gini_root <-2*89/500*411/500# Calcular el Gini medida para el nodo de hoja izquierdogini_ll <-2*401/446*45/446# Calcular el Gini medida para el nodo de hoja derechogini_rl <-2*10/54*44/54# Calcular la ganancia gain <- gini_root -446/500* gini_ll -54/500* gini_rl
Construyendo árboles de decisión usando el paquete rpart()
Ya ha visto como se puede encontrar una división perfecta utilizando la medida Gini. En el ejercicio anterior, sólo analizaste una posible división.
Imagínese tener que comprar manualmente todas las divisiones posibles para encontrar la mejor. Eso sería todo un desafio ¿Verdad?
Afortunadamente, existe un paquete en R que crea árboles de decisión para usted, el paquete rpart. Si bien este paquete es generalmente muy útil para crear árboles de decisión, es importante advertirle desde el prinicipio que crear árboles de decisión en el contexto del riesgo crediticio puede ser todo un desafío. La razón principal de esto es el hecho de que los datos sobre el riesgo de crédito generalmente están muy desequilibrados debido al bajismo porcentaje de impagos. Al utilizar la configuración predeterminada en el conjunto de entrenamiento de loan_data, incluidas todas las variables y especificando el método, como la variable de respuesta loan_status es categórica, recibirá un mensaje de advertencia que indica que solo se crea una raíz.
La razón de esto es que, similar a lo que hemos visto al establecer un límite para un modelo de regresión logística; la mayor precisión se logra simplmente prediciendo que todos los caso no serán predeterminados.
Tres técnicas para superar el desequilibrio
Una primera opción es sobremuestrear su grupo subrepresentado (en este caso, los predeterminados) o submuestreando el grupo sobrerrepresentado (o no predeterminados). Equilibrar el conjunto de entrenamiento tendrá un efecto positivo en el problema de precisión (accuracy) discutido anteriormente, y generalmente conduce a mejores resultados. Tenga en cuenta que el sobremuestreo o el submuestreo solo debe aplicarse al conjunto de entrenamiento y no al conjunto de prueba.
Una segunda opción es cambiar las probabilidades previas en la función rpart(). Por defecto, las probabilidades previas de incumplimiento frente a no predeterminados se establecen iguales a sus proporciones en el conjunto de entrenamiento. Al hacer que las probabilidades previas de incumplimiento sean más grandes, engañas a R en dar más importancia a los incumplimientos, lo que lleva a un mejor árbol de decisiónes.
Como tercera opción, la función rpart() permite especificar una matriz de pérdidas. En esta matriz de pérdidas, se pueden asociar diferentes costos con la clasificación erronea de un incumplimiento como no predeterminado frente a la clasificación errónea de un no predeterminado como predeterminado. Al aumentar el costo de clasificación errónea del primero, nuevamente se presta más atención atraídos por la correcta clasificación de los incumplimientos, mejorando la calidad del árbol de decisión.
Como los tres métodos están destinados a superar el problema del desequilibrio de clases, la validación es muy importante. Donde el submuestreo o el sobremuestreo pueden funcionar muy bien para algunos conjuntos de datos, podría funcionar mal para los otros, y lo mismo podría ser cierto para los otros dos métodos.
Cuál es el mejor método para los datos disponibles solo se aclarará con la validación adecuada del modelo.
library(rpart)
Warning: package 'rpart' was built under R version 4.3.1
tree_prior <-rpart(loan_status ~ ., method ="class",data = training_set, parms =list(prior =c(0.7, 0.3)),control =rpart.control(cp =0.001))# Plot the decision treeplot(tree_prior, uniform =TRUE)# Add labels to the decision treetext(tree_prior)
Podando el árbol de decisiones
Los arboles de decisión resultantes pueden ser muy grandes. Generalmente no se recomienda construir árboles de decisión enormes.
Problemas con árboles de decisión grandes
No sólo son más difíciles de interpretar, sino que también puede ocurrir un sobreajuste, lo que lleva a resultados inferiores al aplicar el modelo al conjunto de prueba. El paquete rpar() proporciona herramientas que facilitan bastante la poda de árboles de decisión. Las funciones útiles son plotcp() y printcp(). Echemos un vistazo alo que hacen estas funciones al aplicarlas al árbol que construimos usando el conjunto de entrenamiento submuestreado. }
Printcp y tree_undersample
Primero hechemos un vistazo a printcp(). Al aplicar esta función a nuestro objeto tree_undersample, obtienes una descripción general de cómo crece el árbol usando más divisiones (dadas en la columna nsplit).
De hecho, puede cambiar el parámetro de complejidad cp, que antes se fijó en el 0.001, para obtener niveles de complejidad correcto. Ahora bien, ¿qué nivel se debe elegir? Desearía minimizar el llamado error de validación cruzada del árbol de decisión. Estos resultados se dan en la columna xerror. Como sugiere el nombre, se utiliza validación cruzada dentro del conjunto de entrenamiento para obtener esta medida de error. Dado que existe un elemento aleatorio en el procesos de validación cruzada, es necesario establecer una semilla si desea que los resultados sean reproducibles.
Plotcp y tree_undersample
También puede trazar el error de validación cruzada en función del parámetro de complejidad cp y el tamaño del árbol utilizando la función plotcp.
El error mínimo de validación cruzada se puede encontrar aquí mismo, donde el parámetro de complejidad cp es igual 0.003653. Para este valor de cp exacto, puedes echar un vistazo a printcp() nuevamente.
Trazar el árbol podado
Ahora, para podar el arbol, se puede usar la función prune(), con el árbol inicial no podado como primer argumento y el valor de cp que minimizo el error de validación cruzada como segundo argumento.
Al trazar el árbol podado se obtiene un árbol de decisión más pequeño. Tenga en cuenta que este árbol no le brinda información sobre el número real de valores predeterminados versus no predeterminados que están presentes en cada hoja.
Si desea agregar esta información, puede incluir el argumento use.n = TRUE en la función text(). Tenga en cuenta que estos valores se refieren únicamente al conjunto de entrenamiento. Tenga en cuenta que una respuesta SÍ a la declaración de prueba en un nodo lo llevará a seguir la rama de la izquierda, y una respuesta NO a la declaración de prueba lo llevará a seguir la ra,a de la derecha. Esto no es muy intuitivo en el gráfico estándar del paquete rpart. Además, la prueba home_ownership es igual a cd no es muy informativa.
Se obtiene un gráfico más intuitivo utilizando la función prp() del paquete rpart.plot. Al trazar usando prp(), recibe orientación sobre qué rama tomar dependiendo de la respuesta a la pregunta dividida. También obtiene el nombre del factor real para las variables de factor, como puede ver para las categorías de propiedad y alquiler.
library(rpart.plot)prp(ptree_undersample)
Ejercicio
Usemos plotcp() para visualizar el error de validación cruzada en relación con el parámetro de complejidad para tree_prior.
plotcp(tree_prior)
Utilice printcp() para imprimir una tabla de información sobre CP, divisiones y errores. Vea si puede identificar qué división tiene el error mínimo de validación cruzada en tree_prior.
Utilice prp() y el argumento extra = 1 para trazar el árbol podado.
prp(ptree_loss_matrix, extra =1)
Otras opciones de árboles y la construcción de matrices de confusión
Hemos cubierto varias opciones para facilitar la construcción de un árbol, epecialmente en datos desiquilibrados. Por supuesto, la gama de posibilidaces es infinita y hay algunos otros argumentos que pueden pasar a la función rpart() para dar forma a su árbol de decisión de incumplimiento de préstamo. Repasaré algunos de los más importantes en este video.
Otros argumentos interesantes de rpart()
Un argumento interesante en rpart() son los pesos (weights), que le permiten incluir pesos de caso para cada uno de los casos en el conjunto de entrenamiento. Aumentar las ponderaciones de los casos de incumplimiento habría sido otra estrategía plausible para constrarrestar el desequilibrio en el árbol de decisión. Los otros argumentos interesantes que mencionaré aquí son todos parte de la función rpart.control que se puede pasar al control de argumentos. Usamos está función antes para cambiar el párametro de complejidad cp. Un argumento interesante aquí es minsplit, que le permite cambiar el número mínimo de observaciones que deben existir en un nodo para que se intente una división. El valor predeterminado para este argumento es igual a 20, pero para datos no balanceados, podría resultar útil reducir este valor. El argumento minbucket específica el número mínimo de observaciones en cualquier nodo hoja. El valor predeterminado aquí es un tercio del valor especificado en minsplit, pero puede resultar útil probar otros valores. Tenga en cuenta que reducir demasiado este valor podría provocar un sobreajuste. Lo último que debemos hacer es asegurarnos de evaluar nuestro árbol de decisiones.
Hacer predicciones utilizando el árbol de decisiones
pred_undersample_class <-predict(tree_undersample, newdata = test_set, type ="class")head(pred_undersample_class)
2 6 7 10 11 13
0 0 0 0 0 0
Levels: 0 1
Hasta ahora, solo usamos el conjunto de entranamiento, pero queremos usar nuestro conjunto de prueba para evaluar el resultado. Esto se puede hacer usando la función predict(). Aquí se muestra el código para realizar predicciones utilizando el modelo con el conjunto de datos submuestreado. Tenga en cuenta que usamos la versión podada del árbol. Incluyendo el tipo de argumento es igual a “class”, se obtiene un vector de predicciones de inmediato, sin tener que usar más un valor de corte, a diferencia de lo que hicimos con la regresión logística. En algunos casos, sin embargo, le gustaría tener una predicción no binaria y elegir un límite usted mismo. En ese caso, simplemente puede omitir el argumento de tipo en la función predict() y obtendrá probabilidades en lugar de predicciones binarias. Estas probabilidades se derivan de las proporciones del nodo hoja donde termina un caso particular dados sus valores de covariables.
Aunque utilizamos submuestreo, se predicen muy pocos valores predeterminados para nuestro conjunto de prueba. Podría resultar útil aquí utilizar predicciones de probabilidad en lugar de predicciones binarias y reducir el límite.
Evaluación de un Modelo de Riesgo Crediticio
En este capítulo, aprenderá cómo evaluar y comparar los resultados obtenidos a través de varios modelos de riesgo crediticio.
Encontrar el límite correcto: la curva estratégica
En los capítulos anteriores, le brindamos una descripción general de cómo se pueden utilizar los modelos de regresión logística y los árboles de decisión para calcular la probabilidad de incumplimiento.
Al utilizar la función predict() en un modelo de regresión logística con type = "response", se obtiene un vector con las probabilidades de incumplimiento previstas.
Usando la función predict() como esta en un modelo de árbol, obtendrá una matriz con dos columnas: