INTRODUCCIÓN

En una organización, se busca comprender y prever los factores que influyen en la rotación de empleados entre distintos cargos. La empresa ha recopilado datos históricos sobre el empleo de sus trabajadores, incluyendo variables como la antigüedad en el cargo actual, el nivel de satisfacción laboral, el salario actual, edad y otros factores relevantes. La gerencia planea desarrollar un modelo de regresión logística que permita estimar la probabilidad de que un empleado cambie de cargo en el próximo período y determinar cuales factores indicen en mayor proporción a estos cambios.

Con esta información, la empresa podrá tomar medidas proactivas para retener a su talento clave, identificar áreas de mejora en la gestión de recursos humanos y fomentar un ambiente laboral más estable y tranquilo. La predicción de la probabilidad de rotación de empleados ayudará a la empresa a tomar decisiones estratégicas informadas y a mantener un equipo de trabajo comprometido y satisfecho en sus roles actuales.

CARGA DE DATOS

data("rotacion")
dplyr::glimpse(rotacion)
Rows: 1,470
Columns: 24
$ Rotación                    <chr> "Si", "No", "Si", "No", "No", "No", "No", …
$ Edad                        <dbl> 41, 49, 37, 33, 27, 32, 59, 30, 38, 36, 35…
$ `Viaje de Negocios`         <chr> "Raramente", "Frecuentemente", "Raramente"…
$ Departamento                <chr> "Ventas", "IyD", "IyD", "IyD", "IyD", "IyD…
$ Distancia_Casa              <dbl> 1, 8, 2, 3, 2, 2, 3, 24, 23, 27, 16, 15, 2…
$ Educación                   <dbl> 2, 1, 2, 4, 1, 2, 3, 1, 3, 3, 3, 2, 1, 2, …
$ Campo_Educación             <chr> "Ciencias", "Ciencias", "Otra", "Ciencias"…
$ Satisfacción_Ambiental      <dbl> 2, 3, 4, 4, 1, 4, 3, 4, 4, 3, 1, 4, 1, 2, …
$ Genero                      <chr> "F", "M", "M", "F", "M", "M", "F", "M", "M…
$ Cargo                       <chr> "Ejecutivo_Ventas", "Investigador_Cientifi…
$ Satisfación_Laboral         <dbl> 4, 2, 3, 3, 2, 4, 1, 3, 3, 3, 2, 3, 3, 4, …
$ Estado_Civil                <chr> "Soltero", "Casado", "Soltero", "Casado", …
$ Ingreso_Mensual             <dbl> 5993, 5130, 2090, 2909, 3468, 3068, 2670, …
$ Trabajos_Anteriores         <dbl> 8, 1, 6, 1, 9, 0, 4, 1, 0, 6, 0, 0, 1, 0, …
$ Horas_Extra                 <chr> "Si", "No", "Si", "Si", "No", "No", "Si", …
$ Porcentaje_aumento_salarial <dbl> 11, 23, 15, 11, 12, 13, 20, 22, 21, 13, 13…
$ Rendimiento_Laboral         <dbl> 3, 4, 3, 3, 3, 3, 4, 4, 4, 3, 3, 3, 3, 3, …
$ Años_Experiencia            <dbl> 8, 10, 7, 8, 6, 8, 12, 1, 10, 17, 6, 10, 5…
$ Capacitaciones              <dbl> 0, 3, 3, 3, 3, 2, 3, 2, 2, 3, 5, 3, 1, 2, …
$ Equilibrio_Trabajo_Vida     <dbl> 1, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3, 2, 3, …
$ Antigüedad                  <dbl> 6, 10, 0, 8, 2, 7, 1, 1, 9, 7, 5, 9, 5, 2,…
$ Antigüedad_Cargo            <dbl> 4, 7, 0, 7, 2, 7, 0, 0, 7, 7, 4, 5, 2, 2, …
$ Años_ultima_promoción       <dbl> 0, 1, 0, 3, 2, 3, 0, 0, 1, 7, 0, 0, 4, 1, …
$ Años_acargo_con_mismo_jefe  <dbl> 5, 7, 0, 0, 2, 6, 0, 0, 8, 7, 3, 8, 3, 2, …

PREPARACIÓN Y LIMPIEZA DE DATOS

LIMPIEZA Y ESTANDARIZACIÓN DE NOMBRE DE VARIABLES

Antes de comenzar con el análisis de los datos, es importante organizar y limpiar los nombres de las variables. Esto se hace porque algunos nombres contienen espacios, tildes o están escritos de forma inconsistente, lo cual puede generar errores al momento de trabajar con el código o construir modelos.

Por ejemplo, hay variables como “Viaje de Negocios” o “Antigüedad”, que contienen espacios y caracteres especiales. Aunque son fáciles de leer para una persona, pueden ser problemáticas para el análisis en R. Para solucionar esto, se utilizó una función que transforma todos los nombres de las variables a un formato más sencillo:

  • Sin espacios
  • Sin tildes
  • En minúsculas
  • Separadas por guiones bajos (_)

Esto permite trabajar de forma más ordenada, evitar errores y facilitar la construcción de modelos más adelante.

# Copia de trabajo
df <- rotacion |>
  janitor::clean_names()

# Revisar nombres nuevos
names(df)
 [1] "rotacion"                    "edad"                       
 [3] "viaje_de_negocios"           "departamento"               
 [5] "distancia_casa"              "educacion"                  
 [7] "campo_educacion"             "satisfaccion_ambiental"     
 [9] "genero"                      "cargo"                      
[11] "satisfacion_laboral"         "estado_civil"               
[13] "ingreso_mensual"             "trabajos_anteriores"        
[15] "horas_extra"                 "porcentaje_aumento_salarial"
[17] "rendimiento_laboral"         "anos_experiencia"           
[19] "capacitaciones"              "equilibrio_trabajo_vida"    
[21] "antiguedad"                  "antiguedad_cargo"           
[23] "anos_ultima_promocion"       "anos_acargo_con_mismo_jefe" 

CREACIÓN DE TABLA DESCRIPTIVA DE VARIABLES

Una vez los nombres de las variables han sido limpiados y estandarizados, es importante construir una tabla descriptiva que permita entender el significado de cada una. Esta tabla funciona como una guía que explica, de manera sencilla, qué representa cada variable, qué tipo de dato es y cómo podría relacionarse con la rotación de empleados.

Este paso es fundamental, ya que permite interpretar correctamente los resultados del análisis y facilita la comunicación de los hallazgos a personas que no tienen conocimientos técnicos.

tabla_variables <- tribble(
  ~VARIABLE, ~TIPO_VARIABLE, ~DESCRIPCIÓN, ~RELACIÓN_CON_ROTACIÓN,
  "rotacion", "Categórica binaria", "Indica si el empleado cambia o no de cargo", "Variable respuesta del estudio",
  "edad", "Cuantitativa", "Edad del empleado en años", "Puede influir en la decisión de cambio",
  "viaje_de_negocios", "Categórica", "Frecuencia de viajes laborales", "Viajes frecuentes pueden generar desgaste",
  "departamento", "Categórica", "Área de trabajo del empleado", "Algunos departamentos pueden tener mayor movilidad",
  "distancia_casa", "Cuantitativa", "Distancia entre casa y trabajo", "Trayectos largos pueden afectar estabilidad",
  "educacion", "Cuantitativa discreta", "Nivel educativo del empleado", "Puede influir en oportunidades de cambio",
  "campo_educacion", "Categórica", "Área de formación académica", "Algunos campos pueden tener mayor movilidad",
  "satisfaccion_ambiental", "Cuantitativa discreta", "Nivel de satisfacción con el ambiente laboral", "Baja satisfacción podría aumentar la rotación",
  "genero", "Categórica", "Género del empleado", "Puede explorarse como factor asociado",
  "cargo", "Categórica", "Puesto actual del empleado", "Algunos cargos pueden tener más rotación",
  "satisfaccion_laboral", "Cuantitativa discreta", "Nivel de satisfacción con el trabajo", "Baja satisfacción podría asociarse a rotación",
  "estado_civil", "Categórica", "Situación civil del empleado", "Podría influir en decisiones laborales",
  "ingreso_mensual", "Cuantitativa", "Salario mensual del empleado", "Salarios bajos podrían aumentar rotación",
  "trabajos_anteriores", "Cuantitativa discreta", "Número de empleos previos", "Mayor historial laboral puede reflejar movilidad",
  "horas_extra", "Categórica", "Indica si trabaja horas extra", "Las horas extra pueden aumentar desgaste",
  "porcentaje_aumento_salarial", "Cuantitativa", "Porcentaje de aumento salarial recibido", "Aumentos bajos podrían generar inconformidad",
  "rendimiento_laboral", "Cuantitativa discreta", "Calificación del desempeño", "Puede influir en cambios o permanencia",
  "anos_experiencia", "Cuantitativa", "Años totales de experiencia laboral", "Puede asociarse con estabilidad o ascenso",
  "capacitaciones", "Cuantitativa discreta", "Cantidad de capacitaciones recibidas", "Mayor formación puede influir en movilidad",
  "equilibrio_trabajo_vida", "Cuantitativa discreta", "Percepción del balance trabajo-vida", "Desequilibrio puede aumentar rotación",
  "antiguedad", "Cuantitativa", "Tiempo total en la empresa", "Menor antigüedad puede asociarse con mayor cambio",
  "antiguedad_cargo", "Cuantitativa", "Tiempo en el cargo actual", "Puede reflejar estabilidad o reciente movimiento",
  "anos_ultima_promocion", "Cuantitativa", "Tiempo desde la última promoción", "Mucho tiempo sin promoción puede desmotivar",
  "anos_acargo_con_mismo_jefe", "Cuantitativa", "Tiempo con el mismo jefe", "Puede influir según la estabilidad del liderazgo"
)

tabla_variables %>%
  kable(
    caption = "Tabla descriptiva de variables del dataset rotacion",
    align = "l"
  ) %>%
  kable_styling(
    full_width = FALSE,
    bootstrap_options = c("striped", "hover", "condensed")
  )
Tabla descriptiva de variables del dataset rotacion
VARIABLE TIPO_VARIABLE DESCRIPCIÓN RELACIÓN_CON_ROTACIÓN
rotacion Categórica binaria Indica si el empleado cambia o no de cargo Variable respuesta del estudio
edad Cuantitativa Edad del empleado en años Puede influir en la decisión de cambio
viaje_de_negocios Categórica Frecuencia de viajes laborales Viajes frecuentes pueden generar desgaste
departamento Categórica Área de trabajo del empleado Algunos departamentos pueden tener mayor movilidad
distancia_casa Cuantitativa Distancia entre casa y trabajo Trayectos largos pueden afectar estabilidad
educacion Cuantitativa discreta Nivel educativo del empleado Puede influir en oportunidades de cambio
campo_educacion Categórica Área de formación académica Algunos campos pueden tener mayor movilidad
satisfaccion_ambiental Cuantitativa discreta Nivel de satisfacción con el ambiente laboral Baja satisfacción podría aumentar la rotación
genero Categórica Género del empleado Puede explorarse como factor asociado
cargo Categórica Puesto actual del empleado Algunos cargos pueden tener más rotación
satisfaccion_laboral Cuantitativa discreta Nivel de satisfacción con el trabajo Baja satisfacción podría asociarse a rotación
estado_civil Categórica Situación civil del empleado Podría influir en decisiones laborales
ingreso_mensual Cuantitativa Salario mensual del empleado Salarios bajos podrían aumentar rotación
trabajos_anteriores Cuantitativa discreta Número de empleos previos Mayor historial laboral puede reflejar movilidad
horas_extra Categórica Indica si trabaja horas extra Las horas extra pueden aumentar desgaste
porcentaje_aumento_salarial Cuantitativa Porcentaje de aumento salarial recibido Aumentos bajos podrían generar inconformidad
rendimiento_laboral Cuantitativa discreta Calificación del desempeño Puede influir en cambios o permanencia
anos_experiencia Cuantitativa Años totales de experiencia laboral Puede asociarse con estabilidad o ascenso
capacitaciones Cuantitativa discreta Cantidad de capacitaciones recibidas Mayor formación puede influir en movilidad
equilibrio_trabajo_vida Cuantitativa discreta Percepción del balance trabajo-vida Desequilibrio puede aumentar rotación
antiguedad Cuantitativa Tiempo total en la empresa Menor antigüedad puede asociarse con mayor cambio
antiguedad_cargo Cuantitativa Tiempo en el cargo actual Puede reflejar estabilidad o reciente movimiento
anos_ultima_promocion Cuantitativa Tiempo desde la última promoción Mucho tiempo sin promoción puede desmotivar
anos_acargo_con_mismo_jefe Cuantitativa Tiempo con el mismo jefe Puede influir según la estabilidad del liderazgo

ANÁLISIS EXPLORATORIO DE DATOS

VISUALIZACIÓN INICIAL DE LOS DATOS

Para comenzar el análisis exploratorio, se visualizan las primeras filas del conjunto de datos. Esto permite tener una idea general de cómo están organizadas las variables y qué tipo de información contiene cada una. Es como observar una pequeña muestra del dataset antes de analizarlo en profundidad.

# Primeras filas
head(df)

DIMENSIONES DEL CONJUNTO DE DATOS

En este paso se analiza el tamaño del conjunto de datos, es decir, cuántas filas y columnas tiene. Las filas representan el número de empleados registrados, mientras que las columnas corresponden a las variables disponibles para cada uno. Conocer estas dimensiones ayuda a entender la cantidad de información con la que se cuenta para el análisis.

