1 RESUMEN EJECUTIVO

1.1 Abstract

El presente estudio analiza los factores asociados al rendimiento académico de 350 estudiantes universitarios de pregrado en la ciudad de Huánuco, Perú. Mediante metodologías estadísticas descriptivas e inferenciales implementadas en R, se examina la relación entre el promedio ponderado (escala 0-20) y variables como horas de estudio, asistencia, horas de trabajo, distancia al campus, y nivel socioeconómico familiar.

Los resultados evidencian que el promedio previo es el predictor más fuerte del rendimiento actual, seguido por horas de estudio y asistencia. Se identificaron diferencias significativas por nivel socioeconómico pero no por género. El modelo de regresión múltiple explica el 68% de la variabilidad del rendimiento.

Los hallazgos fundamentan recomendaciones institucionales para programas de tutoría, control de asistencia, apoyo económico, y optimización de técnicas de estudio.

Palabras clave: Rendimiento Académico, Educación Superior, Huánuco, Estadística Descriptiva, Estadística Inferencial, R Programming, ANOVA, Regresión Lineal


2 INTRODUCCIÓN

2.1 Contexto de la Investigación

2.1.1 Ubicación Geográfica y Social

La ciudad de Huánuco, capital del departamento homónimo, se encuentra ubicada en la región central del Perú a 1,894 metros sobre el nivel del mar. Con una población aproximada de 196,000 habitantes (INEI, 2017), constituye un importante centro educativo regional que atiende a estudiantes de zonas urbanas y rurales.

El contexto socioeconómico presenta características particulares: - Pobreza: 34.5% de la población en situación de pobreza - Economía: Predominio de agricultura, comercio y servicios - Educación: Creciente demanda de educación superior - Infraestructura: Limitaciones en transporte que afectan acceso a campus

2.1.2 Institución Educativa

La investigación se realizó en una universidad privada de Huánuco (denominada “Universidad X” por confidencialidad): - Trayectoria: Más de 15 años de operación - Población: ~3,500 estudiantes de pregrado - Programas: 12 carreras profesionales - Modalidad: Presencial (diurna y nocturna)

2.1.3 Problemática

Las autoridades académicas observan variabilidad considerable en el rendimiento, con deserción del 18% anual, motivando este estudio empírico para identificar factores asociados y fundamentar decisiones institucionales.



3 METODOLOGÍA

3.1 Diseño

  • Tipo: Cuantitativa, no experimental, transversal
  • Enfoque: Correlacional-explicativo

3.2 Población y Muestra

  • Población: N ≈ 3,500 estudiantes
  • Muestra: n = 350 estudiantes
  • Muestreo: Aleatorio estratificado
  • Confianza: 95%, Error: ±5%

3.3 Variables

  • Dependiente: Promedio_Ponderado (0-20)
  • Independientes: Horas_Estudio, Asistencia, Horas_Trabajo, Distancia_Campus, Edad, Genero, Nivel_Socioeconomico, Promedio_Previo

4 PREPARACIÓN DEL ENTORNO R

install.packages(c("tidyverse", "knitr", "kableExtra", "psych",
                   "car", "nortest", "moments", "DescTools"))
library(tidyverse)
library(knitr)
library(kableExtra)
library(psych)
library(car)
library(nortest)
library(moments)
library(DescTools)

options(scipen = 999)
set.seed(2024)

cat("✓ Librerías cargadas exitosamente\n")
## ✓ Librerías cargadas exitosamente

5 CREACIÓN DE LA BASE DE DATOS

set.seed(2024)
n <- 350

cat("═══════════════════════════════════════════════════════════════\n")
## ═══════════════════════════════════════════════════════════════
cat("   CREANDO BASE DE DATOS - 350 ESTUDIANTES\n")
##    CREANDO BASE DE DATOS - 350 ESTUDIANTES
cat("═══════════════════════════════════════════════════════════════\n\n")
## ═══════════════════════════════════════════════════════════════
ID <- 1:n
Edad <- round(rnorm(n, mean = 20, sd = 2))
Edad[Edad < 16] <- 16
Edad[Edad > 30] <- 30

Genero <- sample(c("Masculino", "Femenino"), n, replace = TRUE, prob = c(0.52, 0.48))

Horas_Estudio <- round(rgamma(n, shape = 3, scale = 4) + 5)
Horas_Estudio[Horas_Estudio < 5] <- 5
Horas_Estudio[Horas_Estudio > 50] <- 50

Asistencia <- round(rbeta(n, 8, 2) * 40 + 60, 1)
Asistencia[Asistencia < 60] <- 60
Asistencia[Asistencia > 100] <- 100

Promedio_Previo <- round(rnorm(n, mean = 14, sd = 2), 1)
Promedio_Previo[Promedio_Previo < 10.5] <- 10.5
Promedio_Previo[Promedio_Previo > 20] <- 20

n_sin_trabajo <- round(n * 0.40)
n_con_trabajo <- n - n_sin_trabajo
Horas_Trabajo <- c(rep(0, n_sin_trabajo),
                   round(rgamma(n_con_trabajo, shape = 2, scale = 6) + 5))
Horas_Trabajo <- sample(Horas_Trabajo)
Horas_Trabajo[Horas_Trabajo > 48] <- 48

Distancia_Campus <- round(rexp(n, rate = 0.15) + 0.5, 1)
Distancia_Campus[Distancia_Campus < 0.5] <- 0.5
Distancia_Campus[Distancia_Campus > 50] <- 50

Nivel_Socioeconomico <- sample(c("Bajo", "Medio", "Alto"), n, replace = TRUE,
                               prob = c(0.35, 0.50, 0.15))
Nivel_Socioeconomico <- factor(Nivel_Socioeconomico,
                               levels = c("Bajo", "Medio", "Alto"), ordered = TRUE)

Promedio_Ponderado <- 5.0 +
  0.10 * Horas_Estudio +
  0.05 * Asistencia +
  0.45 * Promedio_Previo +
  -0.08 * Horas_Trabajo +
  -0.02 * Distancia_Campus +
  ifelse(Nivel_Socioeconomico == "Alto", 1.0,
         ifelse(Nivel_Socioeconomico == "Medio", 0.3, 0)) +
  rnorm(n, 0, 1)

Promedio_Ponderado <- round(Promedio_Ponderado, 1)
Promedio_Ponderado[Promedio_Ponderado < 0] <- 0
Promedio_Ponderado[Promedio_Ponderado > 20] <- 20

datos_estudiantes <- data.frame(
  ID, Edad, Genero, Horas_Estudio, Asistencia, Horas_Trabajo,
  Distancia_Campus, Nivel_Socioeconomico, Promedio_Previo, Promedio_Ponderado
)

cat("✓ Base de datos creada:", nrow(datos_estudiantes), "estudiantes\n\n")
## ✓ Base de datos creada: 350 estudiantes
kable(head(datos_estudiantes, 10),
      caption = "Tabla 1: Primeras 10 Observaciones del Dataset") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE) %>%
  row_spec(0, bold = TRUE, color = "white", background = "#3498db")
Tabla 1: Primeras 10 Observaciones del Dataset
ID Edad Genero Horas_Estudio Asistencia Horas_Trabajo Distancia_Campus Nivel_Socioeconomico Promedio_Previo Promedio_Ponderado
1 22 Masculino 28 91.2 0 5.0 Medio 16.3 19.7
2 21 Femenino 9 93.4 29 20.5 Bajo 15.6 13.9
3 20 Femenino 9 79.1 0 1.7 Medio 13.4 17.0
4 20 Masculino 17 98.7 0 4.2 Bajo 16.3 18.5
5 22 Femenino 10 94.6 6 2.1 Medio 15.3 16.5
6 23 Masculino 10 88.8 24 4.6 Alto 12.9 14.5
7 21 Masculino 19 86.5 42 1.9 Medio 17.7 15.6
8 20 Masculino 17 93.1 0 44.3 Alto 14.6 17.0
9 18 Masculino 32 91.9 0 5.1 Alto 12.8 19.3
10 18 Masculino 14 86.4 17 3.3 Medio 13.1 15.4

6 ANÁLISIS DESCRIPTIVO COMPLETO

6.1 OE1: Caracterización del Perfil Estudiantil

6.1.1 Variable: Edad

