Librerias necesarias

library(readxl) # Importar datos de excel 
library(skimr) # Resumen estadísticos
library(readr) # Importar datos csv
library(caret) # Dividir en conjunto de entrenamiento y prueba 
library(partykit) # Arboles de decisión 
library(e1071) # Matriz de confusión 
library(ROCR) # Curva ROC
library(rpart) # Arbol de decision Particionamiento recursivo
library(rpart.plot) # Graficos para rpart
library(randomForest) # Para modelos de bosques aleatorios
library(dplyr) # Manipulacion de datos
library(ggplot2) # Visualizacion de datos

El obejetivo de este documento es cubrir la construcion y evaluacion de un bosque aleatorio. Para ello, es importante que cubramos algunos apsectos iportantes del modelo:

  • Importance parameter: El parametro de importancia, es una medida de que tanto la precicon varia segun se añade o elimina una variable

  • Proximity Parameter: El parametro de proximidad mide la cercania entre pares de casos. La proximidad se calcula para cada par de puntos de muestra. Si dos casos ocupan el mismo nodo terminal atravs de un arbol , su aproximidad aumenta en uno. Despues de ejecutar el modelo con todos los arboles, las proximidades se normalizan dividiendolas por las cantidade de arboles. Las proximidades se utilizar para remplaxar datos faltantes, localizar valores atipicos y determinar puntos de baja dimension en los datos

1) Descripcion de las variables y analisis exploratorio de los datos

Variable Ejemplo Descripción
ID 1 Identificador único de cada registro.
Program.Code HD Código granular que describe el destino y las actividades del viaje (por ejemplo, “HD” para un programa de historia).
FromGrade 8 El grado más bajo en la escuela de un participante en el programa.
ToGrade 8 El grado más alto en la escuela de un participante en el programa.
GroupState IN Abreviatura del estado donde se ubica la escuela de origen. “OTHER” se usa para geografías raras.
IsNonAnnual 1 Indica si el grupo de esta escuela típicamente salta un año entre programas.
Days 3 Número de días que el grupo estuvo en el programa con uno de los instructores.
TransportType A Modo de transporte desde la ubicación de origen al punto de inicio (A = Avión, B = Bus, T = Tren).
SpecialPay NA Indica si el maestro recauda todo el dinero para remitirlo a EduTravel en lugar de hacerlo individualmente.
Price 1174 Precio pagado por participante para asistir al programa.
FRP.Active 72 Número de participantes que compraron seguro de cancelación del viaje.
Income.Level P Indicador del nivel de ingresos de los padres (A = bajo, Q = alto, Z = no clasificado).
EZ.Pay 0.2286 Porcentaje de participantes que se inscriben en un plan de pago automático.
School.Sponsor 0 Indicador binario de si la escuela patrocinó oficialmente el viaje.
Product.Type East Coast Nivel de agrupación del tipo de programa turístico.
New.Existing EXISTING Indica si el grupo ha viajado previamente con EduTravel (“NEW” si no lo ha hecho antes).
FPP 105 Número total de participantes que pagaron completamente para asistir al programa.
Group.Revenue 125735.4 Monto total pagado por todos los participantes del grupo.
Meetings 0 Número de reuniones con los padres antes del viaje.
GradeLow Elementary Tipo de grado más bajo de la escuela.
GradeHigh Elementary Tipo de grado más alto de la escuela.
DepartureMonth January Mes de partida.
Poverty.Code A Código de pobreza del área de origen (A = bajo porcentaje bajo la línea de pobreza, D = alto).
CRM Segment 1 Tipo de segmento de cliente definido en el sistema CRM (números entre 1 y 11).
SchoolType PUBLIC Indica si la escuela es pública o privada.
Meeting.Flag 1 Indica si hubo una reunión con los padres, señalando compromiso con el viaje.
Low.Grade 7 Grado más bajo en la escuela de origen.
High.Grade 8 Grado más alto en la escuela de origen.
School.Enrollment 955 Total de estudiantes inscritos en la escuela.
MajorProgramCode H Agregación del código del programa; la primera letra del código granular del programa.
SingleGrade 1 Indicador de si el viaje incluye estudiantes del mismo grado.
FPP.enrollment 0.06346 Proporción de participantes en el programa respecto al total de la inscripción escolar.
FPP.PAX 0.93650794 Proporción de participantes que pagaron completamente en comparación con el total de pasajeros.
Size L Tamaño de la escuela (S, M, L, S-M, M-L) por quintiles de tamaño.
Retained.in.2020 1 Indicador de éxito (1/0): ¿el grupo volvió al año siguiente?

