1 Introduccion

El presente informe analiza la rotacion de empleados en una organizacion mediante un modelo de regresion logistica binomial. El objetivo es identificar los factores que mas inciden en la probabilidad de que un trabajador cambie de cargo, apoyando decisiones estrategicas de retencion del talento humano.

La base de datos rotacion contiene 1,470 registros y 24 variables sobre caracteristicas laborales y personales de los empleados.


2 Carga de Datos y Paquetes

# install.packages("devtools")
# devtools::install_github("centromagis/paqueteMODELOS", force = TRUE)

library(paqueteMODELOS)
library(dplyr)
library(ggplot2)
library(pROC)
library(knitr)
library(kableExtra)
library(gridExtra)
library(scales)

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, …
# Detectar columnas por patron para ser robusto ante diferencias de codificacion
col_rot     <- grep("otaci",  names(rotacion), value = TRUE)[1]
col_sat     <- grep("atisf",  names(rotacion), value = TRUE)[1]
col_antic   <- grep("ntig.*argo|argo.*ntig", names(rotacion),
                    ignore.case = TRUE, value = TRUE)[1]
col_viaje   <- grep("iaje",   names(rotacion), value = TRUE)[1]
col_ec      <- grep("stado",  names(rotacion), value = TRUE)[1]
col_he      <- grep("ora.*xtra|xtra.*ora", names(rotacion),
                    ignore.case = TRUE, value = TRUE)[1]
col_ing     <- grep("ngreso", names(rotacion), value = TRUE)[1]

cat("Columnas identificadas:\n")
## Columnas identificadas:
cat(" Rotacion:          ", col_rot,   "\n")
##  Rotacion:           Rotación
cat(" Satisfaccion:      ", col_sat,   "\n")
##  Satisfaccion:       Satisfacción_Ambiental
cat(" Antiguedad Cargo:  ", col_antic, "\n")
##  Antiguedad Cargo:   Antigüedad_Cargo
cat(" Viaje Negocios:    ", col_viaje, "\n")
##  Viaje Negocios:     Viaje de Negocios
cat(" Estado Civil:      ", col_ec,    "\n")
##  Estado Civil:       Estado_Civil
cat(" Horas Extra:       ", col_he,    "\n")
##  Horas Extra:        Horas_Extra
cat(" Ingreso Mensual:   ", col_ing,   "\n")
##  Ingreso Mensual:    Ingreso_Mensual
# Crear alias limpios
rotacion <- rotacion %>%
  mutate(
    ROT      = .data[[col_rot]],
    SATLAB   = .data[[col_sat]],
    ANTICARGO= .data[[col_antic]],
    VIAJE    = .data[[col_viaje]],
    EC       = .data[[col_ec]],
    HE       = .data[[col_he]],
    ING      = .data[[col_ing]],
    # Variable respuesta binaria
    ROT_bin  = ifelse(.data[[col_rot]] == "Si", 1, 0),
    # Indicadores para el modelo
    HE_bin   = ifelse(.data[[col_he]]  == "Si", 1, 0),
    SOLTERO  = ifelse(.data[[col_ec]]  == "Soltero", 1, 0),
    VJ_FREC  = ifelse(.data[[col_viaje]] == "Frecuentemente", 1, 0)
  )

cat("\nDistribucion de la variable respuesta:\n")
## 
## Distribucion de la variable respuesta:
print(table(rotacion$ROT))
## 
##   No   Si 
## 1233  237

3 Punto 1: Seleccion de Variables

Se seleccionan 3 variables categoricas y 3 variables cuantitativas con relacion hipotetica frente a la rotacion.

3.1 Variables Categoricas

3.1.1 Horas Extra

  • Descripcion: Indica si el empleado trabaja horas extra (Si / No).
  • Hipotesis: Los empleados que trabajan horas extra tendran mayor probabilidad de rotar. El agotamiento fisico y el desequilibrio trabajo-vida deterioran la satisfaccion y aumentan la busqueda de nuevas oportunidades.
  • Relacion esperada: Positiva.

3.1.2 Estado Civil

  • Descripcion: Estado civil del empleado (Soltero, Casado, Divorciado).
  • Hipotesis: Los empleados solteros, al tener menos compromisos financieros y familiares, tendran mayor probabilidad de rotar en comparacion con los casados.
  • Relacion esperada: Positiva (para la categoria Soltero).

3.1.3 Viaje de Negocios

  • Descripcion: Frecuencia de viajes laborales (Sin Viaje, Raramente, Frecuentemente).
  • Hipotesis: Los empleados que viajan frecuentemente experimentan mayor desgaste fisico y emocional, lo que incrementa la probabilidad de rotar.
  • Relacion esperada: Positiva.