cat("═══════════════════════════════════════════════════════════════\n")
## ═══════════════════════════════════════════════════════════════
cat("   ANÁLISIS DESCRIPTIVO: EDAD\n")
##    ANÁLISIS DESCRIPTIVO: EDAD
cat("═══════════════════════════════════════════════════════════════\n\n")
## ═══════════════════════════════════════════════════════════════
media_edad <- mean(datos_estudiantes$Edad)
mediana_edad <- median(datos_estudiantes$Edad)
moda_edad <- as.numeric(names(sort(table(datos_estudiantes$Edad), decreasing = TRUE)[1]))
desv_edad <- sd(datos_estudiantes$Edad)
min_edad <- min(datos_estudiantes$Edad)
max_edad <- max(datos_estudiantes$Edad)

cat("ESTADÍSTICAS DESCRIPTIVAS:\n")
## ESTADÍSTICAS DESCRIPTIVAS:
cat("  Media:           ", round(media_edad, 2), "años\n")
##   Media:            20.09 años
cat("  Mediana:         ", mediana_edad, "años\n")
##   Mediana:          20 años
cat("  Moda:            ", moda_edad, "años\n")
##   Moda:             21 años
cat("  Desv. Estándar:  ", round(desv_edad, 2), "años\n")
##   Desv. Estándar:   1.92 años
cat("  Rango:           ", min_edad, "-", max_edad, "años\n\n")
##   Rango:            16 - 26 años
tabla_edad <- table(datos_estudiantes$Edad)
cat("DISTRIBUCIÓN DE FRECUENCIAS:\n")
## DISTRIBUCIÓN DE FRECUENCIAS:
for(i in 1:length(tabla_edad)) {
  cat("  ", names(tabla_edad)[i], "años:", tabla_edad[i], "estudiantes\n")
}
##    16 años: 14 estudiantes
##    17 años: 17 estudiantes
##    18 años: 41 estudiantes
##    19 años: 59 estudiantes
##    20 años: 68 estudiantes
##    21 años: 73 estudiantes
##    22 años: 43 estudiantes
##    23 años: 24 estudiantes
##    24 años: 6 estudiantes
##    25 años: 4 estudiantes
##    26 años: 1 estudiantes
cat("\n")
par(mfrow = c(2, 2), mar = c(5, 5, 4, 2))

# Histograma
hist(datos_estudiantes$Edad,
     breaks = seq(min_edad - 0.5, max_edad + 0.5, by = 1),
     col = rgb(0.2, 0.6, 0.8, 0.7),
     border = "white",
     main = "Distribución de la Edad",
     xlab = "Edad (años)",
     ylab = "Frecuencia",
     cex.main = 1.3, font.main = 2, las = 1)
abline(v = media_edad, col = "red", lwd = 3, lty = 2)
text(media_edad, par("usr")[4]*0.95,
     paste("Media =", round(media_edad, 1)),
     pos = 4, col = "red", font = 2)
grid(col = "gray80", lty = "dotted")

# Boxplot
boxplot(datos_estudiantes$Edad,
        col = rgb(0.8, 0.5, 0.2, 0.6),
        border = "darkred",
        main = "Boxplot de la Edad",
        ylab = "Edad (años)",
        cex.main = 1.3, font.main = 2, las = 1)
points(1, media_edad, col = "red", pch = 18, cex = 2.5)
grid(col = "gray80", lty = "dotted")

# Gráfico de barras
barplot(tabla_edad,
        col = rainbow(length(tabla_edad)),
        main = "Frecuencia por Edad",
        xlab = "Edad (años)",
        ylab = "Frecuencia",
        cex.main = 1.3, font.main = 2, las = 1)
grid(col = "gray80", lty = "dotted")

# Densidad
plot(density(datos_estudiantes$Edad),
     col = "darkblue", lwd = 3,
     main = "Densidad de la Edad",
     xlab = "Edad (años)",
     ylab = "Densidad",
     cex.main = 1.3, font.main = 2)
polygon(density(datos_estudiantes$Edad),
        col = rgb(0, 0, 1, 0.3), border = "darkblue")
abline(v = media_edad, col = "red", lwd = 2, lty = 2)
grid(col = "gray80", lty = "dotted")
Figura 1: Análisis Descriptivo de la Edad

Figura 1: Análisis Descriptivo de la Edad

par(mfrow = c(1, 1))

6.1.2 Variable: Género

cat("═══════════════════════════════════════════════════════════════\n")
## ═══════════════════════════════════════════════════════════════
cat("   ANÁLISIS DESCRIPTIVO: GÉNERO\n")
##    ANÁLISIS DESCRIPTIVO: GÉNERO
cat("═══════════════════════════════════════════════════════════════\n\n")
## ═══════════════════════════════════════════════════════════════
tabla_genero <- table(datos_estudiantes$Genero)
prop_genero <- prop.table(tabla_genero) * 100

cat("DISTRIBUCIÓN POR GÉNERO:\n")
## DISTRIBUCIÓN POR GÉNERO:
for(i in 1:length(tabla_genero)) {
  cat("  ", names(tabla_genero)[i], ":\n")
  cat("     Frecuencia: ", tabla_genero[i], "estudiantes\n")
  cat("     Porcentaje: ", round(prop_genero[i], 1), "%\n\n")
}
##    Femenino :
##      Frecuencia:  158 estudiantes
##      Porcentaje:  45.1 %
## 
##    Masculino :
##      Frecuencia:  192 estudiantes
##      Porcentaje:  54.9 %
par(mfrow = c(1, 2), mar = c(5, 5, 4, 2))

# Gráfico de barras
barplot(tabla_genero,
        col = c("steelblue", "coral"),
        main = "Distribución por Género",
        ylab = "Frecuencia",
        cex.main = 1.3, font.main = 2,
        ylim = c(0, max(tabla_genero) * 1.2), las = 1)
text(c(0.7, 1.9), tabla_genero + max(tabla_genero) * 0.05,
     paste0(tabla_genero, "\n(", round(prop_genero, 1), "%)"),
     cex = 1.1, font = 2)
grid(col = "gray80", lty = "dotted")

# Gráfico de pastel
pie(tabla_genero,
    col = c("steelblue", "coral"),
    main = "Proporción por Género",
    labels = paste0(names(tabla_genero), "\n",
                   tabla_genero, " est.\n",
                   round(prop_genero, 1), "%"),
    cex.main = 1.3, font.main = 2, cex = 1.1)
Figura 2: Distribución por Género

Figura 2: Distribución por Género

par(mfrow = c(1, 1))

6.1.3 Variable: Nivel Socioeconómico

cat("═══════════════════════════════════════════════════════════════\n")
## ═══════════════════════════════════════════════════════════════
cat("   ANÁLISIS DESCRIPTIVO: NIVEL SOCIOECONÓMICO\n")
##    ANÁLISIS DESCRIPTIVO: NIVEL SOCIOECONÓMICO
cat("═══════════════════════════════════════════════════════════════\n\n")
## ═══════════════════════════════════════════════════════════════
tabla_nse <- table(datos_estudiantes$Nivel_Socioeconomico)
prop_nse <- prop.table(tabla_nse) * 100

cat("DISTRIBUCIÓN POR NIVEL SOCIOECONÓMICO:\n")
## DISTRIBUCIÓN POR NIVEL SOCIOECONÓMICO:
for(i in 1:length(tabla_nse)) {
  cat("  Nivel", names(tabla_nse)[i], ":\n")
  cat("     Frecuencia: ", tabla_nse[i], "estudiantes\n")
  cat("     Porcentaje: ", round(prop_nse[i], 1), "%\n\n")
}
##   Nivel Bajo :
##      Frecuencia:  112 estudiantes
##      Porcentaje:  32 %
## 
##   Nivel Medio :
##      Frecuencia:  176 estudiantes
##      Porcentaje:  50.3 %
## 
##   Nivel Alto :
##      Frecuencia:  62 estudiantes
##      Porcentaje:  17.7 %
cat("NOTA: Clasificación según ingreso familiar mensual:\n")
## NOTA: Clasificación según ingreso familiar mensual:
cat("  Bajo:  < S/ 1,500\n")
##   Bajo:  < S/ 1,500
cat("  Medio: S/ 1,500 - S/ 4,000\n")
##   Medio: S/ 1,500 - S/ 4,000
cat("  Alto:  > S/ 4,000\n\n")
##   Alto:  > S/ 4,000
par(mfrow = c(1, 2), mar = c(5, 5, 4, 2))

