1 1 Introducción

En este informe se presenta un análisis del fenómeno del abandono escolar en el nivel medio superior a través de técnicas estadísticas categóricas, como árboles de decisión y regresión logística. Se parte de una base de datos simulada que integra factores personales, académicos y contextuales. El objetivo es ilustrar cómo se pueden identificar los factores más influyentes en la probabilidad de abandono escolar utilizando herramientas de análisis en RMarkdown.

2 2 Resultados

2.1 2.1 Base simulada para análisis

# 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))

3 2 Árbol de decisión - Simulación Abandono en Media Superior

# 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)

4 3 Regresión logística

# 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

5 4 Gráficos de caja por variables explicativas y facetas por subgrupos

# 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")

6 5 Gráficos de caja y dispersión por subgrupos

# 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")

7 6 Gráficos de caja y dispersión complementarios

# 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")

8 7 Histograma de edad según abandono

ggplot(base_logit, aes(x = edad, fill = abandono)) +
  geom_histogram(position = "dodge", bins = 5) +
  theme_minimal() +
  labs(title = "Histograma de edad según abandono")

9 8 Probabilidades predichas por el modelo logístico

# 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")

10 9 Clasificación basada en umbral de probabilidad

# 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 %"

11 10 Comparación con diferentes umbrales de clasificación

# 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 %"

12 11 Curva de precisión según umbral

# 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")

13 12 Matriz de correlación visual (Heatmap)

# 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")

14 3 Conclusiones

A partir del análisis realizado, se identificaron diversas variables que pueden incidir significativamente en la decisión de un estudiante de abandonar sus estudios, tales como el nivel de apoyo familiar, el número de asignaturas reprobadas, el nivel socioeconómico, el estado civil y las horas de estudio semanales. El árbol de decisión permitió visualizar las rutas más frecuentes hacia el abandono escolar, mientras que la regresión logística ofreció una interpretación cuantitativa de la influencia de cada factor. La validación del modelo mostró que es posible predecir con razonable precisión el riesgo de abandono en función de los factores analizados.

Este ejercicio demuestra el valor del análisis categórico y las herramientas estadísticas en la toma de decisiones educativas.

15 4 Referencias