# Dimensiones
cat("Dimensiones:", dim(df), "\n")
Dimensiones: 1470 24 
cat("Número de Filas:", nrow(df), "\n")
Número de Filas: 1470 
cat("Cantidad de Columnas:", ncol(df), "\n")
Cantidad de Columnas: 24 

El dataset cuenta con 1470 empleados y 24 variables, lo que proporciona una base suficiente para realizar análisis estadísticos.

ESTRUCTURA DE LOS DATOS

A continuación, se revisa la estructura general del conjunto de datos. Esto permite identificar el tipo de cada variable, es decir, si es numérica o categórica. Este paso es importante porque el tipo de variable determina qué tipo de análisis se puede realizar posteriormente.

# Estructura general
glimpse(df)
Rows: 1,470
Columns: 24
$ rotacion                    <chr> "Si", "No", "Si", "No", "No", "No", "No", …
$ edad                        <dbl> 41, 49, 37, 33, 27, 32, 59, 30, 38, 36, 35…
$ viaje_de_negocios           <chr> "Raramente", "Frecuentemente", "Raramente"…
$ departamento                <chr> "Ventas", "IyD", "IyD", "IyD", "IyD", "IyD…
$ distancia_casa              <dbl> 1, 8, 2, 3, 2, 2, 3, 24, 23, 27, 16, 15, 2…
$ educacion                   <dbl> 2, 1, 2, 4, 1, 2, 3, 1, 3, 3, 3, 2, 1, 2, …
$ campo_educacion             <chr> "Ciencias", "Ciencias", "Otra", "Ciencias"…
$ satisfaccion_ambiental      <dbl> 2, 3, 4, 4, 1, 4, 3, 4, 4, 3, 1, 4, 1, 2, …
$ genero                      <chr> "F", "M", "M", "F", "M", "M", "F", "M", "M…
$ cargo                       <chr> "Ejecutivo_Ventas", "Investigador_Cientifi…
$ satisfacion_laboral         <dbl> 4, 2, 3, 3, 2, 4, 1, 3, 3, 3, 2, 3, 3, 4, …
$ estado_civil                <chr> "Soltero", "Casado", "Soltero", "Casado", …
$ ingreso_mensual             <dbl> 5993, 5130, 2090, 2909, 3468, 3068, 2670, …
$ trabajos_anteriores         <dbl> 8, 1, 6, 1, 9, 0, 4, 1, 0, 6, 0, 0, 1, 0, …
$ horas_extra                 <chr> "Si", "No", "Si", "Si", "No", "No", "Si", …
$ porcentaje_aumento_salarial <dbl> 11, 23, 15, 11, 12, 13, 20, 22, 21, 13, 13…
$ rendimiento_laboral         <dbl> 3, 4, 3, 3, 3, 3, 4, 4, 4, 3, 3, 3, 3, 3, …
$ anos_experiencia            <dbl> 8, 10, 7, 8, 6, 8, 12, 1, 10, 17, 6, 10, 5…
$ capacitaciones              <dbl> 0, 3, 3, 3, 3, 2, 3, 2, 2, 3, 5, 3, 1, 2, …
$ equilibrio_trabajo_vida     <dbl> 1, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3, 2, 3, …
$ antiguedad                  <dbl> 6, 10, 0, 8, 2, 7, 1, 1, 9, 7, 5, 9, 5, 2,…
$ antiguedad_cargo            <dbl> 4, 7, 0, 7, 2, 7, 0, 0, 7, 7, 4, 5, 2, 2, …
$ anos_ultima_promocion       <dbl> 0, 1, 0, 3, 2, 3, 0, 0, 1, 7, 0, 0, 4, 1, …
$ anos_acargo_con_mismo_jefe  <dbl> 5, 7, 0, 0, 2, 6, 0, 0, 8, 7, 3, 8, 3, 2, …

RESUMEN ESTADÍSTICO GENERAL

Se presenta un resumen estadístico de las variables, el cual incluye información como valores mínimos, máximos, promedios y medianas en el caso de variables numéricas. Para las variables categóricas, se muestran las frecuencias de cada categoría. Este resumen permite identificar posibles valores atípicos, rangos de datos y comportamientos generales.

# Resumen rápido
summary(df)
   rotacion              edad       viaje_de_negocios  departamento      
 Length:1470        Min.   :18.00   Length:1470        Length:1470       
 Class :character   1st Qu.:30.00   Class :character   Class :character  
 Mode  :character   Median :36.00   Mode  :character   Mode  :character  
                    Mean   :36.92                                        
                    3rd Qu.:43.00                                        
                    Max.   :60.00                                        
 distancia_casa     educacion     campo_educacion    satisfaccion_ambiental
 Min.   : 1.000   Min.   :1.000   Length:1470        Min.   :1.000         
 1st Qu.: 2.000   1st Qu.:2.000   Class :character   1st Qu.:2.000         
 Median : 7.000   Median :3.000   Mode  :character   Median :3.000         
 Mean   : 9.193   Mean   :2.913                      Mean   :2.722         
 3rd Qu.:14.000   3rd Qu.:4.000                      3rd Qu.:4.000         
 Max.   :29.000   Max.   :5.000                      Max.   :4.000         
    genero             cargo           satisfacion_laboral estado_civil      
 Length:1470        Length:1470        Min.   :1.000       Length:1470       
 Class :character   Class :character   1st Qu.:2.000       Class :character  
 Mode  :character   Mode  :character   Median :3.000       Mode  :character  
                                       Mean   :2.729                         
                                       3rd Qu.:4.000                         
                                       Max.   :4.000                         
 ingreso_mensual trabajos_anteriores horas_extra       
 Min.   : 1009   Min.   :0.000       Length:1470       
 1st Qu.: 2911   1st Qu.:1.000       Class :character  
 Median : 4919   Median :2.000       Mode  :character  
 Mean   : 6503   Mean   :2.693                         
 3rd Qu.: 8379   3rd Qu.:4.000                         
 Max.   :19999   Max.   :9.000                         
 porcentaje_aumento_salarial rendimiento_laboral anos_experiencia
 Min.   :11.00               Min.   :3.000       Min.   : 0.00   
 1st Qu.:12.00               1st Qu.:3.000       1st Qu.: 6.00   
 Median :14.00               Median :3.000       Median :10.00   
 Mean   :15.21               Mean   :3.154       Mean   :11.28   
 3rd Qu.:18.00               3rd Qu.:3.000       3rd Qu.:15.00   
 Max.   :25.00               Max.   :4.000       Max.   :40.00   
 capacitaciones  equilibrio_trabajo_vida   antiguedad     antiguedad_cargo
 Min.   :0.000   Min.   :1.000           Min.   : 0.000   Min.   : 0.000  
 1st Qu.:2.000   1st Qu.:2.000           1st Qu.: 3.000   1st Qu.: 2.000  
 Median :3.000   Median :3.000           Median : 5.000   Median : 3.000  
 Mean   :2.799   Mean   :2.761           Mean   : 7.008   Mean   : 4.229  
 3rd Qu.:3.000   3rd Qu.:3.000           3rd Qu.: 9.000   3rd Qu.: 7.000  
 Max.   :6.000   Max.   :4.000           Max.   :40.000   Max.   :18.000  
 anos_ultima_promocion anos_acargo_con_mismo_jefe
 Min.   : 0.000        Min.   : 0.000            
 1st Qu.: 0.000        1st Qu.: 2.000            
 Median : 1.000        Median : 3.000            
 Mean   : 2.188        Mean   : 4.123            
 3rd Qu.: 3.000        3rd Qu.: 7.000            
 Max.   :15.000        Max.   :17.000            

DESCRIPCIÓN

En este paso se realiza una revisión más detallada de la estructura del conjunto de datos utilizando la función str(). Esta función permite observar de forma compacta el tipo de cada variable, así como algunos valores de ejemplo. A diferencia de otras funciones, str() muestra la información de manera más técnica, lo que resulta útil para confirmar que los datos están correctamente organizados.

Este análisis ayuda a verificar que las variables categóricas y numéricas estén correctamente definidas, lo cual es fundamental antes de continuar con análisis más avanzados o la construcción de modelos.

str(df)
tibble [1,470 × 24] (S3: tbl_df/tbl/data.frame)
 $ rotacion                   : chr [1:1470] "Si" "No" "Si" "No" ...
 $ edad                       : num [1:1470] 41 49 37 33 27 32 59 30 38 36 ...
 $ viaje_de_negocios          : chr [1:1470] "Raramente" "Frecuentemente" "Raramente" "Frecuentemente" ...
 $ departamento               : chr [1:1470] "Ventas" "IyD" "IyD" "IyD" ...
 $ distancia_casa             : num [1:1470] 1 8 2 3 2 2 3 24 23 27 ...
 $ educacion                  : num [1:1470] 2 1 2 4 1 2 3 1 3 3 ...
 $ campo_educacion            : chr [1:1470] "Ciencias" "Ciencias" "Otra" "Ciencias" ...
 $ satisfaccion_ambiental     : num [1:1470] 2 3 4 4 1 4 3 4 4 3 ...
 $ genero                     : chr [1:1470] "F" "M" "M" "F" ...
 $ cargo                      : chr [1:1470] "Ejecutivo_Ventas" "Investigador_Cientifico" "Tecnico_Laboratorio" "Investigador_Cientifico" ...
 $ satisfacion_laboral        : num [1:1470] 4 2 3 3 2 4 1 3 3 3 ...
 $ estado_civil               : chr [1:1470] "Soltero" "Casado" "Soltero" "Casado" ...
 $ ingreso_mensual            : num [1:1470] 5993 5130 2090 2909 3468 ...
 $ trabajos_anteriores        : num [1:1470] 8 1 6 1 9 0 4 1 0 6 ...
 $ horas_extra                : chr [1:1470] "Si" "No" "Si" "Si" ...
 $ porcentaje_aumento_salarial: num [1:1470] 11 23 15 11 12 13 20 22 21 13 ...
 $ rendimiento_laboral        : num [1:1470] 3 4 3 3 3 3 4 4 4 3 ...
 $ anos_experiencia           : num [1:1470] 8 10 7 8 6 8 12 1 10 17 ...
 $ capacitaciones             : num [1:1470] 0 3 3 3 3 2 3 2 2 3 ...
 $ equilibrio_trabajo_vida    : num [1:1470] 1 3 3 3 3 2 2 3 3 2 ...
 $ antiguedad                 : num [1:1470] 6 10 0 8 2 7 1 1 9 7 ...
 $ antiguedad_cargo           : num [1:1470] 4 7 0 7 2 7 0 0 7 7 ...
 $ anos_ultima_promocion      : num [1:1470] 0 1 0 3 2 3 0 0 1 7 ...
 $ anos_acargo_con_mismo_jefe : num [1:1470] 5 7 0 0 2 6 0 0 8 7 ...

REVISIÓN DE VALORES FALTANTES “NA”

En este paso se analiza si existen valores faltantes dentro del conjunto de datos. Los valores faltantes, también conocidos como NA, representan información que no fue registrada o que se perdió. Identificar estos valores es importante, ya que pueden afectar los resultados del análisis y la precisión de los modelos. Si no se manejan correctamente, podrían generar conclusiones incorrectas.

Primero, se calcula el número total de valores faltantes en todo el dataset. Luego, se realiza un análisis más detallado por cada variable, mostrando cuántos datos faltan y qué porcentaje representan.

Esto permite decidir si es necesario limpiar, eliminar o completar la información antes de continuar con el análisis.

#REVISIÓN DE FALTANTES NA

sum(is.na(df))
[1] 0
# NA por variable
faltantes_var <- data.frame(
  variable = names(df),
  faltantes = sapply(df, function(x) sum(is.na(x))),
  porcentaje = round(sapply(df, function(x) mean(is.na(x)) * 100), 2)
)

faltantes_var

REVISIÓN DE VALORES VACIOS ““

En este paso se analiza si existen valores vacíos dentro del conjunto de datos. Los valores vacíos, representados como cadenas ““, indican que la información no fue registrada, aunque no estén marcados como NA. Identificar estos vacíos es importante porque, al igual que los NA, pueden afectar el análisis, generar resultados sesgados o afectar la precisión de los modelos. Primero, se calcula el número total de valores vacíos en cada variable. Luego, se muestra un análisis detallado por variable, indicando cuántos valores vacíos hay y qué porcentaje representan del total.

Este análisis permite decidir si es necesario limpiar, transformar o completar estos valores antes de continuar con el análisis, asegurando que los resultados sean más confiables.

vacios_var <- data.frame(
  variable = names(df),
  vacios = sapply(df, function(x) if(is.character(x) | is.factor(x)) sum(x == "") else 0),
  porcentaje = round(sapply(df, function(x) if(is.character(x) | is.factor(x)) mean(x == "") * 100 else 0), 2)
)

vacios_var

REVISIÓN DE REGISTROS DUPLICADOS

En este paso se verifica si existen registros duplicados en el conjunto de datos. Un registro duplicado es una fila que aparece más de una vez con exactamente la misma información en todas las columnas. Detectar y eliminar duplicados es importante porque pueden sesgar el análisis y afectar la validez de los resultados, ya que algunos empleados podrían contarse más de una vez.

Primero se calcula cuántos registros duplicados hay en total y, si existen, se muestran para poder decidir cómo manejarlos.

# REVISIÓN DE REGISTROS DUPLICADOS
# Número de filas duplicadas exactas
sum(duplicated(df))
[1] 0
# Ver duplicados si existen
#duplicados <- df[duplicated(df), ]
#duplicados

LIMPIEZA DE TEXTO Y AJUSTE DE TIPOS DE VARIABLES

