Resumen

Este proyecto aplica modelos de regresión logística múltiple para identificar los factores que influyen significativamente en el rendimiento académico de estudiantes, usando una base de datos simulada con información académica, personal y contextual. La variable dependiente binaria indica si un estudiante alcanzó una nota igual o superior a 70 en el examen final. Se evaluaron múltiples modelos sucesivos incluyendo variables como horas de estudio, asistencia, tutorías, desempeño previo, actividad física y horas de sueño. El mejor modelo (modelo_4) logró un AUC de 0.94, precisión del 87%, y F1-Score de 0.864, demostrando una excelente capacidad predictiva. Los resultados respaldan el uso del modelo de regresión logística como herramienta para anticipar el desempeño académico y diseñar estrategias de apoyo basadas en datos.

1. Introducción

La comprensión de los factores que influyen en el rendimiento académico de los estudiantes es un aspecto fundamental tanto para las instituciones educativas como para los profesionales interesados en mejorar los procesos de enseñanza y aprendizaje. La posibilidad de anticipar resultados académicos mediante modelos estadísticos no solo permite identificar estudiantes en riesgo de bajo desempeño, sino que también ofrece una herramienta poderosa para la toma de decisiones pedagógicas basadas en evidencia.

En este contexto, el presente trabajo aplica herramientas de análisis estadístico, específicamente regresión logística múltiple, sobre una base de datos simulada que representa características académicas, personales y sociales de una cohorte estudiantil. Las variables incluidas abarcan aspectos como las horas de estudio semanales, la asistencia a clases, el rendimiento previo, las sesiones de tutoría, las horas de sueño, la actividad física semanal, entre otras. La variable dependiente principal es la variable binaria High_Score, que clasifica a los estudiantes según si alcanzaron o no una nota mínima de 70 puntos en el examen final.

Este enfoque permite modelar la probabilidad de aprobar, aportando una visión integral sobre los determinantes del éxito académico. Además, se aplican criterios de diagnóstico y validación como el AIC, la desviancia, la matriz de confusión, la curva ROC y métricas como el AUC y el F1-Score, para evaluar la calidad del modelo y su capacidad predictiva.

Planteamiento del problema

A pesar del creciente interés en el uso de datos para orientar procesos educativos, muchas instituciones aún carecen de herramientas sistemáticas para anticipar el rendimiento de sus estudiantes y actuar preventivamente ante situaciones de riesgo académico. El desafío principal radica en identificar, con evidencia estadística, qué variables tienen un peso significativo sobre el desempeño en pruebas estandarizadas y cómo dichas variables interactúan para predecir el éxito o el fracaso escolar.

De allí surge la necesidad de desarrollar modelos predictivos robustos que integren múltiples dimensiones del estudiante y que, además de cuantificar su influencia sobre la probabilidad de aprobación, permitan clasificar de forma confiable a los estudiantes en categorías de desempeño, facilitando intervenciones educativas focalizadas.

Objetivos:

Objetivo general:

Analizar los factores personales, académicos y contextuales que inciden en la probabilidad de aprobación de los estudiantes, mediante la aplicación de un modelo de regresión logística múltiple, evaluando su capacidad predictiva y clasificatoria.

Objetivos específicos:

2. Base de Datos

Se utilizó la base de datos StudentPerformanceFactors.csv, la cual contiene 6607 observaciones y 20 variables. Esta base incluye tanto variables cuantitativas como categóricas, relacionadas con el entorno familiar, hábitos de estudio, desempeño previo y factores personales.

Carga de librerías y datos

Se cargan las librerías necesarias y se importa la base de datos StudentPerformanceFactors.csv.