3.2 Variables Cuantitativas

3.2.1 Satisfaccion Laboral

  • Descripcion: Nivel de satisfaccion laboral (escala 1 a 4).
  • Hipotesis: A mayor satisfaccion laboral, menor probabilidad de rotacion. Un empleado satisfecho tiene menos incentivos para buscar otros cargos.
  • Relacion esperada: Negativa.

3.2.2 Ingreso Mensual

  • Descripcion: Ingreso mensual del empleado.
  • Hipotesis: Un salario mas alto actua como factor de retencion. A mayor ingreso, menor probabilidad de rotar.
  • Relacion esperada: Negativa.

3.2.3 Antiguedad en el Cargo

  • Descripcion: Anos en el cargo actual.
  • Hipotesis: A mayor antiguedad, mayor estabilidad y menor probabilidad de rotacion. Los empleados consolidados acumulan beneficios y compromisos con la empresa.
  • Relacion esperada: Negativa.

4 Punto 2: Analisis Univariado

4.1 Variable Respuesta: Rotacion

tabla_rot <- rotacion %>%
  count(ROT) %>%
  mutate(Porcentaje = round(n / sum(n) * 100, 1))

tabla_rot %>%
  kable(col.names = c("Rotacion", "Frecuencia", "Porcentaje (%)"),
        caption = "Tabla 1. Frecuencia de Rotacion") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE)
Tabla 1. Frecuencia de Rotacion
Rotacion Frecuencia Porcentaje (%)
No 1233 83.9
Si 237 16.1
ggplot(tabla_rot, aes(x = ROT, y = Porcentaje, fill = ROT)) +
  geom_bar(stat = "identity", width = 0.5) +
  geom_text(aes(label = paste0(Porcentaje, "%")), vjust = -0.5, size = 5) +
  scale_fill_manual(values = c("Si" = "#E74C3C", "No" = "#2ECC71")) +
  labs(title = "Distribucion de la Variable Rotacion",
       x = "Rotacion", y = "Porcentaje (%)") +
  theme_minimal(base_size = 13) +
  theme(legend.position = "none")
Distribucion de la variable Rotacion

Distribucion de la variable Rotacion

Interpretacion: El 16.1% de los empleados presenta rotacion (237 personas). Se observa un claro desbalance de clases, tipico en fenomenos de rotacion laboral donde la mayoria permanece en sus cargos. Este desbalance debe tenerse en cuenta al interpretar las metricas del modelo.


4.2 Variables Categoricas

p1 <- ggplot(rotacion, aes(x = HE, fill = HE)) +
  geom_bar(alpha = 0.9) +
  geom_text(stat = "count", aes(label = after_stat(count)), vjust = -0.4, size = 4) +
  scale_fill_brewer(palette = "Set2") +
  labs(title = "Horas Extra", x = "", y = "Frecuencia") +
  theme_minimal(base_size = 12) + theme(legend.position = "none")

p2 <- ggplot(rotacion, aes(x = EC, fill = EC)) +
  geom_bar(alpha = 0.9) +
  geom_text(stat = "count", aes(label = after_stat(count)), vjust = -0.4, size = 4) +
  scale_fill_brewer(palette = "Set1") +
  labs(title = "Estado Civil", x = "", y = "Frecuencia") +
  theme_minimal(base_size = 12) + theme(legend.position = "none")

p3 <- ggplot(rotacion, aes(x = VIAJE, fill = VIAJE)) +
  geom_bar(alpha = 0.9) +
  geom_text(stat = "count", aes(label = after_stat(count)), vjust = -0.4, size = 4) +
  scale_fill_brewer(palette = "Set3") +
  labs(title = "Viaje de Negocios", x = "", y = "Frecuencia") +
  theme_minimal(base_size = 12) +
  theme(legend.position = "none",
        axis.text.x = element_text(angle = 15, hjust = 1))

grid.arrange(p1, p2, p3, ncol = 3)
Distribucion de variables categoricas

Distribucion de variables categoricas

tab_he <- rotacion %>% count(HE)    %>% mutate(Pct = round(n/sum(n)*100, 1))
tab_ec <- rotacion %>% count(EC)    %>% mutate(Pct = round(n/sum(n)*100, 1))
tab_vn <- rotacion %>% count(VIAJE) %>% mutate(Pct = round(n/sum(n)*100, 1))

tab_he %>%
  kable(col.names = c("Horas Extra", "n", "%"),
        caption = "Tabla 2. Horas Extra") %>%
  kable_styling(bootstrap_options = c("striped","hover","condensed"),
                full_width = FALSE)
