En este taller práctico, se trabajará con un conjunto de datos real que contiene registros académicos de 2000 estudiantes. El objetivo es realizar un Análisis Exploratorio de Datos (EDA) utilizando R Studio, desde la importación de datos hasta la construcción de un modelo de regresión lineal simple.
El Análisis Exploratorio de Datos (EDA) es el proceso de examinar y resumir las características principales de un conjunto de datos. Sus objetivos son:
# Instalar paquetes si es necesario (descomentar si es primera vez)
# install.packages("ggplot2")
# install.packages("dplyr")
# install.packages("corrplot")
# install.packages("reshape2")
# Cargar librerías
library(ggplot2)
library(dplyr)
library(corrplot)
library(reshape2)
# Mostrar números sin notación científica
options(scipen = 999)# Importar el dataset
# NOTA: Ajustar la ruta según la ubicación del archivo
datos <- read.csv("C:\\Users\\andre\\Documents\\CUATRIMESTRE_3_2025\\Big_Data\\Introduccion_Estadistica\\Repositorios\\Calificaciones(1).csv")
# Verificar que se cargó correctamente
cat("El dataset tiene", nrow(datos), "filas y", ncol(datos), "columnas\n")## El dataset tiene 2000 filas y 7 columnas
Respuesta:
## Student_ID Attendance.... Internal.Test.1..out.of.40.
## 1 S1000 84 30
## 2 S1001 91 24
## 3 S1002 73 29
## 4 S1003 80 36
## 5 S1004 84 31
## 6 S1005 100 34
## Internal.Test.2..out.of.40. Assignment.Score..out.of.10. Daily.Study.Hours
## 1 36 7 3
## 2 38 6 3
## 3 26 7 3
## 4 35 7 3
## 5 37 8 3
## 6 34 7 3
## Final.Exam.Marks..out.of.100.
## 1 72
## 2 56
## 3 56
## 4 74
## 5 66
## 6 79
## Student_ID Attendance.... Internal.Test.1..out.of.40.
## 1995 S2994 97 40
## 1996 S2995 82 31
## 1997 S2996 78 38
## 1998 S2997 78 30
## 1999 S2998 82 29
## 2000 S2999 97 32
## Internal.Test.2..out.of.40. Assignment.Score..out.of.10. Daily.Study.Hours
## 1995 38 9 4
## 1996 28 6 2
## 1997 27 7 2
## 1998 33 9 2
## 1999 40 8 3
## 2000 38 7 3
## Final.Exam.Marks..out.of.100.
## 1995 81
## 1996 52
## 1997 57
## 1998 61
## 1999 59
## 2000 64
## 'data.frame': 2000 obs. of 7 variables:
## $ Student_ID : chr "S1000" "S1001" "S1002" "S1003" ...
## $ Attendance.... : int 84 91 73 80 84 100 96 83 91 87 ...
## $ Internal.Test.1..out.of.40. : int 30 24 29 36 31 34 40 39 30 27 ...
## $ Internal.Test.2..out.of.40. : int 36 38 26 35 37 34 36 37 37 37 ...
## $ Assignment.Score..out.of.10. : int 7 6 7 7 8 7 8 7 8 8 ...
## $ Daily.Study.Hours : int 3 3 3 3 3 3 3 3 2 3 ...
## $ Final.Exam.Marks..out.of.100.: int 72 56 56 74 66 79 83 77 71 61 ...
## [1] "Student_ID" "Attendance...."
## [3] "Internal.Test.1..out.of.40." "Internal.Test.2..out.of.40."
## [5] "Assignment.Score..out.of.10." "Daily.Study.Hours"
## [7] "Final.Exam.Marks..out.of.100."
Respuesta:
Variables numericas: 6
Variables de texto: 1
## Student_ID Attendance.... Internal.Test.1..out.of.40.
## Length:2000 Min. : 52.00 Min. :18.00
## Class :character 1st Qu.: 80.00 1st Qu.:29.00
## Mode :character Median : 85.00 Median :32.00
## Mean : 84.89 Mean :32.12
## 3rd Qu.: 90.00 3rd Qu.:35.00
## Max. :100.00 Max. :40.00
## Internal.Test.2..out.of.40. Assignment.Score..out.of.10. Daily.Study.Hours
## Min. :16.00 Min. : 4.000 Min. :1.000
## 1st Qu.:29.00 1st Qu.: 7.000 1st Qu.:2.000
## Median :33.00 Median : 8.000 Median :3.000
## Mean :32.46 Mean : 7.507 Mean :2.824
## 3rd Qu.:36.00 3rd Qu.: 8.000 3rd Qu.:3.000
## Max. :40.00 Max. :10.000 Max. :5.000
## Final.Exam.Marks..out.of.100.
## Min. : 25.00
## 1st Qu.: 58.00
## Median : 65.00
## Mean : 64.86
## 3rd Qu.: 73.00
## Max. :100.00
Respuesta:
Minimo: 25
Maximo: 100
Mediana: 65
Media: 64.86
## [1] "Student_ID" "Attendance...."
## [3] "Internal.Test.1..out.of.40." "Internal.Test.2..out.of.40."
## [5] "Assignment.Score..out.of.10." "Daily.Study.Hours"
## [7] "Final.Exam.Marks..out.of.100."
# Renombrar las columnas a español
colnames(datos) <- c(
"ID", # Student_ID
"Asistencia", # Attendance (%)
"Examen_Interno_1", # Internal Test 1 (out of 40)
"Examen_Interno_2", # Internal Test 2 (out of 40)
"Promedio_Tareas", # Assignment Score (out of 10)
"Horas_Estudio", # Daily Study Hours
"Nota_Final" # Final Exam Marks (out of 100)
)
# Verificar los nuevos nombres
names(datos)## [1] "ID" "Asistencia" "Examen_Interno_1" "Examen_Interno_2"
## [5] "Promedio_Tareas" "Horas_Estudio" "Nota_Final"
## ID Asistencia Examen_Interno_1 Examen_Interno_2
## 0 0 0 0
## Promedio_Tareas Horas_Estudio Nota_Final
## 0 0 0
## Total de valores faltantes: 0
Respuesta: ¿Existen valores faltantes? No
## Media: 64.86
# MEDIANA (valor central)
mediana <- median(datos$Nota_Final)
cat("Mediana:", round(mediana, 2), "\n")## Mediana: 65
# MODA (valor más frecuente)
tabla_freq <- table(round(datos$Nota_Final, 0))
moda <- as.numeric(names(tabla_freq)[which.max(tabla_freq)])
cat("Moda:", moda, "\n")## Moda: 66
Resumen:
## Varianza: 128.62
# DESVIACIÓN ESTÁNDAR
desv_est <- sd(datos$Nota_Final)
cat("Desviación Estándar:", round(desv_est, 2), "\n")## Desviación Estándar: 11.34
# CUARTILES
cuartiles <- quantile(datos$Nota_Final, probs = c(0.25, 0.50, 0.75))
cat("Q1 (25%):", round(cuartiles[1], 2), "\n")## Q1 (25%): 58
## Q2 (50%): 65
## Q3 (75%): 73
## Rango: 75
Resumen:
# Crear categorías de rendimiento
datos$Rendimiento <- cut(datos$Nota_Final,
breaks = c(0, 60, 70, 80, 90, 100),
labels = c("Reprobado", "Suficiente", "Bueno", "Muy Bueno", "Excelente"),
include.lowest = TRUE
)
# Contar estudiantes por categoría
frecuencias <- table(datos$Rendimiento)
porcentajes <- round(prop.table(frecuencias) * 100, 1)
# Crear etiquetas con porcentajes
etiquetas <- paste(names(frecuencias), "\n", porcentajes, "%", sep = "")
# Definir colores
colores <- c("#FF6B6B", "#FFA94D", "#FFD93D", "#6BCB77", "#4D96FF")
# Crear gráfico de pastel
pie(frecuencias,
labels = etiquetas,
col = colores,
main = "Distribución del Rendimiento Académico")
Resumen:
# 7.2 Diagrama de barras horizontales: nivel de asistencia
datos$Nivel_Asistencia <- cut(
datos$Asistencia,
breaks = c(0, 60, 75, 90, 100),
labels = c("Bajo", "Regular", "Bueno", "Excelente"),
include.lowest = TRUE
)
# Tabla de frecuencias por nivel
freq_asistencia <- table(datos$Nivel_Asistencia)
# ---- GRÁFICO ----
barplot(
freq_asistencia,
horiz = TRUE,
col = c("#FF6B6B", "#FFA94D", "#6BCB77", "#4D96FF"),
main = "Estudiantes por Nivel de Asistencia",
xlab = "Número de Estudiantes",
ylab = "Nivel de Asistencia",
las = 1
)##
## Frecuencias por nivel de asistencia:
##
## Bajo Regular Bueno Excelente
## 5 218 1291 486
Respuestas:
# Crear diagrama de cajas
boxplot(datos$Examen_Interno_1, datos$Examen_Interno_2,
names = c("Examen Interno 1", "Examen Interno 2"),
col = c("#4D96FF", "#6BCB77"),
main = "Comparación de Exámenes Internos",
ylab = "Calificación (0-100)",
border = "darkblue")
# Agregar línea de la media
abline(h = mean(datos$Examen_Interno_1), col = "red", lty = 2)## === EXAMEN INTERNO 1 ===
## Media: 32.12
## Mediana: 32
## Desv. Est.: 4.56
## === EXAMEN INTERNO 2 ===
## Media: 32.46
## Mediana: 33
## Desv. Est.: 4.52
Respuestas:
ggplot(datos, aes(x = Nivel_Asistencia, y = Nota_Final, fill = Nivel_Asistencia)) +
geom_violin(trim = FALSE, alpha = 0.7) +
geom_boxplot(width = 0.15, fill = "white") +
scale_fill_manual(values = c("#FF6B6B", "#FFA94D", "#6BCB77", "#4D96FF")) +
labs(
title = "Distribución de Nota Final por Nivel de Asistencia",
x = "Nivel de Asistencia",
y = "Nota del Examen Final"
) +
theme_minimal() +
theme(legend.position = "none")Respuestas - Nivel con notas mas altas: Exelente - Diferencias en las distribuciones: Los estudiantes con mejores notas contiene mejores notas, nos da a entedenter que hay una correlacion positiva —
# Crear histograma
hist(datos$Nota_Final,
breaks = 20,
col = "#4D96FF",
border = "white",
main = "Histograma de Nota Final",
xlab = "Nota del Examen Final",
ylab = "Frecuencia",
freq = FALSE)
# Agregar curva normal teórica
curve(dnorm(x, mean = mean(datos$Nota_Final), sd = sd(datos$Nota_Final)),
add = TRUE,
col = "red",
lwd = 2)
# Agregar leyenda
legend("topright",
legend = "Curva Normal",
col = "red",
lwd = 2)Respuestas - ¿El histograma tiene forma de campana? Si - ¿La distribucion parece simetrica o sesgada? Sesgada a la derecha ya que su centro es en 60
# Crear gráfico Q-Q
qqnorm(datos$Nota_Final,
main = "Gráfico Q-Q: Nota Final",
xlab = "Cuantiles Teóricos",
ylab = "Cuantiles de los Datos",
col = "#4D96FF",
pch = 19,
cex = 0.6)
# Agregar línea de referencia
qqline(datos$Nota_Final, col = "red", lwd = 2)Respuestas
# Prueba de Shapiro-Wilk
shapiro_test <- shapiro.test(datos$Nota_Final)
cat("=== PRUEBA DE SHAPIRO-WILK ===\n")## === PRUEBA DE SHAPIRO-WILK ===
## Estadístico W: 0.9966
## Valor p: 0.0002190907
if(shapiro_test$p.value > 0.05) {
cat("Conclusión: Los datos SON NORMALES (p > 0.05)\n\n")
} else {
cat("Conclusión: Los datos NO SON NORMALES (p <= 0.05)\n\n")
}## Conclusión: Los datos NO SON NORMALES (p <= 0.05)
# Prueba de Kolmogorov-Smirnov
datos_std <- (datos$Nota_Final - mean(datos$Nota_Final)) / sd(datos$Nota_Final)
ks_test <- ks.test(datos_std, "pnorm")
cat("=== PRUEBA DE KOLMOGOROV-SMIRNOV ===\n")## === PRUEBA DE KOLMOGOROV-SMIRNOV ===
## Estadístico D: 0.029
## Valor p: 0.06953239
if(ks_test$p.value > 0.05) {
cat("Conclusión: Los datos SON NORMALES (p > 0.05)\n")
} else {
cat("Conclusión: Los datos NO SON NORMALES (p <= 0.05)\n")
}## Conclusión: Los datos SON NORMALES (p > 0.05)
Respuesta
# Seleccionar solo variables numéricas
vars_numericas <- datos[, c("Asistencia", "Examen_Interno_1",
"Examen_Interno_2", "Promedio_Tareas",
"Horas_Estudio", "Nota_Final")]
# Calcular matriz de correlación
matriz_cor <- cor(vars_numericas)
# Mostrar la matriz
round(matriz_cor, 2)## Asistencia Examen_Interno_1 Examen_Interno_2 Promedio_Tareas
## Asistencia 1.00 0.51 0.49 0.43
## Examen_Interno_1 0.51 1.00 0.26 0.57
## Examen_Interno_2 0.49 0.26 1.00 0.54
## Promedio_Tareas 0.43 0.57 0.54 1.00
## Horas_Estudio 0.30 0.21 0.23 0.17
## Nota_Final 0.73 0.69 0.69 0.67
## Horas_Estudio Nota_Final
## Asistencia 0.30 0.73
## Examen_Interno_1 0.21 0.69
## Examen_Interno_2 0.23 0.69
## Promedio_Tareas 0.17 0.67
## Horas_Estudio 1.00 0.41
## Nota_Final 0.41 1.00
############################################################
# --- 9.1 HEATMAP ---
############################################################
heatmap(
matriz_cor,
col = colorRampPalette(c("#4D96FF", "white", "#FF6B6B"))(20),
symm = TRUE,
main = "Mapa de Calor - Correlaciones"
)############################################################
# --- HEATMAP CON GGPLOT ---
############################################################
library(reshape2)
library(ggplot2)
# Convertir matriz a formato largo
matriz_largo <- melt(matriz_cor)
colnames(matriz_largo) <- c("Variable1", "Variable2", "Correlacion")
ggplot(matriz_largo, aes(x = Variable1, y = Variable2, fill = Correlacion)) +
geom_tile(color = "white") +
geom_text(aes(label = round(Correlacion, 2)), size = 3) +
scale_fill_gradient2(
low = "#4D96FF",
mid = "white",
high = "#FF6B6B",
midpoint = 0,
limit = c(-1, 1)
) +
labs(
title = "Mapa de Calor - Matriz de Correlaciones",
x = "",
y = ""
) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
Respuestas:
##Grafico violin
ggplot(datos, aes(x = Nivel_Asistencia, y = Nota_Final, fill = Nivel_Asistencia)) +
geom_violin(trim = FALSE, alpha = 0.7) +
geom_boxplot(width = 0.15, fill = "white") +
scale_fill_manual(values = c("#FF6B6B", "#FFA94D", "#6BCB77", "#4D96FF")) +
labs(
title = "Distribución de Nota Final por Nivel de Asistencia",
x = "Nivel de Asistencia",
y = "Nota del Examen Final"
) +
theme_minimal() +
theme(legend.position = "none")Respuestas:
Nivel con distribucion mas concentrada: Excelente
Nivel con notas mas altas: Excelente
Conclusion sobre asistencia y rendimiento:A mayor asistencia, mayor es la nota final promedio. El nivel ‘Excelente’ muestra las notas más altas y menor variabilidad. Esto indica una relación positiva entre asistencia y rendimiento académico.
############################################################
# --- 9+.1 MAPA DE CALOR DE CORRELACIONES ---
############################################################
# Seleccionar variables numéricas
vars_numericas <- datos[, c(
"Asistencia",
"Examen_Interno_1",
"Examen_Interno_2",
"Promedio_Tareas",
"Horas_Estudio",
"Nota_Final"
)]
# Matriz de correlación
matriz_cor <- cor(vars_numericas)
# Mostrar matriz redondeada
round(matriz_cor, 2)## Asistencia Examen_Interno_1 Examen_Interno_2 Promedio_Tareas
## Asistencia 1.00 0.51 0.49 0.43
## Examen_Interno_1 0.51 1.00 0.26 0.57
## Examen_Interno_2 0.49 0.26 1.00 0.54
## Promedio_Tareas 0.43 0.57 0.54 1.00
## Horas_Estudio 0.30 0.21 0.23 0.17
## Nota_Final 0.73 0.69 0.69 0.67
## Horas_Estudio Nota_Final
## Asistencia 0.30 0.73
## Examen_Interno_1 0.21 0.69
## Examen_Interno_2 0.23 0.69
## Promedio_Tareas 0.17 0.67
## Horas_Estudio 1.00 0.41
## Nota_Final 0.41 1.00
# Mapa de calor con corrplot
corrplot(
matriz_cor,
method = "color",
type = "upper",
addCoef.col = "black",
number.cex = 0.7,
tl.col = "black",
tl.srt = 45,
col = colorRampPalette(c("#FF6B6B", "white", "#4D96FF"))(100),
title = "Mapa de Calor - Correlaciones",
mar = c(0, 0, 2, 0)
)
Respuestas:
Variables con correlacion mas alta: Examen_Interno_2 con Promedio_Tareas (r ≈ 0.54) Asistencia ↔︎ Nota_Final como la más fuerte. (r ≈ 0.73)
¿Existe correlacion negativa? No, ninguna de las variables tiene correlación negativa.
Variable mas correlacionada con Nota Final: Asistencia (r ≈ 0.73)
# Crear gráfico de dispersión
plot(datos$Asistencia, datos$Nota_Final,
main = "Relación entre Asistencia y Nota Final",
xlab = "Porcentaje de Asistencia",
ylab = "Nota del Examen Final",
col = "#4D96FF",
pch = 19,
cex = 0.7)
# Agregar línea de tendencia
abline(lm(Nota_Final ~ Asistencia, data = datos),
col = "red",
lwd = 2)# Calcular correlación
correlacion <- cor(datos$Asistencia, datos$Nota_Final)
cat("Coeficiente de correlación (r):", round(correlacion, 4), "\n")## Coeficiente de correlación (r): 0.7256
# Prueba de significancia
prueba_cor <- cor.test(datos$Asistencia, datos$Nota_Final)
cat("Valor p:", prueba_cor$p.value, "\n")## Valor p: 0
if(prueba_cor$p.value < 0.05) {
cat("La correlación ES estadísticamente significativa\n")
} else {
cat("La correlación NO es significativa\n")
}## La correlación ES estadísticamente significativa
Respuestas:
Coeficiente r = 0.7256
Valor p = 0
Tipo de correlacion (fuerte/moderada/debil): Fuerte
¿Es significativa? (Si / No): Si
##
## Call:
## lm(formula = Nota_Final ~ Asistencia, data = datos)
##
## Residuals:
## Min 1Q Median 3Q Max
## -23.9094 -5.4021 0.1196 5.4230 23.0906
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -25.1883 1.9181 -13.13 <0.0000000000000002 ***
## Asistencia 1.0607 0.0225 47.14 <0.0000000000000002 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 7.806 on 1998 degrees of freedom
## Multiple R-squared: 0.5266, Adjusted R-squared: 0.5263
## F-statistic: 2222 on 1 and 1998 DF, p-value: < 0.00000000000000022
# Obtener coeficientes
intercepto <- coef(modelo)[1]
pendiente <- coef(modelo)[2]
cat("=== ECUACIÓN DEL MODELO ===\n")## === ECUACIÓN DEL MODELO ===
## Nota_Final = -25.19 + 1.06 * Asistencia
# Coeficiente de determinación R²
r_cuadrado <- summary(modelo)$r.squared
cat("R cuadrado (R²):", round(r_cuadrado, 4), "\n")## R cuadrado (R²): 0.5266
cat("La Asistencia explica el", round(r_cuadrado * 100, 1),
"% de la variabilidad en la Nota Final\n")## La Asistencia explica el 52.7 % de la variabilidad en la Nota Final
respuestas:
Nota_Final = -25.19 + 1.06 × Asistencia
R² = 0.5266
Interpretación: La Asistencia explica el 52.7% de la variabilidad en la nota final.
ggplot(datos, aes(x = Asistencia, y = Nota_Final)) +
geom_point(color = "#4D96FF", alpha = 0.5) +
geom_smooth(method = "lm", color = "red", se = TRUE) +
labs(
title = "Regresión Lineal: Nota Final vs Asistencia",
subtitle = paste("R² =", round(r_cuadrado, 4)),
x = "Porcentaje de Asistencia",
y = "Nota del Examen Final"
) +
theme_minimal()# Crear datos para predicción
nuevos_datos <- data.frame(Asistencia = c(60, 70, 80, 85, 90, 100))
# Realizar predicciones
predicciones <- predict(modelo, newdata = nuevos_datos)
# Mostrar resultados
cat("=== PREDICCIONES ===\n")## === PREDICCIONES ===
for(i in 1:length(nuevos_datos$Asistencia)) {
cat("Asistencia:", nuevos_datos$Asistencia[i],
"% -> Nota predicha:", round(predicciones[i], 1), "\n")
}## Asistencia: 60 % -> Nota predicha: 38.5
## Asistencia: 70 % -> Nota predicha: 49.1
## Asistencia: 80 % -> Nota predicha: 59.7
## Asistencia: 85 % -> Nota predicha: 65
## Asistencia: 90 % -> Nota predicha: 70.3
## Asistencia: 100 % -> Nota predicha: 80.9
respuesta:
Promedio de Nota Final: 64.86 puntos
Normalidad: Los datos NO siguen una distribución normal según la prueba de Shapiro-Wilk (p = 0.0002). Además, el histograma mostró asimetría (sesgo a la derecha) y no tiene la forma de campana perfecta. El Q-Q plot también muestra desviaciones importantes en las colas.
Correlación: Existe una correlación fuerte (r = 0.7256) entre Asistencia y Nota Final, que ES estadísticamente significativa
Modelo de Regresión: La asistencia explica el 52.7% de la variabilidad en la nota final. Por cada punto porcentual adicional de asistencia, la nota final aumenta aproximadamente 1.06 puntos
Basándose en el análisis realizado: