# Crear base simulada
set.seed(123)
base_simulada <- tibble(
genero = sample(c("Masculino", "Femenino"), 300, replace = TRUE),
edad = sample(15:19, 300, replace = TRUE),
apoyo_familiar = sample(c("Bajo", "Medio", "Alto"), 300, replace = TRUE, prob = c(0.4, 0.4, 0.2)),
calificaciones = sample(c("Bajo", "Medio", "Alto"), 300, replace = TRUE, prob = c(0.4, 0.4, 0.2)),
tecnologia_acceso = sample(c("Sí", "No"), 300, replace = TRUE, prob = c(0.7, 0.3)),
situacion_economica = sample(c("Baja", "Media", "Alta"), 300, replace = TRUE, prob = c(0.5, 0.4, 0.1)),
nivel_socioeconomico = sample(c("Bajo", "Medio", "Alto"), 300, replace = TRUE, prob = c(0.6, 0.3, 0.1)),
horas_estudio = sample(c("2 horas", "3 horas", "5 horas"), 300, replace = TRUE, prob = c(0.4, 0.4, 0.2)),
estado_civil = sample(c("Soltero/a", "Casado/a", "Unión libre"), 300, replace = TRUE, prob = c(0.6, 0.25, 0.15)),
asignaturas_reprobadas = sample(c("Ninguna", "Una", "Dos o más"), 300, replace = TRUE, prob = c(0.3, 0.4, 0.3)),
cantidad_reprobadas = sample(0:5, 300, replace = TRUE, prob = c(0.3, 0.2, 0.2, 0.15, 0.1, 0.05)),
abandono = sample(c("Sí", "No"), 300, replace = TRUE, prob = c(0.35, 0.65))
)
# Asegurar variables categóricas como factores
base_simulada <- base_simulada %>% mutate(across(-cantidad_reprobadas, as.factor))
# Crear árbol de decisión
arbol_modelo <- rpart(abandono ~ ., data = base_simulada, method = "class")
rpart.plot(arbol_modelo, type = 4, extra = 104, under = TRUE, cex = 0.9)
# Preparar base para regresión (convertir abandono a binaria y asegurar variables numéricas)
base_logit <- base_simulada %>%
mutate(
abandono_bin = ifelse(abandono == "Sí", 1, 0),
edad = as.numeric(as.character(edad)),
cantidad_reprobadas = as.numeric(as.character(cantidad_reprobadas))
)
# Verificar nombres de variables y valores faltantes
print(names(base_logit))
## [1] "genero" "edad" "apoyo_familiar"
## [4] "calificaciones" "tecnologia_acceso" "situacion_economica"
## [7] "nivel_socioeconomico" "horas_estudio" "estado_civil"
## [10] "asignaturas_reprobadas" "cantidad_reprobadas" "abandono"
## [13] "abandono_bin"
print(colSums(is.na(base_logit)))
## genero edad apoyo_familiar
## 0 0 0
## calificaciones tecnologia_acceso situacion_economica
## 0 0 0
## nivel_socioeconomico horas_estudio estado_civil
## 0 0 0
## asignaturas_reprobadas cantidad_reprobadas abandono
## 0 0 0
## abandono_bin
## 0
# Eliminar filas con valores faltantes
base_logit <- na.omit(base_logit)
# Ajustar modelo
modelo_logit <- glm(abandono_bin ~ genero + edad + apoyo_familiar + calificaciones +
tecnologia_acceso + situacion_economica + nivel_socioeconomico +
horas_estudio + estado_civil + asignaturas_reprobadas + cantidad_reprobadas,
data = base_logit, family = binomial)
summary(modelo_logit)
##
## Call:
## glm(formula = abandono_bin ~ genero + edad + apoyo_familiar +
## calificaciones + tecnologia_acceso + situacion_economica +
## nivel_socioeconomico + horas_estudio + estado_civil + asignaturas_reprobadas +
## cantidad_reprobadas, family = binomial, data = base_logit)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.08755 1.68097 -0.647 0.5176
## generoMasculino 0.46181 0.25355 1.821 0.0685 .
## edad -0.01989 0.09211 -0.216 0.8290
## apoyo_familiarBajo 0.05560 0.37076 0.150 0.8808
## apoyo_familiarMedio 0.56626 0.37078 1.527 0.1267
## calificacionesBajo -0.39538 0.35644 -1.109 0.2673
## calificacionesMedio -0.32048 0.35087 -0.913 0.3610
## tecnologia_accesoSí 0.21568 0.27497 0.784 0.4328
## situacion_economicaBaja 0.25557 0.43307 0.590 0.5551
## situacion_economicaMedia -0.13664 0.42786 -0.319 0.7494
## nivel_socioeconomicoBajo 0.30376 0.40843 0.744 0.4570
## nivel_socioeconomicoMedio 0.01479 0.44532 0.033 0.9735
## horas_estudio3 horas 0.18221 0.28044 0.650 0.5159
## horas_estudio5 horas -0.30113 0.37171 -0.810 0.4179
## estado_civilSoltero/a -0.43738 0.29577 -1.479 0.1392
## estado_civilUnión libre 0.21405 0.39409 0.543 0.5870
## asignaturas_reprobadasNinguna 0.23210 0.33727 0.688 0.4913
## asignaturas_reprobadasUna 0.31550 0.31768 0.993 0.3207
## cantidad_reprobadas 0.17406 0.08859 1.965 0.0494 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 396.42 on 299 degrees of freedom
## Residual deviance: 373.11 on 281 degrees of freedom
## AIC: 411.11
##
## Number of Fisher Scoring iterations: 4
# Gráfico de caja: cantidad de reprobadas por apoyo familiar
ggplot(base_logit, aes(x = apoyo_familiar, y = cantidad_reprobadas, fill = abandono)) +
geom_boxplot() +
theme_minimal() +
labs(title = "Asignaturas reprobadas por apoyo familiar", y = "Cantidad reprobadas")
# Gráfico de caja: edad por nivel socioeconómico
ggplot(base_logit, aes(x = nivel_socioeconomico, y = edad, fill = abandono)) +
geom_boxplot() +
theme_minimal() +
labs(title = "Edad por nivel socioeconómico", y = "Edad")
# Gráfico de caja: edad por calificaciones
ggplot(base_logit, aes(x = calificaciones, y = edad, fill = abandono)) +
geom_boxplot() +
theme_minimal() +
labs(title = "Edad por nivel de calificaciones", y = "Edad")
# Gráfico de caja: edad por apoyo familiar y género
ggplot(base_logit, aes(x = apoyo_familiar, y = edad, fill = abandono)) +
geom_boxplot() +
facet_wrap(~genero) +
theme_minimal() +
labs(title = "Edad por apoyo familiar según género", y = "Edad")
# Gráfico de caja: cantidad de reprobadas por estado civil y género
ggplot(base_logit, aes(x = estado_civil, y = cantidad_reprobadas, fill = abandono)) +
geom_boxplot() +
facet_wrap(~genero) +
theme_minimal() +
labs(title = "Asignaturas reprobadas por estado civil según género", y = "Cantidad reprobadas")
# Gráfico de caja: edad por horas de estudio y abandono
ggplot(base_logit, aes(x = horas_estudio, y = edad, fill = abandono)) +
geom_boxplot() +
facet_wrap(~abandono) +
theme_minimal() +
labs(title = "Edad según horas de estudio y abandono", y = "Edad")
# Gráfico de caja: edad vs abandono
ggplot(base_logit, aes(x = abandono, y = edad, fill = abandono)) +
geom_boxplot() +
theme_minimal() +
labs(title = "Distribución de edad según abandono")
# Gráfico de dispersión: edad vs cantidad reprobadas
ggplot(base_logit, aes(x = edad, y = cantidad_reprobadas, color = abandono)) +
geom_jitter(width = 0.2, height = 0.2, alpha = 0.6) +
theme_minimal() +
labs(title = "Dispersión entre edad y cantidad de asignaturas reprobadas")
ggplot(base_logit, aes(x = edad, fill = abandono)) +
geom_histogram(position = "dodge", bins = 5) +
theme_minimal() +
labs(title = "Histograma de edad según abandono")
# Agregar columna de probabilidades
base_logit$probabilidad_abandono <- predict(modelo_logit, type = "response")
# Mostrar primeras filas
head(base_logit[, c("abandono", "probabilidad_abandono")])
## # A tibble: 6 × 2
## abandono probabilidad_abandono
## <fct> <dbl>
## 1 No 0.309
## 2 Sí 0.610
## 3 No 0.497
## 4 No 0.200
## 5 No 0.605
## 6 No 0.246
# Gráfico de densidad de probabilidades por grupo
ggplot(base_logit, aes(x = probabilidad_abandono, fill = abandono)) +
geom_density(alpha = 0.6) +
theme_minimal() +
labs(title = "Distribución de probabilidades predichas de abandono",
x = "Probabilidad predicha", y = "Densidad")
# Clasificar abandono predicho según umbral 0.5
base_logit$prediccion_abandono <- ifelse(base_logit$probabilidad_abandono >= 0.5, "Sí", "No")
# Matriz de confusión
matriz_confusion <- table(Predicho = base_logit$prediccion_abandono, Real = base_logit$abandono)
matriz_confusion
## Real
## Predicho No Sí
## No 166 78
## Sí 22 34
# Precisión del modelo
precision <- mean(base_logit$prediccion_abandono == base_logit$abandono)
paste("Precisión del modelo: ", round(precision * 100, 2), "%")
## [1] "Precisión del modelo: 66.67 %"
# Función para generar matriz de confusión y precisión por umbral
analizar_umbral <- function(umbral) {
pred <- ifelse(base_logit$probabilidad_abandono >= umbral, "Sí", "No")
matriz <- table(Predicho = pred, Real = base_logit$abandono)
precision <- mean(pred == base_logit$abandono)
list(umbral = umbral, matriz = matriz, precision = round(precision * 100, 2))
}
# Resultados para umbrales 0.4, 0.5 y 0.6
res_04 <- analizar_umbral(0.4)
res_05 <- analizar_umbral(0.5)
res_06 <- analizar_umbral(0.6)
# Mostrar resultados
res_04$matriz
## Real
## Predicho No Sí
## No 132 55
## Sí 56 57
paste("Precisión con umbral 0.4:", res_04$precision, "%")
## [1] "Precisión con umbral 0.4: 63 %"
res_05$matriz
## Real
## Predicho No Sí
## No 166 78
## Sí 22 34
paste("Precisión con umbral 0.5:", res_05$precision, "%")
## [1] "Precisión con umbral 0.5: 66.67 %"
res_06$matriz
## Real
## Predicho No Sí
## No 177 102
## Sí 11 10
paste("Precisión con umbral 0.6:", res_06$precision, "%")
## [1] "Precisión con umbral 0.6: 62.33 %"
# Crear secuencia de umbrales
umbrales <- seq(0.1, 0.9, by = 0.05)
# Calcular precisión para cada umbral
resultados <- tibble(
umbral = umbrales,
precision = map_dbl(umbrales, ~ mean(ifelse(base_logit$probabilidad_abandono >= .x, "Sí", "No") == base_logit$abandono))
)
# Graficar curva
ggplot(resultados, aes(x = umbral, y = precision)) +
geom_line(color = "blue", size = 1.2) +
geom_point(color = "darkred") +
theme_minimal() +
labs(title = "Curva de precisión según el umbral de clasificación",
x = "Umbral de probabilidad",
y = "Precisión del modelo")
# Seleccionar variables numéricas
vars_cor <- base_logit %>%
select(edad, cantidad_reprobadas, abandono_bin, probabilidad_abandono)
# Calcular matriz de correlación
cor_matrix <- round(cor(vars_cor), 2)
# Convertir a formato largo para ggplot
cor_data <- as.data.frame(as.table(cor_matrix)) %>%
rename(Var1 = Var1, Var2 = Var2, Correlación = Freq)
# Gráfico heatmap
ggplot(cor_data, aes(Var1, Var2, fill = Correlación)) +
geom_tile(color = "white") +
geom_text(aes(label = Correlación), color = "black", size = 4) +
scale_fill_gradient2(low = "blue", high = "red", mid = "white", midpoint = 0) +
theme_minimal() +
labs(title = "Matriz de correlación entre variables numéricas")
El árbol de decisión nos ayuda a visualizar cómo diferentes factores se relacionan con el abandono escolar.
La regresión logística permite identificar la magnitud del efecto de cada variable.
Los gráficos de caja, dispersión e histogramas permiten reforzar visualmente los patrones.
Este enfoque mixto de análisis categórico e inferencial proporciona una comprensión más completa del fenómeno de abandono escolar.