Tabla 2. Horas Extra
Horas Extra n %
No 1054 71.7
Si 416 28.3
tab_ec %>%
  kable(col.names = c("Estado Civil", "n", "%"),
        caption = "Tabla 3. Estado Civil") %>%
  kable_styling(bootstrap_options = c("striped","hover","condensed"),
                full_width = FALSE)
Tabla 3. Estado Civil
Estado Civil n %
Casado 673 45.8
Divorciado 327 22.2
Soltero 470 32.0
tab_vn %>%
  kable(col.names = c("Viaje de Negocios", "n", "%"),
        caption = "Tabla 4. Viaje de Negocios") %>%
  kable_styling(bootstrap_options = c("striped","hover","condensed"),
                full_width = FALSE)
Tabla 4. Viaje de Negocios
Viaje de Negocios n %
Frecuentemente 277 18.8
No_Viaja 150 10.2
Raramente 1043 71.0

Interpretacion:
- Horas Extra: El 28.3% trabaja horas extra. Aunque es minoria, sera una variable clave en el modelo.
- Estado Civil: La mayoria son casados (45.8%), seguidos de solteros (32%) y divorciados.
- Viaje de Negocios: El 71% viaja raramente. Solo un porcentaje reducido lo hace frecuentemente.


4.3 Variables Cuantitativas

p4 <- ggplot(rotacion, aes(x = factor(SATLAB))) +
  geom_bar(fill = "#3498DB", alpha = 0.85) +
  geom_text(stat = "count", aes(label = after_stat(count)), vjust = -0.4, size = 4) +
  labs(title = "Satisfaccion Laboral",
       x = "Nivel (1=Bajo, 4=Alto)", y = "Frecuencia") +
  theme_minimal(base_size = 12)

p5 <- ggplot(rotacion, aes(x = ING)) +
  geom_histogram(bins = 30, fill = "#9B59B6", color = "white", alpha = 0.85) +
  labs(title = "Ingreso Mensual", x = "Ingreso", y = "Frecuencia") +
  theme_minimal(base_size = 12)

p6 <- ggplot(rotacion, aes(x = ANTICARGO)) +
  geom_histogram(bins = 20, fill = "#E67E22", color = "white", alpha = 0.85) +
  labs(title = "Antiguedad en el Cargo", x = "Anos", y = "Frecuencia") +
  theme_minimal(base_size = 12)

grid.arrange(p4, p5, p6, ncol = 3)
Distribucion de variables cuantitativas

Distribucion de variables cuantitativas

data.frame(
  Variable  = c("Satisfaccion Laboral", "Ingreso Mensual", "Antiguedad Cargo"),
  Min       = c(min(rotacion$SATLAB),   min(rotacion$ING),   min(rotacion$ANTICARGO)),
  Media     = c(round(mean(rotacion$SATLAB), 2), round(mean(rotacion$ING), 2),
                round(mean(rotacion$ANTICARGO), 2)),
  Mediana   = c(median(rotacion$SATLAB), median(rotacion$ING), median(rotacion$ANTICARGO)),
  Max       = c(max(rotacion$SATLAB),   max(rotacion$ING),   max(rotacion$ANTICARGO)),
  Desv.Est  = c(round(sd(rotacion$SATLAB), 2), round(sd(rotacion$ING), 2),
                round(sd(rotacion$ANTICARGO), 2))
) %>%
  kable(col.names = c("Variable","Min","Media","Mediana","Max","Desv. Estandar"),
        caption = "Tabla 5. Estadisticas descriptivas - Variables cuantitativas") %>%
  kable_styling(bootstrap_options = c("striped","hover","condensed"), full_width = FALSE)
Tabla 5. Estadisticas descriptivas - Variables cuantitativas
Variable Min Media Mediana Max Desv. Estandar
Satisfaccion Laboral 1 2.72 3 4 1.09
Ingreso Mensual 1009 6502.93 4919 19999 4707.96
Antiguedad Cargo 0 4.23 3 18 3.62

Interpretacion:
- Satisfaccion Laboral: Media de 2.72 en escala 1-4. Distribucion aproximadamente uniforme entre niveles.
- Ingreso Mensual: Distribucion asimetrica positiva (media 6503). La mayoria percibe ingresos bajos con pocos casos de salarios muy altos.
- Antiguedad en el Cargo: Mediana de 3 anos. Concentracion en empleados con poca antiguedad en el cargo actual.


5 Punto 3: Analisis Bivariado

5.1 Variables Categoricas vs. Rotacion