1.1) Transformacion de tipo variable

edutravel$Program.Code <- as.factor(edutravel$Program.Code)
edutravel$FromGrade <- as.factor(edutravel$FromGrade)
edutravel$ToGrade <- as.factor(edutravel$ToGrade)
edutravel$GroupState <- as.factor(edutravel$GroupState)
edutravel$IsNonAnnual <- as.factor(edutravel$IsNonAnnual)
edutravel$Days <- as.factor(edutravel$Days)
edutravel$TransportType <- as.factor(edutravel$TransportType)
edutravel$SpecialPay <- as.factor(edutravel$SpecialPay)
edutravel$Poverty.Code <- as.factor(edutravel$Poverty.Code)
edutravel$Region <- as.factor(edutravel$Region )
edutravel$CRMSegment <- as.factor(edutravel$CRMSegment)
edutravel$SchoolType <- as.factor(edutravel$SchoolType)
edutravel$Meeting.Flag <- as.factor(edutravel$Meeting.Flag)
edutravel$Income.Level <- as.factor(edutravel$Income.Level)
edutravel$Product.Type <- as.factor(edutravel$Product.Type)
edutravel$New.Existing <- as.factor(edutravel$New.Existing)
edutravel$GradeLow <- as.factor(edutravel$GradeLow)
edutravel$GradeHigh <- as.factor(edutravel$GradeHigh)
edutravel$DepartureMonth <- as.factor(edutravel$DepartureMonth)
edutravel$Meetings <- as.factor(edutravel$Meetings)
edutravel$AggregatedCode <- as.factor(edutravel$AggregatedCode)
edutravel$SingleGrade <- as.factor(edutravel$SingleGrade)
edutravel$Size <- as.factor(edutravel$Size)
edutravel$Low.Grade <- as.factor(edutravel$Low.Grade)
edutravel$Low.High <- as.factor(edutravel$High.Grade)
edutravel$Retained.in.2020 <- as.factor(edutravel$Retained.in.2020) 

1.2) Manejo de datos faltantes

# definimos funcion 
FillNAs<-function(data_frame){ 
  fill_number<-0 
  fill_factor<-"NA_filled" 
  fill_character<-"NA_filled"
  fill_date<-as.Date("1900-01-01")
  
  
  
  # Make a loop in the columns of the data frame and according to the 
  # data type, fill the respective value and create a surrogate column
  
  for (i in 1 : ncol(data_frame)){
    if (class(data_frame[,i]) %in% c("numeric","integer")) { 
      if (any(is.na(data_frame[,i]))){
        data_frame[,paste0(colnames(data_frame)[i],"_filledNA")]<- as.factor(ifelse(is.na(data_frame[,i]),"1","0"))
        data_frame[is.na(data_frame[,i]),i]<-fill_number
      }
    } else
      if (class(data_frame[,i]) %in% c("factor")) { 
        if (any(is.na(data_frame[,i]))){
          data_frame[,i]<-as.character(data_frame[,i]) 
          data_frame[,paste0(colnames(data_frame)[i],"_filledNA")]<-as.factor(ifelse(is.na(data_frame[,i]),"1","0")) 
          data_frame[is.na(data_frame[,i]),i]<-fill_factor
          data_frame[,i]<-as.factor(data_frame[,i])
          
        }
      } else {
        if (class(data_frame[,i]) %in% c("character")) { 
          if (any(is.na(data_frame[,i]))){
            data_frame[,paste0(colnames(data_frame)[i],"_filledNA")]<- as.factor(ifelse(is.na(data_frame[,i]),"1","0"))
            data_frame[is.na(data_frame[,i]),i]<-afill_character
          }
        } else {
          if (class(data_frame[,i]) %in% c("Date")) {
            if (any(is.na(data_frame[,i]))){ 
              data_frame[,paste0(colnames(data_frame)[i],"_filledNA")]<-as.factor(ifelse(is.na(data_frame[,i]),"1","0")) 
              data_frame[is.na(data_frame[,i]),i]<-fill_date
            }
          }
        }
      }
  }
  return(data_frame)
}