En este paso se realiza la limpieza y preparación de las variables de texto para facilitar el análisis. Primero, se eliminan espacios en blanco extras al inicio, final y entre palabras en las variables de texto. Esto evita errores por diferencias en espacios que podrían hacer que una misma categoría se registre como distinta.

Luego, se convierten todas las variables de texto en factores, que es el tipo adecuado para trabajar con variables categóricas en análisis estadístico y modelado. Finalmente, se asegura que la variable objetivo rotacion esté ordenada correctamente con niveles "No" y "Si". Además, se crea una variable binaria numérica (rotacion_bin) con valores 0 y 1 para facilitar modelos que requieran variables numéricas.

Después, se revisan los niveles de todas las variables categóricas para detectar posibles errores de escritura, categorías poco frecuentes o inconsistencias que podrían afectar el análisis.

# Limpiar espacios en variables de texto
df <- df |>
  mutate(across(where(is.character), ~ str_squish(str_trim(.x))))

# Convertir variables de texto a factor
df <- df |>
  mutate(across(where(is.character), as.factor))

# Ajustar variable objetivo 'rotacion' y crear variable binaria
df <- df |>
  mutate(
    rotacion = factor(rotacion, levels = c("No", "Si")),
    rotacion_bin = ifelse(rotacion == "Si", 1, 0)
  )

# Revisar la estructura para verificar cambios
str(df)
tibble [1,470 × 25] (S3: tbl_df/tbl/data.frame)
 $ rotacion                   : Factor w/ 2 levels "No","Si": 2 1 2 1 1 1 1 1 1 1 ...
 $ edad                       : num [1:1470] 41 49 37 33 27 32 59 30 38 36 ...
 $ viaje_de_negocios          : Factor w/ 3 levels "Frecuentemente",..: 3 1 3 1 3 1 3 3 1 3 ...
 $ departamento               : Factor w/ 3 levels "IyD","RH","Ventas": 3 1 1 1 1 1 1 1 1 1 ...
 $ distancia_casa             : num [1:1470] 1 8 2 3 2 2 3 24 23 27 ...
 $ educacion                  : num [1:1470] 2 1 2 4 1 2 3 1 3 3 ...
 $ campo_educacion            : Factor w/ 6 levels "Ciencias","Humanidades",..: 1 1 4 1 5 1 5 1 1 5 ...
 $ satisfaccion_ambiental     : num [1:1470] 2 3 4 4 1 4 3 4 4 3 ...
 $ genero                     : Factor w/ 2 levels "F","M": 1 2 2 1 2 2 1 2 2 2 ...
 $ cargo                      : Factor w/ 9 levels "Director_Investigación",..: 3 5 9 5 9 9 9 9 2 7 ...
 $ satisfacion_laboral        : num [1:1470] 4 2 3 3 2 4 1 3 3 3 ...
 $ estado_civil               : Factor w/ 3 levels "Casado","Divorciado",..: 3 1 3 1 1 3 1 2 3 1 ...
 $ ingreso_mensual            : num [1:1470] 5993 5130 2090 2909 3468 ...
 $ trabajos_anteriores        : num [1:1470] 8 1 6 1 9 0 4 1 0 6 ...
 $ horas_extra                : Factor w/ 2 levels "No","Si": 2 1 2 2 1 1 2 1 1 1 ...
 $ porcentaje_aumento_salarial: num [1:1470] 11 23 15 11 12 13 20 22 21 13 ...
 $ rendimiento_laboral        : num [1:1470] 3 4 3 3 3 3 4 4 4 3 ...
 $ anos_experiencia           : num [1:1470] 8 10 7 8 6 8 12 1 10 17 ...
 $ capacitaciones             : num [1:1470] 0 3 3 3 3 2 3 2 2 3 ...
 $ equilibrio_trabajo_vida    : num [1:1470] 1 3 3 3 3 2 2 3 3 2 ...
 $ antiguedad                 : num [1:1470] 6 10 0 8 2 7 1 1 9 7 ...
 $ antiguedad_cargo           : num [1:1470] 4 7 0 7 2 7 0 0 7 7 ...
 $ anos_ultima_promocion      : num [1:1470] 0 1 0 3 2 3 0 0 1 7 ...
 $ anos_acargo_con_mismo_jefe : num [1:1470] 5 7 0 0 2 6 0 0 8 7 ...
 $ rotacion_bin               : num [1:1470] 1 0 1 0 0 0 0 0 0 0 ...
# Revisar niveles y frecuencias de variables categóricas
variables_categoricas <- names(df)[sapply(df, is.factor)]

for (v in variables_categoricas) {
  cat("\n=============================\n")
  cat("Variable:", v, "\n")
  print(table(df[[v]], useNA = "ifany"))
}

=============================
Variable: rotacion 

  No   Si 
1233  237 

=============================
Variable: viaje_de_negocios 

Frecuentemente       No_Viaja      Raramente 
           277            150           1043 

=============================
Variable: departamento 

   IyD     RH Ventas 
   961     63    446 

=============================
Variable: campo_educacion 

   Ciencias Humanidades    Mercadeo        Otra       Salud    Tecnicos 
        606          27         159          82         464         132 

=============================
Variable: genero 

  F   M 
588 882 

=============================
Variable: cargo 

 Director_Investigación    Director_Manofactura        Ejecutivo_Ventas 
                     80                     145                     326 
                Gerente Investigador_Cientifico        Recursos_Humanos 
                    102                     292                      52 
    Representante_Salud    Representante_Ventas     Tecnico_Laboratorio 
                    131                      83                     259 

=============================
Variable: estado_civil 

    Casado Divorciado    Soltero 
       673        327        470 

=============================
Variable: horas_extra 

  No   Si 
1054  416 

REVISIÓN DE VALORES FUERA DE RANGOS RAZONABLES

En este paso se verifican las variables cuantitativas para asegurarnos de que no tengan valores imposibles o sospechosos.

  • Por ejemplo, la edad de un empleado debería estar entre 18 y 70 años.
  • Las variables de satisfacción o rendimiento laboral suelen estar en escalas definidas (por ejemplo, de 1 a 4).
  • Los porcentajes de aumento salarial no pueden ser negativos, y el número de capacitaciones tampoco puede ser menor que cero.

Detectar valores fuera de estos rangos ayuda a identificar errores de registro, inconsistencias o datos que necesitan limpieza antes de hacer análisis o modelos predictivos.

# Validar valores fuera de rangos razonables
chequeo_rangos <- data.frame(
  variable = c("edad", "educacion", "satisfaccion_ambiental", "satisfacion_laboral",
               "porcentaje_aumento_salarial", "rendimiento_laboral",
               "capacitaciones", "equilibrio_trabajo_vida"),
  fuera_rango = c(
    sum(df$edad < 18 | df$edad > 70, na.rm = TRUE),
    sum(df$educacion < 1 | df$educacion > 5, na.rm = TRUE),
    sum(df$satisfaccion_ambiental < 1 | df$satisfaccion_ambiental > 4, na.rm = TRUE),
    sum(df$satisfacion_laboral < 1 | df$satisfacion_laboral > 4, na.rm = TRUE),
    sum(df$porcentaje_aumento_salarial < 0, na.rm = TRUE),
    sum(df$rendimiento_laboral < 1 | df$rendimiento_laboral > 4, na.rm = TRUE),
    sum(df$capacitaciones < 0, na.rm = TRUE),
    sum(df$equilibrio_trabajo_vida < 1 | df$equilibrio_trabajo_vida > 4, na.rm = TRUE)
  )
)

chequeo_rangos

DETECCIÓN DE OUTLIERS EN VARIABLES CUANTITATIVAS

En este paso buscamos valores que se alejan demasiado del resto de los datos, llamados outliers o valores atípicos.

  • Los outliers pueden ser errores de registro o casos extremos pero reales.
  • Por ejemplo, si la mayoría de empleados tiene entre 20 y 60 años, un valor de 120 años sería claramente sospechoso.
  • Identificar estos valores nos ayuda a decidir si debemos corregirlos, eliminarlos o dejarlos según el contexto.
#Identificar variables numéricas
variables_cuantitativas <- names(df)[sapply(df, is.numeric)]
variables_cuantitativas
 [1] "edad"                        "distancia_casa"             
 [3] "educacion"                   "satisfaccion_ambiental"     
 [5] "satisfacion_laboral"         "ingreso_mensual"            
 [7] "trabajos_anteriores"         "porcentaje_aumento_salarial"
 [9] "rendimiento_laboral"         "anos_experiencia"           
[11] "capacitaciones"              "equilibrio_trabajo_vida"    
[13] "antiguedad"                  "antiguedad_cargo"           
[15] "anos_ultima_promocion"       "anos_acargo_con_mismo_jefe" 
[17] "rotacion_bin"               
variables_cuantitativas <- setdiff(variables_cuantitativas, "rotacion_bin")

#Resumen de outliers con regla IQR
calcular_outliers <- function(x) {
  q1 <- quantile(x, 0.25, na.rm = TRUE)
  q3 <- quantile(x, 0.75, na.rm = TRUE)
  iqr <- q3 - q1
  li <- q1 - 1.5 * iqr
  ls <- q3 + 1.5 * iqr
  sum(x < li | x > ls, na.rm = TRUE)
}

resumen_outliers <- data.frame(
  variable = variables_cuantitativas,
  n_outliers = sapply(df[variables_cuantitativas], calcular_outliers)
)

resumen_outliers

VISUALIZACIÓN DE VALORES ATÍPICOS Y DISTRIBUCIÓN DE VARIABLES CUANTITATIVAS

En este paso usamos gráficos para entender mejor los datos y detectar casos extremos de manera visual:

  1. Gráfico de barras de outliers:
  • Muestra cuántos valores atípicos tiene cada variable cuantitativa.
  • Permite identificar rápidamente cuáles variables tienen más registros extremos que podrían afectar el análisis.
  1. Boxplots para todas las variables cuantitativas:
  • Cada caja representa la distribución de los datos (mediana, cuartiles y posibles outliers).
  • Los puntos fuera de la caja son los valores atípicos.
  • Esto permite comparar dispersión y rangos de todas las variables en un solo vistazo.
#Gráfico de outliers por variable
ggplot(resumen_outliers, aes(x = reorder(variable, n_outliers), y = n_outliers)) +
  geom_col() +
  coord_flip() +
  labs(title = "Cantidad de valores atípicos por variable",
       x = "Variable", y = "Número de outliers")

#Boxplots para todas las variables cuantitativas
df |>
  select(all_of(variables_cuantitativas)) |>
  pivot_longer(cols = everything(), names_to = "variable", values_to = "valor") |>
  ggplot(aes(x = variable, y = valor)) +
  geom_boxplot() +
  coord_flip() +
  labs(title = "Boxplots de variables cuantitativas",
       x = "Variable", y = "Valor")

TABLA DESCRIPTIVA GENERAL DEL DATASET

En este paso creamos una tabla resumen que nos da una visión general de todas las variables del dataset:

  • Variable: Nombre de la columna en los datos.
  • Tipo de variable: Indica si es numérica, factor (categórica) o carácter (texto).
  • Valores únicos: Número de valores distintos que tiene cada variable. Esto ayuda a identificar variables categóricas con pocas categorías o variables continuas.
  • Faltantes: Cantidad de valores ausentes en cada columna.
  • Porcentaje de faltantes: Porcentaje de datos faltantes respecto al total, para evaluar si alguna variable necesita limpieza especial.
tabla_descriptiva <- data.frame(
  variable = names(df),
  tipo = sapply(df, function(x) class(x)[1]),
  valores_unicos = sapply(df, function(x) length(unique(x))),
  faltantes = sapply(df, function(x) sum(is.na(x))),
  porcentaje_faltantes = round(sapply(df, function(x) mean(is.na(x)) * 100), 2)
)

tabla_descriptiva |>
  kable(caption = "Tabla descriptiva general del dataset") |>
  kable_styling(full_width = FALSE)
Tabla descriptiva general del dataset
variable tipo valores_unicos faltantes porcentaje_faltantes
rotacion rotacion factor 2 0 0
edad edad numeric 43 0 0
viaje_de_negocios viaje_de_negocios factor 3 0 0
departamento departamento factor 3 0 0
distancia_casa distancia_casa numeric 29 0 0
educacion educacion numeric 5 0 0
campo_educacion campo_educacion factor 6 0 0
satisfaccion_ambiental satisfaccion_ambiental numeric 4 0 0
genero genero factor 2 0 0
cargo cargo factor 9 0 0
satisfacion_laboral satisfacion_laboral numeric 4 0 0
estado_civil estado_civil factor 3 0 0
ingreso_mensual ingreso_mensual numeric 1349 0 0
trabajos_anteriores trabajos_anteriores numeric 10 0 0
horas_extra horas_extra factor 2 0 0
porcentaje_aumento_salarial porcentaje_aumento_salarial numeric 15 0 0
rendimiento_laboral rendimiento_laboral numeric 2 0 0
anos_experiencia anos_experiencia numeric 40 0 0
capacitaciones capacitaciones numeric 7 0 0
equilibrio_trabajo_vida equilibrio_trabajo_vida numeric 4 0 0
antiguedad antiguedad numeric 37 0 0
antiguedad_cargo antiguedad_cargo numeric 19 0 0
anos_ultima_promocion anos_ultima_promocion numeric 16 0 0
anos_acargo_con_mismo_jefe anos_acargo_con_mismo_jefe numeric 18 0 0
rotacion_bin rotacion_bin numeric 2 0 0