p7 <- rotacion %>%
  count(HE, ROT) %>% group_by(HE) %>%
  mutate(pct = n / sum(n) * 100) %>%
  ggplot(aes(x = HE, y = pct, fill = ROT)) +
  geom_bar(stat = "identity", position = "fill", alpha = 0.9) +
  geom_text(aes(label = paste0(round(pct,1),"%")),
            position = position_fill(vjust = 0.5), size = 3.5, color = "white") +
  scale_fill_manual(values = c("Si"="#E74C3C","No"="#2ECC71")) +
  scale_y_continuous(labels = percent) +
  labs(title = "Horas Extra", x = "", y = "Proporcion", fill = "Rota") +
  theme_minimal(base_size = 12)

p8 <- rotacion %>%
  count(EC, ROT) %>% group_by(EC) %>%
  mutate(pct = n / sum(n) * 100) %>%
  ggplot(aes(x = EC, y = pct, fill = ROT)) +
  geom_bar(stat = "identity", position = "fill", alpha = 0.9) +
  geom_text(aes(label = paste0(round(pct,1),"%")),
            position = position_fill(vjust = 0.5), size = 3.5, color = "white") +
  scale_fill_manual(values = c("Si"="#E74C3C","No"="#2ECC71")) +
  scale_y_continuous(labels = percent) +
  labs(title = "Estado Civil", x = "", y = "Proporcion", fill = "Rota") +
  theme_minimal(base_size = 12)

p9 <- rotacion %>%
  count(VIAJE, ROT) %>% group_by(VIAJE) %>%
  mutate(pct = n / sum(n) * 100) %>%
  ggplot(aes(x = VIAJE, y = pct, fill = ROT)) +
  geom_bar(stat = "identity", position = "fill", alpha = 0.9) +
  geom_text(aes(label = paste0(round(pct,1),"%")),
            position = position_fill(vjust = 0.5), size = 3.5, color = "white") +
  scale_fill_manual(values = c("Si"="#E74C3C","No"="#2ECC71")) +
  scale_y_continuous(labels = percent) +
  labs(title = "Viaje de Negocios", x = "", y = "Proporcion", fill = "Rota") +
  theme_minimal(base_size = 12) +
  theme(axis.text.x = element_text(angle = 15, hjust = 1))

grid.arrange(p7, p8, p9, ncol = 3)
Proporcion de rotacion por variable categorica

Proporcion de rotacion por variable categorica

5.2 Variables Cuantitativas vs. Rotacion

p10 <- ggplot(rotacion, aes(x = ROT, y = SATLAB, fill = ROT)) +
  geom_boxplot(alpha = 0.75) +
  scale_fill_manual(values = c("Si"="#E74C3C","No"="#2ECC71")) +
  labs(title = "Satisfaccion Laboral", x = "Rotacion", y = "Nivel") +
  theme_minimal(base_size = 12) + theme(legend.position = "none")

p11 <- ggplot(rotacion, aes(x = ROT, y = ING, fill = ROT)) +
  geom_boxplot(alpha = 0.75) +
  scale_fill_manual(values = c("Si"="#E74C3C","No"="#2ECC71")) +
  labs(title = "Ingreso Mensual", x = "Rotacion", y = "Ingreso") +
  theme_minimal(base_size = 12) + theme(legend.position = "none")

p12 <- ggplot(rotacion, aes(x = ROT, y = ANTICARGO, fill = ROT)) +
  geom_boxplot(alpha = 0.75) +
  scale_fill_manual(values = c("Si"="#E74C3C","No"="#2ECC71")) +
  labs(title = "Antiguedad en el Cargo", x = "Rotacion", y = "Anos") +
  theme_minimal(base_size = 12) + theme(legend.position = "none")

grid.arrange(p10, p11, p12, ncol = 3)
Distribucion de variables cuantitativas segun Rotacion

Distribucion de variables cuantitativas segun Rotacion

5.3 Modelos Logisticos Univariados (Bivariado)

biv_result <- function(var_name, label) {
  form <- as.formula(paste("ROT_bin ~", var_name))
  m    <- glm(form, data = rotacion, family = binomial)
  s    <- coef(summary(m))[2, ]
  data.frame(
    Variable = label,
    Beta     = round(s["Estimate"],      4),
    OR       = round(exp(s["Estimate"]), 4),
    pvalor   = round(s["Pr(>|z|)"],      4),
    Sig      = ifelse(s["Pr(>|z|)"] < 0.05, "Significativa", "No significativa"),
    stringsAsFactors = FALSE
  )
}

res_biv <- rbind(
  biv_result("HE_bin",    "Horas Extra (Si=1)"),
  biv_result("SOLTERO",   "Estado Civil Soltero (1=Si)"),
  biv_result("VJ_FREC",   "Viaje Frecuente (1=Si)"),
  biv_result("SATLAB",    "Satisfaccion Laboral"),
  biv_result("ING",       "Ingreso Mensual"),
  biv_result("ANTICARGO", "Antiguedad en el Cargo")
)