# aplicamos función
edutravelNA <-FillNAs(edutravel)

# combinamos categorías

1.3) Manejo de datos categoricos con pocas observaciones

El propósito de esta función, en un contexto práctico, es simplificar y mejorar la calidad de los análisis de datos categóricos, especialmente en situaciones donde:

Reducción de complejidad en las categorías:

En un dataset con muchas categorías, algunas pueden tener muy pocas observaciones, lo que hace que los análisis sean menos significativos y más complejos de interpretar. Combinar estas categorías poco representadas en una genérica llamada “Others” ayuda a reducir el ruido en los datos y enfocar los análisis en las categorías principales. Facilitar la visualización de datos:

Al crear gráficos (por ejemplo, gráficos de barras, de pastel o tablas resumen), un exceso de categorías hace que la visualización sea desordenada y difícil de leer. Agrupar las categorías con pocos datos bajo “Others” mejora la claridad visual y destaca las categorías más relevantes. Mejorar los modelos estadísticos o de machine learning:

En modelos de regresión, clasificación o cualquier algoritmo que utilice variables categóricas, demasiadas categorías con baja frecuencia pueden llevar a problemas de sobreajuste (overfitting) o resultados inestables. Agrupar las categorías pequeñas en “Others” permite que los modelos se centren en las categorías más significativas, mejorando su rendimiento. Normalización de los datos para reportes:

En informes o reportes donde se presenten resultados agrupados, es común agrupar valores menores en una categoría “Otros” para que los resultados sean más concisos y comprensibles. Análisis exploratorio de datos:

Durante el análisis inicial de un dataset, agrupar categorías poco representadas facilita la identificación de patrones significativos en las categorías principales sin distracciones innecesarias.

### Combining Categories

# Definimos funcion
CombineCategories <-function(data_frame,mincount){ 
  for (i in 1 : ncol(data_frame)){
    a<-data_frame[,i]
    replace <- names(which(table(a) < mincount))
    levels(a)[levels(a) %in%    replace]    <- paste("Others",colnames(data_frame)[i],sep=".")
    
    
    
    data_frame[,i]<-a } 
  return(data_frame) 
}

# aplicamos funcion
# dataframe with a mincount of 10
#head(CombineCategories(edutravelNA, 10))

2) Estructuramos modelo de bosque aleatorio

2.1) Separamos en conjunto de prueba y entrenamiento

# indicamos semilla para consistencia
set.seed(2021) 

# separamos datos (80% entrenamiento y 20% prueba)
Partition <- createDataPartition(y = edutravelNA$Retained.in.2020, 
                                 p = 0.8, # porcentaje de entrenamiento.
                                 list = FALSE)

# sepramos en objetos
training <- edutravelNA[ Partition,] 
testing <- edutravelNA[ -Partition,]

2.2) Indicamos los respectivos parametros

El parámetro cutoff en randomForest ajusta el umbral de votos necesario para asignar una clase en problemas de clasificación, siendo especialmente útil en casos con clases desbalanceadas. Permite priorizar la detección de la clase minoritaria o ajustar el trade-off entre sensibilidad y especificidad. Por ejemplo, en un modelo para predecir fraudes, puedes usar cutoff = c(0.4, 0.6) para dar más peso a la clase minoritaria. Esto mejora el rendimiento en escenarios donde es crítico identificar correctamente ciertos casos, configurándose directamente al crear el modelo.

