ACTIVIDAD

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.

data("rotacion")
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, …
#Almacenar el dataset original en otro.
data_rotacion<-rotacion
write.xlsx(data_rotacion, file = "D://data_rotacion.xlsx")

Variables de la base de datos

colnames(rotacion)
##  [1] "Rotación"                    "Edad"                       
##  [3] "Viaje de Negocios"           "Departamento"               
##  [5] "Distancia_Casa"              "Educación"                  
##  [7] "Campo_Educación"             "Satisfacción_Ambiental"     
##  [9] "Genero"                      "Cargo"                      
## [11] "Satisfación_Laboral"         "Estado_Civil"               
## [13] "Ingreso_Mensual"             "Trabajos_Anteriores"        
## [15] "Horas_Extra"                 "Porcentaje_aumento_salarial"
## [17] "Rendimiento_Laboral"         "Años_Experiencia"           
## [19] "Capacitaciones"              "Equilibrio_Trabajo_Vida"    
## [21] "Antigüedad"                  "Antigüedad_Cargo"           
## [23] "Años_ultima_promoción"       "Años_acargo_con_mismo_jefe"

3 primeros Registros de la base de datos

head(data_rotacion,3)
## # A tibble: 3 × 24
##   Rotación  Edad `Viaje de Negocios` Departamento Distancia_Casa Educación
##   <chr>    <dbl> <chr>               <chr>                 <dbl>     <dbl>
## 1 Si          41 Raramente           Ventas                    1         2
## 2 No          49 Frecuentemente      IyD                       8         1
## 3 Si          37 Raramente           IyD                       2         2
## # ℹ 18 more variables: Campo_Educación <chr>, Satisfacción_Ambiental <dbl>,
## #   Genero <chr>, Cargo <chr>, Satisfación_Laboral <dbl>, Estado_Civil <chr>,
## #   Ingreso_Mensual <dbl>, Trabajos_Anteriores <dbl>, Horas_Extra <chr>,
## #   Porcentaje_aumento_salarial <dbl>, Rendimiento_Laboral <dbl>,
## #   Años_Experiencia <dbl>, Capacitaciones <dbl>,
## #   Equilibrio_Trabajo_Vida <dbl>, Antigüedad <dbl>, Antigüedad_Cargo <dbl>,
## #   Años_ultima_promoción <dbl>, Años_acargo_con_mismo_jefe <dbl>

número total de registros

nrow(data_rotacion)
## [1] 1470

EXPLORACION DE LOS DATOS

Se inicia con la exploracion del Dataset, asi como con el resumen estadistico

Estructura del dataset

# 
kable(head(data_rotacion), format = "markdown")
Rotación Edad Viaje de Negocios Departamento Distancia_Casa Educación Campo_Educación Satisfacción_Ambiental Genero Cargo Satisfación_Laboral Estado_Civil Ingreso_Mensual Trabajos_Anteriores Horas_Extra Porcentaje_aumento_salarial Rendimiento_Laboral Años_Experiencia Capacitaciones Equilibrio_Trabajo_Vida Antigüedad Antigüedad_Cargo Años_ultima_promoción Años_acargo_con_mismo_jefe
Si 41 Raramente Ventas 1 2 Ciencias 2 F Ejecutivo_Ventas 4 Soltero 5993 8 Si 11 3 8 0 1 6 4 0 5
No 49 Frecuentemente IyD 8 1 Ciencias 3 M Investigador_Cientifico 2 Casado 5130 1 No 23 4 10 3 3 10 7 1 7
Si 37 Raramente IyD 2 2 Otra 4 M Tecnico_Laboratorio 3 Soltero 2090 6 Si 15 3 7 3 3 0 0 0 0
No 33 Frecuentemente IyD 3 4 Ciencias 4 F Investigador_Cientifico 3 Casado 2909 1 Si 11 3 8 3 3 8 7 3 0
No 27 Raramente IyD 2 1 Salud 1 M Tecnico_Laboratorio 2 Casado 3468 9 No 12 3 6 3 3 2 2 2 2
No 32 Frecuentemente IyD 2 2 Ciencias 4 M Tecnico_Laboratorio 4 Soltero 3068 0 No 13 3 8 2 2 7 7 3 6

Estadísticas descriptivas

summary(data_rotacion)
##    Rotación              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     Educación     Campo_Educación    Satisfacción_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           Satisfación_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 Años_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   Antigüedad     Antigüedad_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  
##  Años_ultima_promoción Años_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

Se realiza la verificación de valores nulos por cada una de las variables que conforman la data.

# Verificar valores nulos
sum(is.na(data_rotacion))
## [1] 0
# Verificar la cantidad de valores nulos por columna
colSums(is.na(data_rotacion))
##                    Rotación                        Edad 
##                           0                           0 
##           Viaje de Negocios                Departamento 
##                           0                           0 
##              Distancia_Casa                   Educación 
##                           0                           0 
##             Campo_Educación      Satisfacción_Ambiental 
##                           0                           0 
##                      Genero                       Cargo 
##                           0                           0 
##         Satisfación_Laboral                Estado_Civil 
##                           0                           0 
##             Ingreso_Mensual         Trabajos_Anteriores 
##                           0                           0 
##                 Horas_Extra Porcentaje_aumento_salarial 
##                           0                           0 
##         Rendimiento_Laboral            Años_Experiencia 
##                           0                           0 
##              Capacitaciones     Equilibrio_Trabajo_Vida 
##                           0                           0 
##                  Antigüedad            Antigüedad_Cargo 
##                           0                           0 
##       Años_ultima_promoción  Años_acargo_con_mismo_jefe 
##                           0                           0
grafico_faltantes <-md.pattern(data_rotacion, rotate.names = TRUE)
##  /\     /\
## {  `---'  }
## {  O   O  }
## ==>  V <==  No need for mice. This data set is completely observed.
##  \  \|/  /
##   `-----'

