La rotación de empleados es un desafío estratégico para las organizaciones, ya que impacta la estabilidad del equipo y aumentan costos operativos. Con el fin de comprender los factores que influyen en la movilidad interna de los trabajadores, se ha desarrollado un modelo de regresión logística que permite estimar la probabilidad de que un empleado cambie de cargo en el próximo período.
Este análisis se basa en datos históricos de la empresa, los cuales incluyen variables clave como la edad, el ingreso mensual, la antigüedad en el cargo y otros factores relevantes. Mediante técnicas estadísticas se busca identificar los principales motivos de la rotación y generar predicciones con la que la empresa pueda actuar a tiempo para retener el talento clave para la corporación.
#Tabla 1
str(rotacion)
## tibble [1,470 × 24] (S3: tbl_df/tbl/data.frame)
## $ Rotación : 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 ...
## $ Educación : num [1:1470] 2 1 2 4 1 2 3 1 3 3 ...
## $ Campo_Educación : chr [1:1470] "Ciencias" "Ciencias" "Otra" "Ciencias" ...
## $ Satisfacción_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" ...
## $ Satisfación_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 ...
## $ Años_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 ...
## $ Antigüedad : num [1:1470] 6 10 0 8 2 7 1 1 9 7 ...
## $ Antigüedad_Cargo : num [1:1470] 4 7 0 7 2 7 0 0 7 7 ...
## $ Años_ultima_promoción : num [1:1470] 0 1 0 3 2 3 0 0 1 7 ...
## $ Años_acargo_con_mismo_jefe : num [1:1470] 5 7 0 0 2 6 0 0 8 7 ...
#Tabla 2
# Eliminar todas las filas que tengan al menos un NA
rotacion_clean <- na.omit(rotacion)
# Verificar el resultado
summary(rotacion_clean)
## 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
Categoricas:
Departamento: es posible que, dependiendo de los departamentos de la empresa, se tengan mayores niveles de estrés o ambientes que podrían incidir en la rotación de los empleados.
Horas extras: un mayor número de horas laborales podría conllevar a mayor agotamiento y el deseo de buscar un cambio.
Viajes de negocios: que el trabajo afecte la vida personal puede ser un factor para la rotación.
Cuantitativas:
# Resumen estadístico de variables cuantitativas seleccionadas
rotacion_clean %>%
select( Edad, Ingreso_Mensual, Antigüedad_Cargo) %>%
summary()
## Edad Ingreso_Mensual Antigüedad_Cargo
## Min. :18.00 Min. : 1009 Min. : 0.000
## 1st Qu.:30.00 1st Qu.: 2911 1st Qu.: 2.000
## Median :36.00 Median : 4919 Median : 3.000
## Mean :36.92 Mean : 6503 Mean : 4.229
## 3rd Qu.:43.00 3rd Qu.: 8379 3rd Qu.: 7.000
## Max. :60.00 Max. :19999 Max. :18.000
# Histogramas para visualizar la distribución
ggplot(rotacion_clean, aes(x = Edad)) +
geom_histogram(binwidth = 5, fill = "skyblue", color = "black") +
labs(title = "Distribución de la Edad - Gráfico 1", x = "Edad", y = "Frecuencia")
ggplot(rotacion_clean, aes(x = Ingreso_Mensual)) +
geom_histogram(binwidth = 1000, fill = "blue", color = "black", alpha = 0.7) +
labs(title = "Distribución del Ingreso Mensual- Gráfico 2",
x = "Ingreso mensual",
y = "Frecuencia") +
theme_minimal()
ggplot(rotacion_clean, aes(x = Antigüedad_Cargo)) +
geom_histogram(binwidth = 1, fill = "lightgreen", color = "black") +
labs(title = "Distribución de la Antigüedad en el Cargo - Gráfico 3", x = "Antigüedad en el Cargo", y = "Frecuencia")
Distribución de la Edad: Con una distribución relativamente concentrada alrededor de la mediana (36 años), se puede explorar si hay diferencias en la probabilidad de rotación entre empleados jóvenes y mayores. Por ejemplo, se podría tener como hipótesis que empleados muy jóvenes o con más experiencia (y posiblemente mayores) tienen distintas expectativas y tasas de rotación.
Distribución del Ingreso mensual: Este comportamiento podría indicar que mientras la mayoría de los empleados se sitúan en un rango de ingresos intermedios, existen casos con ingresos significativamente altos. Se podría plantear la hipótesis de que, en algunos contextos, un ingreso relativamente bajo podría estar asociado a una mayor intención de rotación, o bien que empleados con ingresos altos podrían sentir mayor presión y responsabilidad, lo que también influya en su decisión de cambiar de cargo.
Distribución de la Antigüedad en el Cargo:Una baja antigüedad en el cargo puede estar relacionada con una mayor probabilidad de rotación, ya que los empleados en etapas tempranas de su rol podrían estar buscando crecer o explorar otras oportunidades. Además, podría indicar que la organización tiene un flujo considerable de cambios internos, lo que debe ser evaluado en conjunto con otras variables.
# Convertir la variable Rotación a factor (0 = No, 1 = Si) para análisis posterior
rotacion_clean <- rotacion_clean %>%
mutate(Rotacion_bin = ifelse(Rotación == "Si", 1, 0),
Departamento = as.factor(Departamento),
Horas_Extra = as.factor(Horas_Extra),
Viaje_de_Negocios = as.factor(`Viaje de Negocios`))
# Mostrar tablas de frecuencia en la consola
cat("Tabla de Frecuencia - Rotación :\n")
## Tabla de Frecuencia - Rotación :
print(table(rotacion_clean$Rotación))
##
## No Si
## 1233 237
cat("\nTabla de Frecuencia - Departamento:\n")
##
## Tabla de Frecuencia - Departamento:
print(table(rotacion_clean$Departamento))
##
## IyD RH Ventas
## 961 63 446
cat("\nTabla de Frecuencia - Horas Extra:\n")
##
## Tabla de Frecuencia - Horas Extra:
print(table(rotacion_clean$Horas_Extra))
##
## No Si
## 1054 416
# Gráfico de frecuencia de Rotación
p1 <- ggplot(rotacion_clean, aes(x = Rotación)) +
geom_bar(fill = "purple") +
labs(title = "Frecuencia de Rotación - Gráfico 4", x = "Rotación", y = "Cuenta")
# Gráfico de frecuencia por Departamento
p2 <- ggplot(rotacion_clean, aes(x = Departamento)) +
geom_bar(fill = "orange") +
labs(title = "Frecuencia por Departamento Gráfico 5", x = "Departamento", y = "Cuenta") +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotar etiquetas si hay muchos departamentos
# Gráfico de frecuencia de Horas Extra
p3 <- ggplot(rotacion_clean, aes(x = Horas_Extra)) +
geom_bar(fill = "blue") +
labs(title = "Frecuencia de Horas Extra Gráfico 6", x = "Horas Extra", y = "Cuenta")
# Mostrar los gráficos
print(p1)
print(p2)
print(p3)
Análisis de rotación: Tenemos 1233 (83,9%) empleados en “No rotación” y
237 (16.1%) empleados en “rotación”, la mayoría de los empleados no han
rotado de cargo solo unos pocos han experimentado un cambio, esto indica
que la rotación dentro de la empresa es baja.
Análisis de departamento: La gran mayoría de los empleados se encuentra en el departamento “IyD” con 961, seguido por “Ventas” con 446 y “RH” con 63.En este caso recursos humanos tiene la menor cantidad de empleados, lo que significa menor impacto proporcional en la rotación global.Al ver las frecuencias abre puerta a visualizar las claras diferencias significativas en la tasa de rotación variando entre departamentos de la misma empresa. Al ver “IyD” con mas empleados podría significar que son puestos más técnicos lo que hace que los empleados se queden en sus puestos y no roten tanto, en ventas podría estar relacionado al cumplimiento de metas de unidades vendidas por ejemplo y en ciertos casos de no lograrlo, terminan forzando la rotación del personal.
Análisis de horas extra: Empleados que no trabajan horas extra: 1054 (71,7%) y empleados que sí trabajan horas extra: 416 empleados (28,3%), un número significativo de empleados que ejercen extra tiempo laboral puede indicar que existe una sobrecarga laboral dentro de la empresa.Por lo tanto, aquellos que trabajan más horas extras podrían estar más propensos a cambiar de cargo debido al agotamiento o un descontento con la jornada laboral.
ggplot(rotacion_clean, aes(x = "", y = Ingreso_Mensual)) +
geom_boxplot(fill = "orange") +
labs(title = "Distribución del Ingreso Mensual - Gráfico 7", y = "Ingreso Mensual")
Análisis de la distribución del Ingreso Mensual: El rango
intercuantílico es grande, lo que indica una alta variabilidad en los
ingresos, además a esto la linea horizontal dentro de la caja se
encuentra por debajo de la mitad lo que nos muestra que la mayoría de
los empleados gana menos de la mediana global, esto se debe a que dentro
de la compañía un grupo reducido de personas reciben salarios
significativamente más altos. También, existen outliers que refuerzan la
idea de los sueldos muy elevados (seguramente puestos de ejecutivos o
junta directiva)
# Tablas de contingencia y prueba de chi-cuadrado para Departamento
tabla_dep <- table(rotacion_clean$Departamento, rotacion_clean$Rotación)
print(tabla_dep)
##
## No Si
## IyD 828 133
## RH 51 12
## Ventas 354 92
chisq.test(tabla_dep)
##
## Pearson's Chi-squared test
##
## data: tabla_dep
## X-squared = 10.796, df = 2, p-value = 0.004526
# Para Horas_Extra
tabla_horas <- table(rotacion_clean$Horas_Extra, rotacion_clean$Rotación)
print(tabla_horas)
##
## No Si
## No 944 110
## Si 289 127
chisq.test(tabla_horas)
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: tabla_horas
## X-squared = 87.564, df = 1, p-value < 2.2e-16
# Para Viaje_de_Negocios
tabla_viaje <- table(rotacion_clean$Viaje_de_Negocios, rotacion_clean$Rotación)
print(tabla_viaje)
##
## No Si
## Frecuentemente 208 69
## No_Viaja 138 12
## Raramente 887 156
chisq.test(tabla_viaje)
##
## Pearson's Chi-squared test
##
## data: tabla_viaje
## X-squared = 24.182, df = 2, p-value = 5.609e-06
Análisis de resultados
Departamento y rotación: Hay una relación significativa entre el departamento y la rotación ( p < 0.05) lo que indica que el departamento de trabajo influye en la rotación de empleados. En las otras areas como ventas y recursos humanos se observan una mayor rotación mayor en comparación con IyD, este departamento presenta la menor tasa de rotación, lo que sugiere allí las condiciones podríán ser mas favorables economicamente o en términos de ambiente. Horas extras: La relación es extremadamente significativa, lo que indica que existe una fuerte asociación entre realizar horas extra y la rotación, el exceso de horas pueden generar niveles más altos de estres en los empleados y agotamiento por lo cual prefieren buscar mejores condiciones en otras áreas o nuevos trabajos ( prefieren rotar). Viaje de negocios: Con el pvalue se confirma que existe una relación muy significativa entre la frecuencia de viajes de negocios y la rotación, los empleados que viajan frecuentemente presentan una tasa de rotación más alta (aproximadamente 24.9%), lo cual es preocupante, ya que sugiere que estos viajes están afectando negativamente su bienestar, ya sea por el estrés, la fatiga o la falta de estabilidad personal.
# Boxplots comparando la variable cuantitativa según la rotación
ggplot(rotacion_clean, aes(x = Rotación, y = Edad)) +
geom_boxplot(fill = "lightblue") +
labs(title = "Edad según Rotación - Gráfico 8", x = "Rotación", y = "Edad")
ggplot(rotacion_clean, aes(x = Rotación, y = Satisfación_Laboral)) +
geom_boxplot(fill = "lightpink") +
labs(title = "Satisfacción Laboral según Rotación - Gráfico 9", x = "Rotación", y = "Satisfacción Laboral")
ggplot(rotacion_clean, aes(x = Rotación, y = Antigüedad_Cargo)) +
geom_boxplot(fill = "lightgreen") +
labs(title = "Antigüedad en el Cargo según Rotación - Gráfico 10", x = "Rotación", y = "Antigüedad en el Cargo")
# Pruebas estadísticas (por ejemplo, t-test)
t.test(Edad ~ Rotación, data = rotacion)
##
## Welch Two Sample t-test
##
## data: Edad by Rotación
## t = 5.8291, df = 316.94, p-value = 1.371e-08
## alternative hypothesis: true difference in means between group No and group Si is not equal to 0
## 95 percent confidence interval:
## 2.619728 5.289170
## sample estimates:
## mean in group No mean in group Si
## 37.56204 33.60759
t.test(Satisfación_Laboral ~ Rotación, data = rotacion)
##
## Welch Two Sample t-test
##
## data: Satisfación_Laboral by Rotación
## t = 3.9261, df = 328.59, p-value = 0.0001052
## alternative hypothesis: true difference in means between group No and group Si is not equal to 0
## 95 percent confidence interval:
## 0.1547890 0.4656797
## sample estimates:
## mean in group No mean in group Si
## 2.778589 2.468354
t.test(Antigüedad_Cargo ~ Rotación, data = rotacion)
##
## Welch Two Sample t-test
##
## data: Antigüedad_Cargo by Rotación
## t = 6.8471, df = 366.57, p-value = 3.187e-11
## alternative hypothesis: true difference in means between group No and group Si is not equal to 0
## 95 percent confidence interval:
## 1.127107 2.035355
## sample estimates:
## mean in group No mean in group Si
## 4.484185 2.902954
# Modelo de regresión logística
modelo <- glm(Rotacion_bin ~ Departamento + Horas_Extra + Viaje_de_Negocios + Edad + Ingreso_Mensual + Antigüedad_Cargo,
data = rotacion_clean, family = binomial)
# Resumen del modelo
summary(modelo)
##
## Call:
## glm(formula = Rotacion_bin ~ Departamento + Horas_Extra + Viaje_de_Negocios +
## Edad + Ingreso_Mensual + Antigüedad_Cargo, family = binomial,
## data = rotacion_clean)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 1.620e-01 3.627e-01 0.447 0.655196
## DepartamentoRH 4.364e-01 3.624e-01 1.204 0.228581
## DepartamentoVentas 6.495e-01 1.653e-01 3.929 8.54e-05 ***
## Horas_ExtraSi 1.424e+00 1.561e-01 9.127 < 2e-16 ***
## Viaje_de_NegociosNo_Viaja -1.354e+00 3.485e-01 -3.885 0.000102 ***
## Viaje_de_NegociosRaramente -6.798e-01 1.788e-01 -3.802 0.000144 ***
## Edad -3.218e-02 1.011e-02 -3.182 0.001461 **
## Ingreso_Mensual -8.188e-05 2.625e-05 -3.119 0.001812 **
## Antigüedad_Cargo -1.118e-01 2.727e-02 -4.098 4.16e-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: 1099.6 on 1461 degrees of freedom
## AIC: 1117.6
##
## Number of Fisher Scoring iterations: 5
El modelo indica que hay factores que aumentan la probabilidad de rotación: Trabajar horas extra y pertenecer al departamento de Ventas, como támbien factores que disminuyen la probabilidad de rotación: Viajar menos (o no viajar), ser mayor, tener un ingreso mensual más alto y mayor antigüedad en el cargo.
Esto permite a la empresa identificar áreas críticas para intervenir—por ejemplo, revisar la carga de horas extra o mejorar incentivos en departamentos con alta rotación—con el objetivo de retener a los empleados clave.
# Instalar y cargar el paquete pROC si no está instalado
# install.packages("pROC")
library(pROC)
## Warning: package 'pROC' was built under R version 4.4.3
## Type 'citation("pROC")' for a citation.
##
## Adjuntando el paquete: 'pROC'
## The following objects are masked from 'package:stats':
##
## cov, smooth, var
# Obtener las probabilidades predichas
rotacion_clean$prob_pred <- predict(modelo, type = "response")
# Calcular la curva ROC
roc_obj <- roc(rotacion_clean$Rotacion_bin, rotacion_clean$prob_pred)
## Setting levels: control = 0, case = 1
## Setting direction: controls < cases
plot(roc_obj, main = "Curva ROC del Modelo de Rotación - Gráfico 11")
# Calcular el AUC
auc_val <- auc(roc_obj)
print(auc_val)
## Area under the curve: 0.7654
Un AUC cercano a 1 indica un excelente poder predictivo, mientras que un AUC cerca de 0.5 indica poca capacidad discriminativa. Visualmente cuando más esté la curva ROC de la diagonal (hacia la esquina superior izquierda), mejor es la capacidad del modelo para distinguir entre empleados que rotan y empleados que no rotan. Además, se observa que la curva ROC se sitúa claramente por encima de la diagonal, lo que indica un desempeño superior al azar.
Dado que la curva ROC se ve bastante por encima de la diagonal, es muy probable que la AUC sea superior a 0.7 (o más), lo cual indica que el modelo tiene buena capacidad de discriminación, esto significa que para un par aleatorio de empleados (uno que rota y otro que no), el modelo asigna consistentemente mayor probabilidad de rotación al que efectivamente rota.
# Definir un caso hipotético (debe tener las mismas variables utilizadas en el modelo)
nuevo_empleado <- data.frame(
Departamento = factor("Ventas", levels = levels(rotacion_clean$Departamento)),
Horas_Extra = factor("Si", levels = levels(rotacion_clean$Horas_Extra)),
Viaje_de_Negocios = factor("Frecuentemente", levels = levels(rotacion_clean$Viaje_de_Negocios)),
Edad = 35,
Ingreso_Mensual = 5000, # Reemplazamos Satisfacción_Laboral por Ingreso_Mensual
Antigüedad_Cargo = 1
)
# Predecir la probabilidad de rotación
prob_nuevo <- predict(modelo, newdata = nuevo_empleado, type = "response")
print(prob_nuevo)
## 1
## 0.6429793
# Definir un umbral (por ejemplo, 0.5) para decidir si intervenir
if(prob_nuevo > 0.5){
cat("Se recomienda intervenir al empleado (alta probabilidad de rotación).\n")
} else {
cat("No se requiere intervención (baja probabilidad de rotación).\n")
}
## Se recomienda intervenir al empleado (alta probabilidad de rotación).
A partir del análisis global y la predicción realizada, el modelo de regresión logística muestra que ciertos factores—como trabajar horas extra, la frecuencia de viajes de negocios, el departamento y, en menor medida, variables cuantitativas como la edad, el ingreso mensual y la antigüedad en el cargo—son determinantes en la probabilidad de que un empleado rote.
En el caso del empleado hipotético evaluado, que pertenece al departamento de Ventas, trabaja horas extra y realiza viajes de negocios con alta frecuencia, la predicción arroja una probabilidad de rotación de aproximadamente 64%. Dado que este valor supera el umbral establecido (0.5), se recomienda intervenir de manera proactiva para evitar la pérdida de talento.