En este ejemplo usamos el tipo de clasificacion, ya que tenemos datos dicotomicos. Sin embargo, podriamos usar el tipo regresion para datos numericos no binarios.

# Creamos el modelo de bosque aleatorio
RF.model <- randomForest(Retained.in.2020~ . -GroupState,  # Todas las variables menos "GroupState"
                         data=training,  # datos de entrenamiento
                         importance=TRUE, proximity=TRUE, # Incluimos parametros
                         cutoff  =  c(0.5, 0.5), # Indicamos el punto de corte en 0.5
                         type="classification" # se puede indicar clasificacion o regresion
                         )

2.3) Imprimimos los resultados del modelo y graficamos

print(RF.model) 
## 
## Call:
##  randomForest(formula = Retained.in.2020 ~ . - GroupState, data = training,      importance = TRUE, proximity = TRUE, cutoff = c(0.5, 0.5),      type = "classification") 
##                Type of random forest: classification
##                      Number of trees: 500
## No. of variables tried at each split: 7
## 
##         OOB estimate of  error rate: 20.03%
## Confusion matrix:
##     0    1 class.error
## 0 497  254   0.3382157
## 1 129 1032   0.1111111

Interpretación del resultado

  • Type of random forest: classification: Confirma que el modelo es de clasificación.

  • Number of trees: 500: Indica que el bosque aleatorio contiene 500 árboles. Este es un número común para garantizar estabilidad en las predicciones.

  • No. of variables tried at each split: 7: Cada árbol considera aleatoriamente 7 variables candidatas para realizar divisiones en cada nodo. Este número es comúnmente \(\sqrt{p}\), donde \(p\) es el número total de predictores.

  • OOB estimate of error rate: 20.03%:

    • Representa la tasa de error de las predicciones hechas con las muestras fuera de bolsa (out-of-bag, OOB).
    • Una tasa del 20.03% implica que el modelo clasifica correctamente el 79.97% de las observaciones en promedio.
  • Confusion matrix: La matriz de confusión resume las predicciones del modelo:

    • Clase 0:
      • Se predijeron correctamente 497 observaciones como 0.
      • Se predijeron incorrectamente 254 observaciones como 1.
      • La tasa de error para esta clase es del 33.82%.
    • Clase 1:
      • Se predijeron correctamente 1032 observaciones como 1.
      • Se predijeron incorrectamente 129 observaciones como 0.
      • La tasa de error para esta clase es del 11.11%.
plot(RF.model) 

Podemos observar como despues de 60 arboles aproximadamente tenemos un error cercano al 0.2 (20%) y se maniene constante. Exto implicam que no importa cuantos arboles nuevos agrgemos no lograremos reducir el error, despues de estu numero de arboles

Interpretación y análisis del gráfico generado por plot(RF.model)