res_biv %>%
  kable(col.names = c("Variable", "Beta", "OR", "p-valor", "Significancia"),
        caption = "Tabla 6. Analisis bivariado: Regresion logistica simple por variable") %>%
  kable_styling(bootstrap_options = c("striped","hover","condensed"), full_width = FALSE) %>%
  row_spec(which(res_biv$Sig == "Significativa"), bold = TRUE, color = "#C0392B")
Tabla 6. Analisis bivariado: Regresion logistica simple por variable
Variable Beta OR p-valor Significancia
Estimate Horas Extra (Si=1) 1.3274 3.7712 0e+00 Significativa
Estimate1 Estado Civil Soltero (1=Si) 0.9507 2.5875 0e+00 Significativa
Estimate2 Viaje Frecuente (1=Si) 0.7051 2.0240 0e+00 Significativa
Estimate3 Satisfaccion Laboral -0.2531 0.7764 1e-04 Significativa
Estimate4 Ingreso Mensual -0.0001 0.9999 0e+00 Significativa
Estimate5 Antiguedad en el Cargo -0.1463 0.8639 0e+00 Significativa

Interpretacion:
- Horas Extra: Beta positivo y significativo. Trabajar horas extra aumenta la probabilidad de rotar. Confirma la hipotesis.
- Estado Civil Soltero: Beta positivo y significativo. Los solteros rotan mas. Confirma la hipotesis.
- Viaje Frecuente: Beta positivo y significativo. Los viajes frecuentes aumentan la rotacion. Confirma la hipotesis.
- Satisfaccion Laboral: Beta negativo y significativo. Mayor satisfaccion reduce la rotacion. Confirma la hipotesis.
- Ingreso Mensual: Beta negativo y significativo. Mayores ingresos reducen la rotacion. Confirma la hipotesis.
- Antiguedad en el Cargo: Beta negativo y significativo. Mayor antiguedad reduce la rotacion. Confirma la hipotesis.

Las seis hipotesis planteadas en el Punto 1 fueron respaldadas por el analisis bivariado.


6 Punto 4: Estimacion del Modelo de Regresion Logistica

6.1 Ajuste del Modelo Multiple

modelo <- glm(
  ROT_bin ~ HE_bin + SOLTERO + VJ_FREC + SATLAB + ING + ANTICARGO,
  data   = rotacion,
  family = binomial(link = "logit")
)

summary(modelo)
## 
## Call:
## glm(formula = ROT_bin ~ HE_bin + SOLTERO + VJ_FREC + SATLAB + 
##     ING + ANTICARGO, family = binomial(link = "logit"), data = rotacion)
## 
## Coefficients:
##               Estimate Std. Error z value Pr(>|z|)    
## (Intercept) -8.805e-01  2.520e-01  -3.494 0.000476 ***
## HE_bin       1.520e+00  1.604e-01   9.478  < 2e-16 ***
## SOLTERO      9.471e-01  1.578e-01   6.002 1.95e-09 ***
## VJ_FREC      7.070e-01  1.801e-01   3.925 8.66e-05 ***
## SATLAB      -3.437e-01  7.125e-02  -4.824 1.41e-06 ***
## ING         -1.056e-04  2.344e-05  -4.506 6.59e-06 ***
## ANTICARGO   -1.038e-01  2.737e-02  -3.793 0.000149 ***
## ---
## 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: 1073.7  on 1463  degrees of freedom
## AIC: 1087.7
## 
## Number of Fisher Scoring iterations: 5

6.2 Tabla de Coeficientes, OR e Intervalos de Confianza

coefs  <- coef(summary(modelo))
OR_vec <- exp(coef(modelo))
ic     <- exp(confint.default(modelo))

data.frame(
  Variable = c("Intercepto", "Horas Extra (Si)", "Soltero (Si)",
               "Viaje Frecuente (Si)", "Satisfaccion Laboral",
               "Ingreso Mensual", "Antiguedad en Cargo"),
  Beta     = round(coefs[, "Estimate"],   4),
  OR       = round(OR_vec,               4),
  IC_inf   = round(ic[, 1],             4),
  IC_sup   = round(ic[, 2],             4),
  pvalor   = round(coefs[, "Pr(>|z|)"], 4),
  Sig      = ifelse(coefs[, "Pr(>|z|)"] < 0.05, "Si *", "No"),
  row.names = NULL
) %>%
  kable(col.names = c("Variable","Beta","OR","IC 2.5%","IC 97.5%","p-valor","Sig (p<0.05)"),
        caption = "Tabla 7. Coeficientes del modelo logistico multiple con OR e IC 95%") %>%
  kable_styling(bootstrap_options = c("striped","hover","condensed"), full_width = FALSE) %>%
  row_spec(which(coefs[, "Pr(>|z|)"] < 0.05), bold = TRUE, color = "#C0392B")