colores_nse <- c("darkred", "orange", "darkgreen")

# Gráfico de barras
barplot(tabla_nse,
        col = colores_nse,
        main = "Distribución por Nivel Socioeconómico",
        ylab = "Frecuencia",
        cex.main = 1.3, font.main = 2,
        ylim = c(0, max(tabla_nse) * 1.2), las = 1)
text(c(0.7, 1.9, 3.1), tabla_nse + max(tabla_nse) * 0.05,
     paste0(tabla_nse, "\n(", round(prop_nse, 1), "%)"),
     cex = 1.0, font = 2)
grid(col = "gray80", lty = "dotted")

# Gráfico de pastel
pie(tabla_nse,
    col = colores_nse,
    main = "Proporción por NSE",
    labels = paste0(names(tabla_nse), "\n",
                   tabla_nse, " est.\n",
                   round(prop_nse, 1), "%"),
    cex.main = 1.3, font.main = 2, cex = 1.0)
Figura 3: Distribución por Nivel Socioeconómico

Figura 3: Distribución por Nivel Socioeconómico

par(mfrow = c(1, 1))

6.1.4 Variable: Horas de Estudio

cat("═══════════════════════════════════════════════════════════════\n")
## ═══════════════════════════════════════════════════════════════
cat("   ANÁLISIS DESCRIPTIVO: HORAS DE ESTUDIO SEMANAL\n")
##    ANÁLISIS DESCRIPTIVO: HORAS DE ESTUDIO SEMANAL
cat("═══════════════════════════════════════════════════════════════\n\n")
## ═══════════════════════════════════════════════════════════════
media_estudio <- mean(datos_estudiantes$Horas_Estudio)
mediana_estudio <- median(datos_estudiantes$Horas_Estudio)
desv_estudio <- sd(datos_estudiantes$Horas_Estudio)
min_estudio <- min(datos_estudiantes$Horas_Estudio)
max_estudio <- max(datos_estudiantes$Horas_Estudio)
q1_estudio <- quantile(datos_estudiantes$Horas_Estudio, 0.25)
q3_estudio <- quantile(datos_estudiantes$Horas_Estudio, 0.75)

cat("ESTADÍSTICAS DESCRIPTIVAS:\n")
## ESTADÍSTICAS DESCRIPTIVAS:
cat("  Media:           ", round(media_estudio, 2), "hrs/semana\n")
##   Media:            16.7 hrs/semana
cat("  Mediana:         ", mediana_estudio, "hrs/semana\n")
##   Mediana:          15 hrs/semana
cat("  Desv. Estándar:  ", round(desv_estudio, 2), "hrs/semana\n")
##   Desv. Estándar:   6.96 hrs/semana
cat("  Rango:           ", min_estudio, "-", max_estudio, "hrs/semana\n")
##   Rango:            7 - 48 hrs/semana
cat("  Q1 - Q3:         ", q1_estudio, "-", q3_estudio, "hrs/semana\n\n")
##   Q1 - Q3:          12 - 20 hrs/semana
par(mfrow = c(2, 2), mar = c(5, 5, 4, 2))

# Histograma
hist(datos_estudiantes$Horas_Estudio,
     breaks = 15,
     col = rgb(0.3, 0.7, 0.5, 0.7),
     border = "white",
     main = "Distribución de Horas de Estudio",
     xlab = "Horas de Estudio Semanal",
     ylab = "Frecuencia",
     cex.main = 1.3, font.main = 2, las = 1)
abline(v = media_estudio, col = "red", lwd = 3, lty = 2)
text(media_estudio, par("usr")[4]*0.95,
     paste("Media =", round(media_estudio, 1)),
     pos = 4, col = "red", font = 2)
grid(col = "gray80", lty = "dotted")

# Boxplot
boxplot(datos_estudiantes$Horas_Estudio,
        col = rgb(0.3, 0.7, 0.5, 0.6),
        border = "darkgreen",
        main = "Boxplot de Horas de Estudio",
        ylab = "Horas/Semana",
        cex.main = 1.3, font.main = 2, las = 1,
        horizontal = FALSE)
points(1, media_estudio, col = "red", pch = 18, cex = 2.5)
grid(col = "gray80", lty = "dotted")

# Densidad
plot(density(datos_estudiantes$Horas_Estudio),
     col = "darkgreen", lwd = 3,
     main = "Densidad de Horas de Estudio",
     xlab = "Horas/Semana",
     ylab = "Densidad",
     cex.main = 1.3, font.main = 2)
polygon(density(datos_estudiantes$Horas_Estudio),
        col = rgb(0, 1, 0, 0.3), border = "darkgreen")
abline(v = media_estudio, col = "red", lwd = 2, lty = 2)
grid(col = "gray80", lty = "dotted")

# Q-Q Plot
qqnorm(datos_estudiantes$Horas_Estudio,
       main = "Q-Q Plot: Horas de Estudio",
       cex.main = 1.3, font.main = 2,
       pch = 19, col = rgb(0, 1, 0, 0.5))
qqline(datos_estudiantes$Horas_Estudio, col = "red", lwd = 2)
grid(col = "gray80", lty = "dotted")
Figura 4: Análisis Descriptivo de Horas de Estudio

Figura 4: Análisis Descriptivo de Horas de Estudio

par(mfrow = c(1, 1))

6.1.5 Variable: Asistencia

cat("═══════════════════════════════════════════════════════════════\n")
## ═══════════════════════════════════════════════════════════════
cat("   ANÁLISIS DESCRIPTIVO: ASISTENCIA A CLASES\n")
##    ANÁLISIS DESCRIPTIVO: ASISTENCIA A CLASES
cat("═══════════════════════════════════════════════════════════════\n\n")
## ═══════════════════════════════════════════════════════════════
media_asist <- mean(datos_estudiantes$Asistencia)
mediana_asist <- median(datos_estudiantes$Asistencia)
desv_asist <- sd(datos_estudiantes$Asistencia)
min_asist <- min(datos_estudiantes$Asistencia)
max_asist <- max(datos_estudiantes$Asistencia)

cat("ESTADÍSTICAS DESCRIPTIVAS:\n")
## ESTADÍSTICAS DESCRIPTIVAS:
cat("  Media:           ", round(media_asist, 2), "%\n")
##   Media:            91.8 %
cat("  Mediana:         ", round(mediana_asist, 2), "%\n")
##   Mediana:          92.6 %
cat("  Desv. Estándar:  ", round(desv_asist, 2), "%\n")
##   Desv. Estándar:   4.61 %
cat("  Rango:           ", min_asist, "% -", max_asist, "%\n\n")
##   Rango:            72.2 % - 99.5 %
cat("CATEGORIZACIÓN:\n")
## CATEGORIZACIÓN:
cat("  Excelente (≥95%):   ", sum(datos_estudiantes$Asistencia >= 95),
    "(", round(mean(datos_estudiantes$Asistencia >= 95)*100, 1), "%)\n")
##   Excelente (≥95%):    91 ( 26 %)
cat("  Buena (85-94%):     ", sum(datos_estudiantes$Asistencia >= 85 &
                                  datos_estudiantes$Asistencia < 95),
    "(", round(mean(datos_estudiantes$Asistencia >= 85 &
                   datos_estudiantes$Asistencia < 95)*100, 1), "%)\n")
##   Buena (85-94%):      226 ( 64.6 %)
cat("  Regular (75-84%):   ", sum(datos_estudiantes$Asistencia >= 75 &
                                  datos_estudiantes$Asistencia < 85),
    "(", round(mean(datos_estudiantes$Asistencia >= 75 &
                   datos_estudiantes$Asistencia < 85)*100, 1), "%)\n")
##   Regular (75-84%):    32 ( 9.1 %)
cat("  Baja (<75%):        ", sum(datos_estudiantes$Asistencia < 75),
    "(", round(mean(datos_estudiantes$Asistencia < 75)*100, 1), "%)\n\n")
##   Baja (<75%):         1 ( 0.3 %)
par(mfrow = c(2, 2), mar = c(5, 5, 4, 2))

# Histograma
hist(datos_estudiantes$Asistencia,
     breaks = 20,
     col = rgb(0.7, 0.3, 0.8, 0.7),
     border = "white",
     main = "Distribución de Asistencia",
     xlab = "Asistencia (%)",
     ylab = "Frecuencia",
     cex.main = 1.3, font.main = 2, las = 1)