# Cambiar nombres a algunas columnas
names(data_rotacion)[names(data_rotacion) == "Rotación"] <- "Rotacion"
names(data_rotacion)[names(data_rotacion) == "Viaje de Negocios"] <- "Viaje_de_Negocios"
names(data_rotacion)[names(data_rotacion) == "Educación"] <- "Educacion"
names(data_rotacion)[names(data_rotacion) == "Campo_Educación"] <- "Campo_Educacion"
names(data_rotacion)[names(data_rotacion) == "Satisfacción_Ambiental"] <- "Satisfaccion_Ambiental"
names(data_rotacion)[names(data_rotacion) == "Satisfación_Laboral"] <- "Satisfacion_Laboral"

ANALISIS EXPLORATORIO DE GRAFICOS

# Función para calcular los porcentajes
add_percentage <- function(df, var) {
  df %>%
    group_by({{ var }}) %>%
    mutate(count = n(),
           percent = count / sum(count) * 100)
}
# Gráfico con etiquetas de valores y porcentajes para la variable categórica Departamento
grafico1 <- data_rotacion %>%
  add_percentage(Departamento) %>%
  ggplot(aes(x = Departamento, fill = Rotacion)) +
  geom_bar(stat = "count", position = "dodge") +  
  geom_text(stat = "count", aes(label = paste0(..count.., " (", round(..count.. / sum(..count..) * 100, 1), "%)")), 
            position = position_dodge(width = 1), vjust = -0.3) +  
  labs(title = "Departamento vs Rotación", x = "Departamento", y = "Cantidad") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))
 
  grafico1

# Gráfico con etiquetas de valores y porcentajes para la variable categórica "Genero"
grafico2 <- data_rotacion %>%
  add_percentage(Genero) %>%
  ggplot(aes(x = Genero, fill = Rotacion)) +
  geom_bar(position = "dodge") +
  geom_text(stat = "count", aes(label = paste0(..count.., " (", round(..count.. / sum(..count..) * 100, 1), "%)")), 
            position = position_dodge(width = 0.8), vjust = -0.3) +
  labs(title = "Género vs Rotación", x = "Género", y = "Cantidad")

grafico2

# Gráfico con etiquetas de valores y porcentajes para la variable categórica "Estado_Civil"
grafico3 <- data_rotacion %>%
  add_percentage(Estado_Civil) %>%
  ggplot(aes(x = Estado_Civil, fill = Rotacion)) +
  geom_bar(position = "dodge") +
  geom_text(stat = "count", aes(label = paste0(..count.., " (", round(..count.. / sum(..count..) * 100, 1), "%)")), 
            position = position_dodge(width = 0.8), vjust = -0.3) +
  labs(title = "Estado Civil vs Rotación", x = "Estado Civil", y = "Cantidad")

grafico3

# Gráfico con etiquetas de valores y porcentajes para la variable categórica "Campo_Educación"
grafico4 <- data_rotacion %>%
  add_percentage(Campo_Educacion) %>%
  ggplot(aes(x = Campo_Educacion, fill = Rotacion)) +
  geom_bar(position = "dodge") +
  geom_text(stat = "count", aes(label = paste0(..count.., " (", round(..count.. / sum(..count..) * 100, 1), "%)")), 
            position = position_dodge(width = 0.8), vjust = -0.3) +
  labs(title = "Campo de Educación vs Rotación", x = "Campo de Educación", y = "Cantidad")

grafico4

# Gráfico con etiquetas de valores y porcentajes para la variable categórica "Educacion"
grafico5 <- data_rotacion %>%
  add_percentage(Educacion) %>%
  ggplot(aes(x = Educacion, fill = Rotacion)) +
  geom_bar(position = "dodge") +
  geom_text(stat = "count", aes(label = paste0(..count.., " (", round(..count.. / sum(..count..) * 100, 1), "%)")), 
            position = position_dodge(width = 0.8), vjust = -0.3) +
  labs(title = "Educacion vs Rotación", x = "Educación", y = "Cantidad")
 
grafico5

# Gráfico con etiquetas de valores y porcentajes para la variable categórica "Viaje_de_Negocios"
grafico6 <- data_rotacion %>%
  add_percentage(Viaje_de_Negocios) %>%
  ggplot(aes(x = Viaje_de_Negocios, fill = Rotacion)) +
  geom_bar(position = "dodge") +
  geom_text(stat = "count", aes(label = paste0(..count.., " (", round(..count.. / sum(..count..) * 100, 1), "%)")), 
            position = position_dodge(width = 0.8), vjust = -0.3) +
  labs(title = "Viaje de Negocios vs Rotación", x = "Viaje de Negocios", y = "Cantidad")

grafico6

