Las entidades financieras desean mejorar sus procedimientos de aprobación de créditos con el fin de disminuir los riesgos de no pago de la deuda. El problema real consiste en poder decidir si se aprueba o no un crédito particular con base en información que puede ser fácilmente recolectada por teléfono o en la web.
Se tiene una muestra de 1000 observaciones. Cada registro contiene 21 variables que recopilan información tanto sobre el crédito como sobre la salud financiera del solicitante. La información fue recolectada por una firma alemana y se puede descargar de http://archive.ics.uci.edu/ml.
In [35]:
# carga de los datos
credit <- read.csv("data/credit.csv")
In [36]:
# verificación de los datos cargados
str(credit)
In [37]:
# Algunas de las columnas son numéricas y
# las otras son factores.
# DM corresponde a Deutsche Marks
table(credit$checking_balance)
In [38]:
table(credit$savings_balance)
In [39]:
# el monto del préstamo va desde 250 DM hasta 18.424 DM
summary(credit$amount)
In [40]:
# la duración del préstamo va desde 4 hasta 72 meses
summary(credit$months_loan_duration)
In [41]:
# la columna default indica si hubo problemas
# en el pago del préstamo (1- pago, 2- no pago)
table(credit$default)
In [42]:
# la columna default indica si el crédito fue pagado o no
# 1-si, 2-no
credit$default
In [43]:
# convierte esta variable a factores
credit$default <- factor(credit$default, labels=c("Yes", "No"))
credit$default
El problema en términos matemáticos se define de la siguiente forma.
El método k-NN asígna una clase (de las $P$ posibles) al nuevo ejemplo en dos pasos. En el primer paso, determina los $k$ ejemplos más cercanos (distancia) al nuevo ejemplo; en el segundo paso, asigna la clase al nuevo punto por mayoría; es decir, asigna la clase con mayor frecuencia entre los $k$ vecinos más cercnos. Por ejemplo, si se consideran 7 vecinos, de los cuales 5 son "benignos" (y 2 "malignos") entonces el nuevo punto es clasificado como "benigno".
La distancia entre dos puntos $p$ y $q$ es:
$$dist(p, q) = \sqrt{\sum_{i=1}^N (p_i - q_i)^2}$$Ejercicio. ¿Cómo se implementa computacionalmente este algoritmo?
Ya que la escala de las variables numéricas afecta la medición, se pueden realizar dos transformaciones:
Normalización min-max.
$$z_j = \frac{x - \text{min}(x_j)}{\text{max}(x_j) - \text{min}(x_j)}$$Estandarización z.
$$z_j = \frac{x - \text{mean}(x_j)}{\text{std}(x_j) }$$Para variables nominales que representan $S$ categorías se crean $S-1$ variables: la primera variable vale 1 si la variable nominal toma el valor de la primera categoría; la segunda variable vale 2 si la variable nominal toma el valor de la segunda categoría, y así sucesivamente. ¿Por qué se requieren $S-1$ variables para $S$ categorías de la variable nominal?.
In [44]:
# se usa el 90% de los datos para entrenamiento y el 10% restante para prueba
set.seed(123) # inicializa la semilla del generador de aleatorios
train_sample <- sample(1000, 900) # muestrea 900 números al azar
str(train_sample)
In [45]:
# genera los conjuntos de entrenamiento
credit_train <- credit[train_sample, ]
credit_test <- credit[-train_sample, ]
In [46]:
# proporción de los créditos pagados y no pagados
# en el conjunto de entrenamiento
prop.table(table(credit_train$default))
In [47]:
# proporción de los créditos pagados y no pagados
# en el conjunto de prueba
prop.table(table(credit_test$default))
In [ ]:
In [ ]:
In [49]:
# carga la librería
# install.packages("C50")
library(C50)
credit_model <- C5.0(credit_train[-17], credit_train$default)
credit_model
In [50]:
summary(credit_model)
Para evaluar el desempeño en problemas de clasificación dicotómicos (dos clases mutuamente excluyentes) se usa la siguiente tabla:
Pronostico
P N
P VP FN
Real
N FP VN
VP - Verdadero positivo (correcto)
VN - Verdadero negativo (correcto)
FN - Falso negativo
FP - Falso positivo
In [51]:
#install.packages("gmodels")
library(gmodels)
credit_pred <- predict(credit_model, credit_test)
CrossTable(credit_test$default,
credit_pred,
prop.chisq = FALSE,
prop.c = FALSE,
prop.r = FALSE,
dnn = c('actual default', 'predicted default'))
In [ ]:
credit_boost10 <- C5.0(credit_train[-17], credit_train$default,
trials = 10)
In [ ]:
credit_boost10
In [ ]:
summary(credit_boost10)
In [ ]:
credit_boost_pred10 <- predict(credit_boost10, credit_test)
In [ ]:
CrossTable(credit_test$default,
credit_boost_pred10,
prop.chisq = FALSE,
prop.c = FALSE,
prop.r = FALSE,
dnn = c('actual default', 'predicted default'))
In [ ]:
In [ ]:
Ejercicio. Determine si el modelo mejora con $k$ = 21 y se estándarizan las variables. Ayuda: use la función scale
.
Ejercicio. Determine el valor óptimo de $k$ cuándo los datos son normalizados. Ayuda: Calcule la cantidad total de ejemplos mal clasificados para $k$ desde 1 hasta 27.
Ejercicio. Los resutados son dependientes de cómo se partieron los datos en entrenamiento y prueba. Cómo podría calcular de una forma más robusta la cantidad de vecinos?