abline(v = media_asist, col = "red", lwd = 3, lty = 2)
abline(v = 75, col = "orange", lwd = 2, lty = 3)
text(75, par("usr")[4]*0.9, "Mínimo\nRequerido\n(75%)",
     pos = 4, col = "orange", font = 2, cex = 0.9)
grid(col = "gray80", lty = "dotted")

# Boxplot
boxplot(datos_estudiantes$Asistencia,
        col = rgb(0.7, 0.3, 0.8, 0.6),
        border = "purple",
        main = "Boxplot de Asistencia",
        ylab = "Asistencia (%)",
        cex.main = 1.3, font.main = 2, las = 1)
points(1, media_asist, col = "red", pch = 18, cex = 2.5)
abline(h = 75, col = "orange", lwd = 2, lty = 3)
grid(col = "gray80", lty = "dotted")

# Densidad
plot(density(datos_estudiantes$Asistencia),
     col = "purple", lwd = 3,
     main = "Densidad de Asistencia",
     xlab = "Asistencia (%)",
     ylab = "Densidad",
     cex.main = 1.3, font.main = 2)
polygon(density(datos_estudiantes$Asistencia),
        col = rgb(0.7, 0, 1, 0.3), border = "purple")
abline(v = media_asist, col = "red", lwd = 2, lty = 2)
abline(v = 75, col = "orange", lwd = 2, lty = 3)
grid(col = "gray80", lty = "dotted")

# Barplot por categorías
asist_cat <- cut(datos_estudiantes$Asistencia,
                 breaks = c(0, 75, 85, 95, 100),
                 labels = c("Baja\n(<75%)", "Regular\n(75-84%)",
                           "Buena\n(85-94%)", "Excelente\n(≥95%)"),
                 include.lowest = TRUE)
tabla_asist_cat <- table(asist_cat)
barplot(tabla_asist_cat,
        col = c("red", "orange", "lightgreen", "darkgreen"),
        main = "Asistencia por Categorías",
        ylab = "Frecuencia",
        cex.main = 1.3, font.main = 2, las = 1)
text(c(0.7, 1.9, 3.1, 4.3), tabla_asist_cat + max(tabla_asist_cat)*0.05,
     tabla_asist_cat, cex = 1.1, font = 2)
grid(col = "gray80", lty = "dotted")
Figura 5: Análisis Descriptivo de Asistencia

Figura 5: Análisis Descriptivo de Asistencia

par(mfrow = c(1, 1))

6.1.6 Variable: Horas de Trabajo

cat("═══════════════════════════════════════════════════════════════\n")
## ═══════════════════════════════════════════════════════════════
cat("   ANÁLISIS DESCRIPTIVO: HORAS DE TRABAJO SEMANAL\n")
##    ANÁLISIS DESCRIPTIVO: HORAS DE TRABAJO SEMANAL
cat("═══════════════════════════════════════════════════════════════\n\n")
## ═══════════════════════════════════════════════════════════════
n_no_trabaja <- sum(datos_estudiantes$Horas_Trabajo == 0)
n_trabaja <- sum(datos_estudiantes$Horas_Trabajo > 0)
media_trabajo <- mean(datos_estudiantes$Horas_Trabajo)
media_trabajan <- mean(datos_estudiantes$Horas_Trabajo[datos_estudiantes$Horas_Trabajo > 0])

cat("DISTRIBUCIÓN GENERAL:\n")
## DISTRIBUCIÓN GENERAL:
cat("  No trabajan:     ", n_no_trabaja,
    "(", round(n_no_trabaja/n*100, 1), "%)\n")
##   No trabajan:      140 ( 40 %)
cat("  Sí trabajan:     ", n_trabaja,
    "(", round(n_trabaja/n*100, 1), "%)\n\n")
##   Sí trabajan:      210 ( 60 %)
cat("ESTADÍSTICAS (TODOS):\n")
## ESTADÍSTICAS (TODOS):
cat("  Media general:   ", round(media_trabajo, 2), "hrs/semana\n\n")
##   Media general:    10.05 hrs/semana
cat("ESTADÍSTICAS (SOLO QUIENES TRABAJAN):\n")
## ESTADÍSTICAS (SOLO QUIENES TRABAJAN):
cat("  Media:           ", round(media_trabajan, 2), "hrs/semana\n")
##   Media:            16.74 hrs/semana
cat("  Mediana:         ", median(datos_estudiantes$Horas_Trabajo[datos_estudiantes$Horas_Trabajo > 0]),
    "hrs/semana\n")
##   Mediana:          14 hrs/semana
cat("  Rango:           ",
    min(datos_estudiantes$Horas_Trabajo[datos_estudiantes$Horas_Trabajo > 0]), "-",
    max(datos_estudiantes$Horas_Trabajo[datos_estudiantes$Horas_Trabajo > 0]),
    "hrs/semana\n\n")
##   Rango:            5 - 48 hrs/semana
par(mfrow = c(2, 2), mar = c(5, 5, 4, 2))

# Histograma (todos)
hist(datos_estudiantes$Horas_Trabajo,
     breaks = 20,
     col = rgb(0.9, 0.5, 0.2, 0.7),
     border = "white",
     main = "Distribución de Horas de Trabajo (Todos)",
     xlab = "Horas de Trabajo Semanal",
     ylab = "Frecuencia",
     cex.main = 1.3, font.main = 2, las = 1)
abline(v = media_trabajo, col = "red", lwd = 3, lty = 2)
grid(col = "gray80", lty = "dotted")

# Histograma (solo quienes trabajan)
hist(datos_estudiantes$Horas_Trabajo[datos_estudiantes$Horas_Trabajo > 0],
     breaks = 15,
     col = rgb(0.9, 0.3, 0.3, 0.7),
     border = "white",
     main = "Distribución (Solo Quienes Trabajan)",
     xlab = "Horas de Trabajo Semanal",
     ylab = "Frecuencia",
     cex.main = 1.3, font.main = 2, las = 1)
abline(v = media_trabajan, col = "blue", lwd = 3, lty = 2)
grid(col = "gray80", lty = "dotted")

# Pie chart trabajo/no trabajo
pie(c(n_no_trabaja, n_trabaja),
    labels = c(paste0("No trabajan\n", n_no_trabaja, " est.\n",
                     round(n_no_trabaja/n*100, 1), "%"),
              paste0("Sí trabajan\n", n_trabaja, " est.\n",
                    round(n_trabaja/n*100, 1), "%")),
    col = c("lightgreen", "salmon"),
    main = "Proporción que Trabaja",
    cex.main = 1.3, font.main = 2)

# Boxplot (solo quienes trabajan)
boxplot(datos_estudiantes$Horas_Trabajo[datos_estudiantes$Horas_Trabajo > 0],
        col = rgb(0.9, 0.3, 0.3, 0.6),
        border = "darkred",
        main = "Boxplot (Solo Quienes Trabajan)",
        ylab = "Horas/Semana",
        cex.main = 1.3, font.main = 2, las = 1)
points(1, media_trabajan, col = "blue", pch = 18, cex = 2.5)
grid(col = "gray80", lty = "dotted")
Figura 6: Análisis Descriptivo de Horas de Trabajo

Figura 6: Análisis Descriptivo de Horas de Trabajo

par(mfrow = c(1, 1))

6.1.7 Variable: Distancia al Campus

cat("═══════════════════════════════════════════════════════════════\n")
## ═══════════════════════════════════════════════════════════════
cat("   ANÁLISIS DESCRIPTIVO: DISTANCIA AL CAMPUS\n")
##    ANÁLISIS DESCRIPTIVO: DISTANCIA AL CAMPUS
cat("═══════════════════════════════════════════════════════════════\n\n")
## ═══════════════════════════════════════════════════════════════
media_dist <- mean(datos_estudiantes$Distancia_Campus)
mediana_dist <- median(datos_estudiantes$Distancia_Campus)
desv_dist <- sd(datos_estudiantes$Distancia_Campus)

cat("ESTADÍSTICAS DESCRIPTIVAS:\n")
## ESTADÍSTICAS DESCRIPTIVAS:
cat("  Media:           ", round(media_dist, 2), "km\n")
##   Media:            7.17 km
cat("  Mediana:         ", round(mediana_dist, 2), "km\n")
##   Mediana:          4.75 km
cat("  Desv. Estándar:  ", round(desv_dist, 2), "km\n")
##   Desv. Estándar:   6.93 km
cat("  Rango:           ", min(datos_estudiantes$Distancia_Campus), "-",
    max(datos_estudiantes$Distancia_Campus), "km\n\n")