Este gráfico muestra cómo evoluciona la tasa de error a medida que se incrementa el número de árboles en el modelo de bosque aleatorio. Aquí se destacan los aspectos principales:

  1. Ejes del gráfico:
    • Eje X (trees): Representa el número de árboles que se han generado en el bosque aleatorio.
    • Eje Y (Error): Representa la tasa de error acumulada para el conjunto de datos OOB (Out-of-Bag) y por clase.
  2. Líneas del gráfico:
    • Línea negra (Error global):
      • Representa la tasa de error promedio para todas las clases, calculada con los datos OOB.
      • Inicialmente, el error es alto, pero disminuye rápidamente conforme se incrementa el número de árboles. Esto indica que el modelo mejora su capacidad de predicción a medida que se construyen más árboles.
      • Después de aproximadamente 100-200 árboles, el error global se estabiliza, mostrando que añadir más árboles no mejora significativamente el rendimiento.
    • Línea roja (Error de clase 0):
      • Muestra el error específicamente para la clase 0.
      • El error es relativamente alto al inicio, pero se estabiliza conforme se incrementa el número de árboles.
      • La estabilización ocurre en un valor más alto que la clase 1, lo que indica que el modelo tiene más dificultades para clasificar correctamente la clase 0.
    • Línea verde (Error de clase 1):
      • Representa el error específicamente para la clase 1.
      • Comienza con un valor más bajo en comparación con la clase 0 y también se estabiliza rápidamente en un nivel muy bajo, lo que indica que el modelo clasifica la clase 1 con mayor precisión.
  3. Patrones observados:
    • Convergencia: Todas las líneas se estabilizan después de un cierto número de árboles (~100-200), indicando que el modelo alcanza un equilibrio en el aprendizaje.
    • Error más alto para la clase 0: El error para la clase 0 (rojo) es mayor que para la clase 1 (verde), lo que sugiere un posible desbalance en las clases o diferencias en la dificultad de clasificación.
  4. Conclusión:
    • El modelo tiene un buen rendimiento general, ya que el error global (negro) se estabiliza alrededor del 20% (coherente con la tasa OOB del resultado anterior).
    • Es posible que el modelo necesite ajustes adicionales para mejorar la clasificación de la clase 0, como:
      • Ajustar pesos para las clases (classwt).
      • Optimizar el número de variables por división (mtry).
      • Aumentar la cantidad de datos representativos de la clase 0 si hay un desbalance.

Analizamos las variables de mayor importancia

#importance(RF.model) 

La función importance() en el paquete randomForest se utiliza para calcular y extraer medidas de importancia de las variables predictoras en el modelo. Esta función ayuda a identificar cuáles variables contribuyen más al poder predictivo del modelo.

Graficamos

La función varImpPlot(RF.model) genera un gráfico que visualiza la importancia de las variables predictoras en un modelo de bosque aleatorio. Utiliza las métricas calculadas por importance(), como MeanDecreaseAccuracy (reducción en la precisión al permutar una variable) o MeanDecreaseGini (reducción acumulada en el índice de Gini). El gráfico ordena las variables de mayor a menor importancia, mostrando en el eje Y los nombres de las variables y en el eje X sus valores de importancia. Este gráfico es útil para identificar visualmente las variables más influyentes en el modelo y facilitar la selección o eliminación de predictores con bajo impacto.

varImpPlot(RF.model)

Interpretación y Análisis del Gráfico

El gráfico presentado es un resultado típico de la función varImpPlot() del paquete randomForest en R y muestra dos métricas clave de la importancia de las variables predictoras en un modelo de bosque aleatorio:

Panel izquierdo: MeanDecreaseAccuracy

  • Significado: Este eje mide cuánto disminuye la precisión del modelo al permutar aleatoriamente los valores de cada variable. Una disminución mayor implica que la variable tiene un impacto significativo en la capacidad predictiva del modelo.
  • Interpretación:
    • La variable IsNonAnnual tiene el mayor impacto en la precisión del modelo, siendo la más importante según esta métrica.
    • Otras variables relevantes incluyen New.Existing, SingleGrade, y FPP.
    • Las variables en la parte inferior del eje Y tienen un impacto mínimo y podrían ser candidatas para ser descartadas si se busca simplificar el modelo.

Panel derecho: MeanDecreaseGini

  • Significado: Mide la reducción acumulada en el índice de Gini (una medida de impureza) al usar una variable para dividir nodos en los árboles. Valores altos indican que la variable contribuye significativamente a mejorar la homogeneidad de las clases dentro de los nodos.
  • Interpretación:
    • Nuevamente, IsNonAnnual es la variable más importante según esta métrica, seguida por Income.Level, SingleGrade, y New.Existing.
    • Las variables en la parte inferior tienen una contribución limitada a la pureza de los nodos.

