Nota: Docmumento académico para la Maestría en ciencia de datos de la Universidad Javeriana de Cali
En una organización, se busca comprender y prever los factores que influyen en la rotación de empleados entre distintos cargos. La empresa ha recopilado datos históricos sobre el empleo de sus trabajadores, incluyendo variables como la antigüedad en el cargo actual, el nivel de satisfacción laboral, el salario actual, edad y otros factores relevantes. La gerencia planea desarrollar un modelo de regresión logística que permita estimar la probabilidad de que un empleado cambie de cargo en el próximo período y determinar cuales factores indicen en mayor proporción a estos cambios.
Con esta información, la empresa podrá tomar medidas proactivas para retener a su talento clave, identificar áreas de mejora en la gestión de recursos humanos y fomentar un ambiente laboral más estable y tranquilo. La predicción de la probabilidad de rotación de empleados ayudará a la empresa a tomar decisiones estratégicas informadas y a mantener un equipo de trabajo comprometido y satisfecho en sus roles actuales.
Para replicar el análisis, inicie instalando el paquete paqueteMODELOS desde GitHub. Posteriormente, cargue dicho paquete junto con dplyr en rstudio.
Se revisa la información contenida en el archivo base
Tamaño de la base
Es una base con 24 columnas y 1470 observaciones
## [1] 1470 24
Lista de Variables originales incluídas en la base
## [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"
Descripción y tipo de varaible
## 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, …
##
## 1 2 3 4 5
## 170 282 572 398 48
##
## IyD RH Ventas
## 961 63 446
##
## Ciencias Humanidades Mercadeo Otra Salud Tecnicos
## 606 27 159 82 464 132
##
## Director_Investigación Director_Manofactura Ejecutivo_Ventas
## 80 145 326
## Gerente Investigador_Cientifico Recursos_Humanos
## 102 292 52
## Representante_Salud Representante_Ventas Tecnico_Laboratorio
## 131 83 259
##
## Casado Divorciado Soltero
## 673 327 470
No hay missing values
##
## Attaching package: 'mice'
## The following object is masked from 'package:stats':
##
## filter
## The following objects are masked from 'package:base':
##
## cbind, rbind
## /\ /\
## { `---' }
## { O O }
## ==> V <== No need for mice. This data set is completely observed.
## \ \|/ /
## `-----'
## Rotación Edad Viaje de Negocios Departamento Distancia_Casa Educación
## 1470 1 1 1 1 1 1
## 0 0 0 0 0 0
## Campo_Educación Satisfacción_Ambiental Genero Cargo Satisfación_Laboral
## 1470 1 1 1 1 1
## 0 0 0 0 0
## Estado_Civil Ingreso_Mensual Trabajos_Anteriores Horas_Extra
## 1470 1 1 1 1
## 0 0 0 0
## Porcentaje_aumento_salarial Rendimiento_Laboral Años_Experiencia
## 1470 1 1 1
## 0 0 0
## Capacitaciones Equilibrio_Trabajo_Vida Antigüedad Antigüedad_Cargo
## 1470 1 1 1 1
## 0 0 0 0
## Años_ultima_promoción Años_acargo_con_mismo_jefe
## 1470 1 1 0
## 0 0 0
Seleccione 3 variables categóricas (distintas de rotación) y 3 variables cuantitativas, que se consideren estén relacionadas con la rotación.
Respuesta
Variables seleccioandas
Numéricas
Ingreso mensual: Los ingresos mensuales están relacionados con la rotación laboral, ya que un menor salario puede llevar a que los empleados busquen oportunidades mejor remuneradas. Se espera una relación negativa, a menor salario o ingreso mensual, mayor probabilidad de rotación laboral. [1]
Antigüedad: Según un análisis del Banco Mundial, existe una relación entre la “antigüedad” en el puesto de trabajo y la rotación laboral, donde una mayor antigüedad se asocia generalmente con mayor estabilidad y bienestar para el empleado. Sin embargo, esta relación puede seguir una forma de “U invertida”, ya que, después de cierto punto, la permanencia prolongada en un puesto puede llevar a un estancamiento, lo que podría incrementar la probabilidad de rotación laboral [2].
Distancia a Casa: Los largos desplazamientos al trabajo incrementan la rotación laboral, ya que reducen la productividad y creatividad de los empleados, especialmente los de alto rendimiento, se espera una relación positiva, de mayor desplazamiento al trabajo, mayor probabilidad de rotación [3]
Categóricas
Horas extra: Un estudio publicado en el Journal of Hospitality and Tourism Insights encontró que las horas extras y el exceso de trabajo tienen un impacto directo en la intención de rotación laboral, especialmente en empleados de hoteles no lujosos. El estudio también señaló que los incentivos no siempre moderan el efecto del trabajo excesivo y las horas extra en la rotación, sugiriendo que estas medidas por sí solas pueden no ser suficientes para retener a los empleados en este contexto, aún así se espera una relación positiva, los trabajadores con horas extra tienden a tener mayor rotación laboral.[4]
Equilibrio trabajo vida: Un estudio del International Journal of Organizational Analysis encontró que problemas con el equilibrio trabajo-vida reducen la satisfacción laboral y aumentan la intención de rotación entre los empleados, en este sentido se debe comparar con un nivel, usualmente uno bajo de equilibrio, en cuyo caso la relación debería ser negativa, mejores nivels de equilibrio, mayor probabilidad de rotación. [5]
Satisfacción laboral: Un estudio de Griffeth, Hom y Gaertner mostró que la satisfacción laboral tiene un impacto directo en la rotación de empleados. Según su meta-análisis, una disminución en la satisfacción laboral incrementa la intención de los empleados de dejar la empresa, lo que afecta las tasas de rotación. Para este caso como el anterio, al comparar niveles bajos de rotación con altos, el signo debe de ser negativo, por cuanto mayor insatisfacción, más probabilidad de rotar. [6]
[1] P. O’Donnell, “The Effect of Income and Working Conditions on Job Satisfaction,” School of Business, The College of New Jersey, 2015. Disponible en: https://business.tcnj.edu/wp-content/uploads/sites/219/2015/08/ECO-495-2015_Patrick-ODonnell.pdf
[2] M. Bussolo, D. Capelle, M. Lokshin, I. Torre, y H. Winkler, “Explaining the Evolution of Job Tenure in Europe, 1995–2020,” Policy Research Working Papers, World Bank, Washington, DC, 2022. [En línea]. Disponible en: https://blogs.worldbank.org/en/jobs/what-were-reading-about-job-tenure-european-labor-markets.
[3] X. Wu, H. Xiao, y J. Kim, “Commuting and Innovation: Are Closer Inventors More Productive?” Journal of Urban Economics, 2017. Disponible en: https://hbswk.hbs.edu/item/commuting-kills-productivity-and-your-best-talent-suffers-most
[4] K.-L. Tan, P.-L. Sim, F.-Q. Goh, C.-M. Leong y H. Ting, “Overwork and overtime on turnover intention in non-luxury hotels: Do incentives matter?”, Journal of Hospitality and Tourism Insights, vol. 3, no. 4, pp. 397-414, 2020. Disponible en: https://doi.org/10.1108/JHTI-09-2019-0104.
[5] P. K. Gautam, D. K. Gautam, y R. Bhetuwal, “Work-life balance, job satisfaction and turnover intentions among nurses,” International Journal of Organizational Analysis, 2024. Disponible en: https://www.emerald.com/insight/content/doi/10.1108/IJOA-09-2023-4002/full/html
[6] R. W. Griffeth, P. W. Hom, y S. Gaertner, “A meta-analysis of antecedents and correlates of employee turnover: Update, moderator tests, and research implications for the next millennium,” Journal of Management, vol. 26, no. 3, pp. 463–488, 2000. Disponible en: https://www.psihoprofile.ro/Content/Questionnaires/1/69/aA_Meta-Analysis_of_Antecedents_and_Corre20160213-22360-fjbwz8-with-cover-page-v2.pdf
Realiza un análisis univariado (caracterización) de la información contenida en la base de datos rotacion.
respuesta
Para nuestro análisis de regresión logística sobre rotación, hemos seleccionado tres variables numéricas (Ingreso Mensual, Antigüedad y Distancia a Casa) y tres categóricas (Horas Extra, Equilibrio Trabajo-Vida y Satisfacción Laboral). Aunque reconocemos que hay otras variables potencialmente relevantes, como Edad, Educación, Trabajos Anteriores, Porcentaje de Aumento Salarial, Años de Experiencia, Capacitaciones, Antigüedad en el Cargo, Años desde la Última Promoción, Viajes de Negocios, Departamento, Campo de Educación, Género, Estado Civil, y Rendimiento Laboral, hemos decidido trabajar solo con estas seis variables siguiendo las instrucciones que recibimos de nuestra profesora. Sabemos que esta limitación podría introducir sesgos en el análisis, pero dado que se trata de un ejercicio académico, los análisis univariados y el modelo estarán enfocados exclusivamente en estas variables y en la variable de rotación.
##
## No Si
## 1233 237
# Calcular la frecuencia absoluta y relativa
freq_abs <- table(rotacion$Rotación)
freq_rel <- prop.table(freq_abs)
# Mostrar la tabla de frecuencias
freq_table <- data.frame(Frecuencia_Absoluta = freq_abs, Frecuencia_Relativa = freq_rel)
print(freq_table)
## Frecuencia_Absoluta.Var1 Frecuencia_Absoluta.Freq Frecuencia_Relativa.Var1
## 1 No 1233 No
## 2 Si 237 Si
## Frecuencia_Relativa.Freq
## 1 0.8387755
## 2 0.1612245
# Gráfico de la frecuencia absoluta con colores y etiquetas
ggplot(data = rotacion, aes(x = Rotación)) +
geom_bar(fill = "orange") +
geom_text(stat='count', aes(label=..count..), vjust=-0.5) + # Añade etiquetas
ggtitle("Frecuencia Absoluta de Rotación") +
xlab("Rotación") +
ylab("Frecuencia Absoluta") +
theme_minimal()
## Warning: The dot-dot notation (`..count..`) was deprecated in ggplot2 3.4.0.
## ℹ Please use `after_stat(count)` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
# Gráfico de la frecuencia relativa con colores y etiquetas
ggplot(data = as.data.frame(freq_rel), aes(x = Var1, y = Freq)) +
geom_bar(stat = "identity", fill = "yellow") +
geom_text(aes(label=round(Freq, 2)), vjust=-0.5) + # Añade etiquetas con 2 decimales
ggtitle("Frecuencia Relativa de Rotación") +
xlab("Rotación") +
ylab("Frecuencia Relativa") +
theme_minimal()
Respecto a la distribución de la variable rotación, se identifica un desbalance en los datos. La categoría “No” representa el 83.88% (1,233 casos) de la muestra, mientras que la categoría “Sí” solo representa el 16.12% (237 casos). Esto indica que la mayoría de los casos corresponden a empleados que no han rotado
# Resumen estadístico para "Ingreso_Mensual" sin dividir por "Rotación"
cat("Resumen estadístico de Ingreso Mensual para todos los empleados:\n")
## Resumen estadístico de Ingreso Mensual para todos los empleados:
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1009 2911 4919 6503 8379 19999
# Crear un boxplot de Ingreso_Mensual sin considerar los valores de Rotación
ggplot(rotacion, aes(y = Ingreso_Mensual)) +
geom_boxplot(fill = "orange") +
ggtitle("Distribución de Ingreso Mensual") +
xlab("") +
ylab("Ingreso Mensual") +
theme_minimal()
Los ingresos mensuales de los empleados varían desde 1,009 hasta 19,999.
El 25% de ellos gana 2,911 o menos, mientras que la mitad tiene un
ingreso igual o inferior a 4,919. El promedio es 6,503, ligeramente
mayor que la mediana, lo que sugiere la presencia de algunos ingresos
altos. El 25% superior de los empleados tiene un ingreso de 8,379 o
más.
# Resumen estadístico para "Antigüedad" sin dividir por "Rotación"
cat("Resumen estadístico de Antigüedad para todos los empleados:\n")
## Resumen estadístico de Antigüedad para todos los empleados:
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.000 3.000 5.000 7.008 9.000 40.000
# Crear un boxplot de Antigüedad sin considerar los valores de Rotación
ggplot(rotacion, aes(y = Antigüedad)) +
geom_boxplot(fill = "#0071CE") +
ggtitle("Distribución de Antigüedad en la Compañía") +
xlab("") +
ylab("Antigüedad (años)") +
theme_minimal()
La antigüedad en la compañía oscila entre 0 y 40 años. Un cuarto de los empleados ha estado 3 años o menos, y la mitad cuenta con 5 años o menos en la empresa. El promedio se sitúa en 7 años, ligeramente por encima de la mediana, lo que sugiere la influencia de empleados con una larga trayectoria. El 25% con mayor antigüedad tiene al menos 9 años en la compañía, destacando un grupo de empleados con periodos de permanencia prolongados.
# Resumen estadístico para "Distancia_Casa" sin dividir por "Rotación"
cat("Resumen estadístico de Distancia a Casa para todos los empleados (en km):\n")
## Resumen estadístico de Distancia a Casa para todos los empleados (en km):
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.000 2.000 7.000 9.193 14.000 29.000
# Crear un boxplot de Distancia_Casa sin considerar los valores de Rotación
ggplot(rotacion, aes(y = Distancia_Casa)) +
geom_boxplot(fill = "#9B59B6") + # Usar el color morado
ggtitle("Distribución de Distancia a Casa") +
xlab("") +
ylab("Distancia a Casa (km)") +
theme_minimal()
La distancia a casa de los empleados varía entre 1 y 29 km. El 25% vive
a 2 km o menos, y la mitad se encuentra a una distancia de 7 km o menos.
El promedio es de 9.19 km, lo que indica que algunos empleados residen
bastante lejos, influyendo en este valor. El 25% que vive más lejos
tiene una distancia de al menos 14 km.
# Crear una tabla de contingencia solo con la variable Horas_Extra
tabla_contingencia <- table(rotacion$Horas_Extra)
# Calcular la frecuencia absoluta y relativa
freq_abs <- tabla_contingencia
freq_rel <- prop.table(tabla_contingencia)
# Mostrar la tabla de frecuencias
freq_table <- data.frame(Frecuencia_Absoluta = as.vector(freq_abs),
Frecuencia_Relativa = as.vector(freq_rel))
rownames(freq_table) <- names(freq_abs)
print(freq_table)
## Frecuencia_Absoluta Frecuencia_Relativa
## No 1054 0.7170068
## Si 416 0.2829932
# Gráfico de la frecuencia absoluta con colores y etiquetas para Horas_Extra
ggplot(as.data.frame(freq_abs), aes(x = names(freq_abs), y = Freq, fill = names(freq_abs))) +
geom_bar(stat = "identity", position = "dodge") +
geom_text(aes(label=Freq), position = position_dodge(width = 0.9), vjust=-0.5) +
ggtitle("Frecuencia Absoluta de Horas Extra") +
xlab("Horas Extra") +
ylab("Frecuencia Absoluta") +
scale_fill_manual(name = "Horas Extra", values = c("orange", "yellow")) +
theme_minimal()
# Gráfico de pastel para la variable "Horas Extra" sin segmentar por Rotación
df_contingencia <- as.data.frame(tabla_contingencia)
colnames(df_contingencia) <- c("Horas_Extra", "Frecuencia")
ggplot(df_contingencia, aes(x = "", y = Frecuencia, fill = Horas_Extra)) +
geom_bar(stat = "identity", width = 1) +
coord_polar("y", start = 0) +
geom_text(aes(label = paste0(round((Frecuencia / sum(Frecuencia)) * 100, 1), "%")),
position = position_stack(vjust = 0.5)) +
ggtitle("Distribución de Horas Extra para Todos los Empleados") +
scale_fill_manual(values = c("#0071CE", "#4E9D2D")) + # Colores moradito y rojito
theme_void()
El 71.7% de los empleados (1,054 personas) no realiza horas extra, mientras que el 28.3% (416 personas) sí lo hace.
# Crear una tabla de contingencia solo con la variable Equilibrio_Trabajo_Vida
tabla_contingencia <- table(rotacion$Equilibrio_Trabajo_Vida)
# Calcular la frecuencia absoluta y relativa
freq_abs <- tabla_contingencia
freq_rel <- prop.table(tabla_contingencia)
# Mostrar la tabla de frecuencias
freq_table <- data.frame(Frecuencia_Absoluta = as.vector(freq_abs),
Frecuencia_Relativa = as.vector(freq_rel))
rownames(freq_table) <- names(freq_abs)
print(freq_table)
## Frecuencia_Absoluta Frecuencia_Relativa
## 1 80 0.05442177
## 2 344 0.23401361
## 3 893 0.60748299
## 4 153 0.10408163
# Gráfico de la frecuencia absoluta con colores y etiquetas para Equilibrio_Trabajo_Vida
ggplot(as.data.frame(freq_abs), aes(x = names(freq_abs), y = Freq, fill = names(freq_abs))) +
geom_bar(stat = "identity", position = "dodge") +
geom_text(aes(label=Freq), position = position_dodge(width = 0.9), vjust=-0.5) +
ggtitle("Frecuencia Absoluta de Equilibrio Trabajo-Vida") +
xlab("Equilibrio Trabajo-Vida") +
ylab("Frecuencia Absoluta") +
scale_fill_manual(name = "Equilibrio Trabajo-Vida", values = c("#E74C3C","orange", "yellow", "#4E9D2D")) +
theme_minimal()
# Gráfico de pastel para la variable "Equilibrio_Trabajo_Vida" sin segmentar por Rotación
df_contingencia <- as.data.frame(tabla_contingencia)
colnames(df_contingencia) <- c("Equilibrio_Trabajo_Vida", "Frecuencia")
ggplot(df_contingencia, aes(x = "", y = Frecuencia, fill = Equilibrio_Trabajo_Vida)) +
geom_bar(stat = "identity", width = 1) +
coord_polar("y", start = 0) +
geom_text(aes(label = paste0(round((Frecuencia / sum(Frecuencia)) * 100, 1), "%")),
position = position_stack(vjust = 0.5)) +
ggtitle("Distribución de Equilibrio Trabajo-Vida para Todos los Empleados") +
scale_fill_manual(values = c("#E74C3C","orange", "yellow", "#4E9D2D")) + # Colores
theme_void()
La mayoría de los empleados percibe un equilibrio medio entre trabajo y vida personal, con un 60.7% (893 personas) calificándolo así. El 23.4% (344 personas) lo evalúa como bajo, mientras que el 10.4% (153 personas) lo considera alto. Solo el 5.4% (80 personas) reporta un equilibrio muy bajo. En general, la percepción más común es un equilibrio intermedio, aunque hay una proporción significativa que siente un desbalance negativo.
# Crear una tabla de contingencia solo con la variable Satisfacción_Laboral
tabla_contingencia <- table(rotacion$Satisfación_Laboral)
# Calcular la frecuencia absoluta y relativa
freq_abs <- tabla_contingencia
freq_rel <- prop.table(tabla_contingencia)
# Mostrar la tabla de frecuencias
freq_table <- data.frame(Frecuencia_Absoluta = as.vector(freq_abs),
Frecuencia_Relativa = as.vector(freq_rel))
rownames(freq_table) <- names(freq_abs)
print(freq_table)
## Frecuencia_Absoluta Frecuencia_Relativa
## 1 289 0.1965986
## 2 280 0.1904762
## 3 442 0.3006803
## 4 459 0.3122449
# Gráfico de la frecuencia absoluta con colores y etiquetas para Satisfacción Laboral
ggplot(as.data.frame(freq_abs), aes(x = names(freq_abs), y = Freq, fill = names(freq_abs))) +
geom_bar(stat = "identity", position = "dodge") +
geom_text(aes(label=Freq), position = position_dodge(width = 0.9), vjust=-0.5) +
ggtitle("Frecuencia Absoluta de Satisfacción Laboral") +
xlab("Satisfacción Laboral") +
ylab("Frecuencia Absoluta") +
scale_fill_manual(name = "Satisfacción Laboral", values = c("#E74C3C","orange", "yellow", "#4E9D2D")) +
theme_minimal()
# Gráfico de pastel para la variable "Satisfacción Laboral" sin segmentar por Rotación
df_contingencia <- as.data.frame(tabla_contingencia)
colnames(df_contingencia) <- c("Satisfacción_Laboral", "Frecuencia")
ggplot(df_contingencia, aes(x = "", y = Frecuencia, fill = Satisfacción_Laboral)) +
geom_bar(stat = "identity", width = 1) +
coord_polar("y", start = 0) +
geom_text(aes(label = paste0(round((Frecuencia / sum(Frecuencia)) * 100, 1), "%")),
position = position_stack(vjust = 0.5)) +
ggtitle("Distribución de Satisfacción Laboral para Todos los Empleados") +
scale_fill_manual(values = c("#E74C3C","orange", "yellow", "#4E9D2D")) + # Colores
theme_void()
La satisfacción laboral muestra que el 31.2% de los empleados (459 personas) se siente muy satisfecho, mientras que el 30.1% (442 personas) está satisfecho. Un 19.7% (289 personas) se encuentra muy insatisfecho y un 19.0% (280 personas) se considera insatisfecho. En general, la mayoría de los empleados tiene una percepción positiva de su ambiente laboral, aunque existe un grupo considerable que manifiesta insatisfacción.
Realiza un análisis de bivariado en donde la variable respuesta sea rotacion 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 hipotesis planteada en el punto 2.
# Resumen estadístico para "Ingreso_Mensual" para cada valor de "Rotación"
cat("Resumen estadístico de Ingreso Mensual para empleados que NO rotaron:\n")
## Resumen estadístico de Ingreso Mensual para empleados que NO rotaron:
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1051 3211 5204 6833 8834 19999
##
## Resumen estadístico de Ingreso Mensual para empleados que SÍ rotaron:
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1009 2373 3202 4787 5916 19859
# Crear un boxplot de Ingreso_Mensual por los valores de Rotación
ggplot(rotacion, aes(x = Rotación, y = Ingreso_Mensual, fill = Rotación)) +
geom_boxplot() +
ggtitle("Distribución de Ingreso Mensual por Rotación") +
xlab("Rotación") +
ylab("Ingreso Mensual") +
scale_fill_manual(values = c("orange", "yellow")) + # Asignar colores específicos
theme_minimal()
Los empleados que no rotaron tienen un ingreso mensual medianamente más alto (Mediana = 5204) en comparación con los empleados que sí rotaron (Mediana = 3202). El promedio de ingreso mensual también es mayor para quienes no rotaron (Media = 6833) frente a los que sí lo hicieron (Media = 4787). Además, los empleados que no rotaron presentan un rango más amplio de ingresos, con un mínimo de 1051 y un máximo de 19999, mientras que los que rotaron tienen un rango de 1009 a 19859. Esto indica que los empleados que no rotaron tienden a tener salarios más altos en general. Si la variable dependiente es la rotación (y=1) entonces, se espera que el signo de este coeficiente sea negativo (los que rotan tienen menores ingresos),
# Resumen estadístico para "Antigüedad" para cada valor de "Rotación"
cat("Resumen estadístico de Antigüedad para empleados que NO rotaron:\n")
## Resumen estadístico de Antigüedad para empleados que NO rotaron:
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.000 3.000 6.000 7.369 10.000 37.000
##
## Resumen estadístico de Antigüedad para empleados que SÍ rotaron:
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.000 1.000 3.000 5.131 7.000 40.000
# Crear un boxplot de Antigüedad por los valores de Rotación
ggplot(rotacion, aes(x = Rotación, y = Antigüedad, fill = Rotación)) +
geom_boxplot() +
ggtitle("Distribución de Antigüedad por Rotación") +
xlab("Rotación") +
ylab("Antigüedad (años)") +
scale_fill_manual(values = c("#0071CE", "#4E9D2D")) + # Asignar colores específicos
theme_minimal()
Se encuentra que los empleados que no rotaron tienen una mayor antigüedad en la compañía, con una mediana de 6 años y un promedio de 7.37 años, mientras que los empleados que sí rotaron tienen una mediana de 3 años y un promedio de 5.13 años. El rango de antigüedad también es más amplio para quienes no rotaron, con un máximo de 37 años, en comparación con 40 años para quienes sí rotaron. Esto indica que los empleados que no rotan tienden a permanecer más tiempo en la compañía. Por lo anterior, la antigüedad tiene un impacto negativo en la probabilidad de rotar, ya que los empleados con mayor antigüedad tienden a permanecer más tiempo en la compañía. Sin embargo, según la teoría revisada, esta relación sigue una forma de U invertida. Por ello, se incluirá la antigüedad al cuadrado en el modelo; se espera un signo negativo para la variable original y un signo positivo para su término cuadrático, lo que reflejaría que, después de ciertos niveles de antigüedad, puede producirse estancamiento y un aumento en la probabilidad de rotació
# Resumen estadístico para "Distancia_Casa" para cada valor de "Rotación"
cat("Resumen estadístico de Distancia a Casa para empleados que NO rotaron (en km):\n")
## Resumen estadístico de Distancia a Casa para empleados que NO rotaron (en km):
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.000 2.000 7.000 8.916 13.000 29.000
##
## Resumen estadístico de Distancia a Casa para empleados que SÍ rotaron (en km):
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.00 3.00 9.00 10.63 17.00 29.00
# Crear un boxplot de Distancia_Casa por los valores de Rotación
ggplot(rotacion, aes(x = Rotación, y = Distancia_Casa, fill = Rotación)) +
geom_boxplot() +
ggtitle("Distribución de Distancia a Casa por Rotación") +
xlab("Rotación") +
ylab("Distancia a Casa (km)") +
scale_fill_manual(values = c("#9B59B6", "#E74C3C")) + # Asignar colores morado y rojito
theme_minimal()
Los empleados que rotaron tienden a vivir más lejos del trabajo en comparación con los que no rotaron. La mediana de la distancia es de 9 km para quienes rotaron, mientras que es de 7 km para quienes no lo hicieron. El promedio también es mayor para los que rotaron (10.63 km) frente a los que no rotaron (8.92 km). Ambos grupos tienen la misma distancia máxima de 29 km, pero los que no rotaron tienden a vivir más cerca en general. Por lo anterior, el signo esperado es positivo, para la probabilidad de rotar, se espera que a mayor distnacia, mayor probabilidad de rotación.
# Crear una tabla de contingencia entre Rotación y Horas_Extra
tabla_contingencia <- table(rotacion$Rotación, rotacion$Horas_Extra)
# Calcular la frecuencia absoluta y relativa
freq_abs <- tabla_contingencia
freq_rel <- prop.table(tabla_contingencia)
# Mostrar la tabla de frecuencias
freq_table <- data.frame(Frecuencia_Absoluta = as.vector(freq_abs),
Frecuencia_Relativa = as.vector(freq_rel))
rownames(freq_table) <- paste(rep(rownames(freq_abs), each = ncol(freq_abs)), colnames(freq_abs), sep = " - ")
print(freq_table)
## Frecuencia_Absoluta Frecuencia_Relativa
## No - No 944 0.64217687
## No - Si 110 0.07482993
## Si - No 289 0.19659864
## Si - Si 127 0.08639456
# Gráfico de la frecuencia absoluta con colores y etiquetas para Rotación y Horas_Extra
ggplot(as.data.frame(freq_abs), aes(x = Var1, y = Freq, fill = Var2)) +
geom_bar(stat = "identity", position = "dodge") +
geom_text(aes(label=Freq), position = position_dodge(width = 0.9), vjust=-0.5) +
ggtitle("Frecuencia Absoluta de Rotación y Horas Extra") +
xlab("Rotación") +
ylab("Frecuencia Absoluta") +
scale_fill_manual(name = "Horas Extra", values = c("orange", "yellow")) +
theme_minimal()
# Crear una tabla de contingencia entre Rotación y Horas_Extra
tabla_contingencia <- table(rotacion$Rotación, rotacion$Horas_Extra)
# Convertir la tabla de contingencia en un data frame para facilitar el uso en ggplot
df_contingencia <- as.data.frame(tabla_contingencia)
colnames(df_contingencia) <- c("Rotación", "Horas_Extra", "Frecuencia")
# Filtrar los datos para cada valor de Rotación
df_si <- subset(df_contingencia, Rotación == "Si")
df_no <- subset(df_contingencia, Rotación == "No")
# Crear el gráfico de pastel para Rotación = "Sí"
ggplot(df_si, aes(x = "", y = Frecuencia, fill = Horas_Extra)) +
geom_bar(stat = "identity", width = 1) +
coord_polar("y", start = 0) +
geom_text(aes(label = paste0(round((Frecuencia / sum(Frecuencia)) * 100, 1), "%")),
position = position_stack(vjust = 0.5)) +
ggtitle("Distribución de Horas Extra para Rotación = Sí") +
scale_fill_manual(values = c("#0071CE", "#4E9D2D")) + # Colores moradito y rojito
theme_void()
# Crear el gráfico de pastel para Rotación = "No"
ggplot(df_no, aes(x = "", y = Frecuencia, fill = Horas_Extra)) +
geom_bar(stat = "identity", width = 1) +
coord_polar("y", start = 0) +
geom_text(aes(label = paste0(round((Frecuencia / sum(Frecuencia)) * 100, 1), "%")),
position = position_stack(vjust = 0.5)) +
ggtitle("Distribución de Horas Extra para Rotación = No") +
scale_fill_manual(values = c("#0071CE", "#4E9D2D")) + # Colores moradito y rojito
theme_void()
Hay una mayor proporción de empleados que realizaron horas extras entre aquellos que rotaron (53.6%), mientras que entre los que no rotaron, la mayoría no hizo horas extras (76.6%). Esto sugiere que la realización de horas extras podría estar relacionada con una mayor probabilidad de rotación laboral, entonces el signo esperado es positivo, tener horas extras tendería a incrementar la probabilidad de rotar.
# Crear una tabla de contingencia entre Rotación y Equilibrio_Trabajo_Vida
tabla_contingencia <- table(rotacion$Rotación, rotacion$Equilibrio_Trabajo_Vida)
# Calcular la frecuencia absoluta y relativa
freq_abs <- tabla_contingencia
freq_rel <- prop.table(tabla_contingencia)
# Mostrar la tabla de frecuencias
freq_table <- data.frame(Frecuencia_Absoluta = as.vector(freq_abs),
Frecuencia_Relativa = as.vector(freq_rel))
rownames(freq_table) <- paste(rep(rownames(freq_abs), each = ncol(freq_abs)), colnames(freq_abs), sep = " - ")
print(freq_table)
## Frecuencia_Absoluta Frecuencia_Relativa
## No - 1 55 0.03741497
## No - 2 25 0.01700680
## No - 3 286 0.19455782
## No - 4 58 0.03945578
## Si - 1 766 0.52108844
## Si - 2 127 0.08639456
## Si - 3 126 0.08571429
## Si - 4 27 0.01836735
# Gráfico de la frecuencia absoluta con colores y etiquetas para Rotación y Equilibrio_Trabajo_Vida
ggplot(as.data.frame(freq_abs), aes(x = Var1, y = Freq, fill = Var2)) +
geom_bar(stat = "identity", position = "dodge") +
geom_text(aes(label=Freq), position = position_dodge(width = 0.9), vjust=-0.5) +
ggtitle("Frecuencia Absoluta de Rotación y Equilibrio Trabajo-Vida") +
xlab("Rotación") +
ylab("Frecuencia Absoluta") +
scale_fill_manual(name = "Equilibrio Trabajo-Vida", values = c("#E74C3C","orange", "yellow", "#4E9D2D")) +
theme_minimal()
# Convertir la tabla de contingencia en un data frame para facilitar el uso en ggplot
df_contingencia <- as.data.frame(tabla_contingencia)
colnames(df_contingencia) <- c("Rotación", "Equilibrio_Trabajo_Vida", "Frecuencia")
# Filtrar los datos para cada valor de Rotación
df_si <- subset(df_contingencia, Rotación == "Si")
df_no <- subset(df_contingencia, Rotación == "No")
# Crear el gráfico de pastel para Rotación = "Sí"
ggplot(df_si, aes(x = "", y = Frecuencia, fill = Equilibrio_Trabajo_Vida)) +
geom_bar(stat = "identity", width = 1) +
coord_polar("y", start = 0) +
geom_text(aes(label = paste0(round((Frecuencia / sum(Frecuencia)) * 100, 1), "%")),
position = position_stack(vjust = 0.5)) +
ggtitle("Distribución de Equilibrio Trabajo-Vida para Rotación = Sí") +
scale_fill_manual(values = c("#E74C3C","orange", "yellow", "#4E9D2D")) + # Colores
theme_void()
# Crear el gráfico de pastel para Rotación = "No"
ggplot(df_no, aes(x = "", y = Frecuencia, fill = Equilibrio_Trabajo_Vida)) +
geom_bar(stat = "identity", width = 1) +
coord_polar("y", start = 0) +
geom_text(aes(label = paste0(round((Frecuencia / sum(Frecuencia)) * 100, 1), "%")),
position = position_stack(vjust = 0.5)) +
ggtitle("Distribución de Equilibrio Trabajo-Vida para Rotación = No") +
scale_fill_manual(values = c("#E74C3C","orange", "yellow", "#4E9D2D")) + # Colores
theme_void()
Se encuentra que la mayoría de los empleados, tanto los que rotaron como los que no rotaron, evaluaron su “Equilibrio Trabajo-Vida” como “Medio” (3), representando el 53.6% y 62.1%, respectivamente. Los empleados que no rotaron tendieron a evaluar su equilibrio de manera más positiva, con una menor proporción calificándolo como “Muy bajo” (1) (4.5%) en comparación con aquellos que rotaron (10.5%). Además, los empleados que rotaron presentaron una mayor diversidad en sus evaluaciones, con una distribución más equilibrada entre las categorías de equilibrio “Bajo” (2), “Medio” (3) y “Alto” (4).
Acá se debe hacer una transformación de la variable con 1 y 0 de las categorias 2=Bajo, 3=Medio, 4=Alto respecto a 1=Muy bajo (que otmará el valor de cero para evitar multicolinealidad), por lo que serán tres coeficientes, se espera que los coeficientes sean negativos, porque mejores niveles de equilibrios frente a “muy bajo” dberían demostrar menores niveles de probabilidad de rotación.
# Crear una tabla de contingencia entre Rotación y Satisfación_Laboral
tabla_contingencia <- table(rotacion$Rotación, rotacion$Satisfación_Laboral)
# Calcular la frecuencia absoluta y relativa
freq_abs <- tabla_contingencia
freq_rel <- prop.table(tabla_contingencia)
# Mostrar la tabla de frecuencias
freq_table <- data.frame(Frecuencia_Absoluta = as.vector(freq_abs),
Frecuencia_Relativa = as.vector(freq_rel))
rownames(freq_table) <- paste(rep(rownames(freq_abs), each = ncol(freq_abs)), colnames(freq_abs), sep = " - ")
print(freq_table)
## Frecuencia_Absoluta Frecuencia_Relativa
## No - 1 223 0.15170068
## No - 2 66 0.04489796
## No - 3 234 0.15918367
## No - 4 46 0.03129252
## Si - 1 369 0.25102041
## Si - 2 73 0.04965986
## Si - 3 407 0.27687075
## Si - 4 52 0.03537415
# Gráfico de la frecuencia absoluta con colores y etiquetas para Rotación y Satisfación_Laboral
ggplot(as.data.frame(freq_abs), aes(x = Var1, y = Freq, fill = Var2)) +
geom_bar(stat = "identity", position = "dodge") +
geom_text(aes(label=Freq), position = position_dodge(width = 0.9), vjust=-0.5) +
ggtitle("Frecuencia Absoluta de Rotación y Satisfación Laboral") +
xlab("Rotación") +
ylab("Frecuencia Absoluta") +
scale_fill_manual(name = "Satisfación Laboral", values = c("#E74C3C","orange", "yellow", "#4E9D2D")) +
theme_minimal()
# Convertir la tabla de contingencia en un data frame para facilitar el uso en ggplot
df_contingencia <- as.data.frame(tabla_contingencia)
colnames(df_contingencia) <- c("Rotación", "Satisfación_Laboral", "Frecuencia")
# Filtrar los datos para cada valor de Rotación
df_si <- subset(df_contingencia, Rotación == "Si")
df_no <- subset(df_contingencia, Rotación == "No")
# Crear el gráfico de pastel para Rotación = "Sí"
ggplot(df_si, aes(x = "", y = Frecuencia, fill = Satisfación_Laboral)) +
geom_bar(stat = "identity", width = 1) +
coord_polar("y", start = 0) +
geom_text(aes(label = paste0(round((Frecuencia / sum(Frecuencia)) * 100, 1), "%")),
position = position_stack(vjust = 0.5)) +
ggtitle("Distribución de Satisfación Laboral para Rotación = Sí") +
scale_fill_manual(values = c("#E74C3C","orange", "yellow", "#4E9D2D")) + # Colores
theme_void()
# Crear el gráfico de pastel para Rotación = "No"
ggplot(df_no, aes(x = "", y = Frecuencia, fill = Satisfación_Laboral)) +
geom_bar(stat = "identity", width = 1) +
coord_polar("y", start = 0) +
geom_text(aes(label = paste0(round((Frecuencia / sum(Frecuencia)) * 100, 1), "%")),
position = position_stack(vjust = 0.5)) +
ggtitle("Distribución de Satisfación Laboral para Rotación = No") +
scale_fill_manual(values = c("#E74C3C","orange", "yellow", "#4E9D2D")) + # Colores
theme_void()
Se muestra que en general, los empleados que no rotaron tienen un mayor porcentaje de satisfacción laboral, con un 33% calificando su satisfacción como “Muy satisfecho” (4) y un 29.9% como “Satisfecho” (3). En contraste, los empleados que rotaron presentan una mayor proporción de niveles más bajos de satisfacción: el 30.8% se clasificó como “Satisfecho” (3) y el 27.8% como “Muy insatisfecho” (1). Esto indica que los empleados que permanecieron en la empresa tienden a tener niveles más altos de satisfacción laboral en comparación con aquellos que experimentaron rotación. Para incorporar esta variable en el modelo, realizaremos una transformación en variables dummy, tomando “Muy insatisfecho” (1) como la categoría de referencia para evitar la multicolinealidad. Las categorías “Insatisfecho” (2), “Satisfecho” (3) y “Muy satisfecho” (4) serán comparadas contra esta base. Esperamos que los coeficientes de estas dummies sean negativos, ya que mayores niveles de satisfacción deberían estar relacionados con una menor probabilidad de rotación en comparación con los empleados que se sienten “Muy insatisfechos”.
Se transforman variables para dejar un solo modelo
# Crear el dataframe modelo
modelo <- data.frame(
Rotación = ifelse(rotacion$Rotación == "Si", 1, 0),
Ingreso_Mensual = rotacion$Ingreso_Mensual,
Antigüedad = rotacion$Antigüedad,
Distancia_Casa = rotacion$Distancia_Casa,
Horas_Extra = ifelse(rotacion$Horas_Extra == "Si", 1, 0),
# One-hot encoding para Equilibrio_Trabajo_Vida con referencia a 1
equilibrio_Trabajo_Vida_bajo = ifelse(rotacion$Equilibrio_Trabajo_Vida == 2, 1, 0),
equilibrio_Trabajo_Vida_medio = ifelse(rotacion$Equilibrio_Trabajo_Vida == 3, 1, 0),
equilibrio_Trabajo_Vida_alto = ifelse(rotacion$Equilibrio_Trabajo_Vida == 4, 1, 0),
# One-hot encoding para Satisfación_Laboral con referencia a 1
satisfaccion_laboral_insatisfecho = ifelse(rotacion$Satisfación_Laboral == 2, 1, 0),
satisfaccion_laboral_satisfecho = ifelse(rotacion$Satisfación_Laboral == 3, 1, 0),
satisfaccion_laboral_muy_satisfecho = ifelse(rotacion$Satisfación_Laboral == 4, 1, 0)
)
# Crear la variable Antiguedad_cuadrado en el DataFrame modelo
modelo$Antiguedad_cuadrado <- modelo$Antigüedad^2
# Verificar el resultado
head(modelo)
Se estima el modelo logit
## Warning: package 'stringr' was built under R version 4.3.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ lubridate 1.9.3 ✔ tibble 3.2.1
## ✔ purrr 1.0.2 ✔ tidyr 1.3.1
## ✔ readr 2.1.5
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ mice::filter() masks dplyr::filter(), stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
# Ajustar el modelo logit utilizando las variables del dataframe modelo
modelo_logit <- glm(
Rotación ~ Ingreso_Mensual + Antigüedad + Antiguedad_cuadrado + Distancia_Casa + Horas_Extra +
equilibrio_Trabajo_Vida_bajo + equilibrio_Trabajo_Vida_medio + equilibrio_Trabajo_Vida_alto +
satisfaccion_laboral_insatisfecho + satisfaccion_laboral_satisfecho + satisfaccion_laboral_muy_satisfecho,
family = binomial(link = "logit"),
data = modelo
)
# Mostrar el resumen del modelo
summary(modelo_logit)
##
## Call:
## glm(formula = Rotación ~ Ingreso_Mensual + Antigüedad + Antiguedad_cuadrado +
## Distancia_Casa + Horas_Extra + equilibrio_Trabajo_Vida_bajo +
## equilibrio_Trabajo_Vida_medio + equilibrio_Trabajo_Vida_alto +
## satisfaccion_laboral_insatisfecho + satisfaccion_laboral_satisfecho +
## satisfaccion_laboral_muy_satisfecho, family = binomial(link = "logit"),
## data = modelo)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 3.982e-01 3.519e-01 1.132 0.25780
## Ingreso_Mensual -1.262e-04 2.554e-05 -4.944 7.66e-07 ***
## Antigüedad -2.032e-01 3.331e-02 -6.100 1.06e-09 ***
## Antiguedad_cuadrado 6.948e-03 1.148e-03 6.052 1.43e-09 ***
## Distancia_Casa 3.048e-02 9.322e-03 3.270 0.00108 **
## Horas_Extra 1.466e+00 1.585e-01 9.255 < 2e-16 ***
## equilibrio_Trabajo_Vida_bajo -8.841e-01 3.111e-01 -2.842 0.00448 **
## equilibrio_Trabajo_Vida_medio -1.128e+00 2.883e-01 -3.912 9.16e-05 ***
## equilibrio_Trabajo_Vida_alto -6.789e-01 3.545e-01 -1.915 0.05547 .
## satisfaccion_laboral_insatisfecho -4.378e-01 2.334e-01 -1.876 0.06071 .
## satisfaccion_laboral_satisfecho -4.696e-01 2.072e-01 -2.267 0.02340 *
## satisfaccion_laboral_muy_satisfecho -1.041e+00 2.232e-01 -4.664 3.10e-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: 1083.3 on 1458 degrees of freedom
## AIC: 1107.3
##
## Number of Fisher Scoring iterations: 5
En el modelo logit que predice la probabilidad de rotar, sin calcular aún los efectos marginales, se observa que las variables Ingreso_Mensual (p = 7.66e-07) y Antigüedad (p = 1.60e-09) son altamente significativas al nivel de confianza del 99.9% (indicado por ’***’), con signos negativos, lo que confirma que mayores ingresos y mayor antigüedad están asociados con una menor probabilidad de rotación. La variable Antigüedad_cuadrado tiene un p-valor de 4.02e-05, también significativo al nivel del 99.9%, y su signo positivo confirma la relación en forma de U invertida, indicando que después de un cierto nivel de antigüedad, la probabilidad de rotación vuelve a aumentar.
La variable Distancia_Casa (p = 0.01008) es significativa al 99% (indicado por ‘**’) y presenta un coeficiente positivo, lo que sugiere que una mayor distancia a casa incrementa la probabilidad de rotación. Horas_Extra tiene un p-valor de < 2e-16, altamente significativo al nivel del 99.9% (’*’), y su signo positivo indica que los empleados que trabajan horas extra son más propensos a rotar.
Respecto a Equilibrio_Trabajo_Vida, “bajo” es significativo al 99% (p = 0.00448) y “medio” al 95% (p = 0.02130), ambos con coeficientes negativos, sugiriendo que mejores niveles de equilibrio reducen la probabilidad de rotación frente a la categoría de referencia “muy bajo”. La categoría “alto” no es significativa (p = 0.05547), lo que indica que su efecto no es tan claro.
Para Satisfacción_Laboral, las categorías “insatisfecho” (p = 0.02340) es significativa al 95%, y “muy satisfecho” (p = 3.10e-06) es altamente significativa al 99.9%, ambas con coeficientes negativos. Esto sugiere que mayores niveles de satisfacción reducen la probabilidad de rotación en comparación con “muy insatisfecho”.
En conclusión, las variables que más influyen en la probabilidad de rotación, con significancia estadística alta y los signos esperados, son Ingreso_Mensual, Antigüedad, Horas_Extra, y la categoría “muy satisfecho” de Satisfacción Laboral, lo que indica que estos factores son los más determinantes en el modelo logit.
# Calcular el p-valor equivalente para evaluar la significancia global del modelo
with(modelo_logit, pchisq(null.deviance - deviance, df.null - df.residual, lower.tail = FALSE))
## [1] 5.019209e-40
Al calcular el p-valor asociado a este chi cuadrado, encontramos que es muy pequeño, cercano a 0, lo que indica que rechazamos la hipótesis nula , que plantea que “ninguna de las variables independientes tiene un efecto significativo en la probabilidad de rotación” (es decir, todos los coeficientes son iguales a 0). Por lo tanto, concluimos que el modelo logit es estadísticamente significativo en su totalidad.
## Warning: package 'margins' was built under R version 4.3.3
# Calcular los efectos marginales del modelo
marginal_effects <- margins(modelo_logit)
# Mostrar los resultados
summary(marginal_effects)
Los efectos marginales indican que, por cada año adicional de antigüedad, la probabilidad de rotación disminuye en 2.31 puntos porcentuales (significativo al 99%), mientras que la antigüedad cuadrada aumenta la probabilidad en 0.08 puntos porcentuales (significativo al 99%), confirmando la relación en forma de U invertida. Cada kilómetro adicional de distancia a casa incrementa la probabilidad de rotación en 0.35 puntos porcentuales (significativo al 95%). Comparado con un “equilibrio trabajo-vida muy bajo”, tener un “equilibrio trabajo-vida bajo” reduce la probabilidad de rotación en 10.03 puntos porcentuales (significativo al 95%), y un “equilibrio trabajo-vida medio” la reduce en 12.80 puntos porcentuales (significativo al 99%); mientras que el “alto” no es estadísticamente significativo. Los empleados que realizan horas extra tienen una probabilidad de rotación 16.64 puntos porcentuales mayor (significativo al 99%). Aunque el ingreso mensual es significativo al 99%, su efecto es prácticamente nulo (cercano a cero), pero el signo negativo sugiere una ligera tendencia a disminuir la probabilidad de rotación con cada dólar adicional. La categoría “insatisfecho” no resulta significativa, pero estar “muy satisfecho” reduce la probabilidad de rotación en 11.81 puntos porcentuales (significativo al 95%) en comparación con “muy insatisfecho”. Adicionalmente, estar “satisfecho” reduce la probabilidad en 5.33 puntos porcentuales respecto a estar “muy insatisfecho” (significativo, p = 0.0227), confirmando que mayores niveles de satisfacción laboral están asociados con una menor probabilidad de rotación.
Realice una partición en los datos de forma aleatoria donde 70% sea un set para entrenar el modelo y 30% para prueba. Estime un modelo logístico con la muestra del 70%. Muestre los resultados.
## Warning: package 'caret' was built under R version 4.3.3
## Loading required package: lattice
##
## Attaching package: 'caret'
## The following object is masked from 'package:purrr':
##
## lift
# Establecer semilla para reproducibilidad
set.seed(123)
# Dividir la base de datos en conjuntos de entrenamiento y prueba (70% y 30%)
training_indices <- createDataPartition(modelo$Rotación, p = 0.7, list = FALSE)
datos_entrenamiento <- modelo[training_indices, ]
datos_prueba <- modelo[-training_indices, ]
# Ajustar el modelo logit utilizando los datos de entrenamiento
modelo_logit_entrenamiento <- glm(
Rotación ~ Ingreso_Mensual + Antigüedad + Antiguedad_cuadrado + Distancia_Casa + Horas_Extra +
equilibrio_Trabajo_Vida_bajo + equilibrio_Trabajo_Vida_medio + equilibrio_Trabajo_Vida_alto +
satisfaccion_laboral_insatisfecho + satisfaccion_laboral_satisfecho + satisfaccion_laboral_muy_satisfecho,
family = binomial(link = "logit"),
data = datos_entrenamiento
)
# Mostrar el resumen del modelo ajustado
summary(modelo_logit_entrenamiento)
##
## Call:
## glm(formula = Rotación ~ Ingreso_Mensual + Antigüedad + Antiguedad_cuadrado +
## Distancia_Casa + Horas_Extra + equilibrio_Trabajo_Vida_bajo +
## equilibrio_Trabajo_Vida_medio + equilibrio_Trabajo_Vida_alto +
## satisfaccion_laboral_insatisfecho + satisfaccion_laboral_satisfecho +
## satisfaccion_laboral_muy_satisfecho, family = binomial(link = "logit"),
## data = datos_entrenamiento)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 7.308e-01 4.213e-01 1.735 0.082829 .
## Ingreso_Mensual -1.592e-04 3.294e-05 -4.832 1.35e-06 ***
## Antigüedad -1.808e-01 3.938e-02 -4.591 4.42e-06 ***
## Antiguedad_cuadrado 6.382e-03 1.303e-03 4.900 9.58e-07 ***
## Distancia_Casa 2.249e-02 1.139e-02 1.974 0.048372 *
## Horas_Extra 1.336e+00 1.910e-01 6.995 2.65e-12 ***
## equilibrio_Trabajo_Vida_bajo -1.027e+00 3.700e-01 -2.776 0.005497 **
## equilibrio_Trabajo_Vida_medio -1.212e+00 3.378e-01 -3.587 0.000334 ***
## equilibrio_Trabajo_Vida_alto -6.790e-01 4.031e-01 -1.684 0.092128 .
## satisfaccion_laboral_insatisfecho -6.104e-01 2.882e-01 -2.118 0.034169 *
## satisfaccion_laboral_satisfecho -5.878e-01 2.508e-01 -2.344 0.019073 *
## satisfaccion_laboral_muy_satisfecho -9.977e-01 2.619e-01 -3.809 0.000140 ***
## ---
## 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: 744.77 on 1017 degrees of freedom
## AIC: 768.77
##
## Number of Fisher Scoring iterations: 6
# Calcular los efectos marginales del modelo ajustado con los datos de entrenamiento
marginal_effects_entrenamiento <- margins(modelo_logit_entrenamiento)
# Mostrar los resultados de los efectos marginales
summary(marginal_effects_entrenamiento)
Al comparar los efectos marginales del modelo original con los del modelo ajustado utilizando solo los datos de entrenamiento, se observa que los resultados son muy similares, tanto en magnitud como en dirección. Los coeficientes mantienen sus signos y los valores no varían significativamente, lo que indica que la partición de los datos no alteró de forma importante las conclusiones sobre el impacto de las variables en la probabilidad de rotación.
# Obtener las predicciones del modelo en los datos de prueba
predicciones <- predict(modelo_logit_entrenamiento, newdata = datos_prueba, type = "response")
# Convertir las probabilidades predichas en clases utilizando un umbral de 0.5
clases_predichas <- ifelse(predicciones > 0.5, 1, 0)
# Ver las primeras predicciones
head(clases_predichas)
## 3 7 14 15 21 22
## 0 1 0 0 0 0
Evaluar el poder predictivo del modelo con base en la curva ROC y el AUC en el set de datos de prueba
# Cargar la librería necesaria
library(caret)
# Crear la matriz de confusión utilizando las clases predichas y la variable Rotación en datos_prueba
matriz_confusion <- confusionMatrix(table(clases_predichas, datos_prueba$Rotación))
# Mostrar la matriz de confusión y las métricas de evaluación
print(matriz_confusion)
## Confusion Matrix and Statistics
##
##
## clases_predichas 0 1
## 0 363 66
## 1 3 9
##
## Accuracy : 0.8435
## 95% CI : (0.8062, 0.8762)
## No Information Rate : 0.8299
## P-Value [Acc > NIR] : 0.2451
##
## Kappa : 0.1679
##
## Mcnemar's Test P-Value : 8.398e-14
##
## Sensitivity : 0.9918
## Specificity : 0.1200
## Pos Pred Value : 0.8462
## Neg Pred Value : 0.7500
## Prevalence : 0.8299
## Detection Rate : 0.8231
## Detection Prevalence : 0.9728
## Balanced Accuracy : 0.5559
##
## 'Positive' Class : 0
##
## Warning: package 'pROC' was built under R version 4.3.3
## Type 'citation("pROC")' for a citation.
##
## Attaching package: 'pROC'
## The following objects are masked from 'package:stats':
##
## cov, smooth, var
# Calcular la curva ROC utilizando las predicciones originales y la variable Rotación en datos_prueba
curva_ROC <- roc(datos_prueba$Rotación, predicciones)
## Setting levels: control = 0, case = 1
## Setting direction: controls < cases
# Calcular el AUC
auc_valor <- round(auc(curva_ROC), 4)
# Visualizar la curva ROC
library(ggplot2)
ggroc(curva_ROC, colour = "#FF7F00", size=1) +
ggtitle(paste0("Curva ROC ", "(AUC = ", auc_valor, ")")) +
xlab("1 - Especificidad") +
ylab("Sensibilidad")
La matriz de confusión muestra que el modelo tiene una exactitud (Accuracy) de 84.35%, lo que indica que el 84.35% de las predicciones realizadas por el modelo son correctas. El intervalo de confianza del 95% para la exactitud es de (80.62%, 87.62%), lo que significa que que el modelo tiene un buen desempeño dentro de este rango.
En cuanto a las métricas de sensibilidad y especificidad, la sensibilidad es 0.9918, lo que significa que el modelo es muy eficaz en identificar los casos negativos correctamente (0 en la variable de rotación). Por otro lado, la especificidad es muy baja (0.12), lo que significa que el modelo tiene dificultad para identificar los casos positivos correctamente. Esto implica que el modelo tiende a clasificar la mayoría de los casos como “no rotaron”. La precisión para las predicciones positivas (valor predicho 0) es 0.8462, mientras que la precisión para las predicciones negativas (valor predicho 1) es 0.7500, indicando que el modelo es más confiable al identificar correctamente los empleados que no rotaron.
La curva ROC muestra la relación entre la sensibilidad (la capacidad del modelo para identificar correctamente los casos positivos) y 1 - especificidad (la tasa de falsos positivos) en diferentes umbrales de probabilidad. En este caso, la curva se eleva por encima de la línea diagonal que representa un modelo sin capacidad de discriminación (AUC = 0.5). Un AUC de 0.759 indica que hay una probabilidad del 75.9% de que el modelo clasifique correctamente a un empleado que rotó frente a uno que no lo hizo. No obstante, el problema con la especificidad indica que se debe hacer algo para balancear el modelo para ver si deja de predecir la clase preponderante, el cero.
# Cargar el paquete dplyr
library(dplyr)
# Calcular el tamaño de la clase minoritaria (1) para el balanceo
n_min <- min(table(modelo$Rotación))
# Seleccionar aleatoriamente n_min instancias de las dos clases
set.seed(123) # Para reproducibilidad
modelo_balanceado <- modelo %>%
group_by(Rotación) %>%
sample_n(n_min) %>%
ungroup()
# Mostrar la cuenta de la variable Rotación
table(modelo_balanceado$Rotación)
##
## 0 1
## 237 237
El balanceo en este caso es importante para evitar que el modelo logístico esté sesgado hacia la clase mayoritaria (no rotación). Al tener un número igual de empleados que rotaron y que no rotaron, el modelo puede aprender de manera equitativa las características que distinguen ambas clases, lo que mejora su capacidad para predecir correctamente la rotación y evita que se incline a predecir siempre la clase dominante. Igualamos por lo bajo en 237 observaciones por clase.
library(caret)
library(margins)
# Establecer semilla para reproducibilidad
set.seed(123)
# Dividir la base de datos balanceada en conjuntos de entrenamiento y prueba (70% y 30%)
training_indices <- createDataPartition(modelo_balanceado$Rotación, p = 0.7, list = FALSE)
datos_entrenamiento <- modelo_balanceado[training_indices, ]
datos_prueba <- modelo_balanceado[-training_indices, ]
# Ajustar el modelo logit utilizando los datos de entrenamiento balanceados
modelo_logit_entrenamiento <- glm(
Rotación ~ Ingreso_Mensual + Antigüedad + Antiguedad_cuadrado + Distancia_Casa + Horas_Extra +
equilibrio_Trabajo_Vida_bajo + equilibrio_Trabajo_Vida_medio + equilibrio_Trabajo_Vida_alto +
satisfaccion_laboral_insatisfecho + satisfaccion_laboral_satisfecho + satisfaccion_laboral_muy_satisfecho,
family = binomial(link = "logit"),
data = datos_entrenamiento
)
# Mostrar el resumen del modelo ajustado
summary(modelo_logit_entrenamiento)
##
## Call:
## glm(formula = Rotación ~ Ingreso_Mensual + Antigüedad + Antiguedad_cuadrado +
## Distancia_Casa + Horas_Extra + equilibrio_Trabajo_Vida_bajo +
## equilibrio_Trabajo_Vida_medio + equilibrio_Trabajo_Vida_alto +
## satisfaccion_laboral_insatisfecho + satisfaccion_laboral_satisfecho +
## satisfaccion_laboral_muy_satisfecho, family = binomial(link = "logit"),
## data = datos_entrenamiento)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 1.747e+00 5.716e-01 3.056 0.002240 **
## Ingreso_Mensual -1.271e-04 3.897e-05 -3.263 0.001103 **
## Antigüedad -1.742e-01 5.136e-02 -3.392 0.000693 ***
## Antiguedad_cuadrado 6.001e-03 1.665e-03 3.604 0.000313 ***
## Distancia_Casa 3.910e-02 1.558e-02 2.509 0.012093 *
## Horas_Extra 1.493e+00 2.705e-01 5.519 3.41e-08 ***
## equilibrio_Trabajo_Vida_bajo -8.693e-01 5.179e-01 -1.678 0.093255 .
## equilibrio_Trabajo_Vida_medio -1.033e+00 4.784e-01 -2.160 0.030780 *
## equilibrio_Trabajo_Vida_alto -9.052e-01 6.181e-01 -1.464 0.143065
## satisfaccion_laboral_insatisfecho -4.034e-01 3.985e-01 -1.012 0.311384
## satisfaccion_laboral_satisfecho -4.789e-01 3.476e-01 -1.378 0.168321
## satisfaccion_laboral_muy_satisfecho -7.580e-01 3.713e-01 -2.041 0.041202 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 460.25 on 331 degrees of freedom
## Residual deviance: 370.25 on 320 degrees of freedom
## AIC: 394.25
##
## Number of Fisher Scoring iterations: 4
# Calcular los efectos marginales del modelo ajustado con los datos de entrenamiento balanceados
marginal_effects_entrenamiento <- margins(modelo_logit_entrenamiento)
# Mostrar los resultados de los efectos marginales
summary(marginal_effects_entrenamiento)
Las variables Antigüedad, Antiguedad_cuadrado, Distancia_Casa, equilibrio_Trabajo_Vida_medio, Horas_Extra, Ingreso_Mensual, y satisfaccion_laboral_muy_satisfecho se mantienen significativas a diferentes niveles de confianza (95% y 99%). Los signos de los coeficientes continúan siendo coherentes con las hipótesis previas: la antigüedad disminuye la probabilidad de rotación, mientras que su cuadrado incrementa esta probabilidad, confirmando la relación de U invertida.
Los efectos marginales muestran que, por cada año adicional de antigüedad, la probabilidad de rotación disminuye en 3.29 puntos porcentuales (significativo al 99%). El efecto cuadrático aumenta la probabilidad de rotación en 0.11 puntos porcentuales por cada año al cuadrado (significativo al 99%). La distancia a casa incrementa la probabilidad de rotación en 0.74 puntos porcentuales por cada kilómetro adicional (significativo al 95%). Realizar horas extra aumenta la probabilidad de rotación en 28.20 puntos porcentuales (significativo al 99%). Tener un equilibrio trabajo-vida medio reduce la probabilidad de rotación en 19.52 puntos porcentuales (significativo al 95%), mientras que el equilibrio “bajo” y “alto” no fueron significativos. El ingreso mensual sigue mostrando un efecto negativo muy pequeño y significativo. En cuanto a la satisfacción laboral, la categoría “muy satisfecho” reduce la probabilidad de rotación en 14.32 puntos porcentuales (significativo al 95%). Al comparar estos resultados con el modelo anterior, vemos que, al trabajar con datos balanceados, la variable “equilibrio_Trabajo_Vida_medio” se vuelve más significativa, y “satisfacción_laboral_satisfecho” pierde su significancia.
# Obtener las predicciones del modelo en los datos de prueba balanceados
predicciones_balanceadas <- predict(modelo_logit_entrenamiento, newdata = datos_prueba, type = "response")
# Convertir las probabilidades predichas en clases utilizando un umbral de 0.5
clases_predichas_balanceadas <- ifelse(predicciones_balanceadas > 0.5, 1, 0)
# Ver las primeras predicciones
head(clases_predichas_balanceadas)
## 1 2 3 4 5 6
## 1 0 0 0 0 1
library(caret)
# Crear la matriz de confusión utilizando las clases predichas y la variable Rotación en datos_prueba balanceados
matriz_confusion_balanceada <- confusionMatrix(table(clases_predichas_balanceadas, datos_prueba$Rotación))
# Mostrar la matriz de confusión y las métricas de evaluación
print(matriz_confusion_balanceada)
## Confusion Matrix and Statistics
##
##
## clases_predichas_balanceadas 0 1
## 0 50 24
## 1 21 47
##
## Accuracy : 0.6831
## 95% CI : (0.5998, 0.7586)
## No Information Rate : 0.5
## P-Value [Acc > NIR] : 7.61e-06
##
## Kappa : 0.3662
##
## Mcnemar's Test P-Value : 0.7656
##
## Sensitivity : 0.7042
## Specificity : 0.6620
## Pos Pred Value : 0.6757
## Neg Pred Value : 0.6912
## Prevalence : 0.5000
## Detection Rate : 0.3521
## Detection Prevalence : 0.5211
## Balanced Accuracy : 0.6831
##
## 'Positive' Class : 0
##
# Cargar la librería pROC para calcular la curva ROC y el AUC (también aseguramos que esté cargada)
library(pROC)
# Calcular la curva ROC utilizando las predicciones originales y la variable Rotación en datos_prueba balanceados
curva_ROC_balanceada <- roc(datos_prueba$Rotación, predicciones_balanceadas)
## Setting levels: control = 0, case = 1
## Setting direction: controls < cases
# Calcular el AUC
auc_valor_balanceado <- round(auc(curva_ROC_balanceada), 4)
# Visualizar la curva ROC
library(ggplot2)
ggroc(curva_ROC_balanceada, colour = "#FF7F00", size=1) +
ggtitle(paste0("Curva ROC ", "(AUC = ", auc_valor_balanceado, ")")) +
xlab("1 - Especificidad") +
ylab("Sensibilidad")
Al comparar ambos modelos, el modelo desbalanceado presenta una mayor exactitud (84.35%) en comparación con el modelo balanceado (68.31%). Sin embargo, esta alta exactitud en el modelo desbalanceado está sesgada hacia la clase mayoritaria, reflejada en su baja especificidad (12.00%) y alta sensibilidad (99.18%), lo que indica que es excelente identificando los casos negativos pero muy deficiente para los positivos.
Por otro lado, el modelo balanceado muestra una sensibilidad más equilibrada (70.42%) y una especificidad significativamente mejorada (66.20%), lo que evidencia su capacidad de identificar correctamente ambas clases. En cuanto a la AUC, el modelo balanceado (0.7733) supera al desbalanceado (0.759), demostrando un mejor poder predictivo global. En conclusión, aunque el modelo desbalanceado tiene mayor exactitud, el modelo balanceado es más adecuado y confiable al proporcionar un rendimiento más equilibrado en la clasificación de rotación laboral.
En las conclusiones adicione una discució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).
Respuesta
En este análisis, se siguió un proceso sistemático para desarrollar un modelo predictivo de rotación laboral. Primero, se definieron los objetivos y se recolectaron los datos relevantes. Se realizó un análisis univariado y multivariado utilizando 6 variables (3 categóricas y 3 numéricas), seleccionadas con base en evidencia teórica. Luego, se llevó a cabo la exploración de los datos para asegurar su calidad evitando que hubiese missing y transformando variables. Posteriormente, los datos se dividieron en conjuntos de entrenamiento y prueba (train/test) y se estimó el modelo utilizando técnicas de regresión logística. Se evaluó y ajustó el modelo, y se realizaron validaciones cruzadas para asegurar su fiabilidad, a partir de datos de balanceo. Finalmente, se interpretaron los resultados y se concluyó sobre la efectividad del modelo, aunque queda pendiente el despliegue final del modelo en un entorno operativo. Cabe destacar que esto es un ejercicio académico que refleja la aplicación práctica del proceso de modelado.
En conclusión, aunque el modelo desbalanceado muestra una mayor exactitud (84.35%), su rendimiento está claramente sesgado hacia la clase mayoritaria, ya que presenta una baja especificidad (12.00%) y alta sensibilidad (99.18%), lo que lo hace ineficaz para identificar correctamente los casos positivos de rotación. El modelo balanceado, por otro lado, ofrece una evaluación más equilibrada, con una sensibilidad (70.42%) y especificidad (66.20%) que indican su capacidad para predecir de manera más justa ambas clases de rotación, y un AUC superior (0.7733 vs. 0.759), demostrando un mejor poder predictivo.
Para futuros análisis, sería recomendable incluir otras variables que no fueron utilizadas en este ejercicio debido a la limitación de trabajar con solo 6 variables, ya que esto podría mejorar aún más el modelo y abordar posibles sesgos. Además, explorar enfoques adicionales para balancear la clase podría ayudar a obtener un modelo predictivo más robusto y representativo de la realidad laboral de la empresa.
Para disminuir la rotación, la empresa debería implementar estrategias que promuevan un mejor equilibrio trabajo-vida, ya que los empleados con niveles “medio” o “alto” tienen menos probabilidad de rotar en comparación con aquellos con un equilibrio “muy bajo”. Reducir las horas extra es otra estrategia clave, dado que su realización aumenta la probabilidad de rotación. Fomentar la permanencia en la empresa también es importante, ya que la antigüedad se asocia con menor rotación, aunque es importante reconocer que después de ciertos años, la rotación podría incrementarse ligeramente, formando una relación en forma de U invertida. Finalmente, se debe trabajar en mejorar la satisfacción laboral, especialmente orientando esfuerzos hacia que los empleados alcancen un estado de “muy satisfechos,” y considerar políticas que reduzcan la carga de desplazamiento o que flexibilicen la ubicación de trabajo para empleados que viven más lejos de la empresa.
Además, aunque el efecto es mínimo, mantener o mejorar los salarios podría ayudar a retener empleados, ya que un mayor ingreso tiene una ligera relación con una menor probabilidad de rotación.
Fin del documento