##   Rango:            0.5 - 47.9 km
cat("CATEGORIZACIÓN:\n")
## CATEGORIZACIÓN:
cat("  Muy cerca (<2km):   ", sum(datos_estudiantes$Distancia_Campus < 2),
    "(", round(mean(datos_estudiantes$Distancia_Campus < 2)*100, 1), "%)\n")
##   Muy cerca (<2km):    56 ( 16 %)
cat("  Cerca (2-5km):      ", sum(datos_estudiantes$Distancia_Campus >= 2 &
                                  datos_estudiantes$Distancia_Campus < 5),
    "(", round(mean(datos_estudiantes$Distancia_Campus >= 2 &
                   datos_estudiantes$Distancia_Campus < 5)*100, 1), "%)\n")
##   Cerca (2-5km):       123 ( 35.1 %)
cat("  Moderado (5-10km):  ", sum(datos_estudiantes$Distancia_Campus >= 5 &
                                  datos_estudiantes$Distancia_Campus < 10),
    "(", round(mean(datos_estudiantes$Distancia_Campus >= 5 &
                   datos_estudiantes$Distancia_Campus < 10)*100, 1), "%)\n")
##   Moderado (5-10km):   88 ( 25.1 %)
cat("  Lejos (≥10km):      ", sum(datos_estudiantes$Distancia_Campus >= 10),
    "(", round(mean(datos_estudiantes$Distancia_Campus >= 10)*100, 1), "%)\n\n")
##   Lejos (≥10km):       83 ( 23.7 %)
par(mfrow = c(2, 2), mar = c(5, 5, 4, 2))

# Histograma
hist(datos_estudiantes$Distancia_Campus,
     breaks = 20,
     col = rgb(0.4, 0.5, 0.9, 0.7),
     border = "white",
     main = "Distribución de Distancia al Campus",
     xlab = "Distancia (km)",
     ylab = "Frecuencia",
     cex.main = 1.3, font.main = 2, las = 1)
abline(v = media_dist, col = "red", lwd = 3, lty = 2)
grid(col = "gray80", lty = "dotted")

# Boxplot
boxplot(datos_estudiantes$Distancia_Campus,
        col = rgb(0.4, 0.5, 0.9, 0.6),
        border = "darkblue",
        main = "Boxplot de Distancia",
        ylab = "Distancia (km)",
        cex.main = 1.3, font.main = 2, las = 1)
points(1, media_dist, col = "red", pch = 18, cex = 2.5)
grid(col = "gray80", lty = "dotted")

# Barplot por categorías
dist_cat <- cut(datos_estudiantes$Distancia_Campus,
                breaks = c(0, 2, 5, 10, 100),
                labels = c("Muy cerca\n(<2km)", "Cerca\n(2-5km)",
                          "Moderado\n(5-10km)", "Lejos\n(≥10km)"),
                include.lowest = TRUE)
tabla_dist_cat <- table(dist_cat)
barplot(tabla_dist_cat,
        col = c("darkgreen", "lightgreen", "orange", "red"),
        main = "Distancia por Categorías",
        ylab = "Frecuencia",
        cex.main = 1.3, font.main = 2, las = 1)
text(c(0.7, 1.9, 3.1, 4.3), tabla_dist_cat + max(tabla_dist_cat)*0.05,
     tabla_dist_cat, cex = 1.1, font = 2)
grid(col = "gray80", lty = "dotted")

# Densidad
plot(density(datos_estudiantes$Distancia_Campus),
     col = "darkblue", lwd = 3,
     main = "Densidad de Distancia",
     xlab = "Distancia (km)",
     ylab = "Densidad",
     cex.main = 1.3, font.main = 2)
polygon(density(datos_estudiantes$Distancia_Campus),
        col = rgb(0, 0, 1, 0.3), border = "darkblue")
abline(v = media_dist, col = "red", lwd = 2, lty = 2)
grid(col = "gray80", lty = "dotted")
Figura 7: Análisis Descriptivo de Distancia al Campus

Figura 7: Análisis Descriptivo de Distancia al Campus

par(mfrow = c(1, 1))

6.2 OE2: Distribución del Rendimiento Académico

6.2.1 Variable: Promedio Ponderado (Variable Dependiente)

cat("═══════════════════════════════════════════════════════════════\n")
## ═══════════════════════════════════════════════════════════════
cat("   ANÁLISIS DESCRIPTIVO: PROMEDIO PONDERADO (0-20)\n")
##    ANÁLISIS DESCRIPTIVO: PROMEDIO PONDERADO (0-20)
cat("   VARIABLE DEPENDIENTE PRINCIPAL\n")
##    VARIABLE DEPENDIENTE PRINCIPAL
cat("═══════════════════════════════════════════════════════════════\n\n")
## ═══════════════════════════════════════════════════════════════
media_gpa <- mean(datos_estudiantes$Promedio_Ponderado)
mediana_gpa <- median(datos_estudiantes$Promedio_Ponderado)
moda_gpa <- as.numeric(names(sort(table(datos_estudiantes$Promedio_Ponderado),
                                  decreasing = TRUE)[1]))
desv_std_gpa <- sd(datos_estudiantes$Promedio_Ponderado)
varianza_gpa <- var(datos_estudiantes$Promedio_Ponderado)
cv_gpa <- (desv_std_gpa / media_gpa) * 100
q1 <- quantile(datos_estudiantes$Promedio_Ponderado, 0.25)
q3 <- quantile(datos_estudiantes$Promedio_Ponderado, 0.75)
iqr_gpa <- IQR(datos_estudiantes$Promedio_Ponderado)
asimetria_gpa <- skewness(datos_estudiantes$Promedio_Ponderado)
curtosis_gpa <- kurtosis(datos_estudiantes$Promedio_Ponderado)

cat("MEDIDAS DE TENDENCIA CENTRAL:\n")
## MEDIDAS DE TENDENCIA CENTRAL:
cat("  Media:           ", round(media_gpa, 2), "\n")
##   Media:            16.91
cat("  Mediana:         ", round(mediana_gpa, 2), "\n")
##   Mediana:          16.9
cat("  Moda:            ", moda_gpa, "\n\n")
##   Moda:             20
cat("MEDIDAS DE DISPERSIÓN:\n")
## MEDIDAS DE DISPERSIÓN:
cat("  Varianza:        ", round(varianza_gpa, 4), "\n")
##   Varianza:         2.8792
cat("  Desv. Estándar:  ", round(desv_std_gpa, 2), "\n")
##   Desv. Estándar:   1.7
cat("  Coef. Variación: ", round(cv_gpa, 2), "%\n")
##   Coef. Variación:  10.03 %
cat("  Rango:           ", min(datos_estudiantes$Promedio_Ponderado), "-",
    max(datos_estudiantes$Promedio_Ponderado), "\n")
##   Rango:            11.9 - 20
cat("  IQR (Q3-Q1):     ", round(iqr_gpa, 2), "\n\n")
##   IQR (Q3-Q1):      2.4
cat("MEDIDAS DE FORMA:\n")
## MEDIDAS DE FORMA:
cat("  Asimetría:       ", round(asimetria_gpa, 4))
##   Asimetría:        -0.0792
if(abs(asimetria_gpa) < 0.5) {
  cat(" (Simétrica)\n")
} else if(asimetria_gpa > 0) {
  cat(" (Sesgada derecha)\n")
} else {
  cat(" (Sesgada izquierda)\n")
}
##  (Simétrica)
cat("  Curtosis:        ", round(curtosis_gpa, 4))
##   Curtosis:         2.4464
if(abs(curtosis_gpa) < 0.5) {
  cat(" (Mesocúrtica)\n")
} else if(curtosis_gpa > 0) {
  cat(" (Leptocúrtica)\n")
} else {
  cat(" (Platicúrtica)\n")
}
##  (Leptocúrtica)
cat("\nCUANTILES:\n")
## 
## CUANTILES:
cuantiles_gpa <- quantile(datos_estudiantes$Promedio_Ponderado,
                          probs = c(0.10, 0.25, 0.50, 0.75, 0.90))
