🎯 Objetivo: Aprender a transformar una base de datos en conocimiento útil, pasando por el planteamiento de un objetivo claro hasta la interpretación de resultados estadísticos.
El análisis descriptivo es el primer paso en cualquier proceso de exploración de datos. Su objetivo no es predecir ni inferir, sino describir y resumir la información que ya tenemos.
Un buen análisis descriptivo responde preguntas como:
Lo primero es cargar los datos y hacer una exploración inicial. Nunca comiences un análisis sin revisar la estructura de tu base.
# Cargamos la base de datos
library(readxl)
datos <- read_excel("~/Documents/Delia Ortega 2023/disco_d/DISCOE/CLASES/JAVERIANA_SALUD/Teoria_Probabilidad/Base_empleados.xlsx")
# Vista preliminar de los primeros registros
head(datos, 10)## Rows: 50
## Columns: 4
## $ GENERO <chr> "Femenino", "Masculino", "Femenino", "Masculino", "Masculin…
## $ ANTIGUEDAD <dbl> 2, 4, 13, 7, 2, 4, 25, 9, 6, 27, 2, 2, 0, 39, 27, 4, 3, 29,…
## $ EDAD <dbl> 34, 47, 42, 29, 51, 29, 54, 36, 37, 50, 32, 31, 41, 60, 56,…
## $ SALARIO <dbl> 1107, 1322, 1367, 1397, 1575, 1645, 1819, 1879, 1961, 2135,…
## GENERO ANTIGUEDAD EDAD SALARIO
## Length:50 Min. : 0.00 Min. :22.00 Min. : 1107
## Class :character 1st Qu.: 2.00 1st Qu.:28.25 1st Qu.: 3044
## Mode :character Median : 4.00 Median :37.00 Median : 4110
## Mean :10.24 Mean :38.82 Mean : 4316
## 3rd Qu.:17.75 3rd Qu.:47.00 3rd Qu.: 5651
## Max. :39.00 Max. :60.00 Max. :11563
## 🔍 Valores faltantes por variable:
colSums(is.na(datos)) %>%
as.data.frame() %>%
setNames("Faltantes") %>%
kable(caption = "Conteo de valores faltantes") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| Faltantes | |
|---|---|
| GENERO | 0 |
| ANTIGUEDAD | 0 |
| EDAD | 0 |
| SALARIO | 0 |
No hay valores faltantes en esta base. Podemos continuar con confianza.
| Variable | Tipo | Descripción |
|---|---|---|
| GENERO | Cualitativa nominal | Género del trabajador: Femenino / Masculino |
| ANTIGUEDAD | Cuantitativa discreta razón | Años de antigüedad en la empresa (0 a 39 años) |
| EDAD | Cuantitativa discreta razón | Edad del trabajador en años (22 a 60 años) |
| SALARIO | Cuantitativa continua razón | Salario mensual del trabajador (en unidades monetarias) |
Un objetivo de análisis debe ser:
| Criterio | Descripción |
|---|---|
| Específico | Referido a variables concretas de la base |
| Medible | Expresado en términos estadísticos (promedios, frecuencias, correlaciones) |
| Relevante | Que responda a una pregunta de interés real |
| Acotado | Limitado a lo que los datos permiten responder |
Objetivo general: Describir las características sociodemográficas y salariales de los trabajadores registrados en la base, identificando posibles diferencias según el género y explorando la relación entre la antigüedad, la edad y el salario.
OE1 — Análisis univariado: Describir la distribución de cada variable (género, antigüedad, edad y salario) mediante medidas de tendencia central, dispersión y gráficos apropiados.
OE2 — Análisis bivariado: Examinar la relación entre el salario y el género, así como entre las variables numéricas (antigüedad, edad y salario).
El análisis univariado estudia cada variable de forma independiente. El tipo de análisis depende del tipo de variable:
| Tipo de variable | Medidas resumen | Gráficos |
|---|---|---|
| Cualitativa (nominal/ordinal) | Frecuencias absolutas y relativas, moda | Gráfico de barras, gráfico de torta |
| Cuantitativa (discreta/continua) | Media, mediana, moda, desviación estándar, rango, cuartiles | Histograma, boxplot, densidad |
# Tabla de frecuencias absoluta y relativa
tabla_genero <- datos %>%
count(GENERO) %>%
mutate(
Porcentaje = round(n / sum(n) * 100, 1),
`% Acumulado` = cumsum(Porcentaje)
) %>%
rename(Categoría = GENERO, Frecuencia = n)
kable(tabla_genero, caption = "Distribución de frecuencias: GÉNERO") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
row_spec(0, bold = TRUE, background = col_main, color = "white")| Categoría | Frecuencia | Porcentaje | % Acumulado |
|---|---|---|---|
| Femenino | 18 | 36 | 36 |
| Masculino | 32 | 64 | 100 |
ggplot(tabla_genero, aes(x = Categoría, y = Frecuencia, fill = Categoría)) +
geom_col(width = 0.5, show.legend = FALSE) +
geom_text(aes(label = paste0(Frecuencia, "\n(", Porcentaje, "%)")),
vjust = -0.4, fontface = "bold", size = 4.5) +
scale_fill_manual(values = c("Femenino" = col_fem, "Masculino" = col_mas)) +
scale_y_continuous(limits = c(0, 40), breaks = seq(0, 40, 5)) +
labs(
title = "Distribución por Género",
subtitle = "Base de datos de empleo — n = 50",
x = "Género",
y = "Número de trabajadores",
caption = "Fuente: Base_empleo.xlsx"
) +
theme_minimal(base_size = 13) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5, color = "gray50"),
axis.title = element_text(face = "bold")
)📝 Interpretación: El 64% de los trabajadores son de género masculino (32 personas) y el 36% femenino (18 personas). La muestra no está balanceada en términos de género.
# Función para calcular estadísticos completos
estadisticos <- function(x, nombre_var) {
data.frame(
Estadístico = c("Mínimo", "Q1 (25%)", "Mediana (Q2)", "Media",
"Q3 (75%)", "Máximo", "Rango", "Desv. Estándar",
"Coef. Variación (%)", "Asimetría (Skewness)"),
Valor = c(
min(x), quantile(x, 0.25), median(x), round(mean(x), 2),
quantile(x, 0.75), max(x), diff(range(x)),
round(sd(x), 2),
round(sd(x)/mean(x)*100, 1),
round(skewness(x), 2)
)
)
}
estadisticos(datos$ANTIGUEDAD, "ANTIGUEDAD") %>%
kable(caption = "📊 Estadísticos descriptivos: ANTIGÜEDAD (años)") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
row_spec(c(4), background = "#D5E8D4", bold = TRUE)| Estadístico | Valor |
|---|---|
| Mínimo | 0.00 |
| Q1 (25%) | 2.00 |
| Mediana (Q2) | 4.00 |
| Media | 10.24 |
| Q3 (75%) | 17.75 |
| Máximo | 39.00 |
| Rango | 39.00 |
| Desv. Estándar | 11.30 |
| Coef. Variación (%) | 110.40 |
| Asimetría (Skewness) | 1.04 |
p1 <- ggplot(datos, aes(x = ANTIGUEDAD)) +
geom_histogram(aes(y = after_stat(density)),
bins = 10, fill = col_mas, color = "white", alpha = 0.85) +
geom_density(color = col_acc, linewidth = 1.2, linetype = "dashed") +
geom_vline(aes(xintercept = mean(ANTIGUEDAD)), color = col_acc,
linewidth = 1, linetype = "solid") +
annotate("text", x = mean(datos$ANTIGUEDAD) + 3, y = 0.06,
label = paste0("Media = ", round(mean(datos$ANTIGUEDAD), 1)),
color = col_acc, fontface = "bold", size = 4) +
labs(title = "Histograma de Antigüedad",
x = "Años de antigüedad", y = "Densidad") +
theme_minimal(base_size = 12) +
theme(plot.title = element_text(face = "bold", hjust = 0.5))
p2 <- ggplot(datos, aes(y = ANTIGUEDAD, x = "")) +
geom_boxplot(fill = col_mas, alpha = 0.7, width = 0.4,
outlier.color = col_acc, outlier.size = 3) +
stat_summary(fun = mean, geom = "point", shape = 18,
size = 4, color = col_acc) +
labs(title = "Boxplot de Antigüedad",
x = "", y = "Años de antigüedad") +
theme_minimal(base_size = 12) +
theme(plot.title = element_text(face = "bold", hjust = 0.5))
p1 + p2📝 Interpretación: La distribución de la antigüedad es asimétrica positiva (cola hacia la derecha), lo que indica que la mayoría de los trabajadores tiene poca antigüedad (mediana = 4 años), pero hay algunos con muchos años en la empresa (hasta 39). La media (10.2 años) está desplazada respecto a la mediana por estos valores altos, lo que confirma la asimetría.
estadisticos(datos$EDAD, "EDAD") %>%
kable(caption = "📊 Estadísticos descriptivos: EDAD (años)") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
row_spec(c(4), background = "#D5E8D4", bold = TRUE)| Estadístico | Valor |
|---|---|
| Mínimo | 22.00 |
| Q1 (25%) | 28.25 |
| Mediana (Q2) | 37.00 |
| Media | 38.82 |
| Q3 (75%) | 47.00 |
| Máximo | 60.00 |
| Rango | 38.00 |
| Desv. Estándar | 11.98 |
| Coef. Variación (%) | 30.90 |
| Asimetría (Skewness) | 0.33 |
p3 <- ggplot(datos, aes(x = EDAD)) +
geom_histogram(aes(y = after_stat(density)),
bins = 10, fill = "#7DCEA0", color = "white", alpha = 0.85) +
geom_density(color = col_acc, linewidth = 1.2, linetype = "dashed") +
geom_vline(aes(xintercept = mean(EDAD)), color = col_acc,
linewidth = 1) +
annotate("text", x = mean(datos$EDAD) + 4, y = 0.038,
label = paste0("Media = ", round(mean(datos$EDAD), 1)),
color = col_acc, fontface = "bold", size = 4) +
labs(title = "Histograma de Edad",
x = "Edad (años)", y = "Densidad") +
theme_minimal(base_size = 12) +
theme(plot.title = element_text(face = "bold", hjust = 0.5))
p4 <- ggplot(datos, aes(y = EDAD, x = "")) +
geom_boxplot(fill = "#7DCEA0", alpha = 0.7, width = 0.4,
outlier.color = col_acc, outlier.size = 3) +
stat_summary(fun = mean, geom = "point", shape = 18,
size = 4, color = col_acc) +
labs(title = "Boxplot de Edad",
x = "", y = "Edad (años)") +
theme_minimal(base_size = 12) +
theme(plot.title = element_text(face = "bold", hjust = 0.5))
p3 + p4📝 Interpretación: La edad se distribuye de manera aproximadamente simétrica con media y mediana muy cercanas (~38-39 años). No se observan valores atípicos. El rango va de 22 a 60 años, cubriendo trabajadores jóvenes y adultos mayores.
estadisticos(datos$SALARIO, "SALARIO") %>%
kable(caption = "📊 Estadísticos descriptivos: SALARIO (unidades monetarias)") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
row_spec(c(4), background = "#D5E8D4", bold = TRUE)| Estadístico | Valor |
|---|---|
| Mínimo | 1107.00 |
| Q1 (25%) | 3044.50 |
| Mediana (Q2) | 4110.50 |
| Media | 4315.52 |
| Q3 (75%) | 5651.25 |
| Máximo | 11563.00 |
| Rango | 10456.00 |
| Desv. Estándar | 2132.12 |
| Coef. Variación (%) | 49.40 |
| Asimetría (Skewness) | 0.86 |
p5 <- ggplot(datos, aes(x = SALARIO)) +
geom_histogram(aes(y = after_stat(density)),
bins = 12, fill = "#F0B27A", color = "white", alpha = 0.85) +
geom_density(color = col_acc, linewidth = 1.2, linetype = "dashed") +
geom_vline(aes(xintercept = mean(SALARIO)), color = col_acc, linewidth = 1) +
geom_vline(aes(xintercept = median(SALARIO)), color = col_main,
linewidth = 1, linetype = "dotted") +
annotate("text", x = mean(datos$SALARIO) + 1500, y = 0.00021,
label = paste0("Media = ", comma(round(mean(datos$SALARIO)))),
color = col_acc, fontface = "bold", size = 3.5) +
annotate("text", x = median(datos$SALARIO) - 1800, y = 0.00021,
label = paste0("Mediana = ", comma(median(datos$SALARIO))),
color = col_main, fontface = "bold", size = 3.5) +
labs(title = "Histograma de Salario",
x = "Salario (u.m.)", y = "Densidad") +
theme_minimal(base_size = 12) +
theme(plot.title = element_text(face = "bold", hjust = 0.5))
p6 <- ggplot(datos, aes(y = SALARIO, x = "")) +
geom_boxplot(fill = "#F0B27A", alpha = 0.7, width = 0.4,
outlier.color = col_acc, outlier.size = 3) +
stat_summary(fun = mean, geom = "point", shape = 18,
size = 4, color = col_acc) +
scale_y_continuous(labels = comma) +
labs(title = "Boxplot de Salario",
x = "", y = "Salario (u.m.)") +
theme_minimal(base_size = 12) +
theme(plot.title = element_text(face = "bold", hjust = 0.5))
p5 + p6📝 Interpretación: El salario presenta una distribución asimétrica positiva: la mediana (4.111) es menor que la media (4.316), señal de que algunos salarios muy altos “jalan” la media hacia arriba. El coeficiente de variación es del ~49%, indicando alta variabilidad en los salarios. Hay al menos un valor atípico superior (>11.000) visible en el boxplot.
| Variable | Tipo | Medida.clave | Dispersión | Distribución |
|---|---|---|---|---|
| GÉNERO | Cualitativa | Moda: Masculino (64%) | — | No aplica |
| ANTIGÜEDAD | Cuantitativa | Mediana: 4 años | Media: 10.2 | CV = 110.4% (muy alta) | Asimétrica positiva |
| EDAD | Cuantitativa | Mediana: 37 años | Media: 38.8 | CV = 30.9% (moderada) | Aproximadamente simétrica |
| SALARIO | Cuantitativa | Mediana: 4.111 | Media: 4.316 | CV = 49.4% (alta) | Asimétrica positiva |
El análisis bivariado estudia la relación entre dos variables. La estrategia depende de las combinaciones de tipos:
| Combinación de variables | Herramientas |
|---|---|
| Cualitativa × Cualitativa | Tablas de contingencia, barras agrupadas |
| Cualitativa × Cuantitativa | Boxplots comparativos, estadísticos por grupo |
| Cuantitativa × Cuantitativa | Diagrama de dispersión, correlación de Pearson/Spearman |
datos %>%
group_by(GENERO) %>%
summarise(
n = n(),
Media = round(mean(SALARIO), 0),
Mediana = median(SALARIO),
`Desv.Est.` = round(sd(SALARIO), 0),
Mínimo = min(SALARIO),
Máximo = max(SALARIO),
CV = paste0(round(sd(SALARIO)/mean(SALARIO)*100, 1), "%")
) %>%
kable(caption = "📊 Salario según Género") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
row_spec(0, bold = TRUE, background = col_main, color = "white")| GENERO | n | Media | Mediana | Desv.Est. | Mínimo | Máximo | CV |
|---|---|---|---|---|---|---|---|
| Femenino | 18 | 3956 | 4217.5 | 1471 | 1107 | 6394 | 37.2% |
| Masculino | 32 | 4518 | 3969.0 | 2425 | 1322 | 11563 | 53.7% |
ggplot(datos, aes(x = GENERO, y = SALARIO, fill = GENERO)) +
geom_boxplot(alpha = 0.75, width = 0.5,
outlier.color = col_acc, outlier.size = 3) +
stat_summary(fun = mean, geom = "point", shape = 18,
size = 5, color = col_acc, show.legend = FALSE) +
stat_summary(fun = mean, geom = "text",
aes(label = paste0("Media:\n", comma(round(..y..)))),
vjust = -0.8, size = 3.5, color = col_acc, fontface = "bold") +
scale_fill_manual(values = c("Femenino" = col_fem, "Masculino" = col_mas)) +
scale_y_continuous(labels = comma) +
labs(
title = "Distribución del Salario según Género",
subtitle = "El diamante (◆) indica la media; la línea central indica la mediana",
x = "Género",
y = "Salario (u.m.)",
fill = "Género",
caption = "Fuente: Base_empleo.xlsx"
) +
theme_minimal(base_size = 13) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5, color = "gray50"),
legend.position = "none"
)📝 Interpretación: Los trabajadores masculinos tienen un salario promedio ligeramente mayor (4.518) frente a las trabajadoras femeninas (3.956), una diferencia del ~14%. Sin embargo, el grupo masculino tiene mayor dispersión (CV = 53.7% vs 37.2%), lo que indica salarios más heterogéneos. El valor atípico superior pertenece a un hombre.
ggplot(datos, aes(x = GENERO, y = ANTIGUEDAD, fill = GENERO)) +
geom_boxplot(alpha = 0.75, width = 0.5,
outlier.color = col_acc, outlier.size = 3) +
stat_summary(fun = mean, geom = "point", shape = 18,
size = 5, color = col_acc) +
scale_fill_manual(values = c("Femenino" = col_fem, "Masculino" = col_mas)) +
labs(
title = "Distribución de la Antigüedad según Género",
x = "Género",
y = "Años de antigüedad",
caption = "Fuente: Base_empleo.xlsx"
) +
theme_minimal(base_size = 13) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
legend.position = "none"
)📝 Interpretación: Los hombres tienen en promedio mayor antigüedad (12.1 años) que las mujeres (6.9 años). En ambos grupos la distribución es asimétrica, con medianas bajas (4 años en ambos) pero valores máximos muy diferentes (39 años en hombres vs. 21 en mujeres).
ggplot(datos, aes(x = EDAD, y = SALARIO, color = GENERO)) +
geom_point(size = 3.5, alpha = 0.8) +
geom_smooth(method = "lm", se = TRUE, color = col_main,
fill = "gray80", linewidth = 1.2) +
scale_color_manual(values = c("Femenino" = col_fem, "Masculino" = col_mas)) +
scale_y_continuous(labels = comma) +
annotate("text",
x = 55, y = 2000,
label = paste0("r = ", round(cor(datos$EDAD, datos$SALARIO), 3)),
fontface = "bold", size = 4.5, color = col_main) +
labs(
title = "Relación entre Edad y Salario",
subtitle = "Línea de tendencia lineal general; puntos coloreados por género",
x = "Edad (años)",
y = "Salario (u.m.)",
color = "Género",
caption = "Fuente: Base_empleo.xlsx"
) +
theme_minimal(base_size = 13) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5, color = "gray50")
)📝 Interpretación: La correlación entre edad y salario es r = 0.178, lo que indica una relación positiva pero débil. A mayor edad, existe una ligera tendencia a ganar más, pero la dispersión es muy grande, lo que sugiere que la edad sola no explica bien el salario.
ggplot(datos, aes(x = ANTIGUEDAD, y = SALARIO, color = GENERO)) +
geom_point(size = 3.5, alpha = 0.8) +
geom_smooth(method = "lm", se = TRUE, color = col_main,
fill = "gray80", linewidth = 1.2) +
scale_color_manual(values = c("Femenino" = col_fem, "Masculino" = col_mas)) +
scale_y_continuous(labels = comma) +
annotate("text",
x = 30, y = 2000,
label = paste0("r = ", round(cor(datos$ANTIGUEDAD, datos$SALARIO), 3)),
fontface = "bold", size = 4.5, color = col_main) +
labs(
title = "Relación entre Antigüedad y Salario",
x = "Años de antigüedad",
y = "Salario (u.m.)",
color = "Género",
caption = "Fuente: Base_empleo.xlsx"
) +
theme_minimal(base_size = 13) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
legend.position = "right"
)📝 Interpretación: La correlación entre antigüedad y salario es r = 0.074, prácticamente nula. Esto es llamativo: la antigüedad no parece explicar linealmente el salario en esta muestra. Podría existir una estructura salarial no lineal o basada en otros factores.
mat_cor <- cor(datos[, c("ANTIGUEDAD", "EDAD", "SALARIO")])
corrplot(mat_cor,
method = "color",
type = "upper",
addCoef.col = "black",
tl.col = col_main,
tl.srt = 45,
col = colorRampPalette(c(col_fem, "white", col_mas))(200),
title = "Matriz de Correlaciones",
mar = c(0, 0, 2, 0),
number.cex = 1.2)| Par | Correlación | Interpretación |
|---|---|---|
| EDAD ↔︎ ANTIGÜEDAD | 0.777 | Fuerte positiva: trabajadores mayores tienen más antigüedad |
| EDAD ↔︎ SALARIO | 0.178 | Débil positiva: ligera tendencia de mayor salario con más edad |
| ANTIGÜEDAD ↔︎ SALARIO | 0.074 | Prácticamente nula: la antigüedad no determina el salario |
📝 Hallazgo clave: La única correlación fuerte es entre edad y antigüedad (r = 0.777), lo cual es lógico: a mayor edad, más tiempo habrá tenido el trabajador para acumular años en la empresa. Las otras correlaciones con el salario son sorprendentemente bajas.
Al finalizar este análisis descriptivo, podemos responder a nuestro objetivo planteado:
Se describieron las características sociodemográficas y salariales de 50 trabajadores. Se encontraron diferencias de género en salario y antigüedad, y se exploró la relación entre variables numéricas.
| # | Hallazgo | Variables involucradas |
|---|---|---|
| 1 | El 64% de los trabajadores son hombres; hay desbalance de género | GÉNERO |
| 2 | La mayoría tiene poca antigüedad (mediana = 4 años), con alta variabilidad | ANTIGÜEDAD |
| 3 | La edad se distribuye simétricamente entre 22 y 60 años (media ≈ 39) | EDAD |
| 4 | El salario es heterogéneo (CV ≈ 49%), con distribución asimétrica positiva | SALARIO |
| 5 | Los hombres ganan ~14% más en promedio y tienen mayor antigüedad | GÉNERO × SALARIO/ANTIGÜEDAD |
| 6 | La edad y la antigüedad están fuertemente correlacionadas (r = 0.78) | EDAD × ANTIGÜEDAD |
| 7 | El salario no se explica bien por la antigüedad ni la edad solas | SALARIO × EDAD/ANTIGÜEDAD |
A partir de este análisis descriptivo emergen nuevas preguntas que requerirían métodos inferenciales:
💡 El análisis descriptivo no termina con tablas y gráficos. Termina cuando somos capaces de contar una historia coherente con los datos y plantear nuevas preguntas informadas. La estadística descriptiva es la base de cualquier análisis más avanzado.
Todo el código de este documento está disponible con el botón Code en cada sección. Puedes reproducir el análisis descargando la base
Base_empleo.xlsxy ejecutando este archivo.Rmden RStudio.
Paquetes utilizados:
library(readxl) # Lectura de archivos Excel
library(dplyr) # Manipulación de datos
library(ggplot2) # Visualizaciones
library(knitr) # Tablas en R Markdown
library(kableExtra) # Formato de tablas HTML
library(scales) # Formato numérico en gráficos
library(patchwork) # Combinar múltiples gráficos
library(corrplot) # Gráfico de matriz de correlaciones
library(moments) # Cálculo de asimetría (skewness)