CLASIFICACIÓN DE VARIABLES EN CATEGÓRICAS Y CUANTITATIVAS

En este paso se separan las variables en dos tipos según su naturaleza:

  1. Variables categóricas (factores):
  • Son variables que representan categorías o grupos, como genero, departamento o rotacion.
  • Útiles para comparar grupos, calcular proporciones o para modelos que manejan factores.
  1. Variables cuantitativas (numéricas):
  • Son variables que representan números, como edad, ingreso_mensual o anos_experiencia.
  • Se usan para calcular medias, desviaciones, hacer gráficos como histogramas, boxplots o para modelos que requieren valores numéricos.
  • Se excluye rotacion_bin porque es la variable objetivo binaria que se usará para modelado y no queremos analizarla como predictor numérico.
# Identificar variables categóricas
variables_categoricas <- names(df)[sapply(df, is.factor)]

# Identificar variables cuantitativas
variables_cuantitativas <- names(df)[sapply(df, is.numeric)]
variables_cuantitativas <- setdiff(variables_cuantitativas, "rotacion_bin")

# Revisar resultados
cat("Variables Categoricas:")
Variables Categoricas:
variables_categoricas
[1] "rotacion"          "viaje_de_negocios" "departamento"     
[4] "campo_educacion"   "genero"            "cargo"            
[7] "estado_civil"      "horas_extra"      
cat("Variables Cuantitativas:")
Variables Cuantitativas:
variables_cuantitativas
 [1] "edad"                        "distancia_casa"             
 [3] "educacion"                   "satisfaccion_ambiental"     
 [5] "satisfacion_laboral"         "ingreso_mensual"            
 [7] "trabajos_anteriores"         "porcentaje_aumento_salarial"
 [9] "rendimiento_laboral"         "anos_experiencia"           
[11] "capacitaciones"              "equilibrio_trabajo_vida"    
[13] "antiguedad"                  "antiguedad_cargo"           
[15] "anos_ultima_promocion"       "anos_acargo_con_mismo_jefe" 

ANÁLISIS UNIVARIADO DE VARIABLES CATEGÓRICAS

En este paso se estudia cada variable categórica de forma individual para entender su distribución y frecuencia de valores:

  1. Tabla de frecuencia y porcentaje:
  • Muestra cuántos empleados pertenecen a cada categoría de la variable.
  • Incluye el porcentaje de cada categoría respecto al total, para tener una idea de su representación relativa.
  1. Gráfico de barras:
  • Visualiza la frecuencia de cada categoría de manera clara y rápida.
  • Permite identificar categorías predominantes, categorías poco frecuentes o valores atípicos en variables categóricas.
for (v in variables_categoricas) {
  cat("\n=============================\n")
  cat("Variable:", v, "\n")
  
  # Tabla de frecuencia y porcentaje
  tab <- as.data.frame(table(df[[v]], useNA = "ifany"))
  names(tab) <- c("categoria", "frecuencia")
  tab$porcentaje <- round(tab$frecuencia / sum(tab$frecuencia) * 100, 2)
  
  print(tab)
  
  # Gráfico de barras
  print(
    ggplot(tab, aes(x = reorder(categoria, frecuencia), y = frecuencia)) +
      geom_col(fill = "skyblue") +
      coord_flip() +
      labs(title = paste("Distribución de", v),
           x = v, y = "Frecuencia")
  )
}

=============================
Variable: rotacion 
  categoria frecuencia porcentaje
1        No       1233      83.88
2        Si        237      16.12


=============================
Variable: viaje_de_negocios 
       categoria frecuencia porcentaje
1 Frecuentemente        277      18.84
2       No_Viaja        150      10.20
3      Raramente       1043      70.95


=============================
Variable: departamento 
  categoria frecuencia porcentaje
1       IyD        961      65.37
2        RH         63       4.29
3    Ventas        446      30.34


=============================
Variable: campo_educacion 
    categoria frecuencia porcentaje
1    Ciencias        606      41.22
2 Humanidades         27       1.84
3    Mercadeo        159      10.82
4        Otra         82       5.58
5       Salud        464      31.56
6    Tecnicos        132       8.98


=============================
Variable: genero 
  categoria frecuencia porcentaje
1         F        588         40
2         M        882         60


=============================
Variable: cargo 
                categoria frecuencia porcentaje
1  Director_Investigación         80       5.44
2    Director_Manofactura        145       9.86
3        Ejecutivo_Ventas        326      22.18
4                 Gerente        102       6.94
5 Investigador_Cientifico        292      19.86
6        Recursos_Humanos         52       3.54
7     Representante_Salud        131       8.91
8    Representante_Ventas         83       5.65
9     Tecnico_Laboratorio        259      17.62


=============================
Variable: estado_civil 
   categoria frecuencia porcentaje
1     Casado        673      45.78
2 Divorciado        327      22.24
3    Soltero        470      31.97


=============================
Variable: horas_extra 
  categoria frecuencia porcentaje
1        No       1054       71.7
2        Si        416       28.3

ANÁLISIS UNIVARIADO DE VARIABLES CUANTITATIVAS

En este paso se estudia cada variable numérica de forma individual para entender su distribución, tendencia central y dispersión:

  1. Resumen estadístico (summary):
  • Muestra valores clave como mínimo, primer cuartil, mediana, media, tercer cuartil y máximo.
  • Ayuda a identificar rangos esperados y posibles valores extremos.
  1. Histograma:
  • Muestra cómo se distribuyen los datos a lo largo de su rango.
  • Permite ver si la variable está normalmente distribuida, sesgada o concentrada en ciertos valores.
  1. Boxplot:
  • Permite identificar valores atípicos (outliers) y la dispersión de la variable.
  • Muestra visualmente la mediana, los cuartiles y los posibles valores extremos.
for (v in variables_cuantitativas) {
  cat("\n=============================\n")
  cat("Variable:", v, "\n")
  
  # Resumen estadístico
  print(summary(df[[v]]))
  
  # Histograma
  print(
    ggplot(df, aes(x = .data[[v]])) +
      geom_histogram(bins = 30, fill = "lightgreen", color = "black") +
      labs(title = paste("Histograma de", v),
           x = v, y = "Frecuencia")
  )
  
  # Boxplot
  print(
    ggplot(df, aes(y = .data[[v]])) +
      geom_boxplot(fill = "salmon") +
      labs(title = paste("Boxplot de", v),
           y = v)
  )
}

=============================
Variable: edad 
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  18.00   30.00   36.00   36.92   43.00   60.00 


=============================
Variable: distancia_casa 
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  1.000   2.000   7.000   9.193  14.000  29.000 


=============================
Variable: educacion 
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  1.000   2.000   3.000   2.913   4.000   5.000 


=============================
Variable: satisfaccion_ambiental 
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  1.000   2.000   3.000   2.722   4.000   4.000 


=============================
Variable: satisfacion_laboral 
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  1.000   2.000   3.000   2.729   4.000   4.000 


=============================
Variable: ingreso_mensual 
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   1009    2911    4919    6503    8379   19999 


=============================
Variable: trabajos_anteriores 
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   1.000   2.000   2.693   4.000   9.000 


=============================
Variable: porcentaje_aumento_salarial 
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  11.00   12.00   14.00   15.21   18.00   25.00 


=============================
Variable: rendimiento_laboral 
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  3.000   3.000   3.000   3.154   3.000   4.000 


=============================
Variable: anos_experiencia 
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   0.00    6.00   10.00   11.28   15.00   40.00 


=============================
Variable: capacitaciones 
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   2.000   3.000   2.799   3.000   6.000 


=============================
Variable: equilibrio_trabajo_vida 
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  1.000   2.000   3.000   2.761   3.000   4.000 


=============================
Variable: antiguedad 
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   3.000   5.000   7.008   9.000  40.000 


=============================
Variable: antiguedad_cargo 
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   2.000   3.000   4.229   7.000  18.000 


=============================
Variable: anos_ultima_promocion 
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   0.000   1.000   2.188   3.000  15.000 


=============================
Variable: anos_acargo_con_mismo_jefe 
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   2.000   3.000   4.123   7.000  17.000 

ANÁLISIS DE LA VARIABLES ROTACION Y RELACIONES ENTRE VARIABLES NUMÉRICAS

  1. Variable Rotación (objetivo):
  • Se analiza cuántos empleados cambiaron de cargo (Si) y cuántos no (No), tanto en frecuencia absoluta como en porcentaje.
  • El gráfico de barras permite visualizar rápidamente si la mayoría de empleados permanecen en su cargo o si hay una rotación significativa.
  • Esta información es clave para entender la distribución de la variable que queremos predecir.
  1. Correlación entre variables cuantitativas:
  • Se calcula la correlación, que indica qué tan relacionadas están dos variables numéricas.
  • Valores cercanos a 1 o -1 indican relaciones muy fuertes, mientras que valores cercanos a 0 indican poca o ninguna relación.
  • Este análisis ayuda a detectar redundancias entre variables y evitar problemas en modelos de predicción.
  1. Mapa de calor de correlación:
  • Permite visualizar de manera intuitiva las relaciones entre todas las variables numéricas.
  • Los colores claros indican correlaciones altas positivas, colores oscuros correlaciones negativas o bajas.
  • Es útil para identificar patrones y relaciones potenciales que podrían ser relevantes en el modelado.
# Tabla de frecuencias
table(df$rotacion)

  No   Si 
1233  237 
# Porcentaje
prop.table(table(df$rotacion)) * 100

      No       Si 
83.87755 16.12245 
# Gráfico de barras
ggplot(df, aes(x = rotacion)) +
  geom_bar(fill = "steelblue") +
  labs(title = "Distribución de la variable Rotación",
       x = "Rotación", y = "Frecuencia")

# Correlación entre variables cuantitativas
matriz_cor <- cor(df[variables_cuantitativas], use = "pairwise.complete.obs")
round(matriz_cor, 2)
                             edad distancia_casa educacion
edad                         1.00           0.00      0.21
distancia_casa               0.00           1.00      0.02
educacion                    0.21           0.02      1.00
satisfaccion_ambiental       0.01          -0.02     -0.03
satisfacion_laboral          0.00           0.00     -0.01
ingreso_mensual              0.50          -0.02      0.09
trabajos_anteriores          0.30          -0.03      0.13
porcentaje_aumento_salarial  0.00           0.04     -0.01
rendimiento_laboral          0.00           0.03     -0.02
anos_experiencia             0.68           0.00      0.15
capacitaciones              -0.02          -0.04     -0.03
equilibrio_trabajo_vida     -0.02          -0.03      0.01
antiguedad                   0.31           0.01      0.07
antiguedad_cargo             0.21           0.02      0.06
anos_ultima_promocion        0.22           0.01      0.05
anos_acargo_con_mismo_jefe   0.20           0.01      0.07
                            satisfaccion_ambiental satisfacion_laboral
edad                                          0.01                0.00
distancia_casa                               -0.02                0.00
educacion                                    -0.03               -0.01
satisfaccion_ambiental                        1.00               -0.01
satisfacion_laboral                          -0.01                1.00
ingreso_mensual                              -0.01               -0.01
trabajos_anteriores                           0.01               -0.06
porcentaje_aumento_salarial                  -0.03                0.02
rendimiento_laboral                          -0.03                0.00
anos_experiencia                              0.00               -0.02
capacitaciones                               -0.02               -0.01
equilibrio_trabajo_vida                       0.03               -0.02
antiguedad                                    0.00                0.00
antiguedad_cargo                              0.02                0.00
anos_ultima_promocion                         0.02               -0.02
anos_acargo_con_mismo_jefe                    0.00               -0.03
                            ingreso_mensual trabajos_anteriores
edad                                   0.50                0.30
distancia_casa                        -0.02               -0.03
educacion                              0.09                0.13
satisfaccion_ambiental                -0.01                0.01
satisfacion_laboral                   -0.01               -0.06
ingreso_mensual                        1.00                0.15
trabajos_anteriores                    0.15                1.00
porcentaje_aumento_salarial           -0.03               -0.01
rendimiento_laboral                   -0.02               -0.01
anos_experiencia                       0.77                0.24
capacitaciones                        -0.02               -0.07
equilibrio_trabajo_vida                0.03               -0.01
antiguedad                             0.51               -0.12
antiguedad_cargo                       0.36               -0.09
anos_ultima_promocion                  0.34               -0.04
anos_acargo_con_mismo_jefe             0.34               -0.11
                            porcentaje_aumento_salarial rendimiento_laboral
edad                                               0.00                0.00
distancia_casa                                     0.04                0.03
educacion                                         -0.01               -0.02
satisfaccion_ambiental                            -0.03               -0.03
satisfacion_laboral                                0.02                0.00
ingreso_mensual                                   -0.03               -0.02
trabajos_anteriores                               -0.01               -0.01
porcentaje_aumento_salarial                        1.00                0.77
rendimiento_laboral                                0.77                1.00
anos_experiencia                                  -0.02                0.01
capacitaciones                                    -0.01               -0.02
equilibrio_trabajo_vida                            0.00                0.00
antiguedad                                        -0.04                0.00
antiguedad_cargo                                   0.00                0.03
anos_ultima_promocion                             -0.02                0.02
anos_acargo_con_mismo_jefe                        -0.01                0.02
                            anos_experiencia capacitaciones