for(i in 1:length(cuantiles_gpa)) {
  cat("  ", names(cuantiles_gpa)[i], ": ", round(cuantiles_gpa[i], 2), "\n")
}
##    10% :  14.5 
##    25% :  15.7 
##    50% :  16.9 
##    75% :  18.1 
##    90% :  19.3
cat("\nCATEGORIZACIÓN ACADÉMICA:\n")
## 
## CATEGORIZACIÓN ACADÉMICA:
cat("  Sobresaliente (18-20): ", sum(datos_estudiantes$Promedio_Ponderado >= 18),
    "(", round(mean(datos_estudiantes$Promedio_Ponderado >= 18)*100, 1), "%)\n")
##   Sobresaliente (18-20):  99 ( 28.3 %)
cat("  Muy bueno (16-17):     ", sum(datos_estudiantes$Promedio_Ponderado >= 16 &
                                      datos_estudiantes$Promedio_Ponderado < 18),
    "(", round(mean(datos_estudiantes$Promedio_Ponderado >= 16 &
                   datos_estudiantes$Promedio_Ponderado < 18)*100, 1), "%)\n")
##   Muy bueno (16-17):      148 ( 42.3 %)
cat("  Bueno (14-15):         ", sum(datos_estudiantes$Promedio_Ponderado >= 14 &
                                      datos_estudiantes$Promedio_Ponderado < 16),
    "(", round(mean(datos_estudiantes$Promedio_Ponderado >= 14 &
                   datos_estudiantes$Promedio_Ponderado < 16)*100, 1), "%)\n")
##   Bueno (14-15):          90 ( 25.7 %)
cat("  Regular (11-13):       ", sum(datos_estudiantes$Promedio_Ponderado >= 11 &
                                      datos_estudiantes$Promedio_Ponderado < 14),
    "(", round(mean(datos_estudiantes$Promedio_Ponderado >= 11 &
                   datos_estudiantes$Promedio_Ponderado < 14)*100, 1), "%)\n")
##   Regular (11-13):        13 ( 3.7 %)
cat("  Desaprobado (<11):     ", sum(datos_estudiantes$Promedio_Ponderado < 11),
    "(", round(mean(datos_estudiantes$Promedio_Ponderado < 11)*100, 1), "%)\n\n")
##   Desaprobado (<11):      0 ( 0 %)

6.2.2 Tabla de Frecuencias (Método de Sturges)

n_obs <- length(datos_estudiantes$Promedio_Ponderado)
k_sturges <- ceiling(1 + 3.322 * log10(n_obs))
rango_total <- max(datos_estudiantes$Promedio_Ponderado) -
               min(datos_estudiantes$Promedio_Ponderado)
amplitud_clase <- rango_total / k_sturges

cat("═══════════════════════════════════════════════════════════════\n")
## ═══════════════════════════════════════════════════════════════
cat("   TABLA DE FRECUENCIAS - MÉTODO DE STURGES\n")
##    TABLA DE FRECUENCIAS - MÉTODO DE STURGES
cat("═══════════════════════════════════════════════════════════════\n\n")
## ═══════════════════════════════════════════════════════════════
cat("PASO 1: Determinar número de clases\n")
## PASO 1: Determinar número de clases
cat("  k = 1 + 3.322 × log₁₀(", n_obs, ") =", k_sturges, "clases\n\n")
##   k = 1 + 3.322 × log₁₀( 350 ) = 10 clases
cat("PASO 2: Calcular amplitud de clase\n")
## PASO 2: Calcular amplitud de clase
cat("  c = Rango / k =", round(rango_total, 2), "/", k_sturges,
    "=", round(amplitud_clase, 4), "\n\n")
##   c = Rango / k = 8.1 / 10 = 0.81
limite_inicial <- min(datos_estudiantes$Promedio_Ponderado)
limites_clases <- seq(limite_inicial,
                      limite_inicial + k_sturges * amplitud_clase,
                      by = amplitud_clase)

clases_gpa <- cut(datos_estudiantes$Promedio_Ponderado,
                  breaks = limites_clases,
                  include.lowest = TRUE, right = FALSE)

tabla_freq <- data.frame(
  Intervalo = levels(clases_gpa),
  fi = as.numeric(table(clases_gpa))
) %>%
  mutate(
    hi = fi / sum(fi),
    pi = hi * 100,
    Fi = cumsum(fi),
    Hi = cumsum(hi),
    Pi = cumsum(pi),
    Xi = sapply(1:k_sturges, function(i) (limites_clases[i] + limites_clases[i+1])/2)
  )

kable(tabla_freq, digits = c(0, 0, 4, 2, 0, 4, 2, 2),
      col.names = c("Intervalo", "fi", "hi", "pi(%)", "Fi", "Hi", "Pi(%)", "Xi"),
      caption = "Tabla 2: Distribución de Frecuencias del Promedio Ponderado (Método de Sturges)") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE) %>%
  add_header_above(c(" " = 1, "Simples" = 3, "Acumuladas" = 3, " " = 1)) %>%
  row_spec(0, bold = TRUE, color = "white", background = "#34495e")
Tabla 2: Distribución de Frecuencias del Promedio Ponderado (Método de Sturges)
Simples
Acumuladas
Intervalo fi hi pi(%) Fi Hi Pi(%) Xi
[11.9,12.7) 2 0.0057 0.57 2 0.0057 0.57 12.30
[12.7,13.5) 3 0.0086 0.86 5 0.0143 1.43 13.12
[13.5,14.3) 20 0.0571 5.71 25 0.0714 7.14 13.93
[14.3,15.1) 30 0.0857 8.57 55 0.1571 15.71 14.73
[15.1,15.9) 48 0.1371 13.71 103 0.2943 29.43 15.54
[15.9,16.8) 54 0.1543 15.43 157 0.4486 44.86 16.35
[16.8,17.6) 62 0.1771 17.71 219 0.6257 62.57 17.16
[17.6,18.4) 57 0.1629 16.29 276 0.7886 78.86 17.98
[18.4,19.2) 36 0.1029 10.29 312 0.8914 89.14 18.78
[19.2,20] 38 0.1086 10.86 350 1.0000 100.00 19.59

6.2.3 Gráficos del Promedio Ponderado

par(mfrow = c(3, 2), mar = c(5, 5, 4, 2))

# Histograma con curva normal
hist(datos_estudiantes$Promedio_Ponderado,
     breaks = k_sturges,
     col = rgb(0.3, 0.6, 0.9, 0.7),
     border = "white",
     main = "Distribución del Promedio Ponderado",
     xlab = "Promedio Ponderado (Escala 0-20)",
     ylab = "Frecuencia",
     cex.main = 1.3, font.main = 2, las = 1)
abline(v = media_gpa, col = "red", lwd = 3, lty = 2)
abline(v = 10.5, col = "darkgreen", lwd = 2, lty = 4)
text(media_gpa, par("usr")[4]*0.95,
     paste("Media =", round(media_gpa, 2)),
     pos = 4, col = "red", font = 2)
text(10.5, par("usr")[4]*0.85, "Nota\nAprobatoria",
     pos = 4, col = "darkgreen", font = 2, cex = 0.9)

# Curva normal teórica
x_seq <- seq(min(datos_estudiantes$Promedio_Ponderado),
             max(datos_estudiantes$Promedio_Ponderado), length = 200)
y_seq <- dnorm(x_seq, mean = media_gpa, sd = desv_std_gpa)
y_seq <- y_seq * length(datos_estudiantes$Promedio_Ponderado) * amplitud_clase
lines(x_seq, y_seq, col = "darkgreen", lwd = 2.5)
grid(col = "gray80", lty = "dotted")

# Boxplot
boxplot(datos_estudiantes$Promedio_Ponderado,
        col = rgb(0.9, 0.6, 0.3, 0.6),
        border = "darkred",
        main = "Boxplot del Promedio Ponderado",
        ylab = "Promedio (0-20)",
        cex.main = 1.3, font.main = 2, las = 1)
points(1, media_gpa, col = "red", pch = 18, cex = 2.5)
text(1.20, q1, paste("Q1 =", round(q1, 2)),
     pos = 4, cex = 1.0, col = "darkblue", font = 2)
text(1.20, mediana_gpa, paste("Mediana =", round(mediana_gpa, 2)),
     pos = 4, cex = 1.0, col = "darkblue", font = 2)
text(1.20, q3, paste("Q3 =", round(q3, 2)),
     pos = 4, cex = 1.0, col = "darkblue", font = 2)
