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.
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:
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.
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>
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>
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.
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))
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)
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.
pairs(datos_modelo[, c("Hours_Studied", "Attendance", "Previous_Scores",
"Tutoring_Sessions", "Sleep_Hours", "Physical_Activity")],
main = "Gráficos de dispersión entre predictores")
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.
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.
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.
Es una extensión de la regresión logística simple, donde en lugar de tener una sola variable independiente, incluyes varias variables explicativas.
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.
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)
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 \]
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
| 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 |
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.
Desviancia baja a 3740.5, lo que representa una mejora considerable.
Confirma que el rendimiento previo es un predictor importante.
Desviancia: 3498.6.
El modelo mejora aún más al considerar el acceso a tutorías, que es otra variable predictiva significativa.
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.
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
| 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 |
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.
# 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.
# 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)
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.
# 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. |
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.
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.
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.
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.
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.