El modelo logit se utiliza cuando la variable dependiente es una variable cualitativa. En ocasiones a los modelos que abordan esta situación se les conoce como modelos de clasificación.
Tenemos dos submuestras para trabajar, la base de datos funds.train que tiene 2,400 observaciones y 21 variables y la base de datos funds.validation que tiene 600 variables y las mismas 21 variables.
dim(funds.train)
[1] 2400 21
dim(funds.validation)
[1] 600 21
La base de datos funds.train la usaremos para realizar las estimaciones de los coeficientes, mientras que la base de datos funds.validation la usaremos para evaluar la efectividad en la predicción de los modelos generados.
Para realizar correr un modelo logit se utiliza la función glm() que utiliza la siguiente sintaxis:
glm(Y ~ X1 + X2 + ... + Xn, data = base_de_datos, family = "binomial")
donde:
En nuestro ejemplo queremos definir las variables que me permiten identificar si un individuo es donador, la variable target en nuestra base de datos.
Con base en esto, el primer modelo vamos a considerar todas las variables como variables independientes.
logit1.fit <- glm(funds.train$target ~ ., data=funds.train, family="binomial")
summary(logit1.fit)
Call:
glm(formula = funds.train$target ~ ., family = "binomial", data = funds.train)
Deviance Residuals:
Min 1Q Median 3Q Max
-1.69941 -1.15796 0.00159 1.14873 1.74170
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -1.613e+00 5.730e-01 -2.814 0.00489 **
zipconvert2Yes -1.376e+01 2.663e+02 -0.052 0.95878
zipconvert3No 1.375e+01 2.663e+02 0.052 0.95882
zipconvert4Yes -1.388e+01 2.663e+02 -0.052 0.95842
zipconvert5Yes -1.377e+01 2.663e+02 -0.052 0.95876
homeownerNo 2.810e-02 1.105e-01 0.254 0.79925
num_child2 3.785e-03 2.447e-01 0.015 0.98766
num_child3 8.313e-01 4.459e-01 1.864 0.06231 .
num_child4 3.922e-01 5.701e-01 0.688 0.49148
num_child5 1.347e+01 5.354e+02 0.025 0.97992
income2 -7.574e-02 1.761e-01 -0.430 0.66711
income3 -1.864e-01 1.943e-01 -0.959 0.33745
income4 -1.220e-01 1.681e-01 -0.726 0.46800
income5 -3.247e-01 1.812e-01 -1.792 0.07311 .
income6 -1.673e-01 2.161e-01 -0.774 0.43874
income7 -2.875e-01 2.220e-01 -1.296 0.19513
femaleNo 8.421e-02 8.672e-02 0.971 0.33151
wealth1 -3.628e-01 2.997e-01 -1.211 0.22601
wealth2 -1.576e-01 3.057e-01 -0.515 0.60631
wealth3 6.425e-02 2.984e-01 0.215 0.82953
wealth4 3.319e-02 3.029e-01 0.110 0.91274
wealth5 1.096e-01 2.887e-01 0.380 0.70417
wealth6 -3.831e-01 3.118e-01 -1.229 0.21909
wealth7 -4.402e-01 3.038e-01 -1.449 0.14734
wealth8 -2.631e-01 2.562e-01 -1.027 0.30445
wealth9 -2.203e-01 3.063e-01 -0.719 0.47208
home_value -2.145e-04 8.054e-05 -2.663 0.00775 **
med_fam_inc -4.679e-04 1.048e-03 -0.446 0.65534
avg_fam_inc 1.630e-03 1.139e-03 1.430 0.15260
pct_lt15k 2.234e-03 5.157e-03 0.433 0.66487
num_prom -3.804e-03 3.364e-03 -1.131 0.25817
lifetime_gifts -5.372e-04 7.374e-04 -0.729 0.46625
largest_gift -2.049e-03 4.890e-03 -0.419 0.67513
last_gift 8.264e-03 8.367e-03 0.988 0.32332
months_since_donate 5.811e-02 1.139e-02 5.103 3.34e-07 ***
time_lag -9.803e-03 7.798e-03 -1.257 0.20871
avg_gift 7.858e-03 1.249e-02 0.629 0.52912
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 3327.1 on 2399 degrees of freedom
Residual deviance: 3232.4 on 2363 degrees of freedom
AIC: 3306.4
Number of Fisher Scoring iterations: 12
A pesar de que existe una gran cantidad de variables que no son significativas, seguiremos con el ejemplo. Para hacer esto vamos a comparar dos vectores o valores, los valores que hay en la base de datos funds.validation y nuestras predicciones.
Lo primero que haremos será generar un vector donde almacenaremos las predicciones realizadas con base en los resultados de nuestro modelo usando la función predict().
La sintaxis de la función predict() que vamos a usar es la siguiente:
predict(objeto_modelo, base_insumo, type="response")
donde:
El resultado de esta función son las probabilidades del modelo logit.
logit1.predict = predict(logit1.fit, funds.validation, type="response")
head(logit1.predict)
1 2 3 4 5 6
0.5682940 0.5048864 0.5579361 0.5010086 0.5106020 0.4201963
Ya que tenemos las probabilidades, es necesario asignar una de las dos opciones, donador o no donador.
Para esto, vamos a crear un vector lleno con la clasificación “No Donor”, y después, con base en las probabilidades, asginar a las observaciones que representa “Donor”.
Para esto usamos la función rep() con la siguiente sintaxis:
rep(valor, cantidad)
donde:
logit1.class = rep("No Donor", length(funds.validation$target))
head(logit1.class)
[1] "No Donor" "No Donor" "No Donor" "No Donor" "No Donor" "No Donor"
tail(logit1.class)
[1] "No Donor" "No Donor" "No Donor" "No Donor" "No Donor" "No Donor"
Una vez que tenemos el vector lleno de la palabra “No Donor” es necesario sustituir las observaciones que tengan una probabilidad mayor a X con la palabra “Donor”. En este caso usamos como probabilidad 50%.
logit1.class[logit1.predict >= 0.5] = "Donor"
head(logit1.predict)
1 2 3 4 5 6
0.5682940 0.5048864 0.5579361 0.5010086 0.5106020 0.4201963
head(logit1.class)
[1] "Donor" "Donor" "Donor" "Donor" "Donor" "No Donor"
tail(logit1.predict)
595 596 597 598 599 600
0.5298910 0.3571833 0.6377934 0.4474450 0.3923074 0.5479109
tail(logit1.class)
[1] "Donor" "No Donor" "Donor" "No Donor" "No Donor" "Donor"
Ya tenenemos el vector con las predicciones logit1.class es momento de compararlos con las observaciones en nuestra base de datos de prueba y ver su efectividad.
La primera forma de evaluar es utilizando una confusion matrix.
table(logit1.class, funds.validation$target)
logit1.class Donor No Donor
Donor 130 157
No Donor 171 142
Otra forma es simplemente encontrar el porcentaje de acierto
mean(logit1.class==funds.validation$target)
[1] 0.4533333
Como existen varias probabilidades que podemos asignar como parámetro de decisión para decir si es “Donor”, vamos a realizar una función que nos permita encontrar el porcentaje de efectividad a partir de la probabildiad
logit.fun <- function(prob){
logit1.class[logit1.predict >= prob] = "Donor"
print(table(logit1.class, funds.validation$target))
print(mean(logit1.class==funds.validation$target))
}
Creamos la función logit.fun que solo tiene un argumento, la probabilidad que sirve como criterio, al asignar como “Donor” a cada una de las observaciones.
logit.fun(.475)
logit1.class Donor No Donor
Donor 179 194
No Donor 122 105
[1] 0.4733333
Para exportar las predicciones de nuestros resultados como un archivo *csv es necesario realizar una serie de sencillos pasos.
El primero es realizar la predicción de las probabilidades, en este caso los valores que usaremos como variables independientes están en una base de datos llamada “future”.
logit1.csv <- predict(logit1.fit, future, type="response")
head(logit1.csv)
1 2 3 4 5 6
0.4449338 0.5114931 0.4594329 0.6381711 0.3222896 0.6578001
Hay que generar el vector donde se depositaran los resultados de la clasificación con base en las probabilidades calculadas. En esta ocasión asignaremos el nombre de “logit1.csv”. Estos pasos son idénticos a los realizados previamente.
logit1.csv.class = rep("No Donor", length(future$home_value))
head(logit1.csv.class)
[1] "No Donor" "No Donor" "No Donor" "No Donor" "No Donor" "No Donor"
Ya que generamos el vector con solo la palabra “No Donor”, vamos a reemplazar los valores con base en la probabilidad
logit1.csv.class[logit1.csv >= .5] = "Donor"
head(logit1.csv)
1 2 3 4 5 6
0.4449338 0.5114931 0.4594329 0.6381711 0.3222896 0.6578001
head(logit1.csv.class)
[1] "No Donor" "Donor" "No Donor" "Donor" "No Donor" "Donor"
En esta ocasión se decidió clasificar como “Donor” a todas aquellas observaciones que tuvieron una probabilidad mayor a 50%.
Para realizar la exportación es necesario cambiar el vector a un data frame. Lo primero que haremos es convertir el vector con las clasificaciones en una matriz de solo una columna. ¡Muy raro!
Para esto utilizaremos la función matrix() en donde utilizaremos el vector de las clasificaciones e indicaremos que solamente tenemos una columna con el argumento ncol=.
value <- matrix(logit1.csv.class, ncol=1)
value
[,1]
[1,] "No Donor"
[2,] "Donor"
[3,] "No Donor"
[4,] "Donor"
[5,] "No Donor"
[6,] "Donor"
[7,] "Donor"
[8,] "No Donor"
[9,] "Donor"
[10,] "Donor"
[11,] "Donor"
[12,] "No Donor"
[13,] "Donor"
[14,] "Donor"
[15,] "No Donor"
[16,] "Donor"
[17,] "No Donor"
[18,] "Donor"
[19,] "No Donor"
[20,] "Donor"
[21,] "Donor"
[22,] "Donor"
[23,] "Donor"
[24,] "No Donor"
[25,] "No Donor"
[26,] "No Donor"
[27,] "No Donor"
[28,] "Donor"
[29,] "Donor"
[30,] "No Donor"
[31,] "Donor"
[32,] "No Donor"
[33,] "Donor"
[34,] "Donor"
[35,] "Donor"
[36,] "Donor"
[37,] "No Donor"
[38,] "Donor"
[39,] "No Donor"
[40,] "No Donor"
[41,] "Donor"
[42,] "No Donor"
[43,] "No Donor"
[44,] "Donor"
[45,] "Donor"
[46,] "No Donor"
[47,] "No Donor"
[48,] "Donor"
[49,] "Donor"
[50,] "No Donor"
[51,] "Donor"
[52,] "No Donor"
[53,] "No Donor"
[54,] "No Donor"
[55,] "Donor"
[56,] "Donor"
[57,] "No Donor"
[58,] "Donor"
[59,] "No Donor"
[60,] "No Donor"
[61,] "No Donor"
[62,] "Donor"
[63,] "Donor"
[64,] "Donor"
[65,] "Donor"
[66,] "No Donor"
[67,] "No Donor"
[68,] "Donor"
[69,] "No Donor"
[70,] "No Donor"
[71,] "Donor"
[72,] "Donor"
[73,] "Donor"
[74,] "Donor"
[75,] "No Donor"
[76,] "No Donor"
[77,] "Donor"
[78,] "Donor"
[79,] "Donor"
[80,] "No Donor"
[81,] "Donor"
[82,] "No Donor"
[83,] "Donor"
[84,] "No Donor"
[85,] "Donor"
[86,] "No Donor"
[87,] "Donor"
[88,] "No Donor"
[89,] "Donor"
[90,] "No Donor"
[91,] "Donor"
[92,] "Donor"
[93,] "No Donor"
[94,] "No Donor"
[95,] "Donor"
[96,] "Donor"
[97,] "Donor"
[98,] "No Donor"
[99,] "No Donor"
[100,] "Donor"
[101,] "No Donor"
[102,] "No Donor"
[103,] "No Donor"
[104,] "Donor"
[105,] "No Donor"
[106,] "Donor"
[107,] "No Donor"
[108,] "Donor"
[109,] "No Donor"
[110,] "Donor"
[111,] "No Donor"
[112,] "No Donor"
[113,] "No Donor"
[114,] "Donor"
[115,] "No Donor"
[116,] "Donor"
[117,] "Donor"
[118,] "No Donor"
[119,] "No Donor"
[120,] "No Donor"
Ya que realizamos esto, podemos convertir esta matriz en un data frame utilizando la función data.frame() donde el único argumento que utilizaremos es el nombre que le asignamos a la matriz, en este caso “value”.
prueba1 <-data.frame(value)
View(prueba1)
Una vez que ya realizamo esto, simplemente usamos la función write_csv() y con esto podremos realizar la exportación de nuestro data frame. Los argumentos necesarios son el data frame a exportar, seguido del nombre que le asignaremos al archivo.
write_csv(prueba1, "logit1.csv")
logit_models.fun <- function(modelofit){
logit1.cvs <- predict(modelofit, future, type="response")
head(logit1.cvs)
logit1.cvs.class = rep("No Donor", length(future$home_value))
logit1.cvs.class[logit1.cvs >= .5] = "Donor"
head(logit1.cvs)
head(logit1.cvs.class)
mat1 <- matrix(logit1.cvs.class, ncol=1)
prueba1 <-data.frame(mat1)
write_csv(prueba1, "logit1.csv")
}
logit5.cvs <- glm(target ~ zipconvert2 + zipconvert3 + zipconvert4 +zipconvert5 + homeowner + income+ female + wealth + home_value +med_fam_inc + avg_fam_inc + pct_lt15k + num_prom +lifetime_gifts + largest_gift +last_gift + months_since_donate +time_lag + avg_gift, data=funds.train, family="binomial")
logit_models.fun(logit5.cvs)