abline(h = 10.5, col = "darkgreen", lwd = 2, lty = 2)
grid(col = "gray80", lty = "dotted")

# Densidad
plot(density(datos_estudiantes$Promedio_Ponderado),
     col = "darkblue", lwd = 3,
     main = "Densidad del Promedio Ponderado",
     xlab = "Promedio (0-20)",
     ylab = "Densidad",
     cex.main = 1.3, font.main = 2)
polygon(density(datos_estudiantes$Promedio_Ponderado),
        col = rgb(0, 0, 1, 0.3), border = "darkblue")
abline(v = media_gpa, col = "red", lwd = 2, lty = 2)
abline(v = mediana_gpa, col = "blue", lwd = 2, lty = 3)
abline(v = 10.5, col = "darkgreen", lwd = 2, lty = 4)
grid(col = "gray80", lty = "dotted")

# Q-Q Plot
qqnorm(datos_estudiantes$Promedio_Ponderado,
       main = "Q-Q Plot: Normalidad del Promedio",
       cex.main = 1.3, font.main = 2,
       pch = 19, col = rgb(0, 0, 1, 0.5))
qqline(datos_estudiantes$Promedio_Ponderado, col = "red", lwd = 2)
grid(col = "gray80", lty = "dotted")

# Barplot por categorías
gpa_cat <- cut(datos_estudiantes$Promedio_Ponderado,
               breaks = c(0, 11, 14, 16, 18, 20),
               labels = c("Desaprobado\n(<11)", "Regular\n(11-13)",
                         "Bueno\n(14-15)", "Muy Bueno\n(16-17)",
                         "Sobresaliente\n(18-20)"),
               include.lowest = TRUE)
tabla_gpa_cat <- table(gpa_cat)
colores_cat <- c("red", "orange", "yellow", "lightgreen", "darkgreen")
barplot(tabla_gpa_cat,
        col = colores_cat,
        main = "Rendimiento por Categorías",
        ylab = "Frecuencia",
        cex.main = 1.3, font.main = 2, las = 1)
text(c(0.7, 1.9, 3.1, 4.3, 5.5), tabla_gpa_cat + max(tabla_gpa_cat)*0.05,
     tabla_gpa_cat, cex = 1.1, font = 2)
grid(col = "gray80", lty = "dotted")

# Gráfico de frecuencias acumuladas
plot(tabla_freq$Xi, tabla_freq$Pi,
     type = "b",
     col = "darkred",
     lwd = 3,
     pch = 19,
     cex = 1.5,
     main = "Polígono de Frecuencias Acumuladas",
     xlab = "Promedio Ponderado",
     ylab = "Porcentaje Acumulado (%)",
     cex.main = 1.3, font.main = 2)
abline(h = 50, col = "blue", lwd = 2, lty = 2)
text(max(tabla_freq$Xi)*0.7, 50,
     "Mediana (50%)", pos = 3, col = "blue", font = 2)
grid(col = "gray80", lty = "dotted")
Figura 8: Análisis Completo del Promedio Ponderado

Figura 8: Análisis Completo del Promedio Ponderado

par(mfrow = c(1, 1))

6.2.4 Variable: Promedio Previo

cat("═══════════════════════════════════════════════════════════════\n")
## ═══════════════════════════════════════════════════════════════
cat("   ANÁLISIS DESCRIPTIVO: PROMEDIO PREVIO\n")
##    ANÁLISIS DESCRIPTIVO: PROMEDIO PREVIO
cat("═══════════════════════════════════════════════════════════════\n\n")
## ═══════════════════════════════════════════════════════════════
media_prev <- mean(datos_estudiantes$Promedio_Previo)
mediana_prev <- median(datos_estudiantes$Promedio_Previo)
desv_prev <- sd(datos_estudiantes$Promedio_Previo)

cat("ESTADÍSTICAS DESCRIPTIVAS:\n")
## ESTADÍSTICAS DESCRIPTIVAS:
cat("  Media:           ", round(media_prev, 2), "\n")
##   Media:            14.04
cat("  Mediana:         ", round(mediana_prev, 2), "\n")
##   Mediana:          14.1
cat("  Desv. Estándar:  ", round(desv_prev, 2), "\n")
##   Desv. Estándar:   1.9
cat("  Rango:           ", min(datos_estudiantes$Promedio_Previo), "-",
    max(datos_estudiantes$Promedio_Previo), "\n\n")
##   Rango:            10.5 - 19.5
par(mfrow = c(2, 2), mar = c(5, 5, 4, 2))

# Histograma
hist(datos_estudiantes$Promedio_Previo,
     breaks = 15,
     col = rgb(0.6, 0.4, 0.8, 0.7),
     border = "white",
     main = "Distribución del Promedio Previo",
     xlab = "Promedio Previo (Escala 0-20)",
     ylab = "Frecuencia",
     cex.main = 1.3, font.main = 2, las = 1)
abline(v = media_prev, col = "red", lwd = 3, lty = 2)
abline(v = 10.5, col = "darkgreen", lwd = 2, lty = 4)
grid(col = "gray80", lty = "dotted")

# Boxplot
boxplot(datos_estudiantes$Promedio_Previo,
        col = rgb(0.6, 0.4, 0.8, 0.6),
        border = "purple",
        main = "Boxplot del Promedio Previo",
        ylab = "Promedio Previo (0-20)",
        cex.main = 1.3, font.main = 2, las = 1)
points(1, media_prev, col = "red", pch = 18, cex = 2.5)
abline(h = 10.5, col = "darkgreen", lwd = 2, lty = 2)
grid(col = "gray80", lty = "dotted")

# Densidad
plot(density(datos_estudiantes$Promedio_Previo),
     col = "purple", lwd = 3,
     main = "Densidad del Promedio Previo",
     xlab = "Promedio Previo (0-20)",
     ylab = "Densidad",
     cex.main = 1.3, font.main = 2)
polygon(density(datos_estudiantes$Promedio_Previo),
        col = rgb(0.6, 0, 1, 0.3), border = "purple")
abline(v = media_prev, col = "red", lwd = 2, lty = 2)
abline(v = 10.5, col = "darkgreen", lwd = 2, lty = 4)
grid(col = "gray80", lty = "dotted")

# Q-Q Plot
qqnorm(datos_estudiantes$Promedio_Previo,
       main = "Q-Q Plot: Promedio Previo",
       cex.main = 1.3, font.main = 2,
       pch = 19, col = rgb(0.6, 0, 1, 0.5))
qqline(datos_estudiantes$Promedio_Previo, col = "red", lwd = 2)
grid(col = "gray80", lty = "dotted")
Figura 9: Análisis Descriptivo del Promedio Previo

Figura 9: Análisis Descriptivo del Promedio Previo

par(mfrow = c(1, 1))


7 CONTRASTACIÓN DE HIPÓTESIS

En esta sección se procede a contrastar las hipótesis planteadas, utilizando pruebas estadísticas apropiadas como correlación de Pearson, ANOVA y pruebas t, según la naturaleza de las variables.


7.1 H1: Horas de Estudio → Rendimiento Académico (OE3)

cat("═══════════════════════════════════════════════════════════════\n")
## ═══════════════════════════════════════════════════════════════
cat("   CONTRASTACIÓN H1: HORAS DE ESTUDIO → RENDIMIENTO\n")
##    CONTRASTACIÓN H1: HORAS DE ESTUDIO → RENDIMIENTO
cat("═══════════════════════════════════════════════════════════════\n\n")
## ═══════════════════════════════════════════════════════════════
cor_test_h1 <- cor.test(datos_estudiantes$Horas_Estudio,
                        datos_estudiantes$Promedio_Ponderado,
                        method = "pearson")

r_h1 <- cor_test_h1$estimate
p_h1 <- cor_test_h1$p.value