Análisis General del Gráfico

  • Consistencia en la importancia:
    • Algunas variables, como IsNonAnnual, New.Existing, y SingleGrade, son consistentemente importantes en ambas métricas, lo que refuerza su relevancia en el modelo.
    • Otras variables, como GradeHigh, tienen bajos valores en ambas métricas, lo que sugiere que podrían ser eliminadas sin afectar significativamente el rendimiento del modelo.
  • Impacto de las métricas:
    • La métrica MeanDecreaseAccuracy está más relacionada con el impacto directo en la precisión global del modelo.
    • La métrica MeanDecreaseGini evalúa cómo las variables ayudan a realizar divisiones efectivas dentro de los árboles.
  • Optimización del modelo:
    • Las variables menos importantes (aquellas con valores bajos en ambas métricas) podrían ser eliminadas para reducir la complejidad del modelo, mejorar la interpretabilidad y reducir posibles problemas de sobreajuste.

Conclusiones

Este gráfico es una herramienta poderosa para identificar las variables más y menos relevantes en el modelo. Las variables como IsNonAnnual y New.Existing son cruciales para el modelo, mientras que otras como GradeHigh podrían no ser necesarias. Esto permite refinar el modelo enfocándose en las variables más importantes y simplificarlo eliminando predictores redundantes o irrelevantes.

3) Usamos el modelo para la tareas de clasificacion

3.1) Obtenemos el valor de corte para la evaluacion del modelo

Primero, identificamos el punto de corte. Para ello, calculamos el promedio de la tasa de retencion

edutravelNA %>% 
  mutate(Retained.in.2020 = as.numeric(as.character(Retained.in.2020))) %>% # Conversiond de variable
  summarise(media_retencion = mean(Retained.in.2020, na.rm = TRUE)) # calculamos el promedio
##   media_retencion
## 1       0.6073671

Obtenemos que la probabilidad media de ser retenido es 0.607, que es lo que usaremos como valor de corte

3.2) Indicamos modelo en conjunto de datos de prueba

prob.rf<-predict(RF.model, # indicamos el tipo de modelo
                 newdata=testing, # indicamos los datos de prueba
                 type="prob" # indicamos el tipo de prediccion
                 )

3.2) Evaluamos el modelo

classification.RF<-rep("1",477)  # Creamos un vector de solo unos "1"
classification.RF[prob.rf[,2]<0.6073671]="0"    # Indicamos que es cero, aquellos menor al punto de corte
classification.RF = as.factor(classification.RF) # Convertimos a tipo factor 

Calculamos matriz de confusion

confusionMatrix(classification.RF,testing$Retained.in.2020,
                positive    = "1") 
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 162  65
##          1  25 225
##                                           
##                Accuracy : 0.8113          
##                  95% CI : (0.7733, 0.8455)
##     No Information Rate : 0.608           
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.6187          
##                                           
##  Mcnemar's Test P-Value : 3.94e-05        
##                                           
##             Sensitivity : 0.7759          
##             Specificity : 0.8663          
##          Pos Pred Value : 0.9000          
##          Neg Pred Value : 0.7137          
##              Prevalence : 0.6080          
##          Detection Rate : 0.4717          
##    Detection Prevalence : 0.5241          
##       Balanced Accuracy : 0.8211          
##                                           
##        'Positive' Class : 1               
## 

Graficamos matriz

# Calcular matriz de confusión
cm <- confusionMatrix(classification.RF, testing$Retained.in.2020, positive = "1")

# Convertir la tabla de la matriz de confusión en un DataFrame
conf_matrix <- as.data.frame(cm$table)
colnames(conf_matrix) <- c("Predicted", "Actual", "Freq")

# Crear el gráfico con ggplot2
ggplot(conf_matrix, aes(x = Actual, y = Predicted, fill = Freq)) +
  geom_tile(color = "white") +
  geom_text(aes(label = Freq), vjust = 1) +
  scale_fill_gradient(low = "white", high = "blue") +
  labs(title = "Matriz de Confusión", x = "Clase Real", y = "Clase Predicha") +
  theme_minimal()

Interpretación y análisis de la matriz de confusión

Matriz de confusión

Clase Real / Predicha 0 (Negativo) 1 (Positivo)
0 (Negativo) 162 65
1 (Positivo) 25 225