Tabla 7. Coeficientes del modelo logistico multiple con OR e IC 95%
Variable Beta OR IC 2.5% IC 97.5% p-valor Sig (p<0.05)
Intercepto -0.8805 0.4146 0.2530 0.6794 5e-04 Si *
Horas Extra (Si) 1.5198 4.5714 3.3386 6.2596 0e+00 Si *
Soltero (Si) 0.9471 2.5783 1.8924 3.5128 0e+00 Si *
Viaje Frecuente (Si) 0.7070 2.0279 1.4247 2.8864 1e-04 Si *
Satisfaccion Laboral -0.3437 0.7092 0.6167 0.8154 0e+00 Si *
Ingreso Mensual -0.0001 0.9999 0.9998 0.9999 0e+00 Si *
Antiguedad en Cargo -0.1038 0.9014 0.8543 0.9511 1e-04 Si *

6.3 Interpretacion de los Coeficientes

Horas Extra (OR = 4.571):
Los empleados que trabajan horas extra tienen 4.57 veces mas probabilidad de rotar en comparacion con quienes no trabajan horas extra, manteniendo las demas variables constantes. Es el factor de mayor impacto en el modelo.

Estado Civil Soltero (OR = 2.578):
Los empleados solteros tienen 2.58 veces mas probabilidad de rotar que los no solteros.

Viaje Frecuente (OR = 2.028):
Quienes viajan frecuentemente tienen 2.03 veces mas probabilidad de rotar respecto a quienes no viajan o lo hacen raramente.

Satisfaccion Laboral (OR = 0.709):
Por cada unidad adicional de satisfaccion, la probabilidad de rotar disminuye en 29.1%, manteniendo el resto constante.

Ingreso Mensual (OR = 0.999894):
Cada unidad adicional de ingreso reduce marginalmente la probabilidad de rotacion (OR cercano pero menor a 1). El efecto es significativo acumulado sobre el rango completo de salarios.

Antiguedad en el Cargo (OR = 0.901):
Por cada ano adicional en el cargo, la probabilidad de rotar disminuye en 9.9%.


7 Punto 5: Evaluacion del Poder Predictivo

7.1 Curva ROC y AUC

rotacion$prob_pred <- predict(modelo, type = "response")

roc_obj <- roc(rotacion$ROT_bin, rotacion$prob_pred, quiet = TRUE)
auc_val <- auc(roc_obj)

plot(roc_obj,
     col         = "#E74C3C",
     lwd         = 2.5,
     main        = paste0("Curva ROC  |  AUC = ", round(auc_val, 4)),
     xlab        = "1 - Especificidad (Tasa de Falsos Positivos)",
     ylab        = "Sensibilidad (Tasa de Verdaderos Positivos)",
     legacy.axes = TRUE)
abline(a = 0, b = 1, col = "gray60", lty = 2)
legend("bottomright",
       legend = paste0("AUC = ", round(auc_val, 4)),
       col = "#E74C3C", lwd = 2.5, bty = "n")
Curva ROC del modelo de regresion logistica

Curva ROC del modelo de regresion logistica

Interpretacion del AUC = 0.7849:

Rango AUC Interpretacion
0.50 Sin poder discriminatorio (azar)
0.70 - 0.80 Poder aceptable
0.80 - 0.90 Poder bueno
> 0.90 Poder excelente

El modelo presenta un poder predictivo ACEPTABLE, siendo capaz de discriminar de forma adecuada entre empleados que rotan y los que permanecen.

7.2 Matriz de Confusion

rotacion$clase_pred <- ifelse(rotacion$prob_pred >= 0.5, 1, 0)

conf_mat <- table(Real = rotacion$ROT_bin,
                  Predicho = rotacion$clase_pred)

conf_mat %>%
  kable(caption = "Tabla 8. Matriz de confusion con punto de corte = 0.50") %>%
  kable_styling(bootstrap_options = c("striped","hover","condensed"),
                full_width = FALSE)
Tabla 8. Matriz de confusion con punto de corte = 0.50
0 1
0 1208 25
1 197 40
VP <- conf_mat["1","1"]; VN <- conf_mat["0","0"]
FP <- conf_mat["0","1"]; FN <- conf_mat["1","0"]