edad                                    0.68          -0.02
distancia_casa                          0.00          -0.04
educacion                               0.15          -0.03
satisfaccion_ambiental                  0.00          -0.02
satisfacion_laboral                    -0.02          -0.01
ingreso_mensual                         0.77          -0.02
trabajos_anteriores                     0.24          -0.07
porcentaje_aumento_salarial            -0.02          -0.01
rendimiento_laboral                     0.01          -0.02
anos_experiencia                        1.00          -0.04
capacitaciones                         -0.04           1.00
equilibrio_trabajo_vida                 0.00           0.03
antiguedad                              0.63           0.00
antiguedad_cargo                        0.46          -0.01
anos_ultima_promocion                   0.40           0.00
anos_acargo_con_mismo_jefe              0.46           0.00
                            equilibrio_trabajo_vida antiguedad antiguedad_cargo
edad                                          -0.02       0.31             0.21
distancia_casa                                -0.03       0.01             0.02
educacion                                      0.01       0.07             0.06
satisfaccion_ambiental                         0.03       0.00             0.02
satisfacion_laboral                           -0.02       0.00             0.00
ingreso_mensual                                0.03       0.51             0.36
trabajos_anteriores                           -0.01      -0.12            -0.09
porcentaje_aumento_salarial                    0.00      -0.04             0.00
rendimiento_laboral                            0.00       0.00             0.03
anos_experiencia                               0.00       0.63             0.46
capacitaciones                                 0.03       0.00            -0.01
equilibrio_trabajo_vida                        1.00       0.01             0.05
antiguedad                                     0.01       1.00             0.76
antiguedad_cargo                               0.05       0.76             1.00
anos_ultima_promocion                          0.01       0.62             0.55
anos_acargo_con_mismo_jefe                     0.00       0.77             0.71
                            anos_ultima_promocion anos_acargo_con_mismo_jefe
edad                                         0.22                       0.20
distancia_casa                               0.01                       0.01
educacion                                    0.05                       0.07
satisfaccion_ambiental                       0.02                       0.00
satisfacion_laboral                         -0.02                      -0.03
ingreso_mensual                              0.34                       0.34
trabajos_anteriores                         -0.04                      -0.11
porcentaje_aumento_salarial                 -0.02                      -0.01
rendimiento_laboral                          0.02                       0.02
anos_experiencia                             0.40                       0.46
capacitaciones                               0.00                       0.00
equilibrio_trabajo_vida                      0.01                       0.00
antiguedad                                   0.62                       0.77
antiguedad_cargo                             0.55                       0.71
anos_ultima_promocion                        1.00                       0.51
anos_acargo_con_mismo_jefe                   0.51                       1.00
# Convertir a formato largo para ggplot
cor_df <- as.data.frame(as.table(matriz_cor))

# Mapa de calor de correlación
ggplot(cor_df, aes(Var1, Var2, fill = Freq)) +
  geom_tile() +
  scale_fill_gradient2(low = "blue", mid = "white", high = "red", midpoint = 0) +
  labs(title = "Mapa de correlación entre variables cuantitativas",
       x = "", y = "", fill = "Correlación") +
  theme(axis.text.x = element_text(angle = 90, hjust = 1))

SELECCION DE 3 VARIABLES CATEGÓRICAS Y 3 CUANTITATIVAS

Para esta actividad, estas 6 variables porque son intuitivas y tienen sentido para la rotación:

CATEGÓRICAS

  • horas_extra
  • viaje_de_negocios
  • estado_civil

CUANTITATIVAS

  • satisfacion_laboral
  • ingreso_mensual
  • antiguedad_cargo

HIPÓTESIS POR VARIABLE

Justificación e hipótesis de cada variable

  1. Horas_Extra: Se espera que las horas extra estén relacionadas con la rotación, porque trabajar más tiempo del habitual puede generar cansancio, estrés y menor equilibrio entre la vida personal y laboral. Cuando una persona siente sobrecarga constante, puede buscar cambiar de cargo o salir de su situación actual.

Hipótesis: los empleados que trabajan horas extra tienen una mayor probabilidad de rotación que aquellos que no trabajan horas extra.

  1. Viaje_de_Negocios: Se espera que la frecuencia de viajes de negocios influya en la rotación, ya que desplazarse con frecuencia puede generar desgaste físico, presión laboral y dificultades para mantener rutinas personales o familiares. Esto puede hacer que algunas personas prefieran cambiar de cargo hacia funciones más estables.

Hipótesis: los empleados que viajan con mayor frecuencia por trabajo tienen una mayor probabilidad de rotación que aquellos que viajan rara vez o no viajan.

  1. Estado_Civil: El estado civil puede estar relacionado con la rotación porque las responsabilidades personales y familiares suelen influir en las decisiones laborales. En algunos casos, las personas solteras pueden tener mayor flexibilidad para cambiar de cargo, mientras que personas casadas pueden buscar mayor estabilidad.

Hipótesis: los empleados solteros presentan una mayor probabilidad de rotación que los empleados casados.

  1. Satisfación_Laboral: La satisfacción laboral es una de las variables más importantes para entender la permanencia en un cargo. Cuando una persona se siente a gusto con sus funciones, su entorno y sus condiciones de trabajo, es menos probable que quiera cambiar.

Hipótesis: a mayor satisfacción laboral, menor probabilidad de rotación.

  1. Ingreso_Mensual: El ingreso mensual puede influir en la rotación porque el salario suele estar asociado con el nivel de bienestar y reconocimiento que percibe el trabajador. Si una persona considera que su remuneración no es suficiente, podría tener mayor interés en cambiar de cargo.

Hipótesis: a mayor ingreso mensual, menor probabilidad de rotación.

  1. Antigüedad_Cargo: La antigüedad en el cargo refleja cuánto tiempo ha permanecido una persona en su rol actual. Un mayor tiempo puede indicar estabilidad, adaptación y experiencia en el cargo, mientras que una baja antigüedad puede estar asociada con cambios más frecuentes.

Hipótesis: a mayor antigüedad en el cargo, menor probabilidad de rotación.

# Crear la tabla resumen
tabla_variables_hipotesis <- tribble(
  ~Variable,            ~Tipo,         ~Justificacion,                                                       ~Hipotesis_esperada,
  "Horas_Extra",        "Categórica",   "La sobrecarga laboral puede generar desgaste y deseo de cambio",      "Quienes hacen horas extra tienen mayor rotación",
  "Viaje_de_Negocios",  "Categórica",   "Viajar con frecuencia puede generar cansancio e inestabilidad",       "Quienes viajan más tienen mayor rotación",
  "Estado_Civil",       "Categórica",   "Las condiciones personales pueden influir en la estabilidad laboral", "Los solteros tendrían mayor rotación",
  "Satisfacion_Laboral","Cuantitativa", "La satisfacción con el trabajo influye en la permanencia",            "A mayor satisfacción, menor rotación",
  "Ingreso_Mensual",    "Cuantitativa", "El salario influye en la motivación y permanencia",                   "A mayor ingreso, menor rotación",
  "Antiguedad_Cargo",   "Cuantitativa", "El tiempo en el cargo refleja estabilidad y adaptación",              "A mayor antigüedad, menor rotación"
)

# Mostrar la tabla bonita
tabla_variables_hipotesis %>%
  kable(caption = "Tabla de variables con justificación e hipótesis esperada") %>%
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover", "condensed"))
Tabla de variables con justificación e hipótesis esperada
Variable Tipo Justificacion Hipotesis_esperada
Horas_Extra Categórica La sobrecarga laboral puede generar desgaste y deseo de cambio Quienes hacen horas extra tienen mayor rotación
Viaje_de_Negocios Categórica Viajar con frecuencia puede generar cansancio e inestabilidad Quienes viajan más tienen mayor rotación
Estado_Civil Categórica Las condiciones personales pueden influir en la estabilidad laboral Los solteros tendrían mayor rotación
Satisfacion_Laboral Cuantitativa La satisfacción con el trabajo influye en la permanencia A mayor satisfacción, menor rotación
Ingreso_Mensual Cuantitativa El salario influye en la motivación y permanencia A mayor ingreso, menor rotación
Antiguedad_Cargo Cuantitativa El tiempo en el cargo refleja estabilidad y adaptación A mayor antigüedad, menor rotación

PREPARACIÓN FINAL DEL DATASET

En este paso, además de limpiar los duplicados y organizar la variable “rotación” como antes, seleccionamos solo las columnas que nos interesan para el análisis y el modelado. Esto hace que nuestro dataset sea más manejable y contenga solo la información relevante. Las columnas elegidas incluyen la variable de interés (rotacion), su versión numérica (rotacion_bin), variables categóricas que podrían influir en la rotación (horas_extra, viaje_de_negocios, estado_civil) y variables numéricas importantes (satisfacion_laboral, ingreso_mensual, antiguedad_cargo).

Esto prepara un dataset limpio y enfocado, listo para construir modelos estadísticos o de machine learning.

## **PREPARACIÓN FINAL DEL DATASET CON VARIABLES SELECCIONADAS**
# Variables que decidimos usar para el modelo
variables_seleccionadas <- c(
  "rotacion", "rotacion_bin",      # Variable respuesta
  "horas_extra", "viaje_de_negocios", "estado_civil",   # Categóricas
  "satisfacion_laboral", "ingreso_mensual", "antiguedad_cargo"  # Cuantitativas
)

# Crear dataset final limpio solo con variables seleccionadas
df_limpio <- df |>
  select(all_of(variables_seleccionadas)) |>  # Selección de columnas
  distinct() |>                               # Eliminar duplicados
  mutate(
    rotacion = factor(rotacion, levels = c("No", "Si")), 
    rotacion_bin = ifelse(rotacion == "Si", 1, 0)
  )

VERIFICACIÓN FINAL DEL DATASET LIMPIO

Antes de comenzar a construir modelos, es importante revisar que el dataset final esté correctamente preparado. En esta verificación se comprueba:

  1. Dimensiones: cuántas filas (empleados) y columnas (variables) tiene el dataset final.
  2. Valores faltantes: asegurarse de que no queden celdas vacías que puedan afectar los modelos.
  3. Duplicados: confirmar que no haya registros repetidos.
  4. Estructura de las variables: revisar los tipos de datos para asegurarse de que las variables categóricas y numéricas estén correctamente definidas, y que la variable de interés rotacion y su versión binaria rotacion_bin estén listas para el análisis.
# Verificación final 
cat("Dimesión del nuevo dataset: ",dim(df_limpio))
Dimesión del nuevo dataset:  1470 8
cat("Cantidad de valores faltantes: ",sum(is.na(df_limpio)))
Cantidad de valores faltantes:  0
cat("Cantidad de valores duplicados: ",sum(duplicated(df_limpio))) 
Cantidad de valores duplicados:  0
str(df_limpio)
tibble [1,470 × 8] (S3: tbl_df/tbl/data.frame)
 $ rotacion           : Factor w/ 2 levels "No","Si": 2 1 2 1 1 1 1 1 1 1 ...
 $ rotacion_bin       : num [1:1470] 1 0 1 0 0 0 0 0 0 0 ...
 $ horas_extra        : Factor w/ 2 levels "No","Si": 2 1 2 2 1 1 2 1 1 1 ...
 $ viaje_de_negocios  : Factor w/ 3 levels "Frecuentemente",..: 3 1 3 1 3 1 3 3 1 3 ...
 $ estado_civil       : Factor w/ 3 levels "Casado","Divorciado",..: 3 1 3 1 1 3 1 2 3 1 ...
 $ satisfacion_laboral: num [1:1470] 4 2 3 3 2 4 1 3 3 3 ...
 $ ingreso_mensual    : num [1:1470] 5993 5130 2090 2909 3468 ...
 $ antiguedad_cargo   : num [1:1470] 4 7 0 7 2 7 0 0 7 7 ...

ANÁLISIS DESCRIPTIVO UNIVARIADO

ANÁLISIS UNIVARIADO DE VARIABLES CUANTITATIVAS

En esta sección se examinan individualmente las variables numéricas seleccionadas para entender cómo se distribuyen sus valores. Para esto, se generan histogramas que muestran la frecuencia con la que aparecen diferentes rangos de valores en cada variable.

Este análisis nos ayuda a visualizar patrones como concentraciones de datos, posibles sesgos, y la presencia de valores extremos o atípicos. Entender la distribución de cada variable es fundamental para tomar decisiones informadas en pasos posteriores del análisis y modelado.

# Selección de variables cuantitativas para análisis univariado
data2 <- df_limpio[, c("satisfacion_laboral", "ingreso_mensual", "antiguedad_cargo")]

# Configurar gráfica 2 filas y 2 columnas
par(mfrow = c(2, 2))

# Histograma para satisfacción laboral
hist(data2$satisfacion_laboral,
     main = "Histograma de Satisfacción Laboral",
     xlab = "Nivel de satisfacción laboral",
     ylab = "Frecuencia",
     col = "lightblue", border = "white")

# Histograma para ingreso mensual
hist(data2$ingreso_mensual,
     main = "Histograma de Ingreso Mensual",
     xlab = "Ingreso mensual",
     ylab = "Frecuencia",
     col = "lightgreen", border = "white")

# Histograma para antigüedad en el cargo
hist(data2$antiguedad_cargo,
     main = "Histograma de Antigüedad en Cargo",
     xlab = "Años en el cargo",
     ylab = "Frecuencia",
     col = "lightcoral", border = "white")

# Resetear layout gráfico
par(mfrow = c(1, 1))

ANÁLISIS UNIVARIADO DE VARIABLES CATEGÓRICAS

En esta sección se analizan una por una las variables categóricas seleccionadas para entender cómo se distribuyen sus diferentes categorías o grupos dentro del conjunto de datos. Se muestra la frecuencia absoluta y el porcentaje de cada categoría, además de gráficos de barras que visualizan estas proporciones.