# Gráfico de variables cuantitativas (Edad, Ingreso_Mensual, Años_Experiencia, etc.)
grafico7 <- ggplot(data_rotacion, aes(x = Edad, fill = Rotacion)) +
  geom_histogram(binwidth = 1, position = "dodge") +
  geom_text(stat = "bin", aes(label = ..count..), position = position_dodge(width = 1), vjust = -0.3) +
  labs(title = "Edad vs Rotación", x = "Edad", y = "Frecuencia")

grafico7
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

grafico8 <- ggplot(data_rotacion, aes(x = Ingreso_Mensual, fill = Rotacion)) +
  geom_histogram(binwidth = 500, position = "dodge") +
  geom_text(stat = "bin", aes(label = ..count..), position = position_dodge(width = 1), vjust = -0.3) +
  labs(title = "Ingreso Mensual vs Rotación", x = "Ingreso Mensual", y = "Frecuencia")

grafico8
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

grafico9 <- ggplot(data_rotacion, aes(x = Años_Experiencia, fill = Rotacion)) +
  geom_histogram(binwidth = 1, position = "dodge") +
  geom_text(stat = "bin", aes(label = ..count..), position = position_dodge(width = 1), vjust = -0.3) +
  labs(title = "Años de Experiencia vs Rotación", x = "Años de Experiencia", y = "Frecuencia")

grafico9
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

grafico10 <- ggplot(data_rotacion, aes(x = Distancia_Casa, fill = Rotacion)) +
  geom_histogram(binwidth = 1, position = "dodge") +
  geom_text(stat = "bin", aes(label = ..count..), position = position_dodge(width = 1), vjust = -0.3) +
  labs(title = "Distancia Casa vs Rotación", x = "Distancia Casa", y = "Frecuencia")

grafico10
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

grafico11 <- ggplot(data_rotacion, aes(x = Satisfacion_Laboral, fill = Rotacion)) +
  geom_histogram(binwidth = 1, position = "dodge") +
    geom_text(stat = "count", aes(label = paste0(..count.., " (", round(..count.. / sum(..count..) * 100, 1), "%)")), 
            position = position_dodge(width = 0.8), vjust = -0.3) +
  labs(title = "Satisfacción Laboral vs Rotación", x = "Satisfacción Laboral", y = "Frecuencia")

grafico11

grafico12 <- ggplot(data_rotacion, aes(x = Satisfaccion_Ambiental, fill = Rotacion)) +
  geom_histogram(binwidth = 1, position = "dodge") +
   geom_text(stat = "count", aes(label = paste0(..count.., " (", round(..count.. / sum(..count..) * 100, 1), "%)")), 
            position = position_dodge(width = 0.8), vjust = -0.3) +
  labs(title = "Satisfacción Ambiental vs Rotación", x = "Satisfacción Ambiental", y = "Frecuencia")

grafico12

# Gráfico con etiquetas de valores y porcentajes para la variable categórica "Viaje_de_Negocios"
grafico13 <- data_rotacion %>%
  add_percentage(Horas_Extra) %>%
  ggplot(aes(x = Horas_Extra, fill = Rotacion)) +
  geom_bar(position = "dodge") +
  geom_text(stat = "count", aes(label = paste0(..count.., " (", round(..count.. / sum(..count..) * 100, 1), "%)")), 
            position = position_dodge(width = 0.8), vjust = -0.3) +
  labs(title = "Hora Extra vs Rotación", x = "Hora Extra", y = "Cantidad")

grafico13

1. Selección de variables

Seleccione 3 variables categóricas (distintas de rotación) y 3 variables cuantitativas, que se consideren estén relacionadas con la rotación.

Variables Cuantitativas:

Edad: La edad puede influir en la decisión de rotación, ya que los empleados más jóvenes podrían estar más interesados en cambiar de puesto para obtener más experiencia, mientras que los empleados mayores pueden estar buscando estabilidad y menos cambios.

Hipótesis: Se espera que los empleados más jóvenes tengan una mayor rotación, mientras que los empleados mayores puedan tener una menor tasa de rotación debido a su búsqueda de estabilidad.

Ingreso_Mensual: El salario puede influir significativamente en la rotación. Los empleados con salarios bajos pueden estar más dispuestos a cambiar de puesto en busca de mejores oportunidades salariales, mientras que los empleados con un salario alto podrían estar más motivados a quedarse.

Hipótesis: Los empleados con ingresos mensuales más bajos tienen una mayor probabilidad de rotación, mientras que los empleados con salarios más altos tienden a permanecer en la empresa.

Antigüedad: La cantidad de tiempo que un empleado lleva en la empresa o en su cargo también puede influir en la rotación. Los empleados con mayor antigüedad pueden estar más estables en sus posiciones, o pueden estar buscando cambios si sienten que ya han alcanzado su potencial en ese cargo.

Hipótesis: La rotación podría ser menor entre los empleados con mayor antigüedad en el cargo debido a su estabilidad, pero también podría aumentar si sienten que sus perspectivas de crecimiento son limitadas.

Variables Categóricas:

Horas_Extra: El número de horas extra trabajadas puede ser un factor importante en la rotación, ya que los empleados que realizan más horas extra pueden sentirse sobrecargados, lo que puede llevar a un agotamiento o insatisfacción laboral.

Hipótesis: Los empleados que realizan muchas horas extra tienen una mayor probabilidad de rotación debido al agotamiento y al impacto en su vida personal.