# Cargar librerías necesarias
library(readr)    # Para leer archivos CSV
library(dplyr)    # Para manipulación de datos
## 
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
# Leer la base de datos
datos <- read_csv("StudentPerformanceFactors.csv")
## Rows: 6607 Columns: 20
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (13): Parental_Involvement, Access_to_Resources, Extracurricular_Activit...
## dbl  (7): Hours_Studied, Attendance, Sleep_Hours, Previous_Scores, Tutoring_...
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Ver las primeras filas
head(datos)
## # A tibble: 6 × 20
##   Hours_Studied Attendance Parental_Involvement Access_to_Resources
##           <dbl>      <dbl> <chr>                <chr>              
## 1            23         84 Low                  High               
## 2            19         64 Low                  Medium             
## 3            24         98 Medium               Medium             
## 4            29         89 Low                  Medium             
## 5            19         92 Medium               Medium             
## 6            19         88 Medium               Medium             
## # ℹ 16 more variables: Extracurricular_Activities <chr>, Sleep_Hours <dbl>,
## #   Previous_Scores <dbl>, Motivation_Level <chr>, Internet_Access <chr>,
## #   Tutoring_Sessions <dbl>, Family_Income <chr>, Teacher_Quality <chr>,
## #   School_Type <chr>, Peer_Influence <chr>, Physical_Activity <dbl>,
## #   Learning_Disabilities <chr>, Parental_Education_Level <chr>,
## #   Distance_from_Home <chr>, Gender <chr>, Exam_Score <dbl>
# Ver estructura de la base
str(datos)
## spc_tbl_ [6,607 × 20] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ Hours_Studied             : num [1:6607] 23 19 24 29 19 19 29 25 17 23 ...
##  $ Attendance                : num [1:6607] 84 64 98 89 92 88 84 78 94 98 ...
##  $ Parental_Involvement      : chr [1:6607] "Low" "Low" "Medium" "Low" ...
##  $ Access_to_Resources       : chr [1:6607] "High" "Medium" "Medium" "Medium" ...
##  $ Extracurricular_Activities: chr [1:6607] "No" "No" "Yes" "Yes" ...
##  $ Sleep_Hours               : num [1:6607] 7 8 7 8 6 8 7 6 6 8 ...
##  $ Previous_Scores           : num [1:6607] 73 59 91 98 65 89 68 50 80 71 ...
##  $ Motivation_Level          : chr [1:6607] "Low" "Low" "Medium" "Medium" ...
##  $ Internet_Access           : chr [1:6607] "Yes" "Yes" "Yes" "Yes" ...
##  $ Tutoring_Sessions         : num [1:6607] 0 2 2 1 3 3 1 1 0 0 ...
##  $ Family_Income             : chr [1:6607] "Low" "Medium" "Medium" "Medium" ...
##  $ Teacher_Quality           : chr [1:6607] "Medium" "Medium" "Medium" "Medium" ...
##  $ School_Type               : chr [1:6607] "Public" "Public" "Public" "Public" ...
##  $ Peer_Influence            : chr [1:6607] "Positive" "Negative" "Neutral" "Negative" ...
##  $ Physical_Activity         : num [1:6607] 3 4 4 4 4 3 2 2 1 5 ...
##  $ Learning_Disabilities     : chr [1:6607] "No" "No" "No" "No" ...
##  $ Parental_Education_Level  : chr [1:6607] "High School" "College" "Postgraduate" "High School" ...
##  $ Distance_from_Home        : chr [1:6607] "Near" "Moderate" "Near" "Moderate" ...
##  $ Gender                    : chr [1:6607] "Male" "Female" "Male" "Male" ...
##  $ Exam_Score                : num [1:6607] 67 61 74 71 70 71 67 66 69 72 ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   Hours_Studied = col_double(),
##   ..   Attendance = col_double(),
##   ..   Parental_Involvement = col_character(),
##   ..   Access_to_Resources = col_character(),
##   ..   Extracurricular_Activities = col_character(),
##   ..   Sleep_Hours = col_double(),
##   ..   Previous_Scores = col_double(),
##   ..   Motivation_Level = col_character(),
##   ..   Internet_Access = col_character(),
##   ..   Tutoring_Sessions = col_double(),
##   ..   Family_Income = col_character(),
##   ..   Teacher_Quality = col_character(),
##   ..   School_Type = col_character(),
##   ..   Peer_Influence = col_character(),
##   ..   Physical_Activity = col_double(),
##   ..   Learning_Disabilities = col_character(),
##   ..   Parental_Education_Level = col_character(),
##   ..   Distance_from_Home = col_character(),
##   ..   Gender = col_character(),
##   ..   Exam_Score = col_double()
##   .. )
##  - attr(*, "problems")=<externalptr>

Selección de variables relevantes

Para este modelo se seleccionan las siguientes variables explicativas:

  • Hours_Studied: Horas de estudio semanales.
  • Sleep_Hours: Horas de sueño promedio por noche.
  • Tutoring_Sessions: Número de sesiones de tutoría por mes.
  • Previous_Scores: Puntajes anteriores.
  • Attendance: Porcentaje de asistencia a clases.
  • Physical_Activity: Horas de actividad física semanal.