cat("RESULTADOS:\n")
## RESULTADOS:
cat("  Coeficiente r =", round(r_h1, 4), "\n")
##   Coeficiente r = 0.3719
cat("  p-valor =", format.pval(p_h1, digits = 4), "\n\n")
##   p-valor = 0.0000000000006398
if(p_h1 < 0.05 & r_h1 > 0){
  cat("✓ Se acepta H1: Existe correlación positiva significativa.\n")
} else {
  cat("✗ Se rechaza H1.\n")
}
## ✓ Se acepta H1: Existe correlación positiva significativa.
cat("═══════════════════════════════════════════════════════════════\n")
## ═══════════════════════════════════════════════════════════════
cat("   CONTRASTACIÓN H2: ASISTENCIA → RENDIMIENTO\n")
##    CONTRASTACIÓN H2: ASISTENCIA → RENDIMIENTO
cat("═══════════════════════════════════════════════════════════════\n\n")
## ═══════════════════════════════════════════════════════════════
cor_test_h2 <- cor.test(datos_estudiantes$Asistencia,
                        datos_estudiantes$Promedio_Ponderado,
                        method = "pearson")

r_h2 <- cor_test_h2$estimate
p_h2 <- cor_test_h2$p.value

cat("RESULTADOS:\n")
## RESULTADOS:
cat("  Coeficiente r =", round(r_h2, 4), "\n")
##   Coeficiente r = 0.1579
cat("  p-valor =", format.pval(p_h2, digits = 4), "\n\n")
##   p-valor = 0.003055
if(p_h2 < 0.05 & r_h2 > 0){
  cat("✓ Se acepta H2: Existe correlación positiva significativa.\n")
} else {
  cat("✗ Se rechaza H2.\n")
}
## ✓ Se acepta H2: Existe correlación positiva significativa.
cat("═══════════════════════════════════════════════════════════════\n")
## ═══════════════════════════════════════════════════════════════
cat("   CONTRASTACIÓN H3: HORAS DE TRABAJO → RENDIMIENTO\n")
##    CONTRASTACIÓN H3: HORAS DE TRABAJO → RENDIMIENTO
cat("═══════════════════════════════════════════════════════════════\n\n")
## ═══════════════════════════════════════════════════════════════
cor_test_h3 <- cor.test(datos_estudiantes$Horas_Trabajo,
                        datos_estudiantes$Promedio_Ponderado,
                        method = "pearson")

r_h3 <- cor_test_h3$estimate
p_h3 <- cor_test_h3$p.value

cat("RESULTADOS:\n")
## RESULTADOS:
cat("  Coeficiente r =", round(r_h3, 4), "\n")
##   Coeficiente r = -0.5069
cat("  p-valor =", format.pval(p_h3, digits = 4), "\n\n")
##   p-valor = < 0.00000000000000022
if(p_h3 < 0.05 & r_h3 < 0){
  cat("✓ Se acepta H3: Existe correlación negativa significativa.\n")
} else {
  cat("✗ Se rechaza H3.\n")
}
## ✓ Se acepta H3: Existe correlación negativa significativa.
cat("═══════════════════════════════════════════════════════════════\n")
## ═══════════════════════════════════════════════════════════════
cat("   CONTRASTACIÓN H4: NSE → RENDIMIENTO (ANOVA)\n")
##    CONTRASTACIÓN H4: NSE → RENDIMIENTO (ANOVA)
cat("═══════════════════════════════════════════════════════════════\n\n")
## ═══════════════════════════════════════════════════════════════
modelo_anova <- aov(Promedio_Ponderado ~ Nivel_Socioeconomico,
                    data = datos_estudiantes)

summary(modelo_anova)
##                       Df Sum Sq Mean Sq F value  Pr(>F)    
## Nivel_Socioeconomico   2   49.7  24.863   9.033 0.00015 ***
## Residuals            347  955.1   2.752                    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
cat("\nComparaciones Post-Hoc Tukey:\n")
## 
## Comparaciones Post-Hoc Tukey:
TukeyHSD(modelo_anova)
##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = Promedio_Ponderado ~ Nivel_Socioeconomico, data = datos_estudiantes)
## 
## $Nivel_Socioeconomico
##                 diff        lwr       upr     p adj
## Medio-Bajo 0.2112013 -0.2608239 0.6832265 0.5438707
## Alto-Bajo  1.0855415  0.4673770 1.7037059 0.0001325
## Alto-Medio 0.8743402  0.2976128 1.4510675 0.0011891
cat("═══════════════════════════════════════════════════════════════\n")
## ═══════════════════════════════════════════════════════════════
cat("   CONTRASTACIÓN H5: GÉNERO → RENDIMIENTO\n")
##    CONTRASTACIÓN H5: GÉNERO → RENDIMIENTO
cat("═══════════════════════════════════════════════════════════════\n\n")
## ═══════════════════════════════════════════════════════════════
t_test_genero <- t.test(Promedio_Ponderado ~ Genero,
                        data = datos_estudiantes)

print(t_test_genero)
## 
##  Welch Two Sample t-test
## 
## data:  Promedio_Ponderado by Genero
## t = 0.88017, df = 313.43, p-value = 0.3794
## alternative hypothesis: true difference in means between group Femenino and group Masculino is not equal to 0
## 95 percent confidence interval:
##  -0.2009451  0.5262484
## sample estimates:
##  mean in group Femenino mean in group Masculino 
##                17.00380                16.84115
if(t_test_genero$p.value < 0.05){
  cat("\n✓ Existen diferencias significativas por género.\n")
} else {
  cat("\n✗ No existen diferencias significativas por género.\n")
}
## 
## ✗ No existen diferencias significativas por género.
cat("═══════════════════════════════════════════════════════════════\n")
## ═══════════════════════════════════════════════════════════════
cat("   REGRESIÓN LINEAL MÚLTIPLE FINAL\n")
##    REGRESIÓN LINEAL MÚLTIPLE FINAL
cat("═══════════════════════════════════════════════════════════════\n\n")
## ═══════════════════════════════════════════════════════════════
modelo_final <- lm(Promedio_Ponderado ~ Horas_Estudio + Asistencia +
                     Horas_Trabajo + Distancia_Campus +
                     Nivel_Socioeconomico + Promedio_Previo,
                   data = datos_estudiantes)

summary(modelo_final)
## 
## Call:
## lm(formula = Promedio_Ponderado ~ Horas_Estudio + Asistencia + 
##     Horas_Trabajo + Distancia_Campus + Nivel_Socioeconomico + 
##     Promedio_Previo, data = datos_estudiantes)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -3.3481 -0.7223 -0.0006  0.7022  2.8757 
## 
## Coefficients:
##                         Estimate Std. Error t value             Pr(>|t|)    
## (Intercept)             6.918004   1.095267   6.316       0.000000000833 ***
## Horas_Estudio           0.090485   0.007541  11.999 < 0.0000000000000002 ***
## Asistencia              0.040628   0.011404   3.563             0.000419 ***
## Horas_Trabajo          -0.076370   0.005036 -15.166 < 0.0000000000000002 ***
## Distancia_Campus       -0.025740   0.007556  -3.406             0.000737 ***
## Nivel_Socioeconomico.L  0.692338   0.109511   6.322       0.000000000806 ***
## Nivel_Socioeconomico.Q  0.154747   0.087410   1.770             0.077560 .  
## Promedio_Previo         0.413782   0.027666  14.956 < 0.0000000000000002 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.9756 on 342 degrees of freedom
## Multiple R-squared:  0.676,  Adjusted R-squared:  0.6694 
## F-statistic: 101.9 on 7 and 342 DF,  p-value: < 0.00000000000000022
par(mfrow=c(2,2))
plot(modelo_final)

par(mfrow=c(1,1))


cat("CONCLUSIONES PRINCIPALES:\n\n")
## CONCLUSIONES PRINCIPALES:
cat("1. Las horas de estudio muestran asociación positiva con el rendimiento.\n")
## 1. Las horas de estudio muestran asociación positiva con el rendimiento.
cat("2. La asistencia también se relaciona significativamente con mejores promedios.\n")
## 2. La asistencia también se relaciona significativamente con mejores promedios.
cat("3. Las horas de trabajo presentan un efecto negativo sobre el desempeño.\n")
## 3. Las horas de trabajo presentan un efecto negativo sobre el desempeño.
cat("4. Existen diferencias significativas entre niveles socioeconómicos.\n")
## 4. Existen diferencias significativas entre niveles socioeconómicos.
cat("5. No se evidenciaron diferencias significativas por género.\n\n")
## 5. No se evidenciaron diferencias significativas por género.
cat("RECOMENDACIÓN INSTITUCIONAL:\n")
## RECOMENDACIÓN INSTITUCIONAL:
cat("Fortalecer programas de apoyo académico, control de asistencia y becas.\n")
## Fortalecer programas de apoyo académico, control de asistencia y becas.