#install.packages("devtools") # solo la primera vez
#devtools::install_github("centromagis/paqueteMODELOS", force =TRUE)
library(paqueteMODELOS)
data("rotacion")
#install.packages("dlookr")
#install.packages("ggcorrplot")
#install.packages("caret")
#install.packages("pROC")
library(paqueteMODELOS)
library(dplyr)
library(dlookr)
library(caret)
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, …
library(pROC)
# Crear el dataframe de seguridad
df <- as.data.frame(rotacion)
df <- df %>%
rename(Attrition = Rotación)
Estadisticas descriptivas:
describe(df)
## # A tibble: 16 × 26
## described_variables n na mean sd se_mean IQR skewness
## <chr> <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Edad 1470 0 3.69e1 9.14e+0 2.38e-1 13 0.413
## 2 Distancia_Casa 1470 0 9.19e0 8.11e+0 2.11e-1 12 0.958
## 3 Educación 1470 0 2.91e0 1.02e+0 2.67e-2 2 -0.290
## 4 Satisfacción_Ambiental 1470 0 2.72e0 1.09e+0 2.85e-2 2 -0.322
## 5 Satisfación_Laboral 1470 0 2.73e0 1.10e+0 2.88e-2 2 -0.330
## 6 Ingreso_Mensual 1470 0 6.50e3 4.71e+3 1.23e+2 5468 1.37
## 7 Trabajos_Anteriores 1470 0 2.69e0 2.50e+0 6.52e-2 3 1.03
## 8 Porcentaje_aumento_salarial 1470 0 1.52e1 3.66e+0 9.55e-2 6 0.821
## 9 Rendimiento_Laboral 1470 0 3.15e0 3.61e-1 9.41e-3 0 1.92
## 10 Años_Experiencia 1470 0 1.13e1 7.78e+0 2.03e-1 9 1.12
## 11 Capacitaciones 1470 0 2.80e0 1.29e+0 3.36e-2 1 0.553
## 12 Equilibrio_Trabajo_Vida 1470 0 2.76e0 7.06e-1 1.84e-2 1 -0.552
## 13 Antigüedad 1470 0 7.01e0 6.13e+0 1.60e-1 6 1.76
## 14 Antigüedad_Cargo 1470 0 4.23e0 3.62e+0 9.45e-2 5 0.917
## 15 Años_ultima_promoción 1470 0 2.19e0 3.22e+0 8.40e-2 3 1.98
## 16 Años_acargo_con_mismo_jefe 1470 0 4.12e0 3.57e+0 9.31e-2 5 0.833
## # ℹ 18 more variables: kurtosis <dbl>, p00 <dbl>, p01 <dbl>, p05 <dbl>,
## # p10 <dbl>, p20 <dbl>, p25 <dbl>, p30 <dbl>, p40 <dbl>, p50 <dbl>,
## # p60 <dbl>, p70 <dbl>, p75 <dbl>, p80 <dbl>, p90 <dbl>, p95 <dbl>,
## # p99 <dbl>, p100 <dbl>
Missing Values
na_df <- data.frame(
Variable = names(df),
Missing = colSums(is.na(df)),
row.names = NULL
)
na_df
## Variable Missing
## 1 Attrition 0
## 2 Edad 0
## 3 Viaje de Negocios 0
## 4 Departamento 0
## 5 Distancia_Casa 0
## 6 Educación 0
## 7 Campo_Educación 0
## 8 Satisfacción_Ambiental 0
## 9 Genero 0
## 10 Cargo 0
## 11 Satisfación_Laboral 0
## 12 Estado_Civil 0
## 13 Ingreso_Mensual 0
## 14 Trabajos_Anteriores 0
## 15 Horas_Extra 0
## 16 Porcentaje_aumento_salarial 0
## 17 Rendimiento_Laboral 0
## 18 Años_Experiencia 0
## 19 Capacitaciones 0
## 20 Equilibrio_Trabajo_Vida 0
## 21 Antigüedad 0
## 22 Antigüedad_Cargo 0
## 23 Años_ultima_promoción 0
## 24 Años_acargo_con_mismo_jefe 0
# Se adiciona equivalencia de rotación
df$rotacion_2 <- ifelse(df$Attrition == "Si", 1, 0)
# Se seleccionan las variables númericas del dataset
df_num <- df[ , sapply(df, is.numeric)]
# Generación de matriz de correlación
cor_matrix <- cor(df_num, use = "complete.obs", method = "pearson")
library(ggcorrplot)
## Warning: package 'ggcorrplot' was built under R version 4.4.3
cor_matrix <- cor(df_num, use = "complete.obs", method = "pearson")
ggcorrplot(cor_matrix,
hc.order = TRUE, # cluster similar variables
type = "lower", # only lower triangle
lab = TRUE, # add correlation values
lab_size = 4,
tl.cex = 10,
colors = c("red", "white", "blue"),
title = "Correlation Matrix Heatmap")
## Warning: `aes_string()` was deprecated in ggplot2 3.0.0.
## ℹ Please use tidy evaluation idioms with `aes()`.
## ℹ See also `vignette("ggplot2-in-packages")` for more information.
## ℹ The deprecated feature was likely used in the ggcorrplot package.
## Please report the issue at <https://github.com/kassambara/ggcorrplot/issues>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
No se encuentran correlaciones positivas muy grandes entre la variable rotacion_2 (1 o 0), sin embargo si existen correlaciones negativas que indican las variables que más podrían agregar valor al modelo como lo son Angigüedad_Cargo, Años con le mismo jefe, Edad, Ingreso_Mensual, Años de experiencia y Satisfacción Laboral. Variables que dentro del contexto del problema si son críticas, puesto que la edad y el salario son variables que influeyen la toma de decisión para cambiar de trabajo.
# Selección de variables categoricas
df_nonnum <- df[ , !sapply(df, is.numeric)]
Estadisticas descriptividad de edad:
summary(df_num$Edad)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 18.00 30.00 36.00 36.92 43.00 60.00
Se puede evidenciar que es un grupo de trabajo relativamente joven, que va desde los 18 hasta los 60 años, sin embargo la mayoría se esta concentrando entre los 30 y 40 años, ajustandose a una distribución normal. Dentro del análisis del negocio, es una muestra buena pues tiene en cuenta una edad en la que por lo general se llega a una madurez laboral temprana y es importante retener los talentos que pasan de junior a senior y puedan aportar a la compañía
ggplot(df_num, aes(x = Edad)) +
geom_histogram(binwidth = 5, fill = "#91C7FA", color = "#000000", alpha = 0.7) +
labs(title = "Distribución de Edad", x = "Edad", y = "Frecuencia") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
axis.title = element_text(size = 14),
axis.text = element_text(size = 12)
)
Estadisticas descriptivas Antigüedad en el cargo:
summary(df_num$Antigüedad_Cargo)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.000 2.000 3.000 4.229 7.000 18.000
ggplot(df_num, aes(x = Antigüedad_Cargo)) +
geom_histogram(binwidth = 5, fill = "#91C7FA", color = "#000000", alpha = 0.7) +
labs(title = "Distribución de Antigüedad en el cargo", x = "Antiguedad", y = "Frecuencia") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
axis.title = element_text(size = 14),
axis.text = element_text(size = 12)
)
Se puede evidenciar que los empleados se concentran entre los 0 y 5 años de antigüedad.
Estadistias descriptivas del ingreso mensual:
summary(df_num$Ingreso_Mensual)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1009 2911 4919 6503 8379 19999
ggplot(df_num, aes(x = Ingreso_Mensual)) +
geom_histogram(binwidth = 500, fill = "#91C7FA", color = "#000000", alpha = 0.7) +
labs(title = "Distribucion de Ingreso Mensual", x = "Ingreso Mensual", y = "Frecuencia") +
scale_x_continuous(labels = scales::comma) + # Añadir comas en los números grandes del eje x
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
axis.title = element_text(size = 14),
axis.text = element_text(size = 12)
)
Esta es una variable fundamental para el análisis del attrition y tiene un promedio de 4919, sin embargo es un valor que está sesgado ya que se tiene una base con múltiples cargos que tienen perfiles diferentes y por ende grados salariales diferentes.
ggplot(df_nonnum, aes(x = Departamento)) +
geom_bar(fill = "#91C7FA", color = "#000000", alpha = 0.7) +
geom_text(stat = "count", aes(label = after_stat(count)),
vjust = -0.3, size = 4) +
labs(title = "Distribucion Departamento", x = "Departamento", y = "Frecuencia") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
axis.title = element_text(size = 14),
axis.text = element_text(size = 12)
)
La mayor cantidad de empleados están en las áreas de Investigación y desarrollo y ventas
# Crear gráfico de barras para una variable categórica
ggplot(df_nonnum, aes(y = Horas_Extra)) +
geom_bar(fill = "#91C7FA", color = "#000000", alpha = 0.7) +
geom_text(stat = "count",
aes(x = after_stat(count), label = after_stat(count)),
hjust = 1.2, color = "black", size = 4) +
labs(title = "Distribucion de Horas Extra", x = "Frecuencia", y = "Horas Extra") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
axis.title = element_text(size = 14),
axis.text = element_text(size = 12)
)
Aproximadamente el 28% de los colaboradores está tomando horas extras para cumplir con sus objetivos.
ggplot(df, aes(x = Attrition, y = Edad, color = Attrition)) +
geom_boxplot() +
geom_jitter(width = 0.3) +
labs(x = "Rotacion", y = "Edad",
title = "Distribución de Edad por Attrition")
De acuerdo con la gráfica anterior, las personas más jovenes tienden a abandonar la compañía ya que la media de ellos es inferior
ggplot(df, aes(x = Attrition, y = Antigüedad_Cargo, color = Attrition)) +
geom_boxplot() +
geom_jitter(width = 0.3) +
labs(x = "Rotacion", y = "Antigüedad_Cargo",
title = "Distribución de Antigüedad_Cargo por Attrition")
Un comportamiento muy similar a la edad, las personas con menor antigüedad en el cargo tienden a abandonar la compañía, puede ser debido a búsqueda de una mejora salarial que puede obtener al cambiar de empleo o de nuevos retos profesionales.
ggplot(df, aes(x = Attrition, y = Ingreso_Mensual, color = Attrition)) +
geom_boxplot() +
geom_jitter(width = 0.3) +
labs(x = "Rotacion", y = "Ingreso_Mensual",
title = "Distribución de Ingreso_Mensual por Attrition")
A pesar de que existe un mix de cargos en el data set, son los colaboradores con menor salario los que muestran una tendencia a abandonar la compañía
# Se crea tabla para análisis cruzado
df_he = table(df$Attrition, df$Horas_Extra)
# Se crea tabla incluyendo los porcentajes
df_he_pct1 <- prop.table(df_he, margin = 1) * 100
# Visualización de las tablas
df_he # En valores
##
## No Si
## No 944 289
## Si 110 127
#df_he_pct1 # Con porcentajes
# Se crea una variante en la manera de calcular los porcentajes
df_he_pct2 <- prop.table(df_he, margin = 2) * 100
#df_he_pct2
Se realiza test de chi-cuadrado para evaluar si hay asociación entre las dos variables categoricas
# Prueba de Chi Cuadrado
chisq.test(df_he)
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: df_he
## X-squared = 87.564, df = 1, p-value < 2.2e-16
El resultado del chi-cuadrado (p-value = 2.2e-16) indica una relación estadísticamente significativa entre Horas Extras y Rotación de personal. Esto significa que la decisión de renunciar no es independiente de trabajar horas extras, aunque se requiere revisar las frecuencias para identificar la dirección de la relación
# Convert to dataframe for ggplot
df_he_pct1 <- as.data.frame(df_he_pct1)
names(df_he_pct1) <- c("Attrition", "Horas_Extra", "Percentage")
# Plot with labels
ggplot(df_he_pct1, aes(x = Horas_Extra,
y = Percentage,
fill = Attrition)) +
geom_col(position = position_dodge(width = 0.9), alpha = 0.8) +
geom_text(aes(label = sprintf("%.1f%%", Percentage)),
position = position_dodge(width = 0.9),
vjust = -0.3, size = 4) +
scale_fill_manual(values = c("No" = "lightblue",
"Si" = "#d62728")) +
labs(title = "Porcentaje de Horas_Extra por Attrition (1)",
x = "Horas_Extra",
y = "Porcentaje (%)") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
axis.title = element_text(size = 14),
axis.text = element_text(size = 12)
)
# Convert to dataframe for ggplot
df_he_pct2 <- as.data.frame(df_he_pct2)
names(df_he_pct2) <- c("Attrition", "Horas_Extra", "Percentage")
# Plot with labels
ggplot(df_he_pct2, aes(x = Horas_Extra,
y = Percentage,
fill = Attrition)) +
geom_col(position = position_dodge(width = 0.9), alpha = 0.8) +
geom_text(aes(label = sprintf("%.1f%%", Percentage)),
position = position_dodge(width = 0.9),
vjust = -0.3, size = 4) +
scale_fill_manual(values = c("No" = "lightblue",
"Si" = "#d62728")) +
labs(title = "Porcentaje de Horas_Extra por Attrition (2)",
x = "Horas_Extra",
y = "Porcentaje (%)") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
axis.title = element_text(size = 14),
axis.text = element_text(size = 12)
)
De las personas que si tomaron horas extras, el 30,5% renunció, mientras que el 69.5% trabajaban dentro de su horario regular decidieron permanecer. Un indicador importante para el análisis de la distribución de cargas laborales
# Se crea tabla para análisis cruzado
df_sl = table(df$Attrition, df$Satisfación_Laboral)
# Se crea tabla incluyendo los porcentajes
df_sl_pct1 <- prop.table(df_sl, margin = 1) * 100
# Se crea una variante en la manera de calcular los porcentajes
df_sl_pct2 <- prop.table(df_sl, margin = 2) * 100
#df_sl_pct2
df_sl
##
## 1 2 3 4
## No 223 234 369 407
## Si 66 46 73 52
#df_sl_pct1
Se realiza test de chi-cuadrado para evaluar si hay asociación entre las dos variables categoricas
# Prueba de Chi Cuadrado
chisq.test(df_sl)
##
## Pearson's Chi-squared test
##
## data: df_sl
## X-squared = 17.505, df = 3, p-value = 0.0005563
El p-value = 0.0005563 indica que la rotación de personal está asociada significativamente con la satisfacción laboral: a menor satisfacción, mayor probabilidad de renunciar
library(ggplot2)
# Convert to dataframe for ggplot
df_sl_pct1 <- as.data.frame(df_sl_pct1)
names(df_sl_pct1) <- c("Attrition", "Satisfacion_Laboral", "Percentage")
# Plot with labels
ggplot(df_sl_pct1, aes(x = Satisfacion_Laboral,
y = Percentage,
fill = Attrition)) +
geom_col(position = position_dodge(width = 0.9), alpha = 0.8) +
geom_text(aes(label = sprintf("%.1f%%", Percentage)),
position = position_dodge(width = 0.9),
vjust = -0.3, size = 4) +
scale_fill_manual(values = c("No" = "lightblue",
"Si" = "#d62728")) +
labs(title = "Porcentaje de Satisfacción Laboral por Attrition",
x = "Satisfacción Laboral",
y = "Porcentaje (%)") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
axis.title = element_text(size = 14),
axis.text = element_text(size = 12)
)
Aproximadamente el 31% de los colaboradores que abandonó la empresa estaban Satisfechos con su trabajo actual, siendo la proporción más alta, sin embargo muy cercano a la proporción de colaboradres Muy Insatisfechos con un 28%. Lo que puede indicar presencia de un mercado laboral atractivo en el área de la organización, ya que apesar de estar satisfechos dejan la empresa por algo en teoría mejor.
# Convert to dataframe for ggplot
df_sl_pct2 <- as.data.frame(df_sl_pct2)
names(df_sl_pct2) <- c("Attrition", "Satisfacion_Laboral", "Percentage")
# Plot with labels
ggplot(df_sl_pct2, aes(x = Satisfacion_Laboral,
y = Percentage,
fill = Attrition)) +
geom_col(position = position_dodge(width = 0.9), alpha = 0.8) +
geom_text(aes(label = sprintf("%.1f%%", Percentage)),
position = position_dodge(width = 0.9),
vjust = -0.3, size = 4) +
scale_fill_manual(values = c("No" = "lightblue",
"Si" = "#d62728")) +
labs(title = "Porcentaje de Satisfacción Laboral por Attrition",
x = "Satisfacción Laboral",
y = "Porcentaje (%)") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
axis.title = element_text(size = 14),
axis.text = element_text(size = 12)
)
df$Attrition <- factor(df$Attrition, levels = c("No","Si"),labels = c(0,1))
#df$Attrition<- as.numeric(df$Attrition=="Si")
#rotacion$Estado_Civil <- as.factor(rotacion$Estado_Civil)
df$Horas_Extra <- as.factor(df$Horas_Extra)
df$Departamento <- as.factor(df$Departamento)
#rotacion$Satisfación_Laboral <- as.factor(rotacion$Satisfación_Laboral)
mod1 <- glm(Attrition ~ Edad + Antigüedad_Cargo + Ingreso_Mensual + Horas_Extra + Departamento + Satisfación_Laboral, data = df, family = binomial(link = "logit"))
summary(mod1)
##
## Call:
## glm(formula = Attrition ~ Edad + Antigüedad_Cargo + Ingreso_Mensual +
## Horas_Extra + Departamento + Satisfación_Laboral, family = binomial(link = "logit"),
## data = df)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 3.615e-01 3.758e-01 0.962 0.336038
## Edad -3.167e-02 1.005e-02 -3.150 0.001631 **
## Antigüedad_Cargo -1.054e-01 2.685e-02 -3.925 8.69e-05 ***
## Ingreso_Mensual -8.738e-05 2.642e-05 -3.307 0.000942 ***
## Horas_ExtraSi 1.482e+00 1.569e-01 9.445 < 2e-16 ***
## DepartamentoRH 4.447e-01 3.633e-01 1.224 0.220886
## DepartamentoVentas 6.704e-01 1.657e-01 4.047 5.19e-05 ***
## Satisfación_Laboral -3.117e-01 6.875e-02 -4.533 5.80e-06 ***
## ---
## 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: 1100.8 on 1462 degrees of freedom
## AIC: 1116.8
##
## Number of Fisher Scoring iterations: 5
Resultados:
Edad (Estimate = -0.0317, p = 0.0016) → A mayor edad, menor probabilidad de rotación.
Antigüedad en el cargo (Estimate = -1.075, p < 0.001) → A mayor antigüedad, menor probabilidad de rotación.
Ingreso mensual (Estimate = -0.0046, p = 0.0094) → A mayor ingreso, menor probabilidad de rotación.
Horas Extra (Sí) (Estimate = 1.482, p < 0.001) → Quienes hacen horas extra tienen mayor probabilidad de renunciar.
Departamento RH (Estimate = 1.447, p = 0.2208) → No es significativo, no podemos concluir relación.
Departamento Ventas (Estimate =+6.704, p < 0.001) → Muy significativo; empleados del departamento de Ventas tienen una probabilidad mucho mayor de rotación en comparación a los otros
Satisfacción Laboral (Estimate = -3.117, p < 0.001) → A mayor satisfacción laboral, menor probabilidad de rotación. Adicional, como se está manejando una escala progresiva se asume que el salto de 1 a 2 es igual de fuerte que el de 3 a 4, obteniendo el mismo efecto lineal sobre la probabilidad de renunciar
# Dividir la base de datos en conjuntos de entrenamiento y prueba
set.seed(123)# Para reproducibilidad
indice_particion <- createDataPartition(rotacion$Rotación, p = 0.7, list = FALSE)
df_training <- df[indice_particion, ]
df_testing <- df[-indice_particion, ]
# Entrenar el modelo
mod2 <- glm(Attrition ~ Edad + Antigüedad_Cargo + Ingreso_Mensual + Departamento + Horas_Extra + Satisfación_Laboral, data = df_training, family = binomial(link = "logit"))
summary(mod2)
##
## Call:
## glm(formula = Attrition ~ Edad + Antigüedad_Cargo + Ingreso_Mensual +
## Departamento + Horas_Extra + Satisfación_Laboral, family = binomial(link = "logit"),
## data = df_training)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 1.692e-01 4.552e-01 0.372 0.710170
## Edad -2.582e-02 1.217e-02 -2.122 0.033878 *
## Antigüedad_Cargo -1.189e-01 3.206e-02 -3.708 0.000209 ***
## Ingreso_Mensual -8.519e-05 3.129e-05 -2.723 0.006475 **
## DepartamentoRH 4.286e-01 4.031e-01 1.063 0.287638
## DepartamentoVentas 5.922e-01 1.953e-01 3.033 0.002425 **
## Horas_ExtraSi 1.349e+00 1.855e-01 7.276 3.45e-13 ***
## Satisfación_Laboral -2.710e-01 8.168e-02 -3.317 0.000909 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 909.69 on 1029 degrees of freedom
## Residual deviance: 781.31 on 1022 degrees of freedom
## AIC: 797.31
##
## Number of Fisher Scoring iterations: 5
levels(df_training$Attrition)
## [1] "0" "1"
valor_pronosticado <- predict(mod2, newdata = df_training, type = "response")
curva_roc <- roc(df_training$Attrition, valor_pronosticado,
levels = c("0", "1"), direction = "<")
auc(curva_roc)
## Area under the curve: 0.7541
plot(curva_roc, col = "blue", main = "Curva ROC - Modelo Logístico")
Con un AUC de 0.7541 se concluye que el modelo tiene un buen poder
predictivo, es decir, logra distinguir bastante bien entre empleados que
se van y los que se quedan. No es excelente, pero es una base sólida que
permitirá tomar decisiones para crear estrategias para los planes de
carrera y equilibrio laboral en la compañía
set.seed(1112228283) # Semilla para aleatoriedad
random_number <- sample(1:nrow(rotacion), 1) # Se selecciona una fila aleatoria para evaluar
# Selección y visualización del registro a evaluar
predict_sample = rotacion[random_number,]
predict_sample
## # A tibble: 1 × 24
## Rotación Edad `Viaje de Negocios` Departamento Distancia_Casa Educación
## <chr> <dbl> <chr> <chr> <dbl> <dbl>
## 1 No 26 Raramente IyD 4 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>
De acuerdo con el valor aleatorio generado, se obtuvo una mujer soltera de 26 años pertenenciente al departamento de Investigación & Desarrollo que aunque realiza horas extras, se encuentra muy satisfecha laboralmente y cuenta con 8 años de experiencia laboral que han sido dentro de la compañía, en la cual lleva 5 años en el mismo cargo y 2 bajo la misma dirección
# Resultados del modelo
logit_results <- predict(mod2, newdata = predict_sample, type = "link") # Log-odds
odds_results <- exp(logit_results) # Odds
prob_results <- odds_results / (1 + odds_results) # Probabilidades
# Crear un dataframe con los resultados
resultados_df <- data.frame(
Empleado = 1:length(prob_results),
Odds = odds_results,
Probabilidad_Rotacion = prob_results
)
# Mostrar la tabla
print(resultados_df)
## Empleado Odds Probabilidad_Rotacion
## 1 1 0.3409803 0.2542769
Según el modelo mod2, la empleada seleccionada tiene una baja probabilidad de attrition (25%), y es más probable que permanezca en la empresa que que se vaya, lo cual indica que el modelo refleja coherencia pues al estar satisfecha y con estabilidad, la probabilidad de rotación tienda a bajar
Asimismo, al obtener un Odds menor que 1 e igual a 0.341, significa que la probabilidad de que esta persona se vaya es menor que la de que se quede y se puede decir que por cada un empleado que se va, hay aproximadamente 2.9 que se quedan
El modelo podría mejorarse segementando inicialmente el dataset por tipos de cargos, como por ejemplo cargos operativos, cargos de análisis y cargos estrátegicos que permitan unos grupos más homogéneos y darle otro enfoque con mayor detalle al problema. Sin embargo, aplicar una regresión logística a problemas de attrition es una base para la toma de decisiones de acuerdo con los resultados y pruebas obtenidas, que permitiría los equipos de RH crear indicadores y alertas para disminuir el attrition con una fuerza laboral motivada y eficiente.
La selección de variables fue adecuada y permitieron dar valor al modelo, inclusó se pudo observar o confirmar que los departamentos de ventas suelen tener alta rotación.
Se propone establecer límites de horas extras y promover una mejor distribución de la carga laboral a través de una revisión de los perfiles y/o descripciones del cargo, ya que de acuerdo con el valor p muy significativo, el exceso de horas extras está altamente asociado con la rotación. Al reducirlas se disminuye el desgaste y el burnout.
Es relativamente complejo generar una estrategia, ya que como se mencionó anteriormente, existe un mix de cargos y niveles profesionales. No obstante se puede diseñar un bono de objetivos de la compañía para repartir en la nómina, dando así una bonificación de resultados.
Realizar una encuesta de ambiente laboral para identificar cuáles son los posibles motivos por área que están generando descontento
Diseñar un plan carrera para promover los ascensos o movimientos verticales que permitan a los colaboradores durar y aportar más a la compañía en diferentes áreas
La mejora en la satisfacción laboral se evidenciará al gestionar los puntos anteriormente comentados.