La base incluye variables de distintos tipos:

Cuantitativas: Hours_Studied, Attendance, Sleep_Hours, Previous_Scores, Tutoring_Sessions, Physical_Activity, Exam_Score.

Categóricas: Parental_Involvement, Access_to_Resources, Motivation_Level, Internet_Access, Gender, School_Type, etc.

Estas variables permiten una caracterización integral de cada estudiante.

# Seleccionar solo las variables necesarias
datos_modelo <- datos %>%
  select(Hours_Studied, Attendance, Previous_Scores, Sleep_Hours, Tutoring_Sessions, Exam_Score, Physical_Activity)

# Eliminar filas con NA
datos_modelo <- na.omit(datos_modelo)

# Ver estructura y primeras filas
str(datos_modelo)
## tibble [6,607 × 7] (S3: tbl_df/tbl/data.frame)
##  $ Hours_Studied    : num [1:6607] 23 19 24 29 19 19 29 25 17 23 ...
##  $ Attendance       : num [1:6607] 84 64 98 89 92 88 84 78 94 98 ...
##  $ Previous_Scores  : num [1:6607] 73 59 91 98 65 89 68 50 80 71 ...
##  $ Sleep_Hours      : num [1:6607] 7 8 7 8 6 8 7 6 6 8 ...
##  $ Tutoring_Sessions: num [1:6607] 0 2 2 1 3 3 1 1 0 0 ...
##  $ Exam_Score       : num [1:6607] 67 61 74 71 70 71 67 66 69 72 ...
##  $ Physical_Activity: num [1:6607] 3 4 4 4 4 3 2 2 1 5 ...
head(datos_modelo)
## # A tibble: 6 × 7
##   Hours_Studied Attendance Previous_Scores Sleep_Hours Tutoring_Sessions
##           <dbl>      <dbl>           <dbl>       <dbl>             <dbl>
## 1            23         84              73           7                 0
## 2            19         64              59           8                 2
## 3            24         98              91           7                 2
## 4            29         89              98           8                 1
## 5            19         92              65           6                 3
## 6            19         88              89           8                 3
## # ℹ 2 more variables: Exam_Score <dbl>, Physical_Activity <dbl>

3. Normalidad

A diferencia de la regresión lineal, en la regresión logística no es necesario ni apropiado exigir que la variable dependiente ni los errores sean normales, porque:

La variable dependiente es binaria (0 = no aprobado, 1 = aprobado), por lo que no puede seguir una distribución normal.

El modelo logístico no asume normalidad de los errores. En su lugar, se basa en la función de verosimilitud y en una distribución binomial para los errores.

4. Análisis de Correlación y Relación Entre Variables:

Análisis gráfico y numérico de la relación entre variables:

Ajuste del modelo de regresión

Paso 1: Crear una variable binaria

Vamos a crear una variable llamada High_Score, que tome el valor 1 si el estudiante aprobó el examen, utilizando como punto de corte una nota ≥ 70, y 0 para indicar que el estudiante reprobó, es decir obtuvo una nora < 70.

datos_modelo <- datos_modelo %>%
  mutate(High_Score = ifelse(Exam_Score >= 70, 1, 0))

4.1 Correlación entre variables cuantitativas

Para evaluar la relación entre los predictores numéricos, se calcula la matriz de correlación de Spearman:

library(corrplot)
## corrplot 0.95 loaded
cor_matrix <- cor(datos_modelo[, c("Hours_Studied", "Attendance", "Previous_Scores",
                                   "Sleep_Hours", "Tutoring_Sessions", "Physical_Activity")],
                  method = "spearman")
corrplot(cor_matrix, method = "color", type = "upper", tl.col = "black", tl.cex = 0.8)

Interpretación

La mayoría de las correlaciones son bajas (< 0.3), lo cual indica baja colinealidad entre predictores. Esto es adecuado para el modelo, ya que reduce el riesgo de multicolinealidad.

4.2 Gráficos de dispersión entre pares de variables

pairs(datos_modelo[, c("Hours_Studied", "Attendance", "Previous_Scores",
                       "Tutoring_Sessions", "Sleep_Hours", "Physical_Activity")],
      main = "Gráficos de dispersión entre predictores")

Interpretación:

Los gráficos de dispersión muestran relaciones débiles o moderadas entre variables, sin colinealidades graves. Se observa tendencia creciente entre algunas variables (como horas de estudio y asistencia) lo que refuerza su utilidad como predictores.

4.3 Boxplots: Comparación de variables según desempeño

Se analizan los predictores numéricos según la variable High_Score (0 = no aprobado, 1 = aprobado)

library(ggplot2)
predictores <- c("Hours_Studied", "Attendance", "Previous_Scores",
                 "Tutoring_Sessions", "Sleep_Hours", "Physical_Activity")

for (var in predictores) {print(ggplot(datos_modelo, aes_string(x = "factor(High_Score)", y = var)) + geom_boxplot(fill = "lightblue") +
      labs(title = paste("Boxplot de", var, "por High_Score"),
           x = "High_Score (0 = No Aprobado, 1 = Aprobado)",
           y = var) +
      theme_minimal())}
## Warning: `aes_string()` was deprecated in ggplot2 3.0.0.
## ℹ Please use tidy evaluation idioms with `aes()`.
## ℹ See also `vignette("ggplot2-in-packages")` for more information.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

Interpretación

Los boxplots muestran que los estudiantes que aprobaron tienden a tener valores más altos en variables como Hours_Studied, Attendance y Previous_Scores. Esta diferenciación apoya su inclusión en el modelo logístico.

5.Selección y Planteamiento del Modelo

Qué es la regresión logística múltiple?

Es una extensión de la regresión logística simple, donde en lugar de tener una sola variable independiente, incluyes varias variables explicativas.

5.1 Justificación estadística del tipo de regresión

Naturaleza de la variable dependiente: La variable objetivo del estudio es High_Score, es una variable categórica dicotómica que indica si un estudiante aprobó (1) o no aprobó (0) el examen final. Dado que se trata de una variable binaria, la regresión logística es el enfoque más adecuado, pues modela la probabilidad de ocurrencia de un evento frente a su no ocurrencia.

Relación no lineal esperada: A diferencia de la regresión lineal, la regresión logística permite modelar relaciones no lineales entre los predictores y la probabilidad de éxito, utilizando la función logística (sigmoidea).

Propósito del análisis: No se busca predecir un valor continuo (como un puntaje), sino estimar la probabilidad de aprobar, clasificar observaciones, e identificar qué variables influyen significativamente en esa probabilidad.

5.2 Variable dependiente e independientes

Variable dependiente: High_Score (1 = aprobado, 0 = no aprobado)

Variables independientes seleccionadas en el modelo final (modelo_4):

Hours_Studied (Horas de estudio semanales)

Sleep_Hours (Horas promedio de sueño por noche)

Tutoring_Sessions (Número de sesiones de tutoría por mes)

Previous_Scores (Puntajes anteriores)

Attendance (Porcentaje de asistencia a clases)

Physical_Activity (Horas semanales de actividad física)

Planteamiento formal del modelo

El modelo tiene esta forma:

\[ \log\left( \frac{p}{1-p} \right) = \beta_0 + \beta_1 X_1 + \beta_2 X_2 + \cdots + \beta_k X_k \]

6. RESULTADOS

Ajustamos varios modelos de regresión logística múltiple, con distintas combinaciones de variables:

modelo_1 <- glm(High_Score ~ Hours_Studied + Attendance, data = datos_modelo, family = binomial)
summary(modelo_1)
## 
## Call:
## glm(formula = High_Score ~ Hours_Studied + Attendance, family = binomial, 
##     data = datos_modelo)
## 
## Coefficients:
##                 Estimate Std. Error z value Pr(>|z|)    
## (Intercept)   -23.053091   0.607793  -37.93   <2e-16 ***
## Hours_Studied   0.286737   0.009446   30.36   <2e-16 ***
## Attendance      0.187612   0.005376   34.90   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 7371.3  on 6606  degrees of freedom
## Residual deviance: 4007.7  on 6604  degrees of freedom
## AIC: 4013.7
## 
## Number of Fisher Scoring iterations: 6
modelo_2 <- glm(High_Score ~ Hours_Studied + Attendance + Previous_Scores, data = datos_modelo, family = binomial)
summary(modelo_2)
## 
## Call:
## glm(formula = High_Score ~ Hours_Studied + Attendance + Previous_Scores, 
##     family = binomial, data = datos_modelo)
## 
## Coefficients:
##                   Estimate Std. Error z value Pr(>|z|)    
## (Intercept)     -28.276954   0.765359  -36.95   <2e-16 ***
## Hours_Studied     0.302602   0.010019   30.20   <2e-16 ***
## Attendance        0.201948   0.005819   34.70   <2e-16 ***
## Previous_Scores   0.048019   0.003091   15.53   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 7371.3  on 6606  degrees of freedom
## Residual deviance: 3740.5  on 6603  degrees of freedom
## AIC: 3748.5
## 
## Number of Fisher Scoring iterations: 6
modelo_3 <- glm(High_Score ~ Hours_Studied + Attendance + Previous_Scores + Tutoring_Sessions, data = datos_modelo, family = binomial)
summary(modelo_3)
## 
## Call:
## glm(formula = High_Score ~ Hours_Studied + Attendance + Previous_Scores + 
##     Tutoring_Sessions, family = binomial, data = datos_modelo)
## 
## Coefficients:
##                     Estimate Std. Error z value Pr(>|z|)    
## (Intercept)       -31.543543   0.871041  -36.21   <2e-16 ***
## Hours_Studied       0.329739   0.010884   30.30   <2e-16 ***
## Attendance          0.218521   0.006396   34.16   <2e-16 ***
## Previous_Scores     0.053212   0.003245   16.40   <2e-16 ***
## Tutoring_Sessions   0.546184   0.036649   14.90   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 7371.3  on 6606  degrees of freedom
## Residual deviance: 3498.6  on 6602  degrees of freedom
## AIC: 3508.6
## 
## Number of Fisher Scoring iterations: 7
modelo_4 <- glm(High_Score ~ Hours_Studied + Sleep_Hours + Tutoring_Sessions + Previous_Scores + Attendance + Physical_Activity, data = datos_modelo, family = binomial)
summary(modelo_4)
## 
## Call:
## glm(formula = High_Score ~ Hours_Studied + Sleep_Hours + Tutoring_Sessions + 
##     Previous_Scores + Attendance + Physical_Activity, family = binomial, 
##     data = datos_modelo)
## 
## Coefficients:
##                     Estimate Std. Error z value Pr(>|z|)    
## (Intercept)       -32.440246   0.925379 -35.056  < 2e-16 ***
## Hours_Studied       0.331895   0.010966  30.266  < 2e-16 ***
## Sleep_Hours         0.009559   0.029601   0.323    0.747    
## Tutoring_Sessions   0.549444   0.036844  14.913  < 2e-16 ***
## Previous_Scores     0.053847   0.003260  16.518  < 2e-16 ***
## Attendance          0.220439   0.006452  34.167  < 2e-16 ***
## Physical_Activity   0.191484   0.042114   4.547 5.45e-06 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 7371.3  on 6606  degrees of freedom
## Residual deviance: 3477.6  on 6600  degrees of freedom
## AIC: 3491.6
## 
## Number of Fisher Scoring iterations: 7

Interpretación de Desviancias:

Modelo Variables incluidas Desviancia
modelo_1 Hours_Studied, Attendance 4007.7
modelo_2 modelo_1 + Previous_Scores 3740.5
modelo_3 modelo_2 + Tutoring_Sessions 3498.6
modelo_4 modelo_3 + Sleep_Hours + Physical_Activity 3477.6
  • modelo_1 Utiliza solo dos predictores: Hours_Studied y Attendance.

Desviancia: 4007.7, la más alta.

Esto indica que el modelo tiene un ajuste pobre y no captura bien toda la información relevante.

  • modelo_2 Añade Previous_Scores, mejorando el ajuste.

Desviancia baja a 3740.5, lo que representa una mejora considerable.

Confirma que el rendimiento previo es un predictor importante.

  • modelo_3 Agrega Tutoring_Sessions.

Desviancia: 3498.6.

El modelo mejora aún más al considerar el acceso a tutorías, que es otra variable predictiva significativa.

  • modelo_4 Incorpora Sleep_Hours y Physical_Activity.

Desviancia final: 3477.6, la más baja de todos los modelos.

Aunque Sleep_Hours no es significativa, el modelo completo mejora el ajuste general.

Calculamos el AIC de cada modelo:

AIC(modelo_1, modelo_2, modelo_3, modelo_4)
##          df      AIC
## modelo_1  3 4013.688
## modelo_2  4 3748.475
## modelo_3  5 3508.571
## modelo_4  7 3491.574

Comparación de modelos según AIC:

Modelo Variables incluidas AIC
modelo_1 Hours_Studied, Attendance 4013.7
modelo_2 modelo_1 + Previous_Scores 3748.5
modelo_3 modelo_2 + Tutoring_Sessions 3508.6
modelo_4 modelo_3 + Sleep_Hours + Physical_Activity 3491.6
  • ¿Cuál es el mejor modelo?:

El modelo_4 tiene el AIC más bajo (3491.6), lo que indica que es el modelo con mejor balance entre ajuste y complejidad.

Aunque Sleep_Hours no fue significativa (p = 0.747), su inclusión no aumentó el AIC, y Physical_Activity sí fue significativa.

Curva logística para modelo_4

# Asegúrate de tener las librerías necesarias
library(ggplot2)
library(patchwork)
## Warning: package 'patchwork' was built under R version 4.4.3
# Obtener coeficientes del modelo
coefs <- coef(modelo_4)

# Media de cada variable (para mantenerlas fijas)
medias <- colMeans(datos_modelo[, c("Hours_Studied", "Sleep_Hours", "Tutoring_Sessions", 
                                    "Previous_Scores", "Attendance", "Physical_Activity")])

# Función para crear una curva logística univariada manteniendo las otras variables fijas
curva_logistica <- function(var, var_label) {
  # Secuencia de valores para la variable
  secuencia <- seq(min(datos_modelo[[var]]), max(datos_modelo[[var]]), length.out = 100)
  
  # Crear data frame con la variable de interés variando y las otras fijas en su media
  datos_curva <- as.data.frame(t(sapply(secuencia, function(x) {
    vec <- medias
    vec[var] <- x
    return(vec)
  })))
  
  # Agregar nombre de columnas
  colnames(datos_curva) <- names(medias)
  
  # Predecir probabilidades
  datos_curva$Probabilidad <- predict(modelo_4, newdata = datos_curva, type = "response")
  datos_curva$Variable <- secuencia
  
  # Graficar
  ggplot(datos_curva, aes(x = Variable, y = Probabilidad)) +
    geom_line(color = "blue", size = 1) +
    labs(x = "Valor de la variable",
         y = "Probabilidad estimada de aprobar",
         title = var_label) +
    theme_minimal()
}

# Crear todas las curvas
g1 <- curva_logistica("Attendance", "Attendance")
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
g2 <- curva_logistica("Hours_Studied", "Hours_Studied")
g3 <- curva_logistica("Previous_Scores", "Previous_Scores")
g4 <- curva_logistica("Tutoring_Sessions", "Tutoring_Sessions")
g5 <- curva_logistica("Sleep_Hours", "Sleep_Hours")
g6 <- curva_logistica("Physical_Activity", "Physical_Activity")

# Juntar los gráficos en una sola figura con 2 filas y 3 columnas
(g1 | g2 | g3) / (g4 | g5 | g6) +
  plot_annotation(title = "Curvas logísticas por variable (modelo_4)")

Interpretación variable por variable:

1. Attendance

Tiene una forma sigmoidea muy clara.

A medida que la asistencia sube del 80% al 100%, la probabilidad de aprobar pasa de cerca de 0 a más de 0.9.

Es uno de los predictores más potentes.

2. Hours_Studied

Similar a Attendance: curva logística muy pronunciada.

El salto más importante en probabilidad ocurre entre 15 y 30 horas semanales de estudio.

3. Previous_Scores

Curva creciente pero más suave.

El efecto es importante, pero más gradual. Mejores puntajes anteriores → mayor probabilidad de éxito actual.

4. Tutoring_Sessions

Relación positiva clara: más tutorías → mayor probabilidad de aprobar.

El cambio es bastante progresivo (no tan abrupto como con Hours_Studied).

5. Sleep_Hours

Curva muy plana: indica muy poca variación en la probabilidad.

Identificado como no significativo en el modelo → esta gráfica lo confirma visualmente.

6. Physical_Activity

Curva creciente leve → contribuye de forma moderada.

La probabilidad de aprobar aumenta, pero en un rango muy estrecho (de 0.04 a 0.11 aprox).

Conclusión visual:

Las variables Attendance y Hours_Studied son las más influyentes.

Sleep_Hours tiene un efecto muy bajo → se podría considerar excluirla si lo que se busca es un modelo más parsimonioso.

Las variables (Previous_Scores, Tutoring_Sessions, Physical_Activity) también contribuyen, con diferentes magnitudes.