data.frame(
  Metrica    = c("Exactitud (Accuracy)", "Sensibilidad (Recall)", "Especificidad"),
  Formula    = c("(VP+VN) / Total", "VP / (VP+FN)", "VN / (VN+FP)"),
  Valor      = paste0(c(
    round((VP+VN)/sum(conf_mat)*100, 2),
    round(VP/(VP+FN)*100, 2),
    round(VN/(VN+FP)*100, 2)
  ), "%")
) %>%
  kable(caption = "Tabla 9. Metricas de desempeno del modelo",
        col.names = c("Metrica", "Formula", "Valor")) %>%
  kable_styling(bootstrap_options = c("striped","hover","condensed"),
                full_width = FALSE)
Tabla 9. Metricas de desempeno del modelo
Metrica Formula Valor
Exactitud (Accuracy) (VP+VN) / Total 84.9%
Sensibilidad (Recall) VP / (VP+FN) 16.88%
Especificidad VN / (VN+FP) 97.97%

8 Punto 6: Predicciones

8.1 Perfil del Empleado Hipotetico

Se define un empleado con caracteristicas de alto riesgo de rotacion para ilustrar el uso del modelo:

empleado <- data.frame(
  HE_bin    = 1,
  SOLTERO   = 1,
  VJ_FREC   = 1,
  SATLAB    = 1,
  ING       = 2500,
  ANTICARGO = 1
)

data.frame(
  Caracteristica = c("Horas Extra", "Estado Civil", "Viaje de Negocios",
                     "Satisfaccion Laboral", "Ingreso Mensual",
                     "Antiguedad en el Cargo"),
  Valor          = c("Si (1)", "Soltero (1)", "Frecuente (1)",
                     "1 (Muy baja)", "$2,500", "1 ano"),
  Justificacion  = c("Perfil de riesgo maximo", "Mayor movilidad laboral",
                     "Alto desgaste", "Insatisfecho",
                     "Salario por debajo del promedio",
                     "Recien ingresado al cargo")
) %>%
  kable(caption = "Tabla 10. Perfil del empleado hipotetico",
        col.names = c("Caracteristica", "Valor", "Justificacion")) %>%
  kable_styling(bootstrap_options = c("striped","hover","condensed"),
                full_width = FALSE)
Tabla 10. Perfil del empleado hipotetico
Caracteristica Valor Justificacion
Horas Extra Si (1) Perfil de riesgo maximo
Estado Civil Soltero (1) Mayor movilidad laboral
Viaje de Negocios Frecuente (1) Alto desgaste
Satisfaccion Laboral 1 (Muy baja) Insatisfecho
Ingreso Mensual $2,500 Salario por debajo del promedio
Antiguedad en el Cargo 1 ano Recien ingresado al cargo
prob_rot <- predict(modelo, newdata = empleado, type = "response")
cat("\nProbabilidad estimada de rotacion:", round(prob_rot * 100, 2), "%\n")
## 
## Probabilidad estimada de rotacion: 82.95 %

8.2 Criterio de Decision e Intervencion

corte <- 0.30

cat("--------------------------------------------------------\n")
## --------------------------------------------------------
cat("Umbral de intervencion definido  :", corte * 100, "%\n")
## Umbral de intervencion definido  : 30 %
cat("Probabilidad estimada del empleado:", round(prob_rot * 100, 2), "%\n")
## Probabilidad estimada del empleado: 82.95 %
cat("--------------------------------------------------------\n")
## --------------------------------------------------------
if (prob_rot >= corte) {
  cat("DECISION: INTERVENIR al empleado.\n")
  cat("La probabilidad supera el umbral del", corte*100,
      "%. Activar estrategias de retencion.\n")
} else {
  cat("DECISION: No requiere intervencion inmediata.\n")
}
## DECISION: INTERVENIR al empleado.
## La probabilidad supera el umbral del 30 %. Activar estrategias de retencion.

Justificacion del umbral al 30%: Dado que la rotacion tiene costos organizacionales elevados (reclutamiento, capacitacion, perdida de conocimiento), se adopta un umbral conservador. Esto maximiza la sensibilidad del modelo (detectar empleados que si rotaran), aceptando intervenir algunos que no necesariamente lo harian. El beneficio de retener un empleado clave supera el costo de una intervencion preventiva innecesaria.


9 Punto 7: Conclusiones y Estrategias

9.1 Resumen de Hallazgos