Estado_Civil: El estado civil puede influir en la rotación ya que las responsabilidades familiares pueden afectar las decisiones laborales. Un empleado casado o con hijos podría estar más interesado en estabilidad, mientras que los solteros podrían estar más dispuestos a asumir riesgos, como cambiar de puesto.

Hipótesis: Los empleados casados o con responsabilidades familiares tienen menos probabilidades de rotar, ya que buscan estabilidad, mientras que los solteros podrían estar más dispuestos a cambiar de cargo.

Viaje_de_Negocios: La frecuencia con la que un empleado viaja por negocios puede afectar su rotación. Los viajes frecuentes pueden generar agotamiento o insatisfacción con el equilibrio trabajo-vida, lo que lleva a una mayor rotación.

Hipótesis: Los empleados que viajan frecuentemente por negocios tienen una mayor probabilidad de rotación debido al impacto de los viajes en su vida personal.

2. Análisis univariado

Análisis univariado (caracterización) de la información contenida en la base de datos rotacion.

# 
data_rotacion2 <- data_rotacion[, c("Rotacion", "Edad", "Ingreso_Mensual", "Antigüedad", "Horas_Extra", "Estado_Civil","Viaje_de_Negocios")]
par(mfrow = c(1, 3))
hist(data_rotacion2$Edad, main = "Histograma Edad", xlab = "Edad", col = "#8EEEFF")
hist(data_rotacion2$Ingreso_Mensual, main = "Histograma Ingreso Mensual", xlab = "Ingreso mensual", col ="#43CD80")
hist(data_rotacion2$Antigüedad, main = "Histograma Antigüedad", xlab = "Antigüedad", col ="#EE3B3B")

Edad: La muestra de trabajadores tiene edades entre 18 y 60 años, con un promedio de 36,9 años y una mediana de 26 años. La distribución no es normal y presenta un sesgo a la derecha, indicando que la mayoría de los empleados son jóvenes, pero hay algunos casos de mayor edad que elevan el promedio.

Ingreso mensual: Los ingresos varían entre 1.009 y 19.999, con una media de 6.503 y una mediana de 4.919. La distribución no es normal, lo que sugiere que hay una mayoría con ingresos más bajos y unos pocos con ingresos muy altos, lo que eleva la media.

Antigüedad: La antigüedad en la empresa va de 0 a 40 años, con un promedio y mediana de 5 años. El 25% de los empleados tienen menos de 3 años de antigüedad, mientras que otro 25% tiene entre 9 y 40 años. Esto muestra una distribución desigual, con una mayoría de empleados recientes y algunos casos de largo tiempo en la empresa, sugiriendo valores extremos superiores.

par(mfrow = c(1, 3))

# Gráfico Horas_Extra 
horas_extra <- table(data_rotacion2$Horas_Extra)
horas_extra_porc <- prop.table(horas_extra) * 100
bar_heights <- barplot(horas_extra, main = "Gráfico barras Horas_Extra", xlab = "Horas_Extra", col = "#FFD700", cex.names = 0.8, ylim = c(0, max(horas_extra) * 1.2))
text_x <- bar_heights
text_y <- horas_extra + (max(horas_extra) * 0.05)
text_y[text_y > (max(horas_extra) * 1.2)] <- (max(horas_extra) * 1.2) * 1.05  # Ajuste superior
text(x = text_x, y = text_y, labels = paste0(round(horas_extra_porc, 1), "%"), pos = 3, cex = 0.8, col = "black")
text(x = text_x, y = horas_extra + (max(horas_extra) * 0.1), labels = horas_extra, pos = 3, cex = 0.8, col = "blue")  


# Gráfico Estado_Civil 
estado_civil <- table(data_rotacion2$Estado_Civil)
estado_civil_porc <- prop.table(estado_civil) * 100
bar_heights <- barplot(estado_civil, main = "Gráfico barras Estado_Civil", xlab = "Estado_Civil", col = "#2E8B57", cex.names = 0.8, ylim = c(0, max(estado_civil) * 1.2)) 
text_x <- bar_heights
text_y <- estado_civil + (max(estado_civil) * 0.05)
text_y[text_y > (max(estado_civil) * 1.2)] <- (max(estado_civil) * 1.2) * 1.05 
text(x = text_x, y = text_y, labels = paste0(round(estado_civil_porc, 1), "%"), pos = 3, cex = 0.8, col = "black")
text(x = text_x, y = estado_civil + (max(estado_civil) * 0.1), labels = estado_civil, pos = 3, cex = 0.8, col = "blue") 


# Gráfico Viaje de Negocios 
viaje_de_negocios <- table(data_rotacion2$Viaje_de_Negocios)
viaje_de_negocios_porc <- prop.table(viaje_de_negocios) * 100
bar_heights <- barplot(viaje_de_negocios, main = "Gráfico barras Viaje_de_Negocios", xlab = "Viaje_de_Negocios", col = "#4876FF", cex.names = 0.6, ylim = c(0, max(viaje_de_negocios) * 1.2))
text_x <- bar_heights
text_y <- viaje_de_negocios + (max(viaje_de_negocios) * 0.05)
text_y[text_y > (max(viaje_de_negocios) * 1.2)] <- (max(viaje_de_negocios) * 1.2) * 1.05  # Ajuste superior
text(x = text_x, y = text_y, labels = paste0(round(viaje_de_negocios_porc, 1), "%"), pos = 3, cex = 0.8, col = "black")
text(x = text_x, y = viaje_de_negocios + (max(viaje_de_negocios) * 0.1), labels = viaje_de_negocios, pos = 3, cex = 0.8, col = "blue") 

El 71.7% de los empleados (n=1,054) no realiza horas extra, mientras que el 28.3% restante (n=416) sí trabaja horas adicionales.

El 45.8% de los empleados (n=373) está casado, el 32% (n=470) es soltero y el 22.2% restante (n=327) está divorciado.

El 71% de los empleados (n=1,043) viaja raramente por motivos laborales, lo que indica que la mayoría tiene una baja frecuencia de desplazamientos. Un 18.8% (n=277) realiza viajes frecuentes, lo que representa una porción significativa con movilidad regular. Finalmente, el 10.2% restante (n=150) no viaja en absoluto.

3. Analisis Bivariado

Realizamos el análisis bivariado para verificar las relaciones entre las variables seleccionadas y la variable de rotación.

Variable Cuantitativa Edad - Rotacion

# Codificar la variable Rotación (Si = 1, No = 0)
data_rotacion2$Rotacion <- ifelse(data_rotacion2$Rotacion == "Si", 1, 0)

data_rotacion2$Rotacion_label <- factor(data_rotacion2$Rotacion, levels = c(0, 1), labels = c("No", "Sí"))

ggplot(data_rotacion2, aes(x = Rotacion_label, y = Edad, fill = Rotacion_label)) +
  geom_boxplot() +
  labs(x = "Rotación", y = "Edad") +
  scale_fill_manual(values = c("#2E8B57", "#8EE5EE"))

la grafica sugiere que la rotación se concentra en edades más jóvenes, mientras que a partir de los 30 años disminuye. Sin embargo, la presencia de casos atípicos en edades superiores a 50 años indica que hay ciertos factores específicos que pueden influir en la decisión de salida en este grupo.

grafico15 <- ggplot(data_rotacion2, aes(x = Edad, fill = Rotacion_label)) +
  geom_histogram(binwidth = 1, position = "dodge") +
  geom_text(stat = "bin", aes(label = ..count..), position = position_dodge(width = 1), vjust = -0.3) +
  labs(title = "Edad vs Rotación", x = "Edad", y = "Frecuencia") +
  scale_fill_manual(values = c("No" = "#2E8B57", "Sí" = "#8EE5EE"))  

# Print the plot
print(grafico15)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Variable Cuantitativa Ingreso Mensual - Rotacion

data_rotacion2$Rotacion_label <- factor(data_rotacion2$Rotacion, levels = c(0, 1), labels = c("No", "Sí"))

ggplot(data_rotacion2, aes(x = Rotacion_label, y = Ingreso_Mensual, fill = Rotacion_label)) +
  geom_boxplot() +
  labs(x = "Rotación", y = "Ingreso_Mensual") +
  scale_fill_manual(values = c("#2E8B57", "#8EE5EE"))

Al analizar la gráfica, se observa que los empleados que han rotado tienen un ingreso mensual inferior en comparación con aquellos que han permanecido en la empresa.

Variable Cuantitativa Antiguedad Vs Rotacion

data_rotacion2$Rotacion_label <- factor(data_rotacion2$Rotacion, levels = c(0, 1), labels = c("No", "Sí"))

ggplot(data_rotacion2, aes(x = Rotacion_label, y = Antigüedad, fill = Rotacion_label)) +
  geom_boxplot() +
  labs(x = "Rotación", y = "Antigüedad") +
  scale_fill_manual(values = c("#2E8B57", "#8EE5EE"))

En la grafica se observan diferencias en la antigüedad entre los empleados que rotan y los que no. En particular, la rotación es más frecuente entre aquellos con menor antigüedad.

# Análisis de correlación para variables cuantitativas
cor(data_rotacion2[, c("Edad", "Ingreso_Mensual", "Antigüedad")], use="complete.obs")
##                      Edad Ingreso_Mensual Antigüedad
## Edad            1.0000000       0.4977532  0.3112408
## Ingreso_Mensual 0.4977532       1.0000000  0.5142848
## Antigüedad      0.3112408       0.5142848  1.0000000

Edad e Ingreso Mensual: 0.4978 (correlación moderada positiva). A medida que aumenta la edad, los ingresos también tienden a ser más altos, lo que puede reducir la rotación, ya que los empleados con mayores ingresos son menos propensos a cambiar de empleo.

Edad y Antigüedad: 0.3112 (correlación moderada positiva). Los empleados mayores tienden a tener más antigüedad en la empresa, lo que también puede reducir la rotación, ya que aquellos con más años en la organización son más estables.

Ingreso Mensual y Antigüedad: 0.5143 (correlación moderada fuerte positiva). Los empleados con más antigüedad tienden a recibir mayores ingresos, lo que también podría contribuir a la menor rotación en este grupo.

Variable Cuantitativa Horas Extra Vs Rotacion

# Calcular los porcentajes fuera del dataset
count_data <- data_rotacion2 %>%
  group_by(Rotacion, Horas_Extra) %>%
  summarise(count = n()) %>%
  ungroup()
## `summarise()` has grouped output by 'Rotacion'. You can override using the
## `.groups` argument.
total_count <- sum(count_data$count)

count_data <- count_data %>%
  mutate(percentage = count / total_count * 100)

# Crear el gráfico con etiquetas de porcentaje
ggplot(count_data, aes(x = factor(Rotacion), fill = Horas_Extra, y = count)) + 
  geom_bar(position = "dodge", stat = "identity") +
  geom_text(aes(label = paste0(round(percentage, 1), "%")), 
            position = position_dodge(width = 0.8), 
            vjust = -0.5, size = 4) +
  labs(title = "Rotación y Horas Extra",
       x = "Rotación",
       y = "Frecuencia",
       fill = "Horas Extra") +
  scale_fill_manual(values = c("#2E8B57", "#8EE5EE", "#FF3030")) +
  scale_x_discrete(labels = c("0" = "NO", "1" = "SI")) +
  theme_minimal()

El 64.2% de los empleados no realizan horas extra y no rotan, lo que indica estabilidad y satisfacción en su trabajo.

El 19.7% de los empleados realizan horas extra y rotan, lo que sugiere que el esfuerzo adicional no siempre asegura la retención, probablemente por insatisfacción o falta de oportunidades de crecimiento.

El 7.5% de los empleados realizan horas extra y no rotan, lo que refleja un alto nivel de compromiso y estabilidad en la empresa.

El 8.6% de los empleados realizan horas extra y rotan, lo que indica que algunos empleados comprometidos aún deciden irse, posiblemente por factores como salario o falta de reconocimiento.

# Gráfico con etiqueta de porcentaje sin cambiar el dataset original
ggplot(data = data_rotacion2, aes(x = factor(Rotacion), fill = Estado_Civil)) + 
  geom_bar(position = "dodge") +
  labs(title = "Rotación y Estado Civil",
       x = "Rotación",
       y = "Frecuencia",
       fill = "Estado_Civil") +
  scale_fill_manual(values = c("#2E8B57", "#8EE5EE", "#FF3030")) +
  scale_x_discrete(labels = c("0" = "NO", "1" = "SI")) +
  geom_text(stat = "count", aes(label = scales::percent(..count../sum(..count..))),
            position = position_dodge(width = 0.8), vjust = -0.5)

Empleados casados: Tienen la mayor proporción de empleados que no rotan (40.0%) y la menor tasa de rotación (5.7%), lo que sugiere estabilidad laboral.

Empleados solteros: Son los más propensos a rotar (8.2%) y tienen una proporción menor entre los que no rotan (23.8%).

Empleados divorciados: Son el grupo menos propenso a rotar (2.2%) y representan una proporción intermedia entre los que no rotan (20.0%).

En general Los empleados casados muestran mayor estabilidad, los solteros son los más propensos a rotar, y los divorciados tienen una rotación baja, indicando estabilidad laboral.

# Gráfico con etiquetas de porcentaje
ggplot(data = data_rotacion2, aes(x = factor(Rotacion), fill = Viaje_de_Negocios)) + 
  geom_bar(position = "dodge") +
  labs(title = "Rotación y Viaje de Negocios",
       x = "Rotación",
       y = "Frecuencia",
       fill = "Viaje_de_Negocios") +
  scale_fill_manual(values = c("#2E8B57", "#8EE5EE", "#FF3030")) +
  scale_x_discrete(labels = c("0" = "NO", "1" = "SI")) +
  geom_text(stat = "count", aes(label = scales::percent(..count../sum(..count..))),
            position = position_dodge(width = 0.8), vjust = -0.5)

Al observar la gráfica, se puede concluir que la frecuencia de los viajes de negocios no parece ser un factor determinante en la rotación de empleados. En ambos grupos (empleados que rotan y empleados que no rotan), la mayoría de los empleados viajan raramente. La proporción de empleados que viajan frecuentemente es ligeramente mayor entre los que no rotan (14.1%) en comparación con los que rotan (4.7%), mientras que un porcentaje muy pequeño de ambos grupos no viaja.

El comportamiento observado en la gráfica muestra que, aunque hay ciertas diferencias en las proporciones, el patrón de viaje es similar en ambos grupos. Esto sugiere que la rotación de empleados no está directamente influenciada por la frecuencia de los viajes de negocios, y podría haber otros factores más relevantes que afectan la decisión de rotación.

4. Estimacion del Modelo

Realiza la estimación de un modelo de regresión logístico en el cual la variable respuesta es rotacion (y=1 es si rotación, y=0 es no rotación) y las covariables las 6 seleccionadas en el punto 1. Interprete los coeficientes del modelo y la significancia de los parámetros.

# Recodificar de variables a variables dummy
estado_civil_dummies <- model.matrix(~ Estado_Civil - 1, data = data_rotacion2)
colnames(estado_civil_dummies) <- paste("Estado_Civil", colnames(estado_civil_dummies), sep = "_")
data_rotacion2 <- cbind(data_rotacion2, estado_civil_dummies)


data_rotacion2$Horas_Extra <- ifelse(data_rotacion2$Horas_Extra == "Si", 1, 0)


Viaje_dummies <- model.matrix(~ Viaje_de_Negocios - 1, data = data_rotacion2)
colnames(Viaje_dummies) <- paste("Viaje_de_Negocios", colnames(Viaje_dummies), sep = "_")
data_rotacion2<- cbind(data_rotacion2, Viaje_dummies)


data_rotacion2 <- data_rotacion2[, !(names(data_rotacion2) %in% c("Estado_Civil", "Viaje_de_Negocios","Rotacion_label"))]

write.xlsx(data_rotacion2, file = "D://data_rotacion4.xlsx")
## Warning in file.create(to[okay]): cannot create file 'D://data_rotacion4.xlsx',
## reason 'Permission denied'
colnames(data_rotacion2)
##  [1] "Rotacion"                                         
##  [2] "Edad"                                             
##  [3] "Ingreso_Mensual"                                  
##  [4] "Antigüedad"                                       
##  [5] "Horas_Extra"                                      
##  [6] "Estado_Civil_Estado_CivilCasado"                  
##  [7] "Estado_Civil_Estado_CivilDivorciado"              
##  [8] "Estado_Civil_Estado_CivilSoltero"                 
##  [9] "Viaje_de_Negocios_Viaje_de_NegociosFrecuentemente"
## [10] "Viaje_de_Negocios_Viaje_de_NegociosNo_Viaja"      
## [11] "Viaje_de_Negocios_Viaje_de_NegociosRaramente"
# Usar createDataPartition para crear índices de entrenamiento (70%)
particion <- createDataPartition(y = data_rotacion2$Rotacion, p = 0.7, list = FALSE)  # 70% para entrenamiento

#Creacion de los conjuntos de datos de entrenamiento y prueba
train <- data_rotacion2[particion, ]  # Datos de entrenamiento
test <- data_rotacion2[-particion, ]  # Datos de prueba

# Mostrar la tabla ordenada de las primeras filas del conjunto de entrenamiento (train)
kable(head(train), caption = "Primeras filas del conjunto de entrenamiento")
Primeras filas del conjunto de entrenamiento
Rotacion Edad Ingreso_Mensual Antigüedad Horas_Extra Estado_Civil_Estado_CivilCasado Estado_Civil_Estado_CivilDivorciado Estado_Civil_Estado_CivilSoltero Viaje_de_Negocios_Viaje_de_NegociosFrecuentemente Viaje_de_Negocios_Viaje_de_NegociosNo_Viaja Viaje_de_Negocios_Viaje_de_NegociosRaramente
2 0 49 5130 10 0 1 0 0 1 0 0
3 1 37 2090 0 1 0 0 1 0 0 1
4 0 33 2909 8 1 1 0 0 1 0 0
5 0 27 3468 2 0 1 0 0 0 0 1
6 0 32 3068 7 0 0 0 1 1 0 0
7 0 59 2670 1 1 1 0 0 0 0 1
# Mostrar la tabla ordenada de las primeras filas del conjunto de prueba (test)
kable(head(test), caption = "Primeras filas del conjunto de prueba")
Primeras filas del conjunto de prueba
Rotacion Edad Ingreso_Mensual Antigüedad Horas_Extra Estado_Civil_Estado_CivilCasado Estado_Civil_Estado_CivilDivorciado Estado_Civil_Estado_CivilSoltero Viaje_de_Negocios_Viaje_de_NegociosFrecuentemente Viaje_de_Negocios_Viaje_de_NegociosNo_Viaja Viaje_de_Negocios_Viaje_de_NegociosRaramente
1 1 41 5993 6 1 0 0 1 0 0 1
8 0 30 2693 1 0 0 1 0 0 0 1
11 0 35 2426 5 0 1 0 0 0 0 1
16 0 29 9980 10 0 0 1 0 0 0 1
17 0 32 3298 6 1 0 1 0 0 0 1
20 0 38 3944 3 1 0 0 1 0 0 1
conteo_data_rotacion2 <- table(data_rotacion2$Rotacion)
conteo_train <- table(train$Rotacion)
conteo_test <- table(test$Rotacion)
all_levels <- c(0, 1)  # 0 = No, 1 = Sí

conteo_data_rotacion2 <- table(factor(data_rotacion2$Rotacion, levels = all_levels))
conteo_train <- table(factor(train$Rotacion, levels = all_levels))
conteo_test <- table(factor(test$Rotacion, levels = all_levels))

count_df <- data.frame(
  "Valor" = c("No Rotacion (0)", "Sí Rotacion (1)"),  # Etiquetas más comprensibles
  "General" = as.vector(conteo_data_rotacion2),
  "Train" = as.vector(conteo_train),
  "Test" = as.vector(conteo_test)
)

kable(count_df, caption = "Conteo de la variable 'Rotación' en Data General, Train y Test")
Conteo de la variable ‘Rotación’ en Data General, Train y Test
Valor General Train Test
No Rotacion (0) 1233 870 363
Sí Rotacion (1) 237 159 78
# Convertir 'Rotacion' a factor con niveles 0 (No) y 1 (Sí)
train$Rotacion <- factor(train$Rotacion, levels = c(0, 1), labels = c("No", "Sí"))
test$Rotacion <- factor(test$Rotacion, levels = c(0, 1), labels = c("No", "Sí"))

trainControl <- trainControl(method = "cv", number = 15) 

** Entrenamiento del modelo**

   # Entrenar el modelo de regresión logística
   modelo_log <-train(Rotacion ~ ., data = train,
                          method = "glm",
                          family = "binomial",
                          trControl = trainControl)


   print(modelo_log)
## Generalized Linear Model 
## 
## 1029 samples
##   10 predictor
##    2 classes: 'No', 'Sí' 
## 
## No pre-processing
## Resampling: Cross-Validated (15 fold) 
## Summary of sample sizes: 960, 961, 961, 961, 960, 961, ... 
## Resampling results:
## 
##   Accuracy   Kappa   
##   0.8571611  0.213791

Resultados de validación:

Accuracy (Precisión): 0.8639 (86.39%)

Esto significa que el modelo clasifica correctamente el 86.39% de las veces en los datos de validación cruzada. Es un valor bastante bueno, lo que sugiere que el modelo tiene un buen desempeño general en términos de precisión.

Kappa: 0.2089

El valor de Kappa mide el acuerdo entre las predicciones del modelo y las observaciones reales, teniendo en cuenta la posibilidad de que el acuerdo se deba al azar. Un valor de Kappa de 0.2089 es relativamente bajo, lo que indica que, aunque el modelo tiene una precisión bastante alta, la relación entre las predicciones correctas y las incorrectas podría no ser tan sólida en comparación con un modelo perfecto.

Los valores de Kappa cercanos a 1 indican un excelente acuerdo entre las predicciones y los valores reales, mientras que valores cercanos a 0 sugieren que el modelo no es mejor que un modelo aleatorio.

5. Evaluación

Evaluar el poder predictivo del modelo con base en la curva ROC y el AUC.

probabilidades <- predict(modelo_log, newdata = test, type = "prob")[,2] # Clase positiva

# Crear el objeto ROC
roc_curve <- roc(test$Rotacion, probabilidades)
## Setting levels: control = No, case = Sí
## Setting direction: controls < cases
# Graficar la curva ROC
plot(roc_curve, col = "blue", main = "Curva ROC")

# Calcular el AUC
auc_value <- auc(roc_curve)
print(paste("AUC: ", auc_value))
## [1] "AUC:  0.76735890372254"

con un AUC de 0.743, es un buen modelo , pero aún hay oportunidades de mejorar la capacidad predictiva.

6. Predicciones

Realiza una predicción la probabilidad de que un individuo (hipotético) rote y defina un corte para decidir si se debe intervenir a este empleado o no (posible estrategia para motivar al empleado).

# Crear un data frame con las características del individuo
individuo_pred <- data.frame(Edad = 20,
  Ingreso_Mensual = 400,
  Antigüedad = 1,
  Horas_Extra = 1,
  Estado_Civil_Estado_CivilCasado = 0,
  Estado_Civil_Estado_CivilDivorciado = 0,
  Estado_Civil_Estado_CivilSoltero = 1,
  Viaje_de_Negocios_Viaje_de_NegociosFrecuentemente = 0,
  Viaje_de_Negocios_Viaje_de_NegociosNo_Viaja = 0,
  Viaje_de_Negocios_Viaje_de_NegociosRaramente = 1
)

# Realizar la predicción de probabilidad
probabilidad_rotacion <- predict(modelo_log, newdata = individuo_pred, type = "prob")[, 2]  # Clase positiva (rotación)

# Mostrar la probabilidad
print(paste("La probabilidad de que este empleado rote es:", round(probabilidad_rotacion, 4)))
## [1] "La probabilidad de que este empleado rote es: 0.6942"

Para el ejemplo de prediccion se tiene valor de 0.6324, lo que significa que según el modelo de regresión logística, existe una probabilidad del 63.24% de que este empleado deje la empresa (lo que sería clasificado como una rotación “alta”). por ejemplo Si nuestro umbral de decisión para clasificar un empleado como “rotación” es 0.5 (por defecto), entonces este empleado sería clasificado como un caso de rotación.

7. Conclusiones

  1. La rotación de empleados está fuertemente influenciada por la edad. Los empleados más jóvenes tienen una mayor propensión a rotar, mientras que aquellos a partir de los 30 años muestran una tendencia a quedarse más tiempo en la empresa. Esto sugiere que las empresas deben implementar estrategias de retención específicas para los empleados más jóvenes, como planes de desarrollo profesional y oportunidades de crecimiento.

  2. Los empleados con ingresos más bajos son más propensos a rotar. Esto indica que la remuneración es un factor clave en la decisión de rotación. Las organizaciones deben considerar revisar sus estructuras salariales para asegurarse de que sean competitivas y adecuadas, especialmente para los empleados que podrían sentirse insatisfechos con su compensación.

  3. La antigüedad está inversamente relacionada con la rotación, lo que sugiere que los empleados con mayor tiempo en la empresa tienen más probabilidades de permanecer. Las empresas deben centrarse en programas de fidelización que valoren la experiencia y antigüedad de los empleados, fomentando un ambiente de estabilidad a largo plazo.

  4. Realizar horas extra no necesariamente garantiza la retención. Aunque algunos empleados que realizan horas extra permanecen en la empresa, otros deciden rotar. Esto indica que otros factores, como la insatisfacción laboral, la falta de reconocimiento o la falta de oportunidades de crecimiento, podrían estar influyendo en la rotación, incluso entre los empleados más comprometidos.

  5. Los empleados casados son los menos propensos a rotar, mientras que los solteros muestran una mayor tasa de rotación. Esto sugiere que la estabilidad personal y familiar influye en la permanencia de los empleados en la empresa. Las organizaciones podrían considerar adaptar sus políticas de retención teniendo en cuenta el estado civil de los empleados y sus necesidades específicas.

  6. A pesar de algunas diferencias en la frecuencia de los viajes de negocios, estos no parecen ser un factor determinante en la rotación de empleados. Esto sugiere que otros aspectos de la experiencia laboral, como el entorno laboral, las oportunidades de desarrollo y la compensación, son factores más influyentes en la decisión de rotación.