7. EVALUACIÓN DEL MODELO

Regresión logística múltiple (modelo_4)

# Paso 1: Generar predicciones de probabilidad
probabilidades <- predict(modelo_4, type = "response")

# Paso 2: Clasificar usando umbral 0.3
predicciones_03 <- ifelse(probabilidades >= 0.3, 1, 0)

# Paso 3: Calcular matriz de confusión
VP <- sum(predicciones_03 == 1 & datos_modelo$High_Score == 1)
VN <- sum(predicciones_03 == 0 & datos_modelo$High_Score == 0)
FP <- sum(predicciones_03 == 1 & datos_modelo$High_Score == 0)
FN <- sum(predicciones_03 == 0 & datos_modelo$High_Score == 1)

Visualización de la matriz de confusión (modelo_4)

library(ggplot2)
library(dplyr)

# Convertir las predicciones y valores reales a factores con etiquetas
datos_modelo$Pred_Logit_03 <- factor(predicciones_03, levels = c(0, 1), labels = c("No Aprobado", "Aprobado"))
datos_modelo$Real_Logit <- factor(datos_modelo$High_Score, levels = c(0, 1), labels = c("No Aprobado", "Aprobado"))

# Crear la tabla de frecuencia
matriz_confusion <- table(Real = datos_modelo$Real_Logit, Predicho = datos_modelo$Pred_Logit_03)
matriz_df <- as.data.frame(matriz_confusion)

# Graficar heatmap
ggplot(matriz_df, aes(x = Real, y = Predicho, fill = Freq)) +
  geom_tile(color = "white") +
  geom_text(aes(label = Freq), size = 6) +
  scale_fill_gradient(low = "#deebf7", high = "#08519c") +
  labs(title = "Matriz de Confusion - Modelo Logistico Multiple",
       x = "Clase real",
       y = "Clase predicha",
       fill = "Frecuencia") +
  theme_minimal(base_size = 14)

Interpretación:

  • Verdaderos Positivos (VP = 1395): Estudiantes que aprobaron y fueron correctamente clasificados.

  • Falsos Negativos (FN = 230): Estudiantes que aprobaron, pero el modelo los clasificó como no aprobados.

  • Verdaderos Negativos (VN = 4355): Estudiantes que no aprobaron y fueron correctamente identificados.

  • Falsos Positivos (FP = 627): Estudiantes que no aprobaron, pero el modelo los clasificó como aprobados.

Métricas:

# Paso 4: Calcular métricas
precision <- (VP + VN) / (VP + VN + FP + FN)
sensibilidad <- VP / (VP + FN)
especificidad <- VN / (VN + FP)
f1_score <- 2 * (precision * sensibilidad) / (precision + sensibilidad)

# Mostrar resultados
cat("Evaluacion modelo_4 (Umbral 0.3):\n")
## Evaluacion modelo_4 (Umbral 0.3):
cat("Precision:", round(precision, 3), "\n")
## Precision: 0.87
cat("Sensibilidad:", round(sensibilidad, 3), "\n")
## Sensibilidad: 0.858
cat("Especificidad:", round(especificidad, 3), "\n")
## Especificidad: 0.874
cat("F1-Score:", round(f1_score, 3), "\n")
## F1-Score: 0.864
Métrica Valor Interpretación
Precisión 0.870 El 87.0% de todas las predicciones fueron correctas.
Sensibilidad 0.858 El modelo identificó correctamente el 85.8% de los estudiantes que aprobaron.
Especificidad 0.874 Identificó correctamente el 87.4% de los estudiantes que no aprobaron.
F1-Score 0.864 Excelente equilibrio entre sensibilidad y precisión.

Interpretación

  • El modelo clasifica de forma muy precisa tanto los aprobados como los no aprobados.

  • La sensibilidad alta indica que rara vez deja de identificar a quienes sí aprobaron.

  • El F1-Score de 0.864 confirma que el modelo tiene un rendimiento equilibrado.

  • Esto lo convierte en una herramienta útil para predecir con anticipación el rendimiento académico, ideal para intervenir antes de que ocurra el fracaso escolar.

Curva ROC y AUC del modelo_4