Métricas clave del modelo

  1. Exactitud (Accuracy):
    • Valor: 0.8113
    • Interpretación: El modelo clasifica correctamente el 81.13% de los casos. Es una medida global de desempeño.
  2. Sensibilidad (Recall o Tasa de Verdaderos Positivos):
    • Valor: 0.7759
    • Interpretación: El modelo identifica correctamente el 77.59% de los casos positivos reales (clase 1).
  3. Especificidad (Tasa de Verdaderos Negativos):
    • Valor: 0.8663
    • Interpretación: El modelo identifica correctamente el 86.63% de los casos negativos reales (clase 0).
  4. Valor predictivo positivo (Precisión):
    • Valor: 0.9000
    • Interpretación: De todas las predicciones positivas realizadas por el modelo, el 90% son correctas.
  5. Valor predictivo negativo:
    • Valor: 0.7137
    • Interpretación: De todas las predicciones negativas realizadas por el modelo, el 71.37% son correctas.
  6. Kappa:
    • Valor: 0.6187
    • Interpretación: Indica un acuerdo sustancial entre las predicciones del modelo y los valores reales, considerando la posibilidad de acuerdo por azar.
  7. Balanced Accuracy:
    • Valor: 0.8211
    • Interpretación: La media de sensibilidad y especificidad, mostrando un equilibrio general en el desempeño del modelo.
  8. Prevalencia:
    • Valor: 0.608
    • Interpretación: El 60.8% de los datos pertenece a la clase positiva (clase 1).

Análisis

  • El modelo tiene un buen equilibrio entre sensibilidad (77.59%) y especificidad (86.63%), lo que indica que es capaz de identificar tanto positivos como negativos con razonable precisión.
  • El valor predictivo positivo (90%) muestra que las predicciones positivas del modelo son muy confiables.
  • Sin embargo, el valor predictivo negativo es más bajo (71.37%), lo que indica que el modelo puede mejorar en la predicción de los casos negativos.
  • La métrica Kappa (0.6187) sugiere un acuerdo sustancial entre las predicciones y los valores reales, más allá del azar.
  • El modelo puede ser útil para aplicaciones donde es más importante evitar falsos negativos (alta sensibilidad), pero si se requiere un mejor equilibrio para ambas clases, puede necesitar ajustes.

Recomendaciones

  1. Ajustar los umbrales de probabilidad para mejorar el valor predictivo negativo si los falsos negativos son críticos.
  2. Evaluar otras métricas como el AUC-ROC para tener una visión más completa del desempeño del modelo.
  3. Considerar técnicas de balanceo de clases (si las clases están desbalanceadas) para mejorar la predicción de la clase minoritaria.

4) Analizamos metricas de comparacion como AUC y la curva ROC

La curva ROC (Receiver Operating Characteristic) es una herramienta gráfica utilizada para evaluar el desempeño de un modelo de clasificación binaria. Representa la relación entre la tasa de verdaderos positivos (sensibilidad o recall) y la tasa de falsos positivos (1 - especificidad) para diferentes umbrales de decisión.

4.1) Analizamos grafico ROC

# Compramos los valores de probabilidad vs el cojunto de datos de prueba 
prediction.RF.ROC   <-  prediction(prob.rf[,2],  # Indicamos la probabilidad de la columna de 1 
                                testing$Retained.in.2020 # Indicamos datos de prueba
                                ) 

# Calculamos la curva ROC
ROC.RF <- performance(prediction.RF.ROC, # Valores de probabilidad
                      "tpr", # Tasa de verdaderos positivos
                      "fpr" # Tasa de falsos positivos
                      )

# Graficamos la curva
plot(ROC.RF)

4.2) Calculamos valores numericos de AUC

# Estimamos el desempeño del modelo
AUC.RF.temp <- performance(prediction.RF.ROC, 
                           "auc" #Calculamos metrica auc
                           ) 

# Extrameos el valor numerico de AUC
AUC.RF<- as.numeric(AUC.RF.temp@y.values) 
AUC.RF
## [1] 0.8986262