Este análisis permite identificar cuáles son las categorías más comunes, detectar posibles desequilibrios o rarezas en los datos, y es útil para comprender mejor el contexto y comportamiento de cada variable antes de explorar relaciones con otras variables o construir modelos.

# Variables categóricas seleccionadas para análisis univariado
vars_cat_sel <- c("horas_extra", "viaje_de_negocios", "estado_civil")

# Análisis univariado para variables categóricas
for (v in vars_cat_sel) {
  cat("\n=============================\n")
  cat("Variable:", v, "\n")
  
  # Tabla de frecuencias y porcentaje
  tab <- as.data.frame(table(df[[v]], useNA = "ifany"))
  names(tab) <- c("categoria", "frecuencia")
  tab$porcentaje <- round(tab$frecuencia / sum(tab$frecuencia) * 100, 2)
  
  print(tab)
  
  # Gráfico de barras con proporciones
  print(
    ggplot(tab, aes(x = reorder(categoria, frecuencia), y = frecuencia)) +
      geom_col(fill = "steelblue") +
      coord_flip() +
      labs(title = paste("Distribución de", v),
           x = v, y = "Frecuencia") +
      theme_minimal()
  )
}

=============================
Variable: horas_extra 
  categoria frecuencia porcentaje
1        No       1054       71.7
2        Si        416       28.3


=============================
Variable: viaje_de_negocios 
       categoria frecuencia porcentaje
1 Frecuentemente        277      18.84
2       No_Viaja        150      10.20
3      Raramente       1043      70.95


=============================
Variable: estado_civil 
   categoria frecuencia porcentaje
1     Casado        673      45.78
2 Divorciado        327      22.24
3    Soltero        470      31.97

ANÁLISIS DESCRIPTIVO BIVARIADO

ANÁLISIS BIVARIADO: VARIABLES CATEGÓRICAS vs ROTACIÓN

En esta sección estamos comparando cada variable categórica con la rotación de los empleados. Para cada variable:

  • Creamos una tabla con conteos y porcentajes, mostrando cuántos empleados rotaron o no según cada categoría.
  • Aplicamos un test estadístico (Chi-cuadrado) para ver si hay relación significativa entre la variable y la rotación.
  • Generamos un gráfico de barras apiladas, donde podemos visualizar fácilmente qué proporción de cada categoría rotó.
## **ANÁLISIS BIVARIADO: VARIABLES CATEGÓRICAS vs ROTACIÓN**
# Variables categóricas seleccionadas
vars_cat_sel <- c("horas_extra", "viaje_de_negocios", "estado_civil")

for (v in vars_cat_sel) {
  cat("\n=============================\n")
  cat("Variable:", v, "\n")
  
  # Tabla de contingencia
  tab <- table(df_limpio[[v]], df_limpio$rotacion)
  print(tab)
  
  # Porcentajes por fila
  prop_fila <- round(prop.table(tab, 1) * 100, 2)
  print(prop_fila)
  
  # Test Chi-cuadrado para asociación
  print(chisq.test(tab))
  
  # Gráfico de proporciones
  print(
    ggplot(df_limpio, aes(x = .data[[v]], fill = rotacion)) +
      geom_bar(position = "fill") +
      scale_y_continuous(labels = function(x) paste0(x * 100, "%")) +
      labs(title = paste("Rotación según", v),
           x = v, y = "Proporción") +
      theme_minimal()
  )
}

=============================
Variable: horas_extra 
    
      No  Si
  No 944 110
  Si 289 127
    
        No    Si
  No 89.56 10.44
  Si 69.47 30.53

    Pearson's Chi-squared test with Yates' continuity correction

data:  tab
X-squared = 87.564, df = 1, p-value < 2.2e-16


=============================
Variable: viaje_de_negocios 
                
                  No  Si
  Frecuentemente 208  69
  No_Viaja       138  12
  Raramente      887 156
                
                    No    Si
  Frecuentemente 75.09 24.91
  No_Viaja       92.00  8.00
  Raramente      85.04 14.96

    Pearson's Chi-squared test

data:  tab
X-squared = 24.182, df = 2, p-value = 5.609e-06


=============================
Variable: estado_civil 
            
              No  Si
  Casado     589  84
  Divorciado 294  33
  Soltero    350 120
            
                No    Si
  Casado     87.52 12.48
  Divorciado 89.91 10.09
  Soltero    74.47 25.53

    Pearson's Chi-squared test

data:  tab
X-squared = 46.164, df = 2, p-value = 9.456e-11

ANÁLISIS BIVARIADO: VARIABLES CUANTITATIVAS vs ROTACIÓN

En esta sección estamos comparando las variables numéricas con la rotación de los empleados. Para cada variable:

  • Calculamos resúmenes estadísticos como promedio, mediana y desviación estándar, separados por quienes rotaron y quienes no.
  • Creamos boxplots para visualizar la distribución de los valores según la rotación, lo que nos ayuda a ver diferencias y posibles patrones.
## **ANÁLISIS BIVARIADO: VARIABLES CUANTITATIVAS vs ROTACIÓN**
vars_num_sel <- c("satisfacion_laboral", "ingreso_mensual", "antiguedad_cargo")

for (v in vars_num_sel) {
  cat("\n=============================\n")
  cat("Variable:", v, "\n")
  
  # Resumen estadístico por grupo de rotación
  resumen <- df_limpio |>
    group_by(rotacion) |>
    summarise(
      n = n(),
      media = mean(.data[[v]], na.rm = TRUE),
      mediana = median(.data[[v]], na.rm = TRUE),
      sd = sd(.data[[v]], na.rm = TRUE)
    )
  
  print(resumen)
  
  # Boxplot para comparar distribución según rotación
  print(
    ggplot(df_limpio, aes(x = rotacion, y = .data[[v]])) +
      geom_boxplot(fill = "#69b3a2", alpha = 0.7) +
      labs(title = paste(v, "según Rotación"),
           x = "Rotación", y = v) +
      theme_minimal()
  )
}

=============================
Variable: satisfacion_laboral 
# A tibble: 2 × 5
  rotacion     n media mediana    sd
  <fct>    <int> <dbl>   <dbl> <dbl>
1 No        1233  2.78       3  1.09
2 Si         237  2.47       3  1.12


=============================
Variable: ingreso_mensual 
# A tibble: 2 × 5
  rotacion     n media mediana    sd
  <fct>    <int> <dbl>   <dbl> <dbl>
1 No        1233 6833.    5204 4818.
2 Si         237 4787.    3202 3640.


=============================
Variable: antiguedad_cargo 
# A tibble: 2 × 5
  rotacion     n media mediana    sd
  <fct>    <int> <dbl>   <dbl> <dbl>
1 No        1233  4.48       3  3.65
2 Si         237  2.90       2  3.17

SIGNO DEL COEFICIENTE EN ANÁLISIS BIVARIADO

En esta sección:

  • Para cada variable seleccionada, se ajusta un modelo de regresión logística simple con la rotación como variable de respuesta.
  • Se extraen los coeficientes (beta), error estándar, valor z y p_value.
  • Se calcula la odds ratio, que indica cómo cambia la probabilidad de rotación al variar la variable explicativa.
  • Esto ayuda a identificar la dirección y fuerza de la relación entre cada variable y la rotación, antes de hacer un modelo multivariado.
## **SIGNO DEL COEFICIENTE EN ANÁLISIS BIVARIADO**
resultado_uni <- function(var, data) {
  formula_uni <- as.formula(paste("rotacion_bin ~", var))
  modelo <- glm(formula_uni, data = data, family = binomial)
  
  coefs <- summary(modelo)$coefficients
  
  salida <- data.frame(
    variable = var,
    termino = rownames(coefs),
    beta = coefs[, 1],
    error_std = coefs[, 2],
    z = coefs[, 3],
    p_value = coefs[, 4],
    odds_ratio = exp(coefs[, 1])
  )
  
  rownames(salida) <- NULL
  salida
}

variables_seleccionadas <- c("horas_extra", "viaje_de_negocios", "estado_civil",
                             "satisfacion_laboral", "ingreso_mensual", "antiguedad_cargo")

# Usar dataset limpio
resultados_bivariados <- do.call(rbind, lapply(variables_seleccionadas, resultado_uni, data = df_limpio))

resultados_bivariados

DISTRIBUCIÓN DE VARIABLES CATEGÓRICAS

En esta sección se realiza un análisis univariado de las variables categóricas seleccionadas para el estudio. Se construyen tablas de frecuencias y porcentajes para cada categoría, lo que permite ver cómo se distribuyen los empleados según sus características (por ejemplo, si hacen horas extra, su estado civil o la frecuencia de viajes de negocios).

Además, se generan gráficos de barras para cada variable, mostrando de manera visual la cantidad de empleados en cada categoría. Esto ayuda a identificar rápidamente categorías predominantes o poco frecuentes, y sirve como referencia para entender cómo estas variables podrían relacionarse con la rotación de empleados.

vars_cat <- c("rotacion", "horas_extra", "viaje_de_negocios", "estado_civil")

for (v in vars_cat) {
  cat("\n============================\n")
  cat("Variable:", v, "\n")
  
  tabla <- as.data.frame(table(df_limpio[[v]]))
  colnames(tabla) <- c("categoria", "frecuencia")
  tabla$porcentaje <- round(100 * tabla$frecuencia / sum(tabla$frecuencia), 2)
  
  print(tabla)
  
  print(
    ggplot(tabla, aes(x = reorder(categoria, frecuencia), y = frecuencia)) +
      geom_col() +
      coord_flip() +
      labs(
        title = paste("Distribución de", v),
        x = "Categoría",
        y = "Frecuencia"
      )
  )
}

============================
Variable: rotacion 
  categoria frecuencia porcentaje
1        No       1233      83.88
2        Si        237      16.12


============================
Variable: horas_extra 
  categoria frecuencia porcentaje
1        No       1054       71.7
2        Si        416       28.3


============================
Variable: viaje_de_negocios 
       categoria frecuencia porcentaje
1 Frecuentemente        277      18.84
2       No_Viaja        150      10.20
3      Raramente       1043      70.95


============================
Variable: estado_civil 
   categoria frecuencia porcentaje
1     Casado        673      45.78
2 Divorciado        327      22.24
3    Soltero        470      31.97

MEDIDAS DESCRIPTIVAS PARA VARIABLES CUANTITATIVAS

En esta sección se analizan las variables numéricas seleccionadas para obtener un panorama general de sus valores. Se calculan medidas estadísticas como:

  • Media: valor promedio de la variable.
  • Mediana: valor que divide a los datos en dos partes iguales.
  • Desviación estándar: cuánto varían los datos respecto a la media.
  • Mínimo y máximo: valores más pequeño y más grande registrados.
vars_num <- c("satisfacion_laboral", "ingreso_mensual", "antiguedad_cargo")

resumen_num <- data.frame(
  variable = vars_num,
  media = sapply(df_limpio[vars_num], mean, na.rm = TRUE),
  mediana = sapply(df_limpio[vars_num], median, na.rm = TRUE),
  desviacion = sapply(df_limpio[vars_num], sd, na.rm = TRUE),
  minimo = sapply(df_limpio[vars_num], min, na.rm = TRUE),
  maximo = sapply(df_limpio[vars_num], max, na.rm = TRUE)
)

resumen_num %>%
  kable(caption = "Resumen descriptivo de variables cuantitativas") %>%
  kable_styling(full_width = FALSE)
Resumen descriptivo de variables cuantitativas
variable media mediana desviacion minimo maximo
satisfacion_laboral satisfacion_laboral 2.728571 3 1.102846 1 4
ingreso_mensual ingreso_mensual 6502.931293 4919 4707.956783 1009 19999
antiguedad_cargo antiguedad_cargo 4.229252 3 3.623137 0 18

HISTOGRAMAS DE VARIABLES CUANTITATIVAS

En esta sección se utilizan gráficos para explorar las variables numéricas seleccionadas de manera más visual:

  • Histogramas: muestran cómo se distribuyen los valores de cada variable. Permiten identificar patrones como concentraciones de datos, asimetrías o posibles valores extremos.
  • Boxplots: resumen la distribución mostrando la mediana, los cuartiles y los valores atípicos (outliers). Ayudan a identificar rápidamente si hay datos extremos que podrían afectar los análisis posteriores.
for (v in vars_num) {
  print(
    ggplot(df_limpio, aes(x = .data[[v]])) +
      geom_histogram(bins = 30) +
      labs(
        title = paste("Histograma de", v),
        x = v,
        y = "Frecuencia"
      )
  )
}

#COEFICIENTE DE VARIABLES SELECCIONADAS CON REGRESIÓN LOGÍSTICA SIMPLE Este paso es muy importante porque la actividad pide interpretar el signo del coeficiente. En esta sección se realiza un análisis bivariado usando regresión logística para cada variable seleccionada respecto a la variable objetivo rotacion_bin (0 = No, 1 = Sí).

El objetivo principal es interpretar el signo del coeficiente (beta) de cada variable:

  • Signo positivo (+): indica que un aumento en esa variable se asocia con una mayor probabilidad de rotación.
  • Signo negativo (-): indica que un aumento en esa variable se asocia con una menor probabilidad de rotación.

Además, se calcula el odds ratio, que transforma el coeficiente logarítmico en una medida más intuitiva de riesgo o probabilidad relativa. Esto permite entender cómo cada característica individual afecta la rotación de empleados antes de construir modelos más complejos.

resultado_uni <- function(var, data) {
  formula_uni <- as.formula(paste("rotacion_bin ~", var))
  modelo <- glm(formula_uni, data = data, family = binomial)
  
  salida <- tidy(modelo) %>%
    mutate(odds_ratio = exp(estimate),
           variable = var)
  
  return(salida)
}