library(pROC)
## Type 'citation("pROC")' for a citation.
## 
## Adjuntando el paquete: 'pROC'
## The following objects are masked from 'package:stats':
## 
##     cov, smooth, var
roc_obj <- roc(datos_modelo$High_Score, probabilidades)
## Setting levels: control = 0, case = 1
## Setting direction: controls < cases
plot(roc_obj, col = "darkblue", main = "Curva ROC - modelo_4")

auc(roc_obj)
## Area under the curve: 0.94

La Curva ROC (Receiver Operating Characteristic) permite visualizar el rendimiento del modelo en todos los posibles umbrales de clasificación. Representa la relación entre:

  • Sensibilidad (eje Y): Tasa de verdaderos positivos.

  • 1 - Especificidad (eje X): Tasa de falsos positivos.

En el gráfico, la línea azul representa la curva del modelo, mientras que la línea diagonal gris representa un clasificador aleatorio.

-Area Bajo la Curva (AUC): 0.94

  • El valor de AUC = 0.94 indica que el modelo tiene una capacidad de discriminación excelente.

  • En términos prácticos: si se selecciona un estudiante que aprobó y uno que no al azar, hay un 94% de probabilidad de que el modelo asigne una probabilidad mayor al estudiante que aprobó.

  • Cuanto más cerca de 1 esté el AUC, mejor es el modelo clasificando correctamente.

8. RESULTADOS Y CONCLUSIONES

Conclusión Final

El presente análisis empleó modelos de regresión logística multiple para predecir la probabilidad de que un estudiante obtenga una nota igual o superior a 70 puntos (variable binaria High_Score), utilizando como predictores variables académicas y de hábitos personales.

Se desarrollaron distintos modelos incluyendo variables predictoras: Attendance, Previous Scores, Tutoring Sessions, Sleep Hours y Physical Activity.

El modelo más completo y con mejor desempeño fue el que incluyó todas las variables anteriores (modelo_4):

  • AUC: 0.94 → excelente discriminación.

  • Precisión: 0.87

  • Sensibilidad: 0.858

  • Especificidad: 0.874

  • F1-Score: 0.864

  • AIC: 3491.6 (el más bajo de todos los modelos probados)

  • Desviancia residual: 3477.6 → la más baja de todos los modelos

Este modelo mostró una gran capacidad de clasificación, tanto en detectar a los estudiantes con alto desempeño como a quienes no alcanzan la nota mínima.

Conclusiones principales

Variables más influyentes: Los predictores Attendance, Hours_Studied, Previous_Scores y Tutoring_Sessions fueron estadísticamente significativos y tuvieron una relación positiva con la probabilidad de aprobar. Entre ellas, la asistencia se destacó como el predictor más relevante.

Variables moderadamente relevantes: Physical_Activity presentó una contribución positiva y significativa, aunque su efecto fue menor. Sleep_Hours, si bien se incluyó en el modelo final, no resultó estadísticamente significativa.

Curvas logísticas: Las visualizaciones confirmaron que las variables con mayor efecto tienen una forma sigmoidea pronunciada, reforzando su capacidad predictiva dentro del modelo logístico.

Matriz de confusión y evaluación de desempeño: El modelo logró un alto desempeño clasificatorio, con una baja tasa de errores tipo I y II. Al aplicar un umbral de 0.3 en lugar del tradicional 0.5, se mejoró notablemente la sensibilidad sin sacrificar especificidad.

Consideraciones finales

El análisis demuestra que el uso de modelos de regresión logística múltiple constituye una herramienta potente para anticipar el rendimiento académico y orientar intervenciones educativas tempranas. La correcta identificación de los factores predictivos permite:

Desarrollar estrategias de apoyo dirigidas a estudiantes en riesgo.

Fomentar políticas institucionales basadas en evidencia.

Promover la toma de decisiones pedagógicas más informadas.

Este modelo puede ser replicado o adaptado a contextos reales con datos académicos institucionales, lo que refuerza su utilidad práctica y su aplicabilidad en la gestión educativa.

Los hallazgos de este estudio demuestran que la regresión logística múltiple es una herramienta robusta y efectiva para modelar la probabilidad de aprobación académica en función de variables observables. La alta capacidad predictiva alcanzada, junto con la claridad en la interpretación de los coeficientes y el rendimiento del modelo, permite utilizar esta metodología como base para intervenciones educativas focalizadas. En contextos institucionales reales, un modelo como el propuesto puede facilitar la identificación temprana de estudiantes en riesgo académico y orientar decisiones pedagógicas más eficientes, sostenidas en evidencia estadistica.