Taller de Probabilidad e Inferencia Estadística
Dataset: IBM HR Analytics Employee Attrition
Contexto: La deserción laboral representa un problema enorme para las organizaciones actuales, es por eso que mediante el presente informe con información de dataset IBM HR Analytics se identificaran patrones demográficos y laborales que influyen en la decisión de los empleados de abandonar la empresa, utilizando la estadistica como herramienta teorica.
Objetivo General: Analizar los factores que inciden en la deserción laboral mediante técnicas de probabilidad e inferencia estadística.
#Librerias a utilizar
library(tidyverse)
library(naniar)
library(ggplot2)
library(dplyr)
library(knitr)
library(kableExtra)
library(tibble)
#carga del dataset
df <- read_csv("input/WA_Fn-UseC_-HR-Employee-Attrition.csv")a) Reporte de dimesiones
## Rows: 1,470
## Columns: 35
## $ Age <dbl> 41, 49, 37, 33, 27, 32, 59, 30, 38, 36, 35, 2…
## $ Attrition <chr> "Yes", "No", "Yes", "No", "No", "No", "No", "…
## $ BusinessTravel <chr> "Travel_Rarely", "Travel_Frequently", "Travel…
## $ DailyRate <dbl> 1102, 279, 1373, 1392, 591, 1005, 1324, 1358,…
## $ Department <chr> "Sales", "Research & Development", "Research …
## $ DistanceFromHome <dbl> 1, 8, 2, 3, 2, 2, 3, 24, 23, 27, 16, 15, 26, …
## $ Education <dbl> 2, 1, 2, 4, 1, 2, 3, 1, 3, 3, 3, 2, 1, 2, 3, …
## $ EducationField <chr> "Life Sciences", "Life Sciences", "Other", "L…
## $ EmployeeCount <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ EmployeeNumber <dbl> 1, 2, 4, 5, 7, 8, 10, 11, 12, 13, 14, 15, 16,…
## $ EnvironmentSatisfaction <dbl> 2, 3, 4, 4, 1, 4, 3, 4, 4, 3, 1, 4, 1, 2, 3, …
## $ Gender <chr> "Female", "Male", "Male", "Female", "Male", "…
## $ HourlyRate <dbl> 94, 61, 92, 56, 40, 79, 81, 67, 44, 94, 84, 4…
## $ JobInvolvement <dbl> 3, 2, 2, 3, 3, 3, 4, 3, 2, 3, 4, 2, 3, 3, 2, …
## $ JobLevel <dbl> 2, 2, 1, 1, 1, 1, 1, 1, 3, 2, 1, 2, 1, 1, 1, …
## $ JobRole <chr> "Sales Executive", "Research Scientist", "Lab…
## $ JobSatisfaction <dbl> 4, 2, 3, 3, 2, 4, 1, 3, 3, 3, 2, 3, 3, 4, 3, …
## $ MaritalStatus <chr> "Single", "Married", "Single", "Married", "Ma…
## $ MonthlyIncome <dbl> 5993, 5130, 2090, 2909, 3468, 3068, 2670, 269…
## $ MonthlyRate <dbl> 19479, 24907, 2396, 23159, 16632, 11864, 9964…
## $ NumCompaniesWorked <dbl> 8, 1, 6, 1, 9, 0, 4, 1, 0, 6, 0, 0, 1, 0, 5, …
## $ Over18 <chr> "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", …
## $ OverTime <chr> "Yes", "No", "Yes", "Yes", "No", "No", "Yes",…
## $ PercentSalaryHike <dbl> 11, 23, 15, 11, 12, 13, 20, 22, 21, 13, 13, 1…
## $ PerformanceRating <dbl> 3, 4, 3, 3, 3, 3, 4, 4, 4, 3, 3, 3, 3, 3, 3, …
## $ RelationshipSatisfaction <dbl> 1, 4, 2, 3, 4, 3, 1, 2, 2, 2, 3, 4, 4, 3, 2, …
## $ StandardHours <dbl> 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 8…
## $ StockOptionLevel <dbl> 0, 1, 0, 0, 1, 0, 3, 1, 0, 2, 1, 0, 1, 1, 0, …
## $ TotalWorkingYears <dbl> 8, 10, 7, 8, 6, 8, 12, 1, 10, 17, 6, 10, 5, 3…
## $ TrainingTimesLastYear <dbl> 0, 3, 3, 3, 3, 2, 3, 2, 2, 3, 5, 3, 1, 2, 4, …
## $ WorkLifeBalance <dbl> 1, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3, 2, 3, 3, …
## $ YearsAtCompany <dbl> 6, 10, 0, 8, 2, 7, 1, 1, 9, 7, 5, 9, 5, 2, 4,…
## $ YearsInCurrentRole <dbl> 4, 7, 0, 7, 2, 7, 0, 0, 7, 7, 4, 5, 2, 2, 2, …
## $ YearsSinceLastPromotion <dbl> 0, 1, 0, 3, 2, 3, 0, 0, 1, 7, 0, 0, 4, 1, 0, …
## $ YearsWithCurrManager <dbl> 5, 7, 0, 0, 2, 6, 0, 0, 8, 7, 3, 8, 3, 2, 3, …
## El dataset contiene 1470 filas y 35 columnas.
##
## character numeric
## 9 26
df_tra <- df %>%
mutate(
Attrition = as.factor(Attrition),
Department = as.factor(Department),
OverTime = as.factor(OverTime),
BusinessTravel = as.factor(BusinessTravel),
EducationField = as.factor(EducationField),
JobRole = as.factor(JobRole),
MaritalStatus = as.factor(MaritalStatus),
Gender = as.factor(Gender)
)Dimensiones: El dataset contiene, 35 variables con un total de 1470 registros los cuales se distribuye en 9 variables character de las cuales 8 se transforman en factor como buena practica, las restantes 26 son valores númericos.
b) Frecuencias absolutas y relativas de Attrition.
tabla_base <- table(df_tra$Attrition)
distribucion <- data.frame(
Absoluta = as.vector(tabla_base),
Relativa = as.vector(prop.table(tabla_base)),
Porcentaje = paste0(round(as.vector(prop.table(tabla_base)) * 100, 2), "%"),
row.names = names(tabla_base)
)
df_resumen <- df_tra %>%
count(Attrition) %>%
mutate(porcentaje = n / sum(n),
etiqueta = paste0("n=", n, "\n(", round(porcentaje*100, 1), "%)"))
distribucion %>%
kable(
caption = "Tabla 1: Distribución de Frecuencias de Attrition",
col.names = c("Frec. Absoluta (n)", "Frec. Relativa", "Porcentaje (%)"),
align = "ccc"
) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed"),
full_width = F,
position = "center"
)| Frec. Absoluta (n) | Frec. Relativa | Porcentaje (%) | |
|---|---|---|---|
| No | 1233 | 0.8387755 | 83.88% |
| Yes | 237 | 0.1612245 | 16.12% |
ggplot(df_resumen, aes(x = "Dataset", y = porcentaje, fill = Attrition)) +
geom_bar(stat = "identity", width = 0.4) +
geom_text(aes(label = etiqueta),
position = position_stack(vjust = 0.5),
color = "white", fontface = "bold", size = 5) +
scale_y_continuous(labels = scales::percent) +
theme_minimal() +
labs(title = "Distribución de Attrition",
subtitle = "Frecuencias Absolutas (n) y Relativas (%)",
x = "",
y = "Proporción del Total") +
scale_fill_manual(values = c("No" = "#2E86AB", "Yes" = "#D90368"))
c) Frecuencias absolutas y relativas de Attrition. RTA
// La distribución de la variable Attrition se encuentra fuertemente
desbalanceada. Como se evidencia en los resultados anteriores, el 83.88%
de los empleados permanecen en la compañía, mientras que solo el 16.12%
corresponden a casos de deserción.
Para un proyecto de clasificación, este desbalanceo representa un desafío crítico ya que un un modelo básico podría alcanzar una alta precisión (accuracy) simplemente prediciendo siempre la clase mayoritaria (“No”), ignorando la clase de interés (“Yes”).
a) Tabla de contingencia entre OverTime VS Attrition
tabla_limpia <- table(df_tra$OverTime, df_tra$Attrition)
tabla_limpia <- addmargins(tabla_limpia)
tabla_limpia_df <- as.data.frame.matrix(tabla_limpia)
rownames(tabla_limpia_df) <- c("No realiza horas extra", "Realiza horas extra", "Total")
colnames(tabla_limpia_df) <- c("Attrition = No", "Attrition = Yes", "Total")
tabla_limpia_df %>%
rownames_to_column(var = "Condición") %>%
kable(
caption = "Tabla 2: Contingencia entre Horas Extra y Deserción",
col.names = c("Condición", "ATT = No", "ATT = Yes", "Total"),
align = c("l", "c", "c", "c"),
booktabs = TRUE
) %>%
add_header_above(c(" " = 1, "Estado de Attrition" = 2, " " = 1), bold = TRUE) %>%
column_spec(1, width = "1%em") %>%
column_spec(2:4, width = "7em") %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE,
position = "center"
)| Condición | ATT = No | ATT = Yes | Total |
|---|---|---|---|
| No realiza horas extra | 944 | 110 | 1054 |
| Realiza horas extra | 289 | 127 | 416 |
| Total | 1233 | 237 | 1470 |
b) Tabla de tabla de probabilidades conjuntas
tabla_conj_raw <- prop.table(table(df_tra$OverTime, df_tra$Attrition))
tabla_conj_marg <- addmargins(tabla_conj_raw)
tabla_conj_marg_df <- as.data.frame.matrix(tabla_conj_marg)
rownames(tabla_conj_marg_df) <- c("OT = No", "OT = Yes", "Marginal col.")
colnames(tabla_conj_marg_df) <- c("ATT = No", "ATT = Yes", "Marginal Fila")
tabla_conj_marg_df %>%
rownames_to_column(var = "Estado") %>%
kable(
caption = "Tabla 3: Probabilidades Conjuntas y Marginales (Distribución Relativa)",
digits = 4,
align = c("l", "c", "c", "c"),
booktabs = TRUE
) %>%
column_spec(1, width = "12em") %>%
column_spec(2:4, width = "10em") %>%
kable_styling(
bootstrap_options = c("striped", "bordered", "hover", "condensed"),
full_width = FALSE,
position = "center"
)| Estado | ATT = No | ATT = Yes | Marginal Fila |
|---|---|---|---|
| OT = No | 0.6422 | 0.0748 | 0.717 |
| OT = Yes | 0.1966 | 0.0864 | 0.283 |
| Marginal col. | 0.8388 | 0.1612 | 1.000 |
c) probabilidades marginales
Probabilidad de deserción según las horas extra
tabla_fila <- prop.table(table(df_tra$OverTime, df_tra$Attrition), margin = 1)
tabla_fila_df <- as.data.frame.matrix(tabla_fila)
tabla_fila_df$`Total fila` <- rowSums(tabla_fila_df)
rownames(tabla_fila_df) <- c("OT = No", "OT = Yes")
colnames(tabla_fila_df)[1:2] <- c("ATT = No", "ATT = Yes")
tabla_fila_df %>%
rownames_to_column("Estado") %>%
kable(
caption = "Tabla 4: Probabilidades condicionales por fila",
digits = 4,
align = c("l","c","c","c")
) %>%
column_spec(1, width = "12em") %>%
column_spec(2:3, width = "10em") %>%
kable_styling(
bootstrap_options = c("striped","hover","condensed"),
full_width = FALSE,
position = "center"
)| Estado | ATT = No | ATT = Yes | Total fila |
|---|---|---|---|
| OT = No | 0.8956 | 0.1044 | 1 |
| OT = Yes | 0.6947 | 0.3053 | 1 |
Para empleados que no realizan horas extra:
Probabilidad de permanecer: 89.56%
Probabilidad de desertar: 10.44%
Para empleados que sí realizan horas extra:
Probabilidad de permanecer: 69.47%
Probabilidad de desertar: 30.53%
Conclusión La probabilidad de deserción es considerablemente mayor entre los empleados que realizan horas extra.
Proporción de empleados con horas extra dentro de cada grupo de deserción
tabla_conj_raw <- prop.table(table(df_tra$OverTime, df_tra$Attrition), margin = 2)
tabla_conj_df <- as.data.frame.matrix(tabla_conj_raw)
tabla_conj_df["Totales", ] <- colSums(tabla_conj_df)
rownames(tabla_conj_df)[1:2] <- c("OT = No", "OT = Yes")
colnames(tabla_conj_df) <- c("ATT = No", "ATT = Yes")
tabla_conj_df %>%
rownames_to_column(var = "Estado") %>%
kable(
caption = "Tabla 5: Probabilidades condicionales por columna",
digits = 4,
align = c("l", "c", "c"),
booktabs = TRUE
) %>%
column_spec(1, width = "12em") %>%
column_spec(2:3, width = "10em") %>%
kable_styling(
bootstrap_options = c("striped", "bordered", "hover", "condensed"),
full_width = FALSE,
position = "center"
)| Estado | ATT = No | ATT = Yes |
|---|---|---|
| OT = No | 0.7656 | 0.4641 |
| OT = Yes | 0.2344 | 0.5359 |
| Totales | 1.0000 | 1.0000 |
Para empleados que no desertan:
76.56% no realiza horas extra
23.44% sí realiza horas extra
Para empleados que sí desertan:
46.41% no realiza horas extra
53.59% sí realiza horas extra
Conclusión Más de la mitad de los empleados que desertan realizan horas extra.
d) Calcule las probabilidades condicionales P(Att=Yes | OT=Yes) y P(Att=Yes | OT=No) usando la definición. Compárelas con P(Att=Yes) y concluya: ¿las horas extra influyen en la deserción?
Esto indica que las horas extra influyen significativamente en la deserción laboral, ya que la probabilidad de que un colaborador deserte al hacer horas extras es considerablemente mayor, esta deducido gracias a la información de la tabla 4.
e) Evalúe si Attrition y OverTime son independientes verificando si P(A ∩ B) = P(A) · P(B) para alguna combinación.
Se debe tomar un caso puntual para cada conjunto A y B:
P(A∩B)=0,0864 <- Esto según la Tabla 3.
Tomando la misma Tabla 3 se observa: P(A) = 0,1612 <- Según nuestra probabilidad marginal de ATT = Yes en la tabla 3. P(B) = 0,283 <- Según nuestra probabilidad marginal de OT = Yes en la tabla 3.
P(A)⋅P(B) 0.1612 × 0.283 = 0.0456
0.0864 != 0.0456
Conclusión Dado que estas variables no cumplen la condición de P(A ∩ B) = P(A) · P(B) se consideran variables dependientes, demostrando así que entre las horas extras y la deserción existe una relación.
a) Construya la tabla de contingencia entre Department y Attrition con frecuencias absolutas y marginales.
tabla_dept <- table(df_tra$Department, df_tra$Attrition)
tabla_dept_marg <- addmargins(tabla_dept)
tabla_dept_df <- as.data.frame.matrix(tabla_dept_marg)
colnames(tabla_dept_df) <- c("ATT = No", "ATT = Yes", "Total")
tabla_dept_df %>%
rownames_to_column(var = "Department") %>%
kable(
caption = "Tabla 6: Contingencia entre Department y Attrition (Frecuencias absolutas)",
align = c("l","c","c","c"),
booktabs = TRUE
) %>%
add_header_above(c(" " = 1, "Estado de Attrition" = 2, " " = 1), bold = TRUE) %>%
column_spec(1, width = "14em") %>%
column_spec(2:4, width = "7em") %>%
kable_styling(
bootstrap_options = c("striped","hover","condensed"),
full_width = FALSE,
position = "center"
)| Department | ATT = No | ATT = Yes | Total |
|---|---|---|---|
| Human Resources | 51 | 12 | 63 |
| Research & Development | 828 | 133 | 961 |
| Sales | 354 | 92 | 446 |
| Sum | 1233 | 237 | 1470 |
b) Tablas de probabilidades conjuntas, marginales y condicionales
tabla_conj_raw_dep <- prop.table(table(df_tra$Department, df_tra$Attrition))
tabla_conj_marg_dep <- addmargins(tabla_conj_raw_dep)
tabla_conj_marg_df_dep <- as.data.frame.matrix(tabla_conj_marg_dep)
colnames(tabla_conj_marg_df_dep) <- c("ATT = No", "ATT = Yes", "Marginal Fila")
tabla_conj_marg_df_dep %>%
rownames_to_column(var = "Departamento") %>%
kable(
caption = "Tabla 7: Probabilidades Conjuntas y Marginales por departamento (Distribución Relativa)",
digits = 4,
align = c("l", "c", "c", "c"),
booktabs = TRUE
) %>%
column_spec(1, width = "12em") %>%
column_spec(2:4, width = "10em") %>%
kable_styling(
bootstrap_options = c("striped", "bordered", "hover", "condensed"),
full_width = FALSE,
position = "center"
)| Departamento | ATT = No | ATT = Yes | Marginal Fila |
|---|---|---|---|
| Human Resources | 0.0347 | 0.0082 | 0.0429 |
| Research & Development | 0.5633 | 0.0905 | 0.6537 |
| Sales | 0.2408 | 0.0626 | 0.3034 |
| Sum | 0.8388 | 0.1612 | 1.0000 |
Probabilidad de deserción según departamento
tabla_fila_dep <- prop.table(table(df_tra$Department, df_tra$Attrition), margin = 1)
tabla_fila_def_df <- as.data.frame.matrix(tabla_fila_dep)
tabla_fila_def_df$`Total fila` <- rowSums(tabla_fila_def_df)
colnames(tabla_fila_df)[1:2] <- c("ATT = No", "ATT = Yes")
tabla_fila_def_df %>%
rownames_to_column("Departamento") %>%
kable(
caption = "Tabla 8: Probabilidades condicionales por deaprtamento",
digits = 4,
align = c("l","c","c","c")
) %>%
column_spec(1, width = "12em") %>%
column_spec(2:3, width = "10em") %>%
kable_styling(
bootstrap_options = c("striped","hover","condensed"),
full_width = FALSE,
position = "center"
)| Departamento | No | Yes | Total fila |
|---|---|---|---|
| Human Resources | 0.8095 | 0.1905 | 1 |
| Research & Development | 0.8616 | 0.1384 | 1 |
| Sales | 0.7937 | 0.2063 | 1 |
Para empleados de Human Resources:
Para empleados de Research & Development:
Para empleados de Sales:
Proporción de empleados por departamento dentro de cada grupo de deserción
tabla_conj_dep <- prop.table(table(df_tra$Department, df_tra$Attrition), margin = 2)
tabla_conj_df_dep <- as.data.frame.matrix(tabla_conj_dep)
tabla_conj_df_dep["Totales", ] <- colSums(tabla_conj_df_dep)
colnames(tabla_conj_df_dep) <- c("ATT = No", "ATT = Yes")
tabla_conj_df_dep %>%
rownames_to_column(var = "Departamento") %>%
kable(
caption = "Tabla 5: Probabilidades condicionales por columna",
digits = 4,
align = c("l", "c", "c"),
booktabs = TRUE
) %>%
column_spec(1, width = "12em") %>%
column_spec(2:3, width = "10em") %>%
kable_styling(
bootstrap_options = c("striped", "bordered", "hover", "condensed"),
full_width = FALSE,
position = "center"
)| Departamento | ATT = No | ATT = Yes |
|---|---|---|
| Human Resources | 0.0414 | 0.0506 |
| Research & Development | 0.6715 | 0.5612 |
| Sales | 0.2871 | 0.3882 |
| Totales | 1.0000 | 1.0000 |
Para empleados que sí desertan:
5,06% es de Human Resources
56,12% es de Research & Development
38,82% es de Sales