variables_seleccionadas <- c(
  "horas_extra", "viaje_de_negocios", "estado_civil",
  "satisfacion_laboral", "ingreso_mensual", "antiguedad_cargo"
)

resultados_bivariados <- do.call(
  rbind,
  lapply(variables_seleccionadas, resultado_uni, data = df_limpio)
)

resultados_bivariados

ESTIMACIÓN DEL MODELO LOGÍSTICO

En esta sección se construye un modelo de regresión logística multivariado para predecir la probabilidad de rotación (rotacion_bin). Aquí se incluyen todas las variables seleccionadas simultáneamente: horas_extra, viaje_de_negocios, estado_civil, satisfacion_laboral, ingreso_mensual y antiguedad_cargo.

El objetivo es evaluar el efecto conjunto de estas variables sobre la rotación, controlando por la influencia de las demás. Los coeficientes resultantes indican cómo cambia la probabilidad de rotación cuando una variable aumenta, manteniendo las demás constantes.

Con este paso podemos identificar qué factores tienen mayor impacto en la decisión de cambiar de cargo, y así interpretar los resultados de manera más completa que en los análisis bivariados.

#ESTIMACIÓN DEL MODELO LOGÍSTICO
#Ajuste del modelo
modelo_logit <- glm(
  rotacion_bin ~ horas_extra + viaje_de_negocios + estado_civil +
    satisfacion_laboral + ingreso_mensual + antiguedad_cargo,
  data = df_limpio,
  family = binomial(link = "logit")
)

summary(modelo_logit)

Call:
glm(formula = rotacion_bin ~ horas_extra + viaje_de_negocios + 
    estado_civil + satisfacion_laboral + ingreso_mensual + antiguedad_cargo, 
    family = binomial(link = "logit"), data = df_limpio)

Coefficients:
                             Estimate Std. Error z value Pr(>|z|)    
(Intercept)                -5.952e-02  2.994e-01  -0.199 0.842409    
horas_extraSi               1.480e+00  1.597e-01   9.269  < 2e-16 ***
viaje_de_negociosNo_Viaja  -1.311e+00  3.561e-01  -3.681 0.000232 ***
viaje_de_negociosRaramente -6.932e-01  1.819e-01  -3.811 0.000139 ***
estado_civilDivorciado     -3.472e-01  2.322e-01  -1.495 0.134789    
estado_civilSoltero         8.615e-01  1.716e-01   5.021 5.13e-07 ***
satisfacion_laboral        -3.342e-01  7.015e-02  -4.765 1.89e-06 ***
ingreso_mensual            -1.004e-04  2.316e-05  -4.335 1.46e-05 ***
antiguedad_cargo           -1.081e-01  2.730e-02  -3.959 7.52e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 1298.6  on 1469  degrees of freedom
Residual deviance: 1067.9  on 1461  degrees of freedom
AIC: 1085.9

Number of Fisher Scoring iterations: 5

INTERPRETACIÓN DE COEFICIENTES Y REVISIÓN DE MULTICOLINEALIDAD

En esta sección se hace un resumen más interpretable del modelo logístico: Se calculan los odds ratio (probabilidades relativas) de cada variable, junto con sus intervalos de confianza. Esto permite entender cuánto aumenta o disminuye la probabilidad de rotación por cada unidad de cambio en la variable, manteniendo constantes las demás.

Se revisa la multicolinealidad con el VIF (Variance Inflation Factor) para detectar si alguna variable está demasiado correlacionada con otra. Valores altos de VIF podrían indicar que una variable no aporta información nueva y podría dificultar la interpretación de los coeficientes.

#TABLA CON ODDS RATIO E INTERVALOS DE CONFIANZA
tabla_or <- broom::tidy(modelo_logit, conf.int = TRUE) %>%
  mutate(
    odds_ratio = exp(estimate),
    or_inf = exp(conf.low),
    or_sup = exp(conf.high)
  )

tabla_or %>%
  kable(caption = "Coeficientes del modelo logístico y odds ratio") %>%
  kable_styling(full_width = FALSE)
Coeficientes del modelo logístico y odds ratio
term estimate std.error statistic p.value conf.low conf.high odds_ratio or_inf or_sup
(Intercept) -0.0595223 0.2993890 -0.1988127 0.8424093 -0.6487736 0.5262167 0.9422145 0.5226864 1.6925169
horas_extraSi 1.4799685 0.1596644 9.2692444 0.0000000 1.1687880 1.7952787 4.3928075 3.2180901 6.0211523
viaje_de_negociosNo_Viaja -1.3110579 0.3561480 -3.6812166 0.0002321 -2.0506181 -0.6448662 0.2695348 0.1286554 0.5247327
viaje_de_negociosRaramente -0.6932427 0.1819272 -3.8105492 0.0001387 -1.0478430 -0.3337424 0.4999523 0.3506934 0.7162383
estado_civilDivorciado -0.3472411 0.2321937 -1.4954805 0.1347891 -0.8134210 0.0991286 0.7066350 0.4433388 1.1042083
estado_civilSoltero 0.8614850 0.1715634 5.0213786 0.0000005 0.5270361 1.2003035 2.3666726 1.6939044 3.3211246
satisfacion_laboral -0.3342400 0.0701452 -4.7649720 0.0000019 -0.4726067 -0.1973650 0.7158819 0.6233752 0.8208909
ingreso_mensual -0.0001004 0.0000232 -4.3352176 0.0000146 -0.0001477 -0.0000567 0.9998996 0.9998523 0.9999433
antiguedad_cargo -0.1080763 0.0272985 -3.9590583 0.0000752 -0.1627137 -0.0555668 0.8975591 0.8498345 0.9459489
#REVISIÓN BÁSICA DE MULTICOLINEALIDAD
car::vif(modelo_logit)
                        GVIF Df GVIF^(1/(2*Df))
horas_extra         1.036616  1        1.018143
viaje_de_negocios   1.013535  2        1.003367
estado_civil        1.026403  2        1.006536
satisfacion_laboral 1.024792  1        1.012320
ingreso_mensual     1.100009  1        1.048813
antiguedad_cargo    1.095149  1        1.046494

PREPARACIÓN DE DATOS PARA EVALUACIÓN DEL MODELO

En esta etapa se divide el conjunto de datos en entrenamiento y prueba para evaluar la capacidad predictiva del modelo:

  • Se toma un 70% de los datos para entrenar el modelo (train) y un 30% para probarlo (test).
  • Esto asegura que podamos validar cómo se comporta el modelo con datos nuevos, que no ha visto antes, lo cual es fundamental para estimar su desempeño real.
set.seed(123)

indice_train <- createDataPartition(df_limpio$rotacion_bin, p = 0.7, list = FALSE)

train <- df_limpio[indice_train, ]
test  <- df_limpio[-indice_train, ]

REVISIÓN DEL BALANCE DE LA VARIABLE RESPUESTA

En esta sección revisamos cómo se distribuyen los empleados que cambiaron de puesto frente a los que no lo hicieron. Esto es importante porque si la mayoría de los datos pertenece a una sola categoría, los modelos podrían aprender más sobre esa categoría y menos sobre la otra, afectando su capacidad de predicción.

Se construyó una tabla con la frecuencia y el porcentaje de empleados en cada grupo (“No” rotación y “Sí” rotación) y un gráfico de barras para visualizar fácilmente la distribución. Esto permite ver si ambas categorías están equilibradas o si hay un desbalance que debemos considerar al entrenar modelos predictivos.

## **REVISIÓN DEL BALANCE DE LA VARIABLE RESPUESTA**
tabla_rotacion <- as.data.frame(table(df_limpio$rotacion))
colnames(tabla_rotacion) <- c("categoria", "frecuencia")
tabla_rotacion$porcentaje <- round(100 * tabla_rotacion$frecuencia / sum(tabla_rotacion$frecuencia), 2)

tabla_rotacion %>%
  kable(caption = "Distribución de la variable rotación") %>%
  kable_styling(full_width = FALSE)
Distribución de la variable rotación
categoria frecuencia porcentaje
No 1233 83.88
Si 237 16.12
ggplot(tabla_rotacion, aes(x = categoria, y = frecuencia, fill = categoria)) +
  geom_col() +
  labs(title = "Balance de la variable rotación",
       x = "Rotación", y = "Frecuencia") +
  theme_minimal()

ENTRENAMIENTO DEL MODELO LOGÍSTICO

En este paso se ajusta el modelo logístico usando solo los datos de entrenamiento (train).

  • La variable que queremos predecir es rotacion_bin (0 = No, 1 = Sí).
  • Las variables explicativas son las seleccionadas previamente: horas_extra, viaje_de_negocios, estado_civil, satisfacion_laboral, ingreso_mensual y antiguedad_cargo.
  • Se utiliza la función glm con familia binomial, que es adecuada para modelos de clasificación binaria.
modelo_train <- glm(
  rotacion_bin ~ horas_extra + viaje_de_negocios + estado_civil +
    satisfacion_laboral + ingreso_mensual + antiguedad_cargo,
  data = train,
  family = binomial(link = "logit")
)

PREDICCIÓN DE PROBABILIDADES EN DATOS DE PRUEBA

Aquí usamos el modelo entrenado (modelo_train) para predecir la probabilidad de que cada empleado tenga rotación en el conjunto de prueba (test).

  • La función predict() calcula la probabilidad de que rotacion_bin sea 1 (Sí).
  • El argumento type = “response” devuelve directamente valores entre 0 y 1, fáciles de interpretar como probabilidades.
  • Esto nos permite luego evaluar qué tan bien el modelo clasifica correctamente a los empleados y comparar con los valores reales.
prob_test <- predict(modelo_train, newdata = test, type = "response")

head(prob_test)
         1          2          3          4          5          6 
0.61473898 0.52949950 0.04620339 0.56473888 0.03381974 0.32315143 

MATRIZ DE CONFUSIÓN DEL MODELO BASE

En esta sección se evalúa el desempeño del modelo utilizando una matriz de confusión, que permite comparar lo que el modelo predice frente a lo que realmente ocurrió.

Primero, se define un punto de corte de 0.50, lo que significa que:

  • Si la probabilidad es mayor o igual a 0.50 → el modelo predice “Sí” (hay rotación).
  • Si es menor → predice “No” (no hay rotación).

Luego, se construye la matriz de confusión, donde se observan cuatro casos posibles:

  • Verdaderos positivos: el modelo acierta cuando predice rotación.
  • Verdaderos negativos: el modelo acierta cuando predice que no hay rotación.
  • Falsos positivos: el modelo dice que hay rotación, pero no la hay.
  • Falsos negativos: el modelo no detecta una rotación que sí ocurre.

Además, se calculan métricas importantes como la precisión, la sensibilidad y la exactitud, que ayudan a entender qué tan bien está funcionando el modelo.

## **MATRIZ DE CONFUSIÓN DEL MODELO BASE**
# Clasificación usando punto de corte 0.50
pred_test <- ifelse(prob_test >= 0.50, "Si", "No")
pred_test <- factor(pred_test, levels = c("No", "Si"))

# Matriz de confusión
matriz_confusion_base <- table(Real = test$rotacion, Predicho = pred_test)
matriz_confusion_base
    Predicho
Real  No  Si
  No 357   9
  Si  59  16
# Métricas de evaluación
conf_base <- confusionMatrix(pred_test, test$rotacion, positive = "Si")
conf_base
Confusion Matrix and Statistics

          Reference
Prediction  No  Si
        No 357  59
        Si   9  16
                                          
               Accuracy : 0.8458          
                 95% CI : (0.8087, 0.8782)
    No Information Rate : 0.8299          
    P-Value [Acc > NIR] : 0.2063          
                                          
                  Kappa : 0.2568          
                                          
 Mcnemar's Test P-Value : 2.814e-09       
                                          
            Sensitivity : 0.21333         
            Specificity : 0.97541         
         Pos Pred Value : 0.64000         
         Neg Pred Value : 0.85817         
             Prevalence : 0.17007         
         Detection Rate : 0.03628         
   Detection Prevalence : 0.05669         
      Balanced Accuracy : 0.59437         
                                          
       'Positive' Class : Si              
                                          

EVALUACIÓN DEL MODELO: CURVA ROC Y AUC

En esta sección evaluamos el desempeño del modelo usando Curva ROC y AUC:

  • La Curva ROC (Receiver Operating Characteristic) muestra la capacidad del modelo para distinguir entre empleados que rotan (rotacion_bin = 1) y los que no (rotacion_bin = 0).
  • El eje X representa la tasa de falsos positivos y el eje Y la tasa de verdaderos positivos.
  • El AUC (Área bajo la curva) resume la efectividad del modelo en un solo número:
    • Un valor cercano a 1 indica que el modelo clasifica muy bien.
    • Un valor cercano a 0.5 indica que el modelo no tiene capacidad predictiva mejor que el azar.

El gráfico resultante permite ver visualmente qué tan bien nuestro modelo predice la rotación de empleados.

roc_modelo <- roc(test$rotacion_bin, prob_test)
auc_modelo <- auc(roc_modelo)

auc_modelo
Area under the curve: 0.7515
plot(roc_modelo, main = paste("Curva ROC - AUC =", round(auc_modelo, 4)))
abline(a = 0, b = 1, lty = 2, col = "gray")

BALANCEO DE CATEGORÍAS

Además de la curva ROC y el AUC, se construyó una matriz de confusión para evaluar el desempeño del modelo en términos de clasificaciones correctas e incorrectas. Esta matriz permite identificar cuántos empleados fueron correctamente clasificados como casos de rotación o no rotación, y calcular métricas como exactitud, sensibilidad, especificidad y precisión.

