Ejercicio de clase Clasificación del rendimiento académico de estudiantes de matemáticas
# Descargar archivo
data <- read.csv("Student-mat.csv", header = FALSE, stringsAsFactors=TRUE)
# Guardar los nombres de las columnas de la primera fila
colnames <- as.character(unlist(data[1,]))
# Eliminar la primera fila de datos y asignar los nombres de columnas
data <- data[-1,]
colnames(data) <- colnames
# Convertir la columna G3 a numérico (ya que al tenerlos como factor se tratan como caracteres)
data$G3 <- as.numeric(as.character(data$G3))
# Crear la variable 'rendimiento'
data$rendimiento <- factor(ifelse(data$G3 > 10, "Aprobado", "No_Aprobado"))
# Verificar la distribución
print("Distribución de rendimiento:")
## [1] "Distribución de rendimiento:"
print(table(data$rendimiento))
##
## Aprobado No_Aprobado
## 209 186
# Como ya existe 'rendimiento', se elimina para evitar conflicto
data$rendimiento <- NULL
# Aprobado si G3 > 10 y No_Aprobado si G3 <= 10
data$rendimiento <- factor(ifelse(data$G3 > 10, "Aprobado", "No_Aprobado"))
# Convertir studytime y failures a numérico ya que están como factores
data$studytime <- as.numeric(as.character(data$studytime))
data$failures <- as.numeric(as.character(data$failures))
# Verificar la distribución
print("Distribución de rendimiento:")
## [1] "Distribución de rendimiento:"
print(table(data$rendimiento))
##
## Aprobado No_Aprobado
## 209 186
# Tabla 1: Distribución por tiempo de estudio y rendimiento
tabla1 <- table(data$studytime, data$rendimiento)
print("Tabla 1: Distribución por tiempo de estudio y rendimiento:")
## [1] "Tabla 1: Distribución por tiempo de estudio y rendimiento:"
print(tabla1)
##
## Aprobado No_Aprobado
## 1 51 54
## 2 100 98
## 3 41 24
## 4 17 10
# Tabla 2: Distribución por fallos previos y rendimiento
tabla2 <- table(data$failures, data$rendimiento)
print("Tabla 2: Distribución por fallos previos y rendimiento:")
## [1] "Tabla 2: Distribución por fallos previos y rendimiento:"
print(tabla2)
##
## Aprobado No_Aprobado
## 0 189 123
## 1 18 32
## 2 2 15
## 3 0 16
set.seed(2025)
library(caret)
## Loading required package: ggplot2
## Loading required package: lattice
# Crear folds basados en la variable de respuesta "rendimiento"
folds <- createFolds(data$rendimiento, k = 5)
# Definir conjunto de entrenamiento y prueba usando el último fold como prueba
entrenamiento <- data[-folds[[5]], ]
prueba <- data[folds[[5]], ]
# Guardar las etiquetas del diagnóstico
entrenamiento_labels <- data$rendimiento[-folds[[5]]]
prueba_labels <- data$rendimiento[folds[[5]]]
# Verificar la distribución en los conjuntos
print("Distribución en el conjunto de entrenamiento:")
## [1] "Distribución en el conjunto de entrenamiento:"
print(table(entrenamiento_labels))
## entrenamiento_labels
## Aprobado No_Aprobado
## 167 149
print("Distribución en el conjunto de prueba:")
## [1] "Distribución en el conjunto de prueba:"
print(table(prueba_labels))
## prueba_labels
## Aprobado No_Aprobado
## 42 37
#Para nuestro dataset de estudiantes, la opción más completa es la segunda: entrenar el modelo naïve Bayes sobre el conjunto de entrenamiento (en este ejemplo usando la variable respuesta "rendimiento") y luego evaluar el modelo sobre el conjunto de prueba. En este caso, seleccionaremos algunas variables (por ejemplo, "studytime" y "failures") y probaremos dos enfoques:
#Primero, usando las variables tal como están (numéricas)
#Luego, convirtiéndolas a factores para ver si mejora la predicción
#A continuación se muestra el código para ambos escenarios:
#Escenario 1: Variables numéricas (tal como están)
library(e1071)
library(caret)
# Modelo usando variables numéricas: studytime y failures (puedes agregar más variables si lo deseas)
modelo_num <- naiveBayes(rendimiento ~ studytime + failures, data = entrenamiento)
# Predicción sobre el conjunto de prueba
pred_num <- predict(modelo_num, prueba)
cm_num <- confusionMatrix(pred_num, prueba_labels)
print("Confusión - Variables numéricas:")
## [1] "Confusión - Variables numéricas:"
print(cm_num)
## Confusion Matrix and Statistics
##
## Reference
## Prediction Aprobado No_Aprobado
## Aprobado 39 27
## No_Aprobado 3 10
##
## Accuracy : 0.6203
## 95% CI : (0.5041, 0.7272)
## No Information Rate : 0.5316
## P-Value [Acc > NIR] : 0.07076
##
## Kappa : 0.2068
##
## Mcnemar's Test P-Value : 2.679e-05
##
## Sensitivity : 0.9286
## Specificity : 0.2703
## Pos Pred Value : 0.5909
## Neg Pred Value : 0.7692
## Prevalence : 0.5316
## Detection Rate : 0.4937
## Detection Prevalence : 0.8354
## Balanced Accuracy : 0.5994
##
## 'Positive' Class : Aprobado
##
#Escenario 2: Variables convertidas a factores
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
# Crear una copia del conjunto de entrenamiento y prueba para transformación
entrenamiento_factor <- entrenamiento %>%
mutate(across(c(studytime, failures), as.factor))
prueba_factor <- prueba %>%
mutate(across(c(studytime, failures), as.factor))
# Modelo usando variables como factores
modelo_fact <- naiveBayes(rendimiento ~ studytime + failures, data = entrenamiento_factor)
# Predicción sobre el conjunto de prueba
pred_fact <- predict(modelo_fact, prueba_factor)
cm_fact <- confusionMatrix(pred_fact, prueba_labels)
print("Confusión - Variables convertidas a factores:")
## [1] "Confusión - Variables convertidas a factores:"
print(cm_fact)
## Confusion Matrix and Statistics
##
## Reference
## Prediction Aprobado No_Aprobado
## Aprobado 39 28
## No_Aprobado 3 9
##
## Accuracy : 0.6076
## 95% CI : (0.4913, 0.7156)
## No Information Rate : 0.5316
## P-Value [Acc > NIR] : 0.1071
##
## Kappa : 0.179
##
## Mcnemar's Test P-Value : 1.629e-05
##
## Sensitivity : 0.9286
## Specificity : 0.2432
## Pos Pred Value : 0.5821
## Neg Pred Value : 0.7500
## Prevalence : 0.5316
## Detection Rate : 0.4937
## Detection Prevalence : 0.8481
## Balanced Accuracy : 0.5859
##
## 'Positive' Class : Aprobado
##
Interpretación:
En el primer escenario se utiliza la información continua (aunque en este caso studytime y failures se leen como numéricas). Esto puede producir un menor desempeño al generar distribuciones continuas para cada predictor.
En el segundo escenario se convierten las variables a factores, lo que en muchos casos mejora la clasificación cuando la variable predictora es discreta o tiene niveles definidos.
Ambos métodos permiten comparar la tasa de aciertos (tasa de aciertos se puede extraer de la matriz de confusión) y determinar cuál es mejor para nuestro modelo en este dataset.
# Instalar naivebayes
install.packages("naivebayes", repos="https://cran.rstudio.com/", dependencies=TRUE)
##
## The downloaded binary packages are in
## /var/folders/17/dvlxxy895txc903kdy2z4_xw0000gn/T//RtmpktXfe9/downloaded_packages
library(naivebayes)
## naivebayes 1.0.0 loaded
## For more information please visit:
## https://majkamichal.github.io/naivebayes/
library(caret)
set.seed(2025)
# Configuración de validación cruzada
train_control <- trainControl(method = "cv", number = 20, savePredictions = TRUE)
# Crear dataset temporal
prueba_temp <- cbind(prueba, rendimiento = prueba_labels)
# Aplicar el clasificador Naive Bayes con validación cruzada
NBC_cv <- train(rendimiento ~ studytime + failures,
data = prueba_temp,
method = "naive_bayes",
trControl = train_control)
# Mostrar resultados
print("Resultados de validación cruzada:")
## [1] "Resultados de validación cruzada:"
print(NBC_cv)
## Naive Bayes
##
## 79 samples
## 2 predictor
## 2 classes: 'Aprobado', 'No_Aprobado'
##
## No pre-processing
## Resampling: Cross-Validated (20 fold)
## Summary of sample sizes: 75, 75, 75, 76, 75, 75, ...
## Resampling results across tuning parameters:
##
## usekernel Accuracy Kappa
## FALSE 0.6216667 0.2033333
## TRUE 0.4925000 0.0000000
##
## Tuning parameter 'laplace' was held constant at a value of 0
## Tuning
## parameter 'adjust' was held constant at a value of 1
## Accuracy was used to select the optimal model using the largest value.
## The final values used for the model were laplace = 0, usekernel = FALSE
## and adjust = 1.
print("Matriz de confusión general:")
## [1] "Matriz de confusión general:"
print(confusionMatrix(NBC_cv$pred$pred, NBC_cv$pred$obs))
## Confusion Matrix and Statistics
##
## Reference
## Prediction Aprobado No_Aprobado
## Aprobado 63 49
## No_Aprobado 21 25
##
## Accuracy : 0.557
## 95% CI : (0.4759, 0.6358)
## No Information Rate : 0.5316
## P-Value [Acc > NIR] : 0.28889
##
## Kappa : 0.0899
##
## Mcnemar's Test P-Value : 0.00125
##
## Sensitivity : 0.7500
## Specificity : 0.3378
## Pos Pred Value : 0.5625
## Neg Pred Value : 0.5435
## Prevalence : 0.5316
## Detection Rate : 0.3987
## Detection Prevalence : 0.7089
## Balanced Accuracy : 0.5439
##
## 'Positive' Class : Aprobado
##
Variables Utilizadas: -studytime: Tiempo de estudio semanal -failures: Número de fallos previos
Estas variables se seleccionaron porque: 1.Son indicadores directos del esfuerzo académico (studytime) y el historial académico (failures) 2.Son variables numéricas que pueden tener una relación directa con el rendimiento 3.Representan tanto el presente (tiempo de estudio) como el pasado (fallos previos) del estudiante
Interpretación Detallada de Resultados: 1.Exactitud (Accuracy): -El modelo alcanzó una exactitud de 55.7% -Intervalo de confianza del 95%: (47.59% - 63.58%) -Esta exactitud está ligeramente por encima de la tasa de No Information Rate (53.16%) -El p-valor (0.28889) > 0.05 indica que la mejora sobre el NIR no es estadísticamente significativa 2.Índice Kappa: -Kappa = 0.0899 -Este valor es < 0.40, lo que indica un desempeño débil -Sugiere que el acuerdo entre las predicciones y los valores reales es apenas superior al azar 3.Sensibilidad y Especificidad: -Sensibilidad (Aprobados): 75.00% -Especificidad (No_Aprobados): 33.78% -El modelo es mejor identificando aprobados que reprobados -Hay un sesgo hacia la predicción de “Aprobado” 4.Valores Predictivos: -Valor Predictivo Positivo (Aprobados): 56.25% -Valor Predictivo Negativo (No_Aprobados): 54.35% -La confiabilidad de las predicciones es similar para ambas clases
5.Matriz de Confusión: Reference
Prediction Aprobado No_Aprobado
Aprobado 63 49
No_Aprobado 21 25
-Aciertos en Aprobados: 63 -Aciertos en No_Aprobados: 25 -Falsos
Aprobados: 49 -Falsos No_Aprobados: 21
6.Validación Cruzada (20 folds): -usekernel = FALSE tuvo mejor desempeño (62.17%) -usekernel = TRUE tuvo peor desempeño (49.25%) -La variación en los resultados sugiere inestabilidad en el modelo
Limitaciones del Modelo: 1.Baja Especificidad: -El modelo tiene dificultad para identificar correctamente a los estudiantes que no aprobarán -Esto es particularmente problemático si el objetivo es identificar estudiantes en riesgo 2.Kappa Bajo: -Indica que gran parte del acierto podría deberse al azar -Sugiere que las variables seleccionadas no son suficientemente predictivas 3.Sesgo hacia Aprobados: -El modelo tiende a clasificar más casos como “Aprobado” -Esto podría llevar a no identificar estudiantes que necesitan apoyo
Conclusiones: 1.El modelo actual tiene un desempeño limitado, apenas superior al azar 2.Las dos variables utilizadas (studytime y failures) no son suficientes para predecir con precisión el rendimiento 3.La alta sensibilidad pero baja especificidad sugiere que el modelo es optimista en sus predicciones 4.La validación cruzada confirma la inestabilidad del modelo, con variaciones significativas en el desempeño