Importar librerías.
Cargar y visualizar la base de datos.
## 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, …
Visualización de las variables de la tabla
## [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"
Diccionario de datos.
Seleccione 3 variables categóricas (distintas de rotación) y 3 variables cuantitativas, que se consideren estén relacionadas con la rotación. Nota: Debes justificar porque estas variables están relacionadas y que tipo de relación se espera entre ellas (Hipótesis).
Variables Numéricas:
Ingreso_Mensual: La compensación económica es uno de los principales factores que influye en la decisión de permanecer o buscar otros empleos. Un salario bajo puede motivar a los empleados a buscar mejores oportunidades. Relación inversa: a mayor ingreso, menor rotación.
Distancia_Casa: La distancia entre la casa del empleado y el lugar de trabajo puede ser un factor clave en su decisión de mantenerse en un empleo. Desplazamientos largos pueden ser desgastantes y reducir la satisfacción laboral. Relación directa: a mayor distancia, mayor rotación.
Antigüedad: La cantidad de tiempo que un empleado ha estado en la empresa puede influir en su decisión de quedarse o irse. Empleados con mayor antigüedad pueden tener más incentivos para quedarse, como beneficios acumulados o estabilidad laboral. Relación inversa: a mayor antigüedad, menor rotación.
Variables Categóricas:
Satisfación_Laboral: La satisfacción con el trabajo desempeñado es crucial. Empleados insatisfechos tienen una mayor probabilidad de dejar sus puestos en búsqueda de mejores condiciones o ambientes laborales. Relación inversa, menos satisfacción más rotación.
Estado_Civil: El estado civil puede influir en la rotación laboral. Por ejemplo, empleados casados podrían buscar mayor estabilidad, mientras que los solteros podrían estar más dispuestos a cambiar de trabajo. Hipótesis: los solteros tienen mayor probabilidad de rotar que los casados.
Departamento: El departamento en el que trabaja el empleado puede influir en su rotación. Algunos departamentos pueden tener una carga de trabajo más alta o ambientes más estresantes, o puede tener bonificaciones o comisiones adicionales, lo que puede llevar a una mayor rotación. Hipótesis: el departamento de Ventas, por la presión de metas y comisiones variables, tiene mayor rotación que Investigación y Desarrollo (IyD).
# Copia de la base completa para la caracterización general (Punto 2)
rotacion_completa <- rotacion
# Seleccionar las columnas deseadas
rotacion <- rotacion %>%
select(Rotación, Ingreso_Mensual, Distancia_Casa, Antigüedad, Satisfación_Laboral, Estado_Civil, Departamento)
# Recodificar la variable Satisfacción_Laboral
rotacion <- rotacion %>%
mutate(Satisfación_Laboral = case_when(
Satisfación_Laboral == 1 ~ "Muy insatisfecho",
Satisfación_Laboral == 2 ~ "Insatisfecho",
Satisfación_Laboral == 3 ~ "Satisfecho",
Satisfación_Laboral == 4 ~ "Muy satisfecho",
TRUE ~ as.character(Satisfación_Laboral) # Mantener otros valores sin cambios
))
# Ordenar los niveles según el diccionario (referencia: Muy insatisfecho)
rotacion$Satisfación_Laboral <- factor(rotacion$Satisfación_Laboral,
levels = c("Muy insatisfecho", "Insatisfecho", "Satisfecho", "Muy satisfecho"))Realiza un análisis univariado (caracterización) de la información contenida en la base de datos rotacion.
## Rotación Ingreso_Mensual Distancia_Casa Antigüedad
## Length :1470 Min. : 1009 Min. : 1.000 Min. : 0.000
## N.unique : 2 1st Qu.: 2911 1st Qu.: 2.000 1st Qu.: 3.000
## N.blank : 0 Median : 4919 Median : 7.000 Median : 5.000
## Min.nchar: 2 Mean : 6503 Mean : 9.193 Mean : 7.008
## Max.nchar: 2 3rd Qu.: 8379 3rd Qu.:14.000 3rd Qu.: 9.000
## Max. :19999 Max. :29.000 Max. :40.000
## Satisfación_Laboral Estado_Civil Departamento
## Muy insatisfecho:289 Length :1470 Length :1470
## Insatisfecho :280 N.unique : 3 N.unique : 3
## Satisfecho :442 N.blank : 0 N.blank : 0
## Muy satisfecho :459 Min.nchar: 6 Min.nchar: 2
## Max.nchar: 10 Max.nchar: 6
##
# Indicadores solo para las variables cuantitativas
# (la media y la desviación no aplican a variables categóricas)
vars_num <- c("Ingreso_Mensual", "Distancia_Casa", "Antigüedad")
data.frame(
Media = sapply(rotacion[vars_num], mean),
Mediana = sapply(rotacion[vars_num], median),
Desv_std = sapply(rotacion[vars_num], sd),
CV = sapply(rotacion[vars_num], function(x) sd(x) / mean(x)),
Min = sapply(rotacion[vars_num], min),
Max = sapply(rotacion[vars_num], max)
) %>% round(2)# Frecuencias para las variables categóricas
for (v in c("Rotación", "Satisfación_Laboral", "Estado_Civil", "Departamento")) {
cat("\n", v, "\n")
print(round(100 * prop.table(table(rotacion[[v]])), 1))
}##
## Rotación
##
## No Si
## 83.9 16.1
##
## Satisfación_Laboral
##
## Muy insatisfecho Insatisfecho Satisfecho Muy satisfecho
## 19.7 19.0 30.1 31.2
##
## Estado_Civil
##
## Casado Divorciado Soltero
## 45.8 22.2 32.0
##
## Departamento
##
## IyD RH Ventas
## 65.4 4.3 30.3
ggplot(rotacion, aes(x = Rotación)) +
geom_histogram(binwidth = 1, fill = "blue", color = "black", stat = "count") +
labs(title = "Histograma de Rotación", x = "Rotación", y = "Frecuencia") +
theme_minimal()La variable de interés está desbalanceada: 237 de los 1470 empleados (16.1%) rotan de sus puestos de trabajo y 1233 (83.9%) no. Es decir, por cada empleado que rota hay aproximadamente cinco que no lo hacen. Este desbalance es importante en la evaluación del modelo, porque una exactitud alta puede ser engañosa y el punto de corte de 0.5 puede no ser adecuado.
graficos_num <- list()
for (v in vars_num) {
graficos_num[[paste0(v, "_h")]] <- ggplot(rotacion, aes(x = .data[[v]])) +
geom_histogram(bins = 30, fill = "steelblue", color = "white") +
labs(title = paste("Histograma de", v), x = v, y = "Frecuencia") +
theme_minimal()
graficos_num[[paste0(v, "_b")]] <- ggplot(rotacion, aes(x = .data[[v]])) +
geom_boxplot(fill = "orange", alpha = 0.6) +
labs(title = paste("Boxplot de", v), x = v) +
theme_minimal() + theme(axis.text.y = element_blank())
}
grid.arrange(grobs = graficos_num, ncol = 2)# Lista de variables categóricas de interés
categorical_vars <- c("Departamento", "Satisfación_Laboral", "Estado_Civil")
# Crear un histograma para cada variable categórica
for (var in categorical_vars) {
print(ggplot(rotacion, aes_string(x = var)) +
geom_bar(fill = "steelblue") +
theme_minimal() +
labs(title = paste("Histograma de", var), x = var, y = "Frecuencia") +
theme(axis.text.x = element_text(angle = 45, hjust = 1)))
}La mayor parte de los empleados está en el departamento de IyD que se supondría se constituye en el área misional de la empresa. El departamento de recursos humanos es de soporte, por lo tanto la cantidad de empleados es menor.
De otra parte, los empleados están mayoritariamente satisfechos o muy satisfechos en sus puestos de trabajo.
Por último, los casados son el estado civil mayoritario en las empresas (45.8%), seguidos por los solteros (32.0%) y los divorciados (22.2%). En cuanto a la satisfacción laboral, aunque el 61.3% está satisfecho o muy satisfecho, un 38.7% está insatisfecho o muy insatisfecho, un grupo considerable.
Para caracterizar la base completa se recodifican, según el diccionario de datos, las variables que vienen como números pero son categóricas ordinales.
etq_satisf <- c("Muy insatisfecho", "Insatisfecho", "Satisfecho", "Muy satisfecho")
base_dic <- rotacion_completa %>%
mutate(
Rendimiento_Laboral = factor(Rendimiento_Laboral, levels = 1:4,
labels = c("Bajo", "Medio", "Alto", "Muy alto")),
Educación = factor(Educación, levels = 1:5,
labels = c("Primaria", "Secundaria", "Técnico/Tecnólogo",
"Pregrado", "Posgrado")),
Satisfacción_Ambiental = factor(Satisfacción_Ambiental, levels = 1:4, labels = etq_satisf),
Satisfación_Laboral = factor(Satisfación_Laboral, levels = 1:4, labels = etq_satisf),
Equilibrio_Trabajo_Vida = factor(Equilibrio_Trabajo_Vida, levels = 1:4,
labels = c("Muy bajo", "Bajo", "Medio", "Alto")),
across(where(is.character), as.factor)
)
# Variables cuantitativas
num <- base_dic %>% select(where(is.numeric))
data.frame(
Media = sapply(num, mean),
Mediana = sapply(num, median),
Desv_std = sapply(num, sd),
Min = sapply(num, min),
Max = sapply(num, max)
) %>% round(2) %>%
kable() %>% kable_styling(full_width = FALSE)| Media | Mediana | Desv_std | Min | Max | |
|---|---|---|---|---|---|
| Edad | 36.92 | 36 | 9.14 | 18 | 60 |
| Distancia_Casa | 9.19 | 7 | 8.11 | 1 | 29 |
| Ingreso_Mensual | 6502.93 | 4919 | 4707.96 | 1009 | 19999 |
| Trabajos_Anteriores | 2.69 | 2 | 2.50 | 0 | 9 |
| Porcentaje_aumento_salarial | 15.21 | 14 | 3.66 | 11 | 25 |
| Años_Experiencia | 11.28 | 10 | 7.78 | 0 | 40 |
| Capacitaciones | 2.80 | 3 | 1.29 | 0 | 6 |
| Antigüedad | 7.01 | 5 | 6.13 | 0 | 40 |
| Antigüedad_Cargo | 4.23 | 3 | 3.62 | 0 | 18 |
| Años_ultima_promoción | 2.19 | 1 | 3.22 | 0 | 15 |
| Años_acargo_con_mismo_jefe | 4.12 | 3 | 3.57 | 0 | 17 |
# Variables categóricas
cat_vars <- names(base_dic)[sapply(base_dic, is.factor)]
tabla_cat <- bind_rows(lapply(cat_vars, function(v) {
t <- table(base_dic[[v]])
data.frame(Variable = v, Categoría = names(t), n = as.vector(t),
Porcentaje = round(100 * as.vector(prop.table(t)), 1))
}))
kable(tabla_cat) %>% kable_styling(full_width = FALSE) %>%
scroll_box(height = "400px")| Variable | Categoría | n | Porcentaje |
|---|---|---|---|
| Rotación | No | 1233 | 83.9 |
| Rotación | Si | 237 | 16.1 |
| Viaje de Negocios | Frecuentemente | 277 | 18.8 |
| Viaje de Negocios | No_Viaja | 150 | 10.2 |
| Viaje de Negocios | Raramente | 1043 | 71.0 |
| Departamento | IyD | 961 | 65.4 |
| Departamento | RH | 63 | 4.3 |
| Departamento | Ventas | 446 | 30.3 |
| Educación | Primaria | 170 | 11.6 |
| Educación | Secundaria | 282 | 19.2 |
| Educación | Técnico/Tecnólogo | 572 | 38.9 |
| Educación | Pregrado | 398 | 27.1 |
| Educación | Posgrado | 48 | 3.3 |
| Campo_Educación | Ciencias | 606 | 41.2 |
| Campo_Educación | Humanidades | 27 | 1.8 |
| Campo_Educación | Mercadeo | 159 | 10.8 |
| Campo_Educación | Otra | 82 | 5.6 |
| Campo_Educación | Salud | 464 | 31.6 |
| Campo_Educación | Tecnicos | 132 | 9.0 |
| Satisfacción_Ambiental | Muy insatisfecho | 284 | 19.3 |
| Satisfacción_Ambiental | Insatisfecho | 287 | 19.5 |
| Satisfacción_Ambiental | Satisfecho | 453 | 30.8 |
| Satisfacción_Ambiental | Muy satisfecho | 446 | 30.3 |
| Genero | F | 588 | 40.0 |
| Genero | M | 882 | 60.0 |
| Cargo | Director_Investigación | 80 | 5.4 |
| Cargo | Director_Manofactura | 145 | 9.9 |
| Cargo | Ejecutivo_Ventas | 326 | 22.2 |
| Cargo | Gerente | 102 | 6.9 |
| Cargo | Investigador_Cientifico | 292 | 19.9 |
| Cargo | Recursos_Humanos | 52 | 3.5 |
| Cargo | Representante_Salud | 131 | 8.9 |
| Cargo | Representante_Ventas | 83 | 5.6 |
| Cargo | Tecnico_Laboratorio | 259 | 17.6 |
| Satisfación_Laboral | Muy insatisfecho | 289 | 19.7 |
| Satisfación_Laboral | Insatisfecho | 280 | 19.0 |
| Satisfación_Laboral | Satisfecho | 442 | 30.1 |
| Satisfación_Laboral | Muy satisfecho | 459 | 31.2 |
| Estado_Civil | Casado | 673 | 45.8 |
| Estado_Civil | Divorciado | 327 | 22.2 |
| Estado_Civil | Soltero | 470 | 32.0 |
| Horas_Extra | No | 1054 | 71.7 |
| Horas_Extra | Si | 416 | 28.3 |
| Rendimiento_Laboral | Bajo | 0 | 0.0 |
| Rendimiento_Laboral | Medio | 0 | 0.0 |
| Rendimiento_Laboral | Alto | 1244 | 84.6 |
| Rendimiento_Laboral | Muy alto | 226 | 15.4 |
| Equilibrio_Trabajo_Vida | Muy bajo | 80 | 5.4 |
| Equilibrio_Trabajo_Vida | Bajo | 344 | 23.4 |
| Equilibrio_Trabajo_Vida | Medio | 893 | 60.7 |
| Equilibrio_Trabajo_Vida | Alto | 153 | 10.4 |
Realiza un análisis bivariado en donde la variable respuesta sea Rotación codificada de la siguiente manera (y=1 es si rotación, y=0 es no rotación). Con base en estos resultados identifique cuales son las variables determinantes de la rotación e interpretar el signo del coeficiente estimado. Compare estos resultados con la hipótesis planteada en el punto 1.
# Análisis bivariado para variables numéricas
# Ingreso_Mensual
ggplot(rotacion, aes(x = Ingreso_Mensual, y = Rotación)) +
geom_point() +
geom_smooth(method = "lm") +
ggtitle("Ingreso Mensual vs Rotación")cor_ingreso <- cor(rotacion$Ingreso_Mensual, rotacion$Rotación)
print(paste("Correlación Ingreso_Mensual y Rotación:", cor_ingreso))## [1] "Correlación Ingreso_Mensual y Rotación: -0.159839582384989"
# Distancia_Casa
ggplot(rotacion, aes(x = Distancia_Casa, y = Rotación)) +
geom_point() +
geom_smooth(method = "lm") +
ggtitle("Distancia Casa vs Rotación")cor_distancia <- cor(rotacion$Distancia_Casa, rotacion$Rotación)
print(paste("Correlación Distancia_Casa y Rotación:", cor_distancia))## [1] "Correlación Distancia_Casa y Rotación: 0.0779235829557037"
# Antigüedad
ggplot(rotacion, aes(x = Antigüedad, y = Rotación)) +
geom_point() +
geom_smooth(method = "lm") +
ggtitle("Antigüedad vs Rotación")cor_antiguedad <- cor(rotacion$Antigüedad, rotacion$Rotación)
print(paste("Correlación Antigüedad y Rotación:", cor_antiguedad))## [1] "Correlación Antigüedad y Rotación: -0.134392213989977"
# Análisis para variables categóricas
# Satisfacción_Laboral
tabla_satisfaccion <- table(rotacion$Satisfación_Laboral, rotacion$Rotación)
chi_sq_satisfaccion <- chisq.test(tabla_satisfaccion)
print(chi_sq_satisfaccion)##
## Pearson's Chi-squared test
##
## data: tabla_satisfaccion
## X-squared = 17.505, df = 3, p-value = 0.0005563
# Estado_Civil
tabla_estado_civil <- table(rotacion$Estado_Civil, rotacion$Rotación)
chi_sq_estado_civil <- chisq.test(tabla_estado_civil)
print(chi_sq_estado_civil)##
## Pearson's Chi-squared test
##
## data: tabla_estado_civil
## X-squared = 46.164, df = 2, p-value = 9.456e-11
# Departamento
tabla_departamento <- table(rotacion$Departamento, rotacion$Rotación)
chi_sq_departamento <- chisq.test(tabla_departamento)
print(chi_sq_departamento)##
## Pearson's Chi-squared test
##
## data: tabla_departamento
## X-squared = 10.796, df = 2, p-value = 0.004526
Resultados de los coeficientes de correlación: Los valores son bajos (cerca de −0.16 para ingreso, 0.08 para distancia y −0.13 para antigüedad), lo cual es esperable porque la rotación es una variable binaria y la correlación de Pearson no capta bien este tipo de relación. Sin embargo, los signos coinciden con las hipótesis: negativo para ingreso y antigüedad, positivo para distancia, y con 1470 observaciones estas correlaciones son estadísticamente distintas de cero. Esto se confirma comparando los promedios: los empleados que rotan ganan en promedio 4.787 frente a 6.833 de los que no rotan, viven a 10.6 km frente a 8.9 km y llevan 5.1 años frente a 7.4 años en la empresa. Por esto se mantienen las tres variables.
# Boxplots de las variables cuantitativas según la rotación
for (v in c("Ingreso_Mensual", "Distancia_Casa", "Antigüedad")) {
print(ggplot(rotacion, aes(x = as.factor(Rotación), y = .data[[v]],
fill = as.factor(Rotación))) +
geom_boxplot(alpha = 0.7) +
labs(title = paste(v, "según rotación"), x = "Rotación", y = v,
fill = "Rotación") +
theme_minimal())
}# Promedios por grupo
rotacion %>%
group_by(Rotación) %>%
summarise(across(c(Ingreso_Mensual, Distancia_Casa, Antigüedad), mean))Pruebas de hipótesis para las variables cuantitativas
Para cada variable cuantitativa se prueba si su distribución difiere entre los empleados que rotan y los que no:
cor.test):
\(H_0\): la correlación es cero.pruebas_num <- bind_rows(lapply(c("Ingreso_Mensual", "Distancia_Casa", "Antigüedad"), function(v) {
x <- rotacion[[v]]
data.frame(
Variable = v,
Media_rota = mean(x[rotacion$Rotación == 1]),
Media_no_rota = mean(x[rotacion$Rotación == 0]),
p_t_Welch = t.test(x ~ rotacion$Rotación)$p.value,
p_Wilcoxon = wilcox.test(x ~ rotacion$Rotación)$p.value,
Correlacion = cor(x, rotacion$Rotación),
p_correlacion = cor.test(x, rotacion$Rotación)$p.value
)
}))
pruebas_num %>%
kable(digits = 4) %>% kable_styling(full_width = FALSE)| Variable | Media_rota | Media_no_rota | p_t_Welch | p_Wilcoxon | Correlacion | p_correlacion |
|---|---|---|---|---|---|---|
| Ingreso_Mensual | 4787.0928 | 6832.7397 | 0.0000 | 0.0000 | -0.1598 | 0.0000 |
| Distancia_Casa | 10.6329 | 8.9157 | 0.0041 | 0.0024 | 0.0779 | 0.0028 |
| Antigüedad | 5.1308 | 7.3690 | 0.0000 | 0.0000 | -0.1344 | 0.0000 |
En las tres variables los valores p de las tres pruebas son menores que 0.05, por lo que se rechaza \(H_0\): el ingreso mensual, la distancia a la casa y la antigüedad difieren significativamente entre los empleados que rotan y los que no. Las diferencias más marcadas se dan en ingreso y antigüedad (valores p muy cercanos a cero); en distancia la diferencia también es significativa, aunque más moderada.
Resultados de Chi-Cuadrado
Satisfacción Laboral vs Rotación: X-squared = 17.505, df = 3, p-value = 0.0005563 Dado que el p-value es mucho menor que 0.05, rechazamos la hipótesis nula. Esto sugiere que hay una relación significativa entre la satisfacción laboral y la rotación. Es decir, la rotación varía de manera significativa según los niveles de satisfacción laboral.
Estado Civil vs Rotación X-squared = 46.164, df = 2, p-value = 9.456e-11 Aquí también, el p-value es extremadamente bajo (mucho menor que 0.05), lo que indica que rechazamos la hipótesis nula. Esto sugiere que existe una relación significativa entre el estado civil y la rotación. La rotación de empleados difiere significativamente en función del estado civil.
Departamento vs Rotación X-squared = 10.796, df = 2, p-value = 0.004526 El p-value es menor que 0.05, lo que indica que también rechazamos la hipótesis nula en este caso. Esto sugiere que hay una relación significativa entre el departamento y la rotación. La rotación de empleados varía significativamente entre los diferentes departamentos.
A continuación se presentan gráficos de barras para ver el comportamiento de las variables categóricas comparadas con la rotación
library(dplyr)
library(ggplot2)
rotacion$Satisfación_Laboral <- as.factor(rotacion$Satisfación_Laboral)
rotacion$Departamento <- as.factor(rotacion$Departamento)
# Gráfico de barras agrupadas para Satisfacción_Laboral
ggplot(rotacion, aes(x = Satisfación_Laboral, fill = as.factor(Rotación))) +
geom_bar(position = "dodge") +
labs(title = "Rotación vs Satisfacción Laboral",
x = "Satisfacción Laboral",
y = "Cantidad",
fill = "Rotación") +
theme_minimal()# Gráfico de barras agrupadas para Departamento
ggplot(rotacion, aes(x = Departamento, fill = as.factor(Rotación))) +
geom_bar(position = "dodge") +
labs(title = "Rotación vs Departamento",
x = "Departamento",
y = "Cantidad",
fill = "Rotación") +
theme_minimal()# Gráfico de barras agrupadas para estado civil
ggplot(rotacion, aes(x = as.factor(Estado_Civil), fill = as.factor(Rotación))) +
geom_bar(position = "dodge") +
labs(title = "Rotación vs Estado civil",
x = "Estado civil",
y = "Cantidad",
fill = "Rotación") +
theme_minimal()En las gráficas se percibe que la variable rotación está desbalanceada, sin embargo, se percibe que a mayor satisfacción laboral, hay menos rotación, si está en un departamento de IyD rota menos o si es casado, rota menos.
# Crear variables dummy
rotacion_dummies <- fastDummies::dummy_cols(rotacion, remove_first_dummy = TRUE, remove_selected_columns = TRUE)
# Calcular matriz de correlación
cor_matrix <- cor(rotacion_dummies, use = "pairwise.complete.obs")
library(corrplot)
corrplot(cor_matrix, method = "color", type = "upper",
tl.col = "black", tl.srt = 45,
addCoef.col = "black", # Añadir coeficientes
number.cex = 0.7, # Tamaño del texto de los coeficientes
tl.cex = 0.6, # Tamaño de los nombres de las variables
main = "Matriz de Correlación", cex.main = 1.2, # Tamaño del título
mar = c(0, 0, 2, 0)) # margen superior para que el título no se corteEn el gráfico de correlación no se evidencian relaciones fuertes entre las variables. La más alta es entre ingreso mensual y antigüedad (0.51), una relación moderada y esperable (quienes llevan más tiempo en la empresa suelen ganar más), que no es lo suficientemente alta para generar problemas de multicolinealidad en el modelo. Con la rotación, la asociación más alta es la de ser soltero (0.18).
Para identificar las variables determinantes e interpretar el signo del coeficiente, se estima un modelo logístico con cada variable por separado.
vars_biv <- c("Ingreso_Mensual", "Distancia_Casa", "Antigüedad",
"Satisfación_Laboral", "Estado_Civil", "Departamento")
resultados_biv <- bind_rows(lapply(vars_biv, function(v) {
m <- glm(as.formula(paste0("Rotación ~ `", v, "`")), data = rotacion,
family = binomial(link = "logit"))
tidy(m) %>% filter(term != "(Intercept)")
})) %>%
mutate(Signo = ifelse(estimate > 0, "+", "-"),
Significativo = ifelse(p.value < 0.05, "Sí", "No")) %>%
select(term, estimate, p.value, Signo, Significativo)
resultados_bivRealiza la estimación de un modelo de regresión
logístico en el cual la variable respuesta es
rotacion (𝑦=1 es si rotación, 𝑦=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.
# Ajuste preliminar de un modelo logístico para ver los coeficientes
modelo_logistico <- glm(Rotación ~ ., data = rotacion, family = binomial())
summary(modelo_logistico)##
## Call:
## glm(formula = Rotación ~ ., family = binomial(), data = rotacion)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.075e+00 2.409e-01 -4.460 8.19e-06 ***
## Ingreso_Mensual -1.099e-04 2.537e-05 -4.331 1.48e-05 ***
## Distancia_Casa 2.994e-02 8.868e-03 3.376 0.000737 ***
## Antigüedad -4.488e-02 1.823e-02 -2.461 0.013842 *
## Satisfación_LaboralInsatisfecho -4.839e-01 2.255e-01 -2.146 0.031885 *
## Satisfación_LaboralSatisfecho -4.670e-01 1.999e-01 -2.336 0.019471 *
## Satisfación_LaboralMuy satisfecho -9.689e-01 2.134e-01 -4.541 5.60e-06 ***
## Estado_CivilDivorciado -2.449e-01 2.235e-01 -1.095 0.273313
## Estado_CivilSoltero 8.640e-01 1.645e-01 5.251 1.51e-07 ***
## DepartamentoRH 5.781e-01 3.522e-01 1.641 0.100706
## DepartamentoVentas 6.087e-01 1.603e-01 3.798 0.000146 ***
## ---
## 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: 1161.8 on 1459 degrees of freedom
## AIC: 1183.8
##
## Number of Fisher Scoring iterations: 5
Los resultados del modelo muestran que las variables ingreso mensual, distancia a casa, antigüedad, estado civil = soltero y departamento = ventas son significativas al 5%. En satisfacción laboral (referencia: muy insatisfecho), las categorías insatisfecho, satisfecho y muy satisfecho también son significativas. En cambio, estar divorciado (frente a casado) o estar en el departamento de recursos humanos (frente a IyD) no tiene una relación significativa con la rotación.
\(H_0: \beta_1 = \beta_2 = \dots = \beta_k = 0\) vs \(H_a:\) algún \(\beta_i \neq 0\)
# Guardar el modelo con toda la base para las interpretaciones
modelo_completo <- modelo_logistico
chi_global <- with(modelo_completo, null.deviance - deviance)
gl_global <- with(modelo_completo, df.null - df.residual)
p_global <- pchisq(chi_global, gl_global, lower.tail = FALSE)
c(Chi2 = chi_global, gl = gl_global, p_valor = p_global)## Chi2 gl p_valor
## 1.368272e+02 1.000000e+01 1.881306e-24
El estadístico es \(X^2\) = 136.83 con 10 grados de libertad y un valor p de 1.88e-24, por lo que se rechaza \(H_0\): el modelo en su conjunto es significativo.
# Obtener los coeficientes y sus valores exponenciales
coeficientes <- tidy(modelo_logistico) %>%
mutate(Exp_Coef = exp(estimate))
# mantener solamente el valor estimado y el exponencial
coeficientes<- coeficientes %>%
select(term, estimate, p.value, Exp_Coef)
# Mostrar la tabla de coeficientes
print(coeficientes)## # A tibble: 11 × 4
## term estimate p.value Exp_Coef
## <chr> <dbl> <dbl> <dbl>
## 1 (Intercept) -1.07 0.00000819 0.341
## 2 Ingreso_Mensual -0.000110 0.0000148 1.000
## 3 Distancia_Casa 0.0299 0.000737 1.03
## 4 Antigüedad -0.0449 0.0138 0.956
## 5 Satisfación_LaboralInsatisfecho -0.484 0.0319 0.616
## 6 Satisfación_LaboralSatisfecho -0.467 0.0195 0.627
## 7 Satisfación_LaboralMuy satisfecho -0.969 0.00000560 0.380
## 8 Estado_CivilDivorciado -0.245 0.273 0.783
## 9 Estado_CivilSoltero 0.864 0.000000151 2.37
## 10 DepartamentoRH 0.578 0.101 1.78
## 11 DepartamentoVentas 0.609 0.000146 1.84
# Intervalos de confianza al 95% para las razones de odds
exp(cbind(RO = coef(modelo_completo), confint.default(modelo_completo)))## RO 2.5 % 97.5 %
## (Intercept) 0.3414062 0.2129012 0.5474756
## Ingreso_Mensual 0.9998901 0.9998404 0.9999398
## Distancia_Casa 1.0303882 1.0126331 1.0484546
## Antigüedad 0.9561121 0.9225457 0.9908998
## Satisfación_LaboralInsatisfecho 0.6163499 0.3961516 0.9589441
## Satisfación_LaboralSatisfecho 0.6268601 0.4236625 0.9275158
## Satisfación_LaboralMuy satisfecho 0.3795021 0.2498042 0.5765391
## Estado_CivilDivorciado 0.7828064 0.5051086 1.2131765
## Estado_CivilSoltero 2.3725411 1.7185716 3.2753663
## DepartamentoRH 1.7826599 0.8938815 3.5551427
## DepartamentoVentas 1.8379945 1.3424942 2.5163788
# Valores para la interpretación
b <- coef(modelo_completo)
ro <- exp(b)
pv <- summary(modelo_completo)$coefficients[, 4]La razón de odds (RO = exp(β)) indica cuántas veces se multiplican los odds (chances) de rotar ante un cambio en la variable, manteniendo las demás constantes. Una RO mayor que 1 aumenta la chance de rotar y una RO menor que 1 la reduce. En las variables categóricas, la comparación se hace frente a la categoría de referencia: muy insatisfecho en satisfacción laboral, casado en estado civil e IyD en departamento.
Ingreso_Mensual Coeficiente: -0.00011 RO: 0.99989 (p = 1.5e-05). Por cada unidad de aumento en el ingreso mensual, los odds de rotar disminuyen muy ligeramente. Como una unidad monetaria es muy poco, es más útil interpretarlo por cada 1.000 unidades: los odds se multiplican por 0.896, es decir, disminuyen cerca de un 10.4%.
Distancia_Casa Coeficiente: 0.0299 RO: 1.0304 (p = 0.00074). Cada kilómetro adicional de distancia aumenta los odds de rotar en un 3%. Vivir 5 km más lejos multiplica los odds por 1.16.
Antigüedad Coeficiente: -0.0449 RO: 0.9561 (p = 0.014). Cada año adicional en la empresa reduce los odds de rotar en un 4.4%. Los empleados más antiguos son menos propensos a irse.
Satisfación_LaboralInsatisfecho Coeficiente: -0.4839 RO: 0.6163 (p = 0.032). Los empleados insatisfechos tienen unos odds de rotar un 38.4% menores que los muy insatisfechos.
Satisfación_LaboralSatisfecho Coeficiente: -0.467 RO: 0.6269 (p = 0.019). Los empleados satisfechos tienen unos odds de rotar un 37.3% menores que los muy insatisfechos.
Satisfación_LaboralMuy satisfecho Coeficiente: -0.9689 RO: 0.3795 (p = 5.6e-06). Es el efecto más fuerte de la satisfacción: los empleados muy satisfechos tienen unos odds de rotar un 62% menores que los muy insatisfechos.
Estado_CivilDivorciado Coeficiente: -0.2449 RO: 0.7828 (p = 0.273). La RO es menor que 1, pero el efecto no es significativo: los divorciados no se diferencian de los casados en su probabilidad de rotar.
Estado_CivilSoltero Coeficiente: 0.864 RO: 2.3725 (p = 1.5e-07). Los empleados solteros tienen unos odds de rotar 2.37 veces los de los casados. Es uno de los efectos más fuertes del modelo.
DepartamentoRH Coeficiente: 0.5781 RO: 1.7827 (p = 0.101). Aunque la RO es mayor que 1, el efecto no es significativo al 5%, en parte porque el departamento solo tiene 63 empleados. No hay evidencia suficiente de que RH rote más que IyD.
DepartamentoVentas Coeficiente: 0.6087 RO: 1.838 (p = 0.00015). Los empleados de Ventas tienen unos odds de rotar 1.84 veces los de IyD, un efecto significativo.
Conclusión de los resultados del modelo:
La interpretación de los coeficientes y las razones de oportunidad permite entender cómo cada variable influye en la probabilidad de rotación del personal. Todas las variables seleccionadas resultan significativas en al menos una de sus categorías y con los signos esperados. Los efectos más fuertes son ser soltero, pertenecer al departamento de Ventas y estar muy insatisfecho. El ingreso mensual y la antigüedad tienen efectos por unidad pequeños, pero se vuelven importantes al considerar cambios grandes (por ejemplo, 1.000 unidades más de salario o varios años en la empresa).
Se adiciona un paso adicional para entrenar el modelo y mostrar reproducibilidad.
# División de los datos
set.seed(123) # Para reproducibilidad
indices <- sample(1:nrow(rotacion), size = 0.7 * nrow(rotacion))
train_data <- rotacion[indices, ]
test_data <- rotacion[-indices, ]
# Ajuste del modelo logístico
modelo_logistico <- glm(Rotación ~ ., data = train_data, family = binomial())
summary(modelo_logistico)##
## Call:
## glm(formula = Rotación ~ ., family = binomial(), data = train_data)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -9.476e-01 2.931e-01 -3.233 0.001223 **
## Ingreso_Mensual -1.415e-04 3.292e-05 -4.298 1.72e-05 ***
## Distancia_Casa 3.016e-02 1.103e-02 2.734 0.006261 **
## Antigüedad -3.542e-02 2.179e-02 -1.626 0.104018
## Satisfación_LaboralInsatisfecho -5.207e-01 2.784e-01 -1.870 0.061461 .
## Satisfación_LaboralSatisfecho -5.871e-01 2.443e-01 -2.403 0.016242 *
## Satisfación_LaboralMuy satisfecho -9.736e-01 2.540e-01 -3.833 0.000126 ***
## Estado_CivilDivorciado -3.363e-01 2.803e-01 -1.200 0.230175
## Estado_CivilSoltero 9.716e-01 1.993e-01 4.875 1.09e-06 ***
## DepartamentoRH 7.455e-01 4.203e-01 1.774 0.076090 .
## DepartamentoVentas 5.739e-01 1.965e-01 2.920 0.003500 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 896.03 on 1028 degrees of freedom
## Residual deviance: 785.38 on 1018 degrees of freedom
## AIC: 807.38
##
## Number of Fisher Scoring iterations: 6
coeficientes <- tidy(modelo_logistico) %>%
mutate(Exp_Coef = exp(estimate))
# Mostrar la tabla de coeficientes
print(coeficientes)## # A tibble: 11 × 6
## term estimate std.error statistic p.value Exp_Coef
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 (Intercept) -9.48e-1 0.293 -3.23 1.22e-3 0.388
## 2 Ingreso_Mensual -1.41e-4 0.0000329 -4.30 1.72e-5 1.000
## 3 Distancia_Casa 3.02e-2 0.0110 2.73 6.26e-3 1.03
## 4 Antigüedad -3.54e-2 0.0218 -1.63 1.04e-1 0.965
## 5 Satisfación_LaboralInsatisfecho -5.21e-1 0.278 -1.87 6.15e-2 0.594
## 6 Satisfación_LaboralSatisfecho -5.87e-1 0.244 -2.40 1.62e-2 0.556
## 7 Satisfación_LaboralMuy satisfe… -9.74e-1 0.254 -3.83 1.26e-4 0.378
## 8 Estado_CivilDivorciado -3.36e-1 0.280 -1.20 2.30e-1 0.714
## 9 Estado_CivilSoltero 9.72e-1 0.199 4.88 1.09e-6 2.64
## 10 DepartamentoRH 7.45e-1 0.420 1.77 7.61e-2 2.11
## 11 DepartamentoVentas 5.74e-1 0.197 2.92 3.50e-3 1.78
Los coeficientes del modelo estimado con la muestra de entrenamiento (70% de los datos) mantienen los mismos signos que los del modelo con toda la base, lo que muestra que los resultados son estables. La antigüedad pierde significancia en este modelo (p ≈ 0.10) porque la muestra es más pequeña; por eso la interpretación de los coeficientes se hace con el modelo estimado con toda la base, y este modelo de entrenamiento se usa para evaluar el poder predictivo con la muestra de prueba.
Evaluar el poder predictivo del modelo con base en la curva ROC y el AUC en el set de datos de prueba.
# Realizamos las predicciones en el conjunto de prueba
predicciones <- predict(modelo_logistico, newdata = test_data, type = "response")
# Calculamos la curva ROC y el AUC
roc_resultados <- roc(test_data$Rotación, predicciones)
plot(roc_resultados)## Area under the curve: 0.6808
## 95% CI: 0.6088-0.7528 (DeLong)
Un AUC de 0.6808 sugiere que el modelo tiene una capacidad moderada para distinguir entre las clases positivas y negativas. Aunque no es excelente, indica que el modelo es mejor que el azar. El intervalo de confianza al 95% del AUC va de 0.609 a 0.753; como no incluye el valor 0.5 (clasificación aleatoria), la capacidad predictiva del modelo es estadísticamente superior al azar.
Esto se corrobora con la gráfica de la curva ROC, al estar arriba de la diagonal, significa que el modelo tiene capacidad predictiva, aunque al estar lejos de la esquina izquierda, significa que esta predicción es limitada.
Se calculan los indicadores de Accuracy, Precision, Recall y F1 Score
# Realizamos las predicciones en el conjunto de prueba
predicciones <- predict(modelo_logistico, newdata = test_data, type = "response")
# Conversión de probabilidades a clases (usualmente 0.5 es el umbral)
# Se usan factores con ambos niveles para que la tabla siempre sea 2x2
clases_predichas <- factor(ifelse(predicciones > 0.5, 1, 0), levels = c(0, 1))
# Tabla de confusión (filas = predicción, columnas = valor real)
tabla_confusion <- table(Predicción = clases_predichas,
Real = factor(test_data$Rotación, levels = c(0, 1)))
tabla_confusion## Real
## Predicción 0 1
## 0 360 72
## 1 6 3
# Calculamos los indicadores
TP <- tabla_confusion[2, 2] # Verdaderos positivos: predijo 1 y era 1
TN <- tabla_confusion[1, 1] # Verdaderos negativos: predijo 0 y era 0
FP <- tabla_confusion[2, 1] # Falsos positivos: predijo 1 y era 0
FN <- tabla_confusion[1, 2] # Falsos negativos: predijo 0 y era 1
# Accuracy
accuracy <- (TP + TN) / sum(tabla_confusion)
# Precision
precision <- TP / (TP + FP)
# Recall (Sensibilidad)
recall <- TP / (TP + FN)
# F1 Score
f1_score <- 2 * ((precision * recall) / (precision + recall))
# Resultados
cat("Accuracy:", accuracy, "\n")## Accuracy: 0.8231293
## Precision: 0.3333333
## Recall: 0.04
## F1 Score: 0.07142857
En síntesis: Aunque el accuracy parece razonablemente alto, los valores de precisión, recall y F1 Score sugieren que el modelo tiene un rendimiento deficiente en la identificación de los empleados que rotan. Esto puede deberse al desbalance en los datos o a que el modelo no está capturando adecuadamente las características relevantes para predecir la rotación. Es recomendable considerar ajustes en el modelo, como la recolección de más datos, el uso de otras variables, la aplicación de técnicas de balanceo de clases o el uso de otro tipo de modelos.
Como se vio en clase, el punto de corte afecta todos los indicadores, y con una variable desbalanceada (16.1% rota) el corte de 0.5 deja sin detectar a casi todos los que rotan. Por eso se elige el corte que maximiza el índice de Youden (sensibilidad + especificidad − 1) sobre la curva ROC.
mejor_corte <- coords(roc_resultados, "best", best.method = "youden",
ret = c("threshold", "sensitivity", "specificity"))
mejor_cortecorte_optimo <- as.numeric(mejor_corte$threshold[1])
# Matriz de confusión con el corte óptimo
clases_optimas <- factor(ifelse(predicciones > corte_optimo, 1, 0), levels = c(0, 1))
cm_optimo <- confusionMatrix(clases_optimas,
factor(test_data$Rotación, levels = c(0, 1)),
positive = "1")
cm_optimo## Confusion Matrix and Statistics
##
## Reference
## Prediction 0 1
## 0 282 32
## 1 84 43
##
## Accuracy : 0.737
## 95% CI : (0.6932, 0.7775)
## No Information Rate : 0.8299
## P-Value [Acc > NIR] : 1
##
## Kappa : 0.2695
##
## Mcnemar's Test P-Value : 2.188e-06
##
## Sensitivity : 0.57333
## Specificity : 0.77049
## Pos Pred Value : 0.33858
## Neg Pred Value : 0.89809
## Prevalence : 0.17007
## Detection Rate : 0.09751
## Detection Prevalence : 0.28798
## Balanced Accuracy : 0.67191
##
## 'Positive' Class : 1
##
Con el corte óptimo de 0.216, la sensibilidad (recall) pasa de 0.04 a 0.573 y la especificidad queda en 0.77. Se sacrifica algo de exactitud global (0.737), pero el modelo ahora sí detecta a una buena parte de los empleados que rotan. Para recursos humanos esto es preferible: es menos costoso hacer una intervención preventiva innecesaria (falso positivo) que perder a un empleado sin haberlo detectado (falso negativo). Este corte es el que se usa en el punto 6.
Para ver cómo cambia el desempeño del modelo según el punto de corte, se calculan los indicadores para cortes entre 0.05 y 0.60.
cortes <- seq(0.05, 0.60, by = 0.05)
sensibilidad_corte <- bind_rows(lapply(cortes, function(k) {
pred_k <- factor(ifelse(predicciones > k, 1, 0), levels = c(0, 1))
t_k <- table(pred_k, factor(test_data$Rotación, levels = c(0, 1)))
VP_k <- t_k[2, 2]; VN_k <- t_k[1, 1]; FP_k <- t_k[2, 1]; FN_k <- t_k[1, 2]
data.frame(
Corte = k,
Exactitud = (VP_k + VN_k) / sum(t_k),
Sensibilidad = VP_k / (VP_k + FN_k),
Especificidad = VN_k / (VN_k + FP_k),
Precision = ifelse(VP_k + FP_k > 0, VP_k / (VP_k + FP_k), NA),
Predichos_rotan = VP_k + FP_k
)
}))
sensibilidad_corte %>%
kable(digits = 3) %>% kable_styling(full_width = FALSE)| Corte | Exactitud | Sensibilidad | Especificidad | Precision | Predichos_rotan |
|---|---|---|---|---|---|
| 0.05 | 0.272 | 0.933 | 0.137 | 0.181 | 386 |
| 0.10 | 0.424 | 0.787 | 0.350 | 0.199 | 297 |
| 0.15 | 0.596 | 0.653 | 0.585 | 0.244 | 201 |
| 0.20 | 0.703 | 0.600 | 0.724 | 0.308 | 146 |
| 0.25 | 0.757 | 0.493 | 0.811 | 0.349 | 106 |
| 0.30 | 0.798 | 0.400 | 0.880 | 0.405 | 74 |
| 0.35 | 0.812 | 0.280 | 0.921 | 0.420 | 50 |
| 0.40 | 0.823 | 0.227 | 0.945 | 0.459 | 37 |
| 0.45 | 0.825 | 0.120 | 0.970 | 0.450 | 20 |
| 0.50 | 0.823 | 0.040 | 0.984 | 0.333 | 9 |
| 0.55 | 0.825 | 0.013 | 0.992 | 0.250 | 4 |
| 0.60 | 0.825 | 0.000 | 0.995 | 0.000 | 2 |
sensibilidad_corte %>%
select(Corte, Exactitud, Sensibilidad, Especificidad, Precision) %>%
pivot_longer(-Corte, names_to = "Indicador", values_to = "Valor") %>%
ggplot(aes(x = Corte, y = Valor, color = Indicador)) +
geom_line(linewidth = 1) +
geom_point() +
geom_vline(xintercept = corte_optimo, linetype = "dashed") +
labs(title = "Indicadores según el punto de corte",
subtitle = paste("Línea punteada: corte óptimo de Youden =", round(corte_optimo, 3)),
x = "Punto de corte", y = "Valor") +
theme_minimal()El análisis muestra el intercambio entre los indicadores:
La elección final del corte depende de la estrategia de la empresa: si el costo de perder a un empleado es alto, conviene un corte algo menor que el óptimo, para detectar más casos en riesgo; si los recursos para intervenir son limitados, conviene un corte mayor, para concentrarse en los casos de mayor probabilidad.
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 individuo hipotético con características de alto riesgo según el modelo
empleado_hipotetico <- data.frame(
Ingreso_Mensual = 2500,
Distancia_Casa = 20,
Antigüedad = 1,
Satisfación_Laboral = "Muy insatisfecho",
Estado_Civil = "Soltero",
Departamento = "RH"
)
# Predecir la probabilidad de rotación
prob_rotacion <- predict(modelo_logistico, newdata = empleado_hipotetico, type = "response")
cat("La probabilidad predicha de que el empleado hipotético rote es del:", round(prob_rotacion * 100, 2), "%\n")## La probabilidad predicha de que el empleado hipotético rote es del: 72.78 %
# Definir un punto de corte (threshold) para intervenir
# Dado el desbalance de clases, el corte de 0.5 casi no detecta rotación,
# por lo que se usa el corte óptimo (índice de Youden) hallado en el punto 5.
corte_intervencion <- corte_optimo
cat("Punto de corte para intervenir:", round(corte_intervencion, 3), "\n")## Punto de corte para intervenir: 0.216
# Decisión de intervención
if (prob_rotacion > corte_intervencion) {
cat("\nDecisión: INTERVENIR al empleado.\n")
cat("Estrategia sugerida: Programar una reunión inmediata (1 a 1) para entender el origen de su insatisfacción.\nConsiderar revisión salarial, ofrecer flexibilidad para trabajo remoto (por la distancia a casa) o cambiarlo de proyecto/área.")
} else {
cat("\nDecisión: NO INTERVENIR en este momento.\n")
cat("El empleado tiene una probabilidad de rotación baja, mantener seguimiento normal.")
}##
## Decisión: INTERVENIR al empleado.
## Estrategia sugerida: Programar una reunión inmediata (1 a 1) para entender el origen de su insatisfacción.
## Considerar revisión salarial, ofrecer flexibilidad para trabajo remoto (por la distancia a casa) o cambiarlo de proyecto/área.
El empleado hipotético (soltero, muy insatisfecho, con ingreso de 2.500, que vive a 20 km y lleva 1 año en la empresa) tiene una probabilidad estimada de rotar de 72.78%, frente a un corte de 21.6%. Por lo tanto, se debe intervenir. La intervención se enfoca en las variables significativas del modelo que la empresa puede modificar: la satisfacción laboral, el salario y las condiciones de desplazamiento.
En las conclusiones adicione una discusión sobre cuál sería la estrategia para disminuir la rotación en la empresa (con base en las variables que resultaron significativas en el punto 3).
Satisfacción Laboral como Factor Crítico: La insatisfacción laboral es un predictor fuerte de la rotación. Los empleados que se sienten “muy insatisfechos” tienen una probabilidad significativamente mayor de dejar la empresa. Esto indica que la satisfacción laboral debe ser una prioridad para la empresa.
Ingreso Mensual: El salario es uno de los determinantes más claros de la rotación: los empleados que rotan ganan en promedio cerca de 2.000 unidades menos que los que permanecen, y a mayor ingreso los odds de rotar disminuyen de forma significativa.
Impacto del Estado Civil: Los empleados solteros tienden a tener una probabilidad mucho mayor de rotación en comparación con aquellos que están casados o divorciados. Esto sugiere que las condiciones personales pueden influir en la decisión de permanecer en la empresa.
Antigüedad y Compromiso: La antigüedad tiene un efecto negativo en la rotación, lo que sugiere que los empleados que llevan más tiempo en la empresa son menos propensos a dejarla. Esto resalta la importancia de fomentar el compromiso a largo plazo.
Efecto de la Distancia: La distancia desde el hogar también se relaciona con la rotación, indicando que los empleados que viven más lejos pueden sentirse menos vinculados a la empresa. Esto puede ser un factor a considerar en políticas de trabajo remoto o flexibilidad.
Departamento de Ventas: Los empleados del departamento de Ventas tienen una mayor propensión a la rotación que los de IyD, con un efecto significativo. Esto puede indicar problemas específicos en ese departamento, como la presión por metas o la dependencia de comisiones, que necesitan ser abordados. Recursos Humanos también muestra una rotación algo mayor, pero el efecto no es significativo.
Capacidad predictiva del modelo: El modelo es globalmente significativo, pero su capacidad de discriminación es limitada (AUC = 0.6808), por lo que debe usarse como herramienta de alerta temprana y no como predictor exacto. Además, por el desbalance de la rotación, el corte de 0.5 no es útil y es preferible el corte basado en la curva ROC (0.216).
Revisión de la Compensación: Revisar la escala salarial de los cargos con menores ingresos y compararla con el mercado, ya que el ingreso es uno de los determinantes más claros de la rotación. Se puede complementar con bonificaciones por permanencia.
Retención en los Primeros Años: Como el riesgo es mayor en los empleados con poca antigüedad, fortalecer la inducción, asignar mentores y definir planes de carrera desde el ingreso.
Mejorar la Satisfacción Laboral: Implementar encuestas regulares de satisfacción laboral y actuar sobre los resultados. Crear programas de reconocimiento y recompensas para los empleados que se sientan valorados.
Desarrollo Profesional: Ofrecer oportunidades de desarrollo y capacitación. Programas de mentoría y planes de carrera pueden ayudar a aumentar la satisfacción y el compromiso.
Flexibilidad Laboral: Considerar políticas de trabajo flexible o remoto, especialmente para aquellos que viven lejos de la oficina. Esto puede ayudar a reducir la rotación al mejorar la calidad de vida de los empleados.
Atención a la Diversidad en el Estado Civil: Desarrollar programas de bienestar que aborden las necesidades de diferentes grupos de empleados, incluyendo aquellos que son solteros. Esto podría incluir actividades sociales o de integración.
Análisis de la Rotación en Ventas: Realizar un análisis más profundo de por qué los empleados en el departamento de Ventas tienden a rotar más, revisando metas, carga de trabajo y esquema de comisiones. Podría ser útil llevar a cabo entrevistas de salida para entender mejor sus motivaciones.
Fomentar la Cultura Organizacional: Crear una cultura organizacional positiva que fomente la comunicación abierta y el apoyo entre empleados. Esto puede ayudar a crear un ambiente donde los empleados se sientan cómodos y valorados.
Al abordar estos factores y poner en práctica estrategias específicas, la empresa puede mejorar la satisfacción y el compromiso de los empleados, lo que a su vez puede reducir la rotación y contribuir a un entorno de trabajo más estable y productivo.