data.frame(
  Variable  = c("Horas Extra","Estado Civil Soltero","Viaje Frecuente",
                "Satisfaccion Laboral","Ingreso Mensual","Antiguedad Cargo"),
  Efecto    = c("Aumenta rotacion","Aumenta rotacion","Aumenta rotacion",
                "Reduce rotacion","Reduce rotacion","Reduce rotacion"),
  OR        = round(c(OR_vec["HE_bin"], OR_vec["SOLTERO"], OR_vec["VJ_FREC"],
                      OR_vec["SATLAB"], OR_vec["ING"], OR_vec["ANTICARGO"]), 4),
  pvalor    = round(coefs[c("HE_bin","SOLTERO","VJ_FREC",
                             "SATLAB","ING","ANTICARGO"), "Pr(>|z|)"], 4),
  Hipotesis = rep("Confirmada", 6),
  row.names = NULL
) %>%
  kable(col.names = c("Variable","Efecto sobre Rotacion","OR","p-valor","Hipotesis"),
        caption = "Tabla 11. Resumen de variables significativas del modelo") %>%
  kable_styling(bootstrap_options = c("striped","hover","condensed"),
                full_width = FALSE) %>%
  row_spec(1:3, color = "#C0392B") %>%
  row_spec(4:6, color = "#1A7A4A")
Tabla 11. Resumen de variables significativas del modelo
Variable Efecto sobre Rotacion OR p-valor Hipotesis
Horas Extra Aumenta rotacion 4.5714 0e+00 Confirmada
Estado Civil Soltero Aumenta rotacion 2.5783 0e+00 Confirmada
Viaje Frecuente Aumenta rotacion 2.0279 1e-04 Confirmada
Satisfaccion Laboral Reduce rotacion 0.7092 0e+00 Confirmada
Ingreso Mensual Reduce rotacion 0.9999 0e+00 Confirmada
Antiguedad Cargo Reduce rotacion 0.9014 1e-04 Confirmada

9.2 Estrategias para Disminuir la Rotacion

9.2.1 Reducir las Horas Extra (factor de mayor impacto)

  • Contratar personal adicional para distribuir la carga laboral y evitar sobrecargas.
  • Establecer politicas de desconexion digital fuera del horario laboral.
  • Compensar con dias libres o bonificaciones a quienes realicen horas extra puntuales.
  • Monitorear sistematicamente las areas con mayor proporcion de horas extra.

9.2.2 Retencion de Empleados Solteros

  • Desarrollar programas de integracion social y comunidad organizacional que fortalezcan el sentido de pertenencia.
  • Ofrecer beneficios valorados por este grupo: flexibilidad horaria, teletrabajo y oportunidades de desarrollo profesional acelerado.
  • Disenar planes de carrera claros con metas y reconocimientos a corto plazo.

9.2.3 Gestion de Viajes de Negocio

  • Limitar la frecuencia maxima de viajes por empleado en el ano.
  • Ofrecer dias de descanso recuperatorios tras viajes de larga duracion.
  • Evaluar alternativas digitales (videoconferencias) cuando sea posible.

9.2.4 Mejorar la Satisfaccion Laboral

  • Realizar encuestas periodicas de clima organizacional y actuar sobre los resultados.
  • Implementar sistemas de reconocimiento formal e informal.
  • Ofrecer programas de bienestar: salud mental, pausas activas y horarios flexibles.
  • Promover la participacion del empleado en decisiones que lo afecten.

9.2.5 Politica Salarial Competitiva

  • Revisar y ajustar la estructura salarial conforme al mercado laboral del sector.
  • Implementar bonos por desempeno, metas alcanzadas y permanencia.
  • Complementar con beneficios no monetarios: seguro de salud, educacion, auxilios.

9.2.6 Reconocimiento de la Antiguedad

  • Escalar beneficios segun anos de servicio (vacaciones adicionales, mayor flexibilidad).
  • Asignar roles de mentoria y liderazgo a empleados con experiencia consolidada.
  • Crear ceremonias de reconocimiento por hitos de permanencia.

9.3 Reflexion Final

El modelo de regresion logistica desarrollado alcanza un AUC = 0.785, evidenciando un poder predictivo aceptable para discriminar entre empleados que rotan y los que permanecen. Todas las hipotesis planteadas inicialmente fueron confirmadas por los datos.

Implementar este modelo como herramienta de alerta temprana en Recursos Humanos permitira a la empresa actuar de forma proactiva sobre los empleados con mayor riesgo, antes de que la decision de rotar sea irreversible. La estrategia mas costo-efectiva a corto plazo es controlar las horas extra, por ser el predictor de mayor impacto. A mediano plazo, mejorar la satisfaccion laboral y la competitividad salarial generara un ambiente organizacional mas estable y comprometido.


10 Referencias

  • Weiers, R. M. (2006). Introduccion a la estadistica para Negocios. 5 ed. Thomson.
  • Hosmer, D. W., & Lemeshow, S. (2000). Applied Logistic Regression. Wiley.
  • R Core Team (2024). R: A Language and Environment for Statistical Computing.
  • Paquete paqueteMODELOS. Centro MAGIS.

Informe generado con R Markdown | Actividad 3 - Modelos Lineales Generalizados