## **BALANCEO DE CATEGORÍAS EN LA MUESTRA DE ENTRENAMIENTO**
set.seed(123)

train_balanceado <- ovun.sample(
  rotacion ~ horas_extra + viaje_de_negocios + estado_civil +
    satisfacion_laboral + ingreso_mensual + antiguedad_cargo,
  data = train,
  method = "over"
)$data

# Ver distribución después del balanceo
tabla_balanceo <- as.data.frame(table(train_balanceado$rotacion))
colnames(tabla_balanceo) <- c("categoria", "frecuencia")
tabla_balanceo$porcentaje <- round(100 * tabla_balanceo$frecuencia / sum(tabla_balanceo$frecuencia), 2)

tabla_balanceo %>%
  kable(caption = "Distribución de la variable rotación después del balanceo") %>%
  kable_styling(full_width = FALSE)
Distribución de la variable rotación después del balanceo
categoria frecuencia porcentaje
No 867 50.38
Si 854 49.62

ENTRENAMIENTO DEL MODELO BALANCEADO

Debido a que la variable respuesta presentaba desbalance entre sus categorías, se aplicó una técnica de sobremuestreo sobre la muestra de entrenamiento. Este procedimiento busca que el modelo aprenda de forma más equilibrada los patrones asociados tanto a la rotación como a la no rotación, mejorando así su capacidad predictiva sobre la clase menos frecuente.

## **ENTRENAMIENTO DEL MODELO LOGÍSTICO BALANCEADO**
modelo_balanceado <- glm(
  rotacion ~ horas_extra + viaje_de_negocios + estado_civil +
    satisfacion_laboral + ingreso_mensual + antiguedad_cargo,
  data = train_balanceado,
  family = binomial(link = "logit")
)

summary(modelo_balanceado)

Call:
glm(formula = rotacion ~ horas_extra + viaje_de_negocios + estado_civil + 
    satisfacion_laboral + ingreso_mensual + antiguedad_cargo, 
    family = binomial(link = "logit"), data = train_balanceado)

Coefficients:
                             Estimate Std. Error z value Pr(>|z|)    
(Intercept)                 1.510e+00  2.193e-01   6.887 5.68e-12 ***
horas_extraSi               1.412e+00  1.167e-01  12.098  < 2e-16 ***
viaje_de_negociosNo_Viaja  -1.335e+00  2.395e-01  -5.574 2.50e-08 ***
viaje_de_negociosRaramente -7.186e-01  1.343e-01  -5.350 8.78e-08 ***
estado_civilDivorciado     -5.179e-01  1.588e-01  -3.260  0.00111 ** 
estado_civilSoltero         7.624e-01  1.246e-01   6.119 9.41e-10 ***
satisfacion_laboral        -3.038e-01  5.062e-02  -6.001 1.96e-09 ***
ingreso_mensual            -1.032e-04  1.583e-05  -6.516 7.20e-11 ***
antiguedad_cargo           -7.846e-02  1.865e-02  -4.207 2.59e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 2385.7  on 1720  degrees of freedom
Residual deviance: 1906.2  on 1712  degrees of freedom
AIC: 1924.2

Number of Fisher Scoring iterations: 4

EVALUACIÓN DEL MODELO BALANCEADO

En esta sección se evalúa el desempeño del modelo ajustado con datos balanceados, con el objetivo de verificar si mejora la capacidad de predicción, especialmente para los empleados que sí rotan. Primero, el modelo calcula la probabilidad de rotación para cada empleado del conjunto de prueba. Luego, se utiliza un punto de corte de 0.50 para clasificar:

  • Probabilidad ≥ 0.50 → “Sí” (rotación)
  • Probabilidad < 0.50 → “No” (no rotación)

Con estas predicciones se construye una matriz de confusión, que permite comparar lo que el modelo predice frente a la realidad. Esto ayuda a identificar aciertos y errores del modelo. Además, se calculan métricas como la exactitud, la sensibilidad (qué tan bien detecta a quienes sí rotan) y la especificidad (qué tan bien identifica a quienes no rotan).

## **PREDICCIÓN Y MATRIZ DE CONFUSIÓN DEL MODELO BALANCEADO**
prob_test_balanceado <- predict(modelo_balanceado, newdata = test, type = "response")

pred_test_balanceado <- ifelse(prob_test_balanceado >= 0.50, "Si", "No")
pred_test_balanceado <- factor(pred_test_balanceado, levels = c("No", "Si"))

matriz_confusion_balanceado <- table(Real = test$rotacion, Predicho = pred_test_balanceado)
matriz_confusion_balanceado
    Predicho
Real  No  Si
  No 254 112
  Si  23  52
conf_balanceado <- confusionMatrix(pred_test_balanceado, test$rotacion, positive = "Si")
conf_balanceado
Confusion Matrix and Statistics

          Reference
Prediction  No  Si
        No 254  23
        Si 112  52
                                          
               Accuracy : 0.6939          
                 95% CI : (0.6485, 0.7366)
    No Information Rate : 0.8299          
    P-Value [Acc > NIR] : 1               
                                          
                  Kappa : 0.2632          
                                          
 Mcnemar's Test P-Value : 3.624e-14       
                                          
            Sensitivity : 0.6933          
            Specificity : 0.6940          
         Pos Pred Value : 0.3171          
         Neg Pred Value : 0.9170          
             Prevalence : 0.1701          
         Detection Rate : 0.1179          
   Detection Prevalence : 0.3719          
      Balanced Accuracy : 0.6937          
                                          
       'Positive' Class : Si              
                                          

EVALUACIÓN DEL MODELO BALANCEADO: CURVA ROC Y AUC

En esta sección se analiza qué tan bien funciona el modelo balanceado para distinguir entre empleados que rotan y los que no.

  • La curva ROC es un gráfico que muestra qué tan bien el modelo separa ambos grupos.
  • La línea diagonal representa un modelo sin capacidad predictiva (como adivinar al azar).
  • Mientras más se aleje la curva de esa línea y se acerque a la esquina superior izquierda, mejor es el modelo.

Además, se calcula el AUC (Área Bajo la Curva), que resume el desempeño del modelo en un solo número:

  • Un valor cercano a 1 indica un modelo muy bueno.
  • Un valor cercano a 0.5 indica que el modelo no es mejor que el azar.
## **CURVA ROC Y AUC DEL MODELO BALANCEADO**
roc_balanceado <- roc(test$rotacion, prob_test_balanceado, levels = c("No", "Si"), direction = "<")
auc_balanceado <- auc(roc_balanceado)

auc_balanceado
Area under the curve: 0.7611
plot(roc_balanceado, main = paste("Curva ROC modelo balanceado - AUC =", round(auc_balanceado, 4)))
abline(a = 0, b = 1, lty = 2, col = "gray")

COMPARACIÓN ENTRE MODELO BASE Y MODELO BALANCEADO

En esta sección se comparan los resultados del modelo base y el modelo balanceado para identificar cuál tiene mejor desempeño al predecir la rotación de empleados.

Se analizan varias métricas importantes:

  • AUC: mide la capacidad general del modelo para diferenciar entre empleados que rotan y los que no.
  • Accuracy (exactitud): porcentaje total de aciertos del modelo.
  • Sensibilidad: qué tan bien el modelo identifica a los empleados que sí rotan.
  • Especificidad: qué tan bien identifica a los empleados que no rotan.
  • Precisión: qué tan confiables son las predicciones de rotación.

Esta comparación permite entender si el modelo balanceado realmente mejora el desempeño, especialmente en la detección de empleados con mayor riesgo de rotación. En muchos casos, aunque la exactitud general no cambie mucho, el modelo balanceado puede ser mejor identificando los casos más importantes, lo que lo hace más útil para la toma de decisiones.

## **COMPARACIÓN ENTRE MODELO BASE Y MODELO BALANCEADO**
comparacion_modelos <- data.frame(
  Modelo = c("Base", "Balanceado"),
  AUC = c(as.numeric(auc_modelo), as.numeric(auc_balanceado)),
  Accuracy = c(conf_base$overall["Accuracy"], conf_balanceado$overall["Accuracy"]),
  Sensibilidad = c(conf_base$byClass["Sensitivity"], conf_balanceado$byClass["Sensitivity"]),
  Especificidad = c(conf_base$byClass["Specificity"], conf_balanceado$byClass["Specificity"]),
  Precision = c(conf_base$byClass["Pos Pred Value"], conf_balanceado$byClass["Pos Pred Value"])
)

comparacion_modelos %>%
  kable(caption = "Comparación entre modelo base y modelo balanceado") %>%
  kable_styling(full_width = FALSE)
Comparación entre modelo base y modelo balanceado
Modelo AUC Accuracy Sensibilidad Especificidad Precision
Base 0.7515118 0.8458050 0.2133333 0.9754098 0.6400000
Balanceado 0.7610929 0.6938776 0.6933333 0.6939891 0.3170732

Cómo interpretar esta comparación - Si el modelo balanceado mejora la sensibilidad, puede ser más útil si lo importante es detectar empleados en riesgo. - Si el modelo base conserva mejor el AUC y además tiene buen equilibrio, se podría dejar ese. - En rotación, muchas veces interesa bastante la sensibilidad, porque la empresa quiere identificar empleados que sí podrían cambiar de cargo.

PREDICCIÓN DE ROTACIÓN PARA UN EMPLEADO HIPOTÉTICO

En esta sección se realiza una predicción de la probabilidad de rotación para un empleado con características específicas:

  • Se define un empleado hipotético con valores concretos en las variables seleccionadas (horas_extra, viaje_de_negocios, estado_civil, satisfacion_laboral, ingreso_mensual, antiguedad_cargo).
  • Se utiliza el modelo logístico entrenado para estimar la probabilidad de que este empleado experimente rotación.
  • El resultado (prob_rotacion) indica la probabilidad de rotación de este individuo, expresada como un valor entre 0 y 1, lo que permite evaluar el riesgo relativo según las características proporcionadas.
#Crear un empleado hipotético
nuevo_empleado <- data.frame(
  horas_extra = factor("Si", levels = levels(df_limpio$horas_extra)),
  viaje_de_negocios = factor("Frecuentemente", levels = levels(df_limpio$viaje_de_negocios)),
  estado_civil = factor("Soltero", levels = levels(df_limpio$estado_civil)),
  satisfacion_laboral = 2,
  ingreso_mensual = 3000,
  antiguedad_cargo = 1
)

prob_rotacion <- predict(modelo_train, newdata = nuevo_empleado, type = "response")
prob_rotacion
        1 
0.7921705 

DECISIÓN BASADA EN EL PUNTO DE CORTE

En esta etapa se aplica un umbral de decisión para interpretar la probabilidad de rotación calculada por el modelo:

  • Se define un punto de corte (corte = 0.30), que representa el nivel de probabilidad a partir del cual se considera que un empleado tiene riesgo significativo de rotación.
  • Si la probabilidad predicha para el empleado hipotético es mayor o igual al corte, se clasifica como “Intervenir al empleado”, sugiriendo medidas preventivas.
  • Si la probabilidad es menor al corte, se clasifica como “No requiere intervención inmediata”, indicando un riesgo bajo.
#Definir un punto de corte
corte <- 0.30

decision <- ifelse(prob_rotacion >= corte,
                   "Empleado con alto riesgo de cambiar de cargo",
                   "No requiere intervención inmediata el empleado")

decision
                                             1 
"Empleado con alto riesgo de cambiar de cargo" 

CONCLUSIÓN

Del análisis realizado, se puede ver que la rotación de empleados en la empresa no es al azar, sino que depende de varias características de los trabajadores y de su trabajo. Por ejemplo, encontramos que:

  • Horas extra, viajes frecuentes por trabajo y ser soltero están asociados con mayor probabilidad de cambiar de puesto.
  • Tener mayor satisfacción en el trabajo, un mejor ingreso y más antigüedad en el cargo está asociado con menor probabilidad de rotación.

En otras palabras, la rotación se relaciona principalmente con tres cosas:

  • Carga laboral: Mucho trabajo o viajes frecuentes pueden hacer que el empleado quiera cambiar.
  • Bienestar del empleado: Sentirse contento en el trabajo y tener buen salario ayuda a que permanezca.
  • Tiempo en el cargo: Los empleados nuevos o con poco tiempo en su puesto tienden a cambiar más.

El modelo que construimos para predecir la rotación tiene una capacidad aceptable para diferenciar quiénes tienen más riesgo de cambiar de puesto. Esto significa que puede servir como una herramienta para ayudar a la empresa a tomar decisiones sobre su personal. Con base en los resultados, se recomiendan acciones como:

  • Revisar las horas extra: Distribuir mejor el trabajo para que nadie se sobrecargue.
  • Evaluar los viajes de negocios: Reducir la frecuencia o dar apoyo a quienes viajan mucho.
  • Mejorar la satisfacción laboral: Reconocer el buen desempeño, ofrecer oportunidades de crecimiento y escuchar las opiniones de los empleados.
  • Revisar incentivos económicos: Ajustes salariales o beneficios adicionales pueden ayudar a que las personas se queden.
  • Acompañar a los empleados nuevos: Darles inducción, seguimiento y apoyo para que se adapten y se comprometan con su puesto.

En resumen, la empresa puede reducir la rotación si cuida el equilibrio del trabajo, mejora la satisfacción y el salario, y acompaña a quienes están empezando. Esto ayuda a mantener un ambiente laboral más estable y agradable para todos.