# ============================================================
# CARGA DE LIBRERÍAS
# ============================================================
library(tidyverse)
library(ggplot2)
library(plotly)
library(DT)
library(knitr)
library(rmarkdown)
library(scales)
library(readxl) # lectura directa del archivo .xlsx# ============================================================
# CARGA Y LIMPIEZA DE DATOS
# Lee directamente desde el archivo .xlsx -- no se necesitan CSVs
# IMPORTANTE: ajuste la ruta al .xlsx si el archivo esta en otra carpeta
# ============================================================
ARCHIVO_XLSX <- "C:/Users/User/Downloads/BASES DE DATOS UNIFICADAS (1).xlsx" # <-- cambie solo esta linea si es necesario
# Verifica que el archivo exista y muestra un mensaje claro si no
if (!file.exists(ARCHIVO_XLSX)) {
stop(paste0(
"No se encontro el archivo: '", ARCHIVO_XLSX, "'\n",
"Directorio de trabajo actual: ", getwd(), "\n",
"Coloque el archivo .xlsx en esa carpeta o ajuste la variable ARCHIVO_XLSX."
))
}
# --- Helper: normaliza nombres de columna ---
limpiar_nombres <- function(df) {
names(df) <- trimws(gsub("\n", " ", names(df)))
df
}
# --- Helper: convierte tasa decimal (0-1) a porcentaje (0-100) fila por fila ---
# Usa el maximo de toda la columna para decidir, no dentro de mutate por fila
normalizar_tasa <- function(x) {
if (max(x, na.rm = TRUE) <= 1) x * 100 else x
}
# 1) 23 Ciudades (trimestral) -- hoja: "23 ciudades "
# FILTROS CRITICOS:
# a) Excluir filas de totales agregados ("Total 23 ciudades...", etc.)
# b) Excluir filas donde Ciudad esta vacia
df_ciudades <- read_excel(ARCHIVO_XLSX, sheet = "23 ciudades ") |>
limpiar_nombres()
df_ciudades$Ciudad <- trimws(df_ciudades$Ciudad)
df_ciudades$Año <- as.integer(df_ciudades$Año)
df_ciudades$Periodo <- paste(df_ciudades$Año, df_ciudades$Trimestre, sep = " - ")
# Eliminar filas de totales y filas sin ciudad
df_ciudades <- df_ciudades |>
filter(
!is.na(Ciudad),
Ciudad != "",
!grepl("^[Tt]otal", Ciudad) # excluye "Total 23 ciudades...", "Total 13...", etc.
) |>
mutate(
`Tasa de Ocupación (TO)` = normalizar_tasa(`Tasa de Ocupación (TO)`),
`Tasa de Desocupación (TD)` = normalizar_tasa(`Tasa de Desocupación (TD)`)
)
# 2) Total Nacional (mensual) -- hoja: "Total_Nacional"
df_nacional <- read_excel(ARCHIVO_XLSX, sheet = "Total_Nacional") |>
limpiar_nombres()
df_nacional$Año <- as.integer(df_nacional$Año)
# Normalizar tasas antes de promediar (fila por fila sobre columna completa)
df_nacional <- df_nacional |>
mutate(
`Tasa de Ocupación (TO)` = normalizar_tasa(`Tasa de Ocupación (TO)`),
`Tasa de Desocupación (TD)` = normalizar_tasa(`Tasa de Desocupación (TD)`)
)
# Promedio anual -- solo años con 12 meses completos para cifras exactas
# Se calcula cuantos registros tiene cada año y se excluye el ultimo si esta incompleto
conteo_meses <- df_nacional |> count(Año)
meses_max <- max(conteo_meses$n)
anios_completos <- conteo_meses$Año[conteo_meses$n >= meses_max * 0.9]
df_nac_anual <- df_nacional |>
group_by(Año) |>
summarise(
`Fuerza de trabajo` = mean(`Fuerza de trabajo`, na.rm = TRUE),
`Población ocupada` = mean(`Población ocupada`, na.rm = TRUE),
`Población desocupada` = mean(`Población desocupada`, na.rm = TRUE),
`Tasa de Ocupación (TO)` = mean(`Tasa de Ocupación (TO)`, na.rm = TRUE),
`Tasa de Desocupación (TD)` = mean(`Tasa de Desocupación (TD)`, na.rm = TRUE),
n_meses = n(),
.groups = "drop"
)
# 3) Pobreza Monetaria — hoja: "PobrezaMonetaria"
# readxl preserva \n en nombres de columna; se renombran por posicion para evitar
# problemas de grep con espacios dobles o saltos residuales.
df_pobreza_raw <- read_excel(ARCHIVO_XLSX, sheet = "PobrezaMonetaria",
col_names = FALSE, skip = 1)
names(df_pobreza_raw) <- c("Año", "Poblacion_Nacional_miles",
"Personas_Pobreza_miles", "Tasa_Pobreza_pct",
"Reduccion_pp", "Var_Personas_miles")
df_pobreza <- df_pobreza_raw |>
mutate(
Año = suppressWarnings(as.integer(Año)),
Personas_Pobreza_miles = suppressWarnings(as.numeric(Personas_Pobreza_miles)),
Tasa_Pobreza_pct = suppressWarnings(as.numeric(Tasa_Pobreza_pct))
) |>
filter(!is.na(Año), !is.na(Tasa_Pobreza_pct))
# Variables de referencia usadas en los graficos de pobreza
col_tasa <- "Tasa_Pobreza_pct"
col_personas <- "Personas_Pobreza_miles"
# Normalizar: si la tasa viene como decimal (0–1) convertir a porcentaje (0–100)
if (max(df_pobreza[[col_tasa]], na.rm = TRUE) <= 1) {
df_pobreza[[col_tasa]] <- df_pobreza[[col_tasa]] * 100
}
# 4) Género — hoja: "Genero"
df_genero <- read_excel(ARCHIVO_XLSX, sheet = "Genero") |>
limpiar_nombres()
df_genero$Año <- as.integer(df_genero$Año)
df_gen_anual <- df_genero |>
mutate(
`Tasa Global de Participación (TGP)` = normalizar_tasa(`Tasa Global de Participación (TGP)`),
`Tasa de Ocupación (TO)` = normalizar_tasa(`Tasa de Ocupación (TO)`),
`Tasa de Desocupación (TD)` = normalizar_tasa(`Tasa de Desocupación (TD)`)
) |>
group_by(Año, `SEXO + TOTAL`) |>
summarise(
TGP = mean(`Tasa Global de Participación (TGP)`, na.rm = TRUE),
TO = mean(`Tasa de Ocupación (TO)`, na.rm = TRUE),
TD = mean(`Tasa de Desocupación (TD)`, na.rm = TRUE),
.groups = "drop"
) |>
pivot_longer(c(TGP, TO, TD), names_to = "Indicador", values_to = "Valor")
# 5) SMLV vs Fuerza de Trabajo — hoja: "SMLV_FuerzaTrabajo"
df_smlv <- read_excel(ARCHIVO_XLSX, sheet = "SMLV_FuerzaTrabajo") |>
limpiar_nombres()
# Renombrar columnas de forma robusta
ft_col <- grep("Fuerza de trabajo", names(df_smlv), value = TRUE)[1]
sm_col <- grep("Salario [Mm]in", names(df_smlv), value = TRUE)[1]
names(df_smlv)[names(df_smlv) == ft_col] <- "FuerzaTrabajo"
names(df_smlv)[names(df_smlv) == sm_col] <- "SalarioMinimo"
df_smlv <- df_smlv |>
mutate(
FuerzaTrabajo = suppressWarnings(as.numeric(FuerzaTrabajo)),
SalarioMinimo = suppressWarnings(as.numeric(SalarioMinimo))
) |>
filter(!is.na(FuerzaTrabajo), !is.na(SalarioMinimo))Servicio Nacional de Aprendizaje — SENA
Período de análisis: 2010 – 2025 | Fuente: DANE – GEIH
02 de julio de 2026
Colombia es un país en permanente transformación socioeconómica. Desde la primera década del siglo XXI, el país ha experimentado cambios estructurales en su mercado laboral, impulsados por el crecimiento económico, las reformas institucionales, los choques externos como la pandemia de COVID-19 en 2020 y las políticas de protección social.
El presente informe analiza la evolución de los principales indicadores del mercado laboral y la pobreza monetaria en Colombia durante el período 2010–2025, utilizando datos oficiales del Departamento Administrativo Nacional de Estadística (DANE), obtenidos a través de la Gran Encuesta Integrada de Hogares (GEIH).
Nota metodológica: Todos los indicadores de tasas se expresan en porcentaje (%). Las cifras de población se expresan en miles de personas, conforme a la presentación original del DANE.
El análisis abarca cinco dimensiones complementarias:
Analizar la evolución de los indicadores socioeconómicos de Colombia entre 2010 y 2026, identificando tendencias, brechas y factores de cambio en el mercado laboral y la pobreza monetaria.
| Módulo | Fuente | Cobertura temporal | Periodicidad |
|---|---|---|---|
| Mercado laboral nacional | DANE – GEIH | 2010–2026 | Mensual |
| 23 ciudades AM | DANE – GEIH | 2010–2026 | Trimestral |
| Pobreza monetaria | DANE – Informe oficial | 2012–2023 | Anual |
| Género | DANE – GEIH | 2010–2025 | Mensual |
| SMLV | Ministerio del Trabajo / DANE | 2010–2024 | Anual |
Los datos fueron procesados en R (4.6.0) mediante el
ecosistema tidyverse. El preprocesamiento incluyó:
| Indicador | Sigla | Definición |
|---|---|---|
| Tasa Global de Participación | TGP | Porcentaje de la PET que hace parte de la Fuerza de Trabajo. |
| Tasa de Ocupación | TO | Porcentaje de la PET que se encuentra empleada. |
| Tasa de Desocupación | TD | Porcentaje de la Fuerza de Trabajo que no tiene empleo y lo busca activamente. |
| Fuerza de Trabajo | FT | Suma de Población Ocupada y Población Desocupada (miles de personas). |
| Tasa de Pobreza Monetaria | TPM | Porcentaje de personas con ingresos por debajo de la línea de pobreza. |
df_nac_largo <- df_nac_anual |>
select(Año, `Fuerza de trabajo`, `Población ocupada`, `Población desocupada`) |>
pivot_longer(-Año, names_to = "Variable", values_to = "Valor")
## Nota de legibilidad: en la version original las 3 series usaban tonos de azul
## muy cercanos entre si (dificiles de distinguir, especialmente para personas
## con daltonismo). Se usa un color de alto contraste (NARANJA) para la
## Poblacion Desocupada, ya que es la serie mas relevante para el diagnostico.
pal_nac <- c(
"Fuerza de trabajo" = AZUL_DESTACADOS,
"Población ocupada" = AZUL_PRINCIPAL,
"Población desocupada" = NARANJA
)
p_nac <- ggplot(df_nac_largo, aes(x = Año, y = Valor / 1000,
color = Variable, group = Variable)) +
geom_line(linewidth = 1.6) +
geom_point(size = 2.8, shape = 21, fill = "white", stroke = 1.5) +
scale_color_manual(values = pal_nac, name = "") +
scale_y_continuous(labels = scales::label_comma(suffix = " M")) +
scale_x_continuous(breaks = seq(min(df_nac_anual$Año),
max(df_nac_anual$Año), by = 2)) +
labs(title = "Evolución del Mercado Laboral Nacional",
subtitle = "Promedio anual — miles de personas",
x = "Año", y = "Millones de personas",
caption = "Fuente: DANE — Gran Encuesta Integrada de Hogares (GEIH)") +
tema_corporativo
ggplotly(p_nac, tooltip = c("x", "y", "colour")) |>
layout(
paper_bgcolor = FONDO_APP,
plot_bgcolor = "#FFFFFF",
margin = list(l = 60, r = 60, t = 80, b = 80),
legend = list(orientation = "h", x = 0.2, y = -0.2)
) |>
centrar_grafico()Diagnóstico del gráfico — Figura 1
Tipo de gráfico: líneas múltiples con marcadores (serie de tiempo).
¿Por qué este tipo de gráfico? Se usa una serie de tiempo de líneas porque el objetivo es mostrar la evolución continua de tres variables numéricas (Fuerza de Trabajo, Población Ocupada y Población Desocupada) a lo largo de los años. Las líneas permiten identificar tendencias, puntos de quiebre y la relación de crecimiento paralelo entre las tres series, algo que un gráfico de barras dificultaría al comparar 16 años simultáneamente. El color naranja resalta la Población Desocupada, que es la serie con menor magnitud pero mayor relevancia analítica.
Lectura diagnóstica: las tres curvas muestran una tendencia creciente y casi paralela hasta 2019, lo que indica que el crecimiento de la Fuerza de Trabajo fue absorbido mayoritariamente por la Población Ocupada. El quiebre de 2020 es visible como una discontinuidad en la pendiente de la Población Desocupada, coherente con el choque pandémico.
library(dplyr)
library(tidyr)
library(ggplot2)
library(plotly)
library(scales)
# 🔹 Transformación de datos
df_tasas_largo <- df_nac_anual |>
select(Año, `Tasa de Ocupación (TO)`, `Tasa de Desocupación (TD)`) |>
pivot_longer(
cols = -Año,
names_to = "Tasa",
values_to = "Valor"
)
# 🔹 Colores
pal_tasas <- c(
"Tasa de Ocupación (TO)" = AZUL_PRINCIPAL,
"Tasa de Desocupación (TD)" = AZUL_DESTACADOS
)
# 🔹 Gráfico base
p_tasas <- ggplot(df_tasas_largo, aes(
x = Año,
y = Valor,
color = Tasa,
group = Tasa
)) +
# Área sombreada (solo desempleo)
geom_ribbon(
data = df_tasas_largo |> filter(Tasa == "Tasa de Desocupación (TD)"),
aes(ymin = 0, ymax = Valor),
fill = AZUL_DESTACADOS,
alpha = 0.12,
color = NA
) +
# Líneas
geom_line(linewidth = 1.6) +
# Puntos
geom_point(size = 3, shape = 21, fill = "white", stroke = 1.2) +
# Colores
scale_color_manual(values = pal_tasas, name = "") +
# Formato porcentaje
scale_y_continuous(labels = label_percent(scale = 1, suffix = "%")) +
# Eje X (años ordenados)
scale_x_continuous(
breaks = seq(min(df_nac_anual$Año),
max(df_nac_anual$Año),
by = 2)
) +
# Etiquetas
labs(
title = "Tasas de Ocupación y Desocupación — Colombia",
subtitle = "Promedio anual (%)",
x = "Año",
y = "Tasa (%)",
caption = "Fuente: DANE — GEIH"
) +
# Tema corporativo
tema_corporativo +
theme(
legend.position = "bottom",
legend.direction = "horizontal",
plot.margin = margin(t = 20, r = 20, b = 20, l = 20)
)
# 🔹 Convertir a interactivo (Plotly)
ggplotly(p_tasas, tooltip = c("x", "y", "colour")) |>
layout(
paper_bgcolor = FONDO_APP,
plot_bgcolor = "#FFFFFF",
margin = list(l = 60, r = 60, t = 80, b = 80),
legend = list(orientation = "h", x = 0.2, y = -0.2)
) |>
centrar_grafico()Diagnóstico del gráfico — Figura 2
Tipo de gráfico: líneas dobles con área sombreada (serie de tiempo, dos tasas en %).
¿Por qué este tipo de gráfico? Al tratarse de dos tasas expresadas en la misma unidad (%), el gráfico de líneas permite compararlas directamente en la misma escala del eje Y. El área sombreada bajo la TD es un recurso visual adicional (no un tercer gráfico) que refuerza la lectura del desempleo como la variable de mayor interés del módulo, sin sacrificar la comparabilidad con la TO.
Lectura diagnóstica: la TO se mantiene consistentemente por encima de la TD durante todo el período, lo cual es esperable (la TD es un subconjunto de la Fuerza de Trabajo). El área sombreada permite detectar visualmente, sin necesidad de leer valores exactos, el momento y la magnitud del repunte de desempleo de 2020.
df_nac_anual |>
mutate(across(c(`Fuerza de trabajo`, `Población ocupada`, `Población desocupada`),
~ scales::comma(round(., 0))),
across(c(`Tasa de Ocupación (TO)`, `Tasa de Desocupación (TD)`),
~ paste0(round(., 1), "%"))) |>
select(Año, `Fuerza de trabajo`, `Población ocupada`, `Población desocupada`,
`Tasa de Ocupación (TO)`, `Tasa de Desocupación (TD)`) |>
DT::datatable(
caption = "Tabla 2. Indicadores del Mercado Laboral Nacional — Promedio anual.",
rownames = FALSE,
filter = "top",
extensions = "Buttons",
options = list(
dom = "Bfrtip",
buttons = c("csv", "excel"),
pageLength = 10,
language = list(url = "//cdn.datatables.net/plug-ins/1.10.11/i18n/Spanish.json")
)
)Hallazgos principales del mercado laboral nacional:
La Fuerza de Trabajo en Colombia mostró una tendencia de crecimiento sostenido entre 2010 y 2019, alcanzando 23.9 millones de personas antes de la pandemia, lo que refleja el dinamismo demográfico y la incorporación progresiva de la población al mercado laboral.
La crisis por COVID-19 en 2020 generó una ruptura estructural severa: la Tasa de Desocupación alcanzó su máximo histórico del período con 16.7% en 2020, evidenciando la vulnerabilidad del mercado laboral colombiano ante choques externos.
La recuperación post-pandémica fue notable en términos de Población Ocupada, pero la Tasa de Desocupación se mantuvo por encima de los niveles prepandémicos (TO 2019: 57.7% vs. TO 2025: 58.6%), sugiriendo la persistencia de informalidad y subempleo.
La Tasa de Desocupación al inicio del período (2010) era de 12%, y en 2025 se sitúa en 8.9%, reflejando el balance de la evolución estructural del mercado laboral.
anio_max_ciu <- max(df_ciudades$Año)
anio_inicio_ciu <- max(anio_max_ciu - 4, min(df_ciudades$Año))
df_ciu_resumen <- df_ciudades |>
filter(Año >= anio_inicio_ciu) |>
group_by(Ciudad) |>
summarise(
TO_prom = mean(`Tasa de Ocupación (TO)`, na.rm = TRUE),
TD_prom = mean(`Tasa de Desocupación (TD)`, na.rm = TRUE),
.groups = "drop"
) |>
arrange(desc(TD_prom)) |>
mutate(Ciudad = factor(Ciudad, levels = Ciudad))
# Separación fija para las etiquetas (proporcional al valor máximo,
# así se ve pareja en todas las barras, cortas y largas)
offset_etiqueta <- max(df_ciu_resumen$TD_prom, na.rm = TRUE) * 0.035
p_ciu_td <- ggplot(df_ciu_resumen,
aes(x = TD_prom, y = Ciudad, fill = TD_prom)) +
geom_col(width = 0.65, show.legend = FALSE) +
geom_text(aes(x = TD_prom + offset_etiqueta,
label = paste0(round(TD_prom, 1), "%")),
hjust = 0, size = 3.4, color = TEXTO) +
scale_fill_gradient(low = AZUL_CLARO, high = AZUL_PRINCIPAL) +
scale_x_continuous(expand = expansion(mult = c(0, 0.20)),
labels = scales::label_percent(scale = 1, suffix = "%")) +
labs(title = "Tasa de Desocupación (TD) por Ciudad",
subtitle = paste0("Promedio ", anio_inicio_ciu, "–", anio_max_ciu,
" — Áreas Metropolitanas"),
x = "TD Promedio (%)", y = NULL,
caption = "Fuente: DANE — GEIH") +
tema_corporativo +
theme(panel.grid.major.y = element_blank(),
axis.text.y = element_text(size = 12))
ggplotly(p_ciu_td, tooltip = c("x", "y")) |>
layout(paper_bgcolor = FONDO_APP, plot_bgcolor = "#FFFFFF") |>
centrar_grafico()Diagnóstico del gráfico — Figura 3
Tipo de gráfico: barras horizontales ordenadas, con codificación de color por intensidad (gradiente).
¿Por qué este tipo de gráfico? Con 23 categorías (ciudades), las barras horizontales son preferibles a las verticales porque los nombres de ciudad son largos y no caben legibles en el eje X sin rotarlos. Ordenar de mayor a menor TD convierte al gráfico en un ranking, facilitando identificar de inmediato las ciudades con peor desempeño. El gradiente de color refuerza (sin reemplazar) la codificación por posición, ayudando a distinguir rápidamente los extremos.
Lectura diagnóstica: la dispersión entre la ciudad con mayor y menor TD evidencia heterogeneidad territorial marcada; la posición de cada barra respecto al promedio nacional (Figura 2) permite ubicar a cada ciudad por encima o por debajo del comportamiento agregado del país.
offset_etiqueta_to <- max(df_ciu_resumen$TO_prom, na.rm = TRUE) * 0.05
p_ciu_to <- df_ciu_resumen |>
arrange(desc(TO_prom)) |>
mutate(Ciudad = factor(Ciudad, levels = Ciudad)) |>
ggplot(aes(x = TO_prom, y = Ciudad, fill = TO_prom)) +
geom_col(width = 0.65, show.legend = FALSE) +
geom_text(aes(x = TO_prom + offset_etiqueta_to,
label = paste0(round(TO_prom, 1), "%")),
hjust = 0, size = 3.4, color = TEXTO, fontface = "bold") +
scale_fill_gradient(low = AZUL_CLARO, high = AZUL_PRINCIPAL) +
scale_x_continuous(expand = expansion(mult = c(0, 0.30)),
labels = scales::label_percent(scale = 1, suffix = "%")) +
coord_cartesian(clip = "off") +
labs(title = "Tasa de Ocupación (TO) por Ciudad",
subtitle = paste0("Promedio ", anio_inicio_ciu, "–", anio_max_ciu,
" — Áreas Metropolitanas"),
x = "TO Promedio (%)", y = NULL,
caption = "Fuente: DANE — GEIH") +
tema_corporativo +
theme(panel.grid.major.y = element_blank(),
axis.text.y = element_text(size = 12),
plot.margin = margin(t = 10, r = 40, b = 10, l = 10))
ggplotly(p_ciu_to, tooltip = c("x", "y")) |>
layout(paper_bgcolor = FONDO_APP, plot_bgcolor = "#FFFFFF",
margin = list(r = 60)) |>
centrar_grafico()Diagnóstico del gráfico — Figura 4
Tipo de gráfico: barras horizontales ordenadas (ranking), mismo diseño que la Figura 3 para permitir comparación directa entre ambas.
¿Por qué este tipo de gráfico? Se mantiene deliberadamente el mismo formato visual que la Figura 3 (barras horizontales, mismo orden por categoría) para que el lector pueda comparar visualmente TD y TO ciudad por ciudad sin tener que reinterpretar un tipo de gráfico distinto. Esta consistencia entre figuras es una buena práctica de diseño de reportes.
Lectura diagnóstica: las ciudades que encabezan este ranking (mayor TO) tienden a coincidir con las que muestran menor TD en la Figura 3, patrón que se confirma estadísticamente en la Figura 6 (dispersión TO vs. TD).
# 1. Cargar las librerías necesarias
library(ggplot2)
library(plotly)
library(dplyr)
# 2. Construir el dataset A PARTIR DE LOS DATOS REALES cargados del .xlsx
# (df_nac_anual, calculado en el chunk 'carga_datos'). Antes este gráfico usaba
# una tabla de valores escritos a mano que no coincidía con el archivo fuente;
# se corrige para que sea coherente con la Figura 2 y con el resto del informe.
datos <- df_nac_anual |>
transmute(anio = Año, tasa = round(`Tasa de Desocupación (TD)`, 1))
# El año atípico se identifica dinámicamente (no queda "quemado" en el código):
# corresponde al año de mayor TD del período, calculado más arriba en el
# chunk 'interp_nacional' (anio_pico_td).
# Colores dentro de la paleta corporativa: AZUL_DESTACADOS para años normales,
# ROJO_ALERTA para el año atípico (pico pandémico) — mantiene coherencia
# visual con el resto del informe en lugar de colores ajenos a la paleta.
datos <- datos %>%
mutate(
color_barra = ifelse(anio == anio_pico_td, ROJO_ALERTA, AZUL_DESTACADOS),
texto_hover = paste0("Año: ", anio, "<br>Tasa: ", format(tasa, decimal.mark = ","), "%")
)
# 3. Crear el gráfico base con ggplot2
# Todas las barras muestran su etiqueta (se eliminó el filtro de años fijos,
# que dejaba años sin dato visible y no se adaptaba si cambia el rango del
# archivo fuente).
p <- ggplot(datos, aes(x = factor(anio), y = tasa, fill = color_barra, text = texto_hover)) +
geom_bar(stat = "identity", width = 0.8) +
geom_text(
aes(y = tasa + max(datos$tasa, na.rm = TRUE) * 0.03,
label = paste0(format(tasa, decimal.mark = ","), "%")),
vjust = 0,
fontface = "bold",
size = 3.4,
color = TEXTO
) +
scale_fill_identity() +
labs(
title = "Promedio Anual de la Tasa de Desempleo Nacional",
subtitle = paste0(min(datos$anio), "–", max(datos$anio),
" · Año resaltado: ", anio_pico_td,
" (pico histórico del período)"),
x = NULL,
y = NULL,
caption = "Fuente: DANE — GEIH"
) +
scale_y_continuous(limits = c(0, max(datos$tasa, na.rm = TRUE) * 1.15)) +
tema_corporativo +
theme(
axis.text.x = element_text(angle = 35, hjust = 1, vjust = 1, face = "bold"),
axis.text.y = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = "none"
)
# 4. Convertir a gráfico interactivo con Plotly
grafico_interactivo <- ggplotly(p, tooltip = "text") %>%
layout(paper_bgcolor = FONDO_APP, plot_bgcolor = "#FFFFFF") %>%
config(displayModeBar = FALSE)
# 5. Centrar y mostrar el gráfico
centrar_grafico(grafico_interactivo)Diagnóstico del gráfico — Figura 5
Tipo de gráfico: barras verticales de serie de tiempo con un valor atípico resaltado por color.
¿Por qué este tipo de gráfico? Aunque la Figura 2 ya muestra la TD como línea, aquí se usan barras porque el objetivo específico de esta figura es destacar un único año atípico (el pico pandémico) frente al resto del período. Las barras facilitan comparar magnitudes año a año como bloques discretos, y el resaltado por color (rojo vs. azul corporativo) dirige la atención inmediatamente al quiebre estructural, algo menos evidente en una línea continua.
Lectura diagnóstica: la altura de la barra roja frente a las azules cuantifica visualmente la magnitud del choque pandémico en el desempleo; las barras posteriores, aunque decrecientes, no vuelven a la altura mínima previa, señal de una recuperación incompleta.
p_scatter_ciu <- ggplot(df_ciu_resumen,
aes(x = TO_prom, y = TD_prom, label = Ciudad)) +
geom_point(size = 4, color = AZUL_DESTACADOS, alpha = 0.8,
shape = 21, fill = AZUL_CLARO, stroke = 1.5) +
geom_smooth(method = "lm", se = TRUE,
color = AZUL_PRINCIPAL, fill = AZUL_MUY_CLARO,
linetype = "dashed", linewidth = 1) +
scale_x_continuous(labels = scales::label_percent(scale = 1, suffix = "%")) +
scale_y_continuous(labels = scales::label_percent(scale = 1, suffix = "%")) +
labs(title = "TO vs. TD por Ciudad",
subtitle = "Cada punto representa una ciudad/área metropolitana",
x = "Tasa de Ocupación promedio (%)",
y = "Tasa de Desocupación promedio (%)",
caption = "Fuente: DANE — GEIH") +
tema_corporativo
ggplotly(p_scatter_ciu, tooltip = c("label", "x", "y")) |>
layout(paper_bgcolor = FONDO_APP, plot_bgcolor = "#FFFFFF") |>
centrar_grafico()Diagnóstico del gráfico — Figura 6
Tipo de gráfico: diagrama de dispersión (scatter plot) con línea de regresión y banda de confianza.
¿Por qué este tipo de gráfico? Cuando el objetivo es evaluar la relación entre dos variables numéricas continuas (TO y TD) medidas sobre las mismas unidades de análisis (ciudades), el diagrama de dispersión es el gráfico estadísticamente correcto: cada punto representa una ciudad y su posición revela simultáneamente ambos valores. La línea de tendencia (regresión lineal) resume la dirección de la asociación sin necesidad de calcular manualmente la correlación.
Lectura diagnóstica: la pendiente negativa de la línea confirma la relación inversa esperada entre TO y TD (a mayor ocupación, menor desocupación); la banda de confianza sombreada indica el nivel de incertidumbre de esa relación, y las ciudades que se alejan de la línea son casos atípicos que merecen revisión particular.
Hallazgos principales del análisis territorial:
Existe una heterogeneidad territorial significativa: la brecha entre la ciudad con mayor y menor Tasa de Desocupación es de 17.3 puntos porcentuales (Quibdó con 26.2% vs. Bucaramanga con 8.9%), lo que refleja diferencias estructurales en las economías locales.
Las ciudades con mayor diversificación económica (Bogotá D.C. lidera con una TO de 62.8%) tienden a mostrar Tasas de Ocupación más altas y Tasas de Desocupación más bajas.
El impacto del COVID-19 fue generalizado pero diferencial por ciudad, siendo más pronunciado en aquellas con mayor dependencia del sector servicios y comercio informal.
La correlación negativa entre TO y TD (observable en la Figura 6) confirma que ambas tasas capturan fenómenos complementarios, aunque no perfectamente opuestos debido al comportamiento de la TGP.
# Dos paneles separados — evita el problema del eje secundario mal escalado
offset_etiqueta_pobreza <- diff(range(df_pobreza[[col_tasa]], na.rm = TRUE)) * 0.12
p_pobreza_tasa <- ggplot(df_pobreza, aes(x = Año, y = .data[[col_tasa]])) +
geom_area(fill = AZUL_CLARO, alpha = 0.18) +
geom_line(color = AZUL_PRINCIPAL, linewidth = 1.1) +
geom_point(color = AZUL_PRINCIPAL, size = 2.6) +
geom_text(aes(y = .data[[col_tasa]] + offset_etiqueta_pobreza,
label = paste0(round(.data[[col_tasa]], 1), "%")),
size = 3.3, color = TEXTO, fontface = "bold") +
scale_y_continuous(labels = scales::label_percent(scale = 1, suffix = "%"),
expand = expansion(mult = c(0.05, 0.22))) +
scale_x_continuous(breaks = df_pobreza$Año) +
labs(title = "Evolución de la Tasa de Pobreza Monetaria",
subtitle = paste0("Colombia, ", min(df_pobreza$Año), "–", max(df_pobreza$Año)),
x = NULL, y = "Tasa de Pobreza (%)",
caption = "Fuente: DANE") +
tema_corporativo +
theme(panel.grid.minor = element_blank(),
axis.text.x = element_text(angle = 0))
ggplotly(p_pobreza_tasa, tooltip = c("x", "y")) |>
layout(paper_bgcolor = FONDO_APP, plot_bgcolor = "#FFFFFF") |>
centrar_grafico()Diagnóstico del gráfico — Figura 7
Tipo de gráfico: gráfico de área con línea y puntos (serie de tiempo anual).
¿Por qué este tipo de gráfico? El área sombreada bajo la línea refuerza visualmente la magnitud acumulada del fenómeno (pobreza monetaria) y facilita distinguir este indicador de los gráficos de línea simple usados en otras secciones del informe. Al ser datos anuales (no mensuales), los puntos marcados sobre la línea permiten ubicar con precisión cada observación real, evitando que el lector interprete valores interpolados entre años como datos reales.
Lectura diagnóstica: el área permite apreciar de un vistazo los tres períodos: la fase de reducción sostenida (2012–2019), el salto abrupto durante la pandemia y la posterior fase de recuperación, sin necesidad de comparar valores exactos punto por punto.
df_pob_var <- df_pobreza |>
arrange(Año) |>
mutate(
Tasa_pct = .data[[col_tasa]],
Variacion = Tasa_pct - lag(Tasa_pct),
Color_var = ifelse(Variacion >= 0, "Aumento", "Reducción")
) |>
filter(!is.na(Variacion))
offset_etiqueta_var <- diff(range(df_pob_var$Variacion, na.rm = TRUE)) * 0.05
p_var_pob <- ggplot(df_pob_var, aes(x = factor(Año), y = Variacion, fill = Color_var)) +
geom_col(width = 0.65) +
geom_hline(yintercept = 0, color = TEXTO, linewidth = 0.7) +
geom_text(aes(y = Variacion + ifelse(Variacion >= 0, offset_etiqueta_var, -offset_etiqueta_var),
label = paste0(ifelse(Variacion > 0, "+", ""), round(Variacion, 1), " pp")),
size = 3.3, color = TEXTO) +
scale_fill_manual(values = c("Aumento" = AZUL_DESTACADOS, "Reducción" = VERDE),
name = "") +
scale_y_continuous(expand = expansion(mult = c(0.15, 0.15))) +
labs(title = "Variación Anual de la Tasa de Pobreza",
subtitle = "Puntos porcentuales (pp) respecto al año anterior",
x = "Año", y = "Variación (pp)",
caption = "Fuente: DANE — Informe de Pobreza Monetaria") +
tema_corporativo +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
ggplotly(p_var_pob, tooltip = c("x", "y", "fill")) |>
layout(paper_bgcolor = FONDO_APP, plot_bgcolor = "#FFFFFF") |>
centrar_grafico()Diagnóstico del gráfico — Figura 8
Tipo de gráfico: barras divergentes (positivas/negativas) con línea base en cero.
¿Por qué este tipo de gráfico? La Figura 7 muestra el nivel de la tasa de pobreza, pero no responde con la misma claridad “¿en qué años empeoró o mejoró la situación, y en cuánto?”. Las barras divergentes están diseñadas específicamente para variables de cambio o variación (aumento vs. reducción): al anclarse en una línea base de cero, la dirección de la barra (hacia arriba o hacia abajo) codifica el signo del cambio, y el color refuerza esa lectura sin ambigüedad.
Lectura diagnóstica: las barras verdes (reducción) predominan en los años de recuperación económica, mientras que la barra azul de mayor tamaño identifica inmediatamente el año de mayor deterioro (el salto pandémico), permitiendo cuantificar el retroceso en puntos porcentuales de un solo vistazo.
df_pobreza |>
mutate(
Tasa_fmt = paste0(round(.data[[col_tasa]], 1), "%"),
Personas_fmt = scales::comma(round(.data[[col_personas]], 0))
) |>
select(Año, Tasa_fmt, Personas_fmt) |>
setNames(c("Año", "Tasa de Pobreza (%)", "Personas en Pobreza (miles)")) |>
knitr::kable(caption = "Tabla 3. Indicadores de Pobreza Monetaria en Colombia.",
align = c("c", "c", "r"))| Año | Tasa de Pobreza (%) | Personas en Pobreza (miles) |
|---|---|---|
| 2012 | 41% | 17,938 |
| 2013 | 38.7% | 17,086 |
| 2014 | 37% | 16,465 |
| 2015 | 36.8% | 16,526 |
| 2016 | 36.8% | 16,712 |
| 2017 | 35.9% | 16,500 |
| 2018 | 35.5% | 16,644 |
| 2019 | 36.5% | 17,461 |
| 2020 | 43.1% | 21,059 |
| 2021 | 39.7% | 19,634 |
| 2022 | 36.6% | 18,332 |
| 2023 | 34.6% | 17,505 |
| 2024 | 31.8% | 16,238 |
| 2025 | 28% | 14,447 |
Hallazgos principales sobre pobreza monetaria:
Colombia logró reducir la pobreza monetaria del 41% en 2012 al 36.5% en 2019, producto del crecimiento económico y la expansión de los programas sociales.
El año 2020 (COVID-19) representó el mayor retroceso en la reducción de la pobreza del período analizado, alcanzando una tasa de 43.1%, con un incremento significativo tanto en la tasa como en el número de personas afectadas.
La recuperación posterior incluyó la mayor reducción anual registrada en 2025 (-3.8 pp), impulsada por la reactivación económica y los subsidios gubernamentales.
Al 2025, la tasa se sitúa en 28% (mínimo histórico del período: 28% en 2025). Persiste un núcleo de pobreza estructural que subraya la necesidad de políticas focalizadas más allá del crecimiento del PIB.
anio_genero_max <- max(df_gen_anual$Año)
df_gen_ref <- df_gen_anual |>
filter(Año == anio_genero_max)
# Detectar los valores reales de sexo en los datos
sexos_unicos <- unique(df_gen_ref$`SEXO + TOTAL`)
es_femenino <- function(x) grepl("FEM|MUJ|fem|muj|F$|mujer", x, ignore.case = TRUE)
color_sexo <- ifelse(es_femenino(sexos_unicos), AZUL_DESTACADOS, AZUL_PRINCIPAL)
names(color_sexo) <- sexos_unicos
label_sexo <- ifelse(es_femenino(sexos_unicos), "Mujer", "Hombre")
names(label_sexo) <- sexos_unicos
offset_etiqueta_gen <- max(df_gen_ref$Valor, na.rm = TRUE) * 0.06
p_gen_barras <- ggplot(df_gen_ref,
aes(x = Indicador, y = Valor,
fill = `SEXO + TOTAL`)) +
geom_col(position = position_dodge(0.75), width = 0.65) +
geom_text(aes(y = Valor + offset_etiqueta_gen,
label = paste0(round(Valor, 1), "%")),
position = position_dodge(0.75),
size = 3.5, color = TEXTO) +
scale_fill_manual(values = color_sexo, name = "Género",
labels = label_sexo) +
scale_y_continuous(labels = scales::label_percent(scale = 1, suffix = "%"),
expand = expansion(mult = c(0, 0.18))) +
labs(title = paste0("Brechas de Género en el Mercado Laboral — ", anio_genero_max),
subtitle = "Tasa Global de Participación (TGP), Tasa de Ocupación (TO), Tasa de Desocupación (TD)",
x = "Indicador", y = "(%)",
caption = "Fuente: DANE — GEIH") +
tema_corporativo
ggplotly(p_gen_barras, tooltip = c("x", "y", "fill")) |>
layout(paper_bgcolor = FONDO_APP, plot_bgcolor = "#FFFFFF",
barmode = "group",
legend = list(orientation = "h", x = 0.3, y = -0.2)) |>
centrar_grafico()Diagnóstico del gráfico — Figura 9
Tipo de gráfico: barras agrupadas (comparación categórica cruzada: indicador × género).
¿Por qué este tipo de gráfico? Se busca comparar tres indicadores (TGP, TO, TD) entre dos grupos (hombres/mujeres) en un único año. Las barras agrupadas son el estándar para este tipo de comparación de dos factores categóricos, ya que permiten leer tanto la diferencia entre géneros dentro de cada indicador (comparando barras adyacentes) como la relación entre los tres indicadores dentro de un mismo género.
Lectura diagnóstica: la brecha visual entre cada par de barras (hombre/mujer) cuantifica directamente la desigualdad de género en cada indicador; la comparación entre pares permite identificar en cuál de los tres indicadores la brecha es proporcionalmente mayor.
df_brecha <- df_gen_anual |>
pivot_wider(names_from = `SEXO + TOTAL`,
values_from = Valor,
names_prefix = "Sexo_") |>
# Detectar columnas de sexo generadas por pivot_wider
(\(d) {
cols_sexo <- setdiff(names(d), c("Año", "Indicador"))
col_masc <- cols_sexo[!grepl("FEM|MUJ|fem|muj", cols_sexo, ignore.case = TRUE)][1]
col_fem <- cols_sexo[ grepl("FEM|MUJ|fem|muj", cols_sexo, ignore.case = TRUE)][1]
d |> mutate(Brecha = .data[[col_masc]] - .data[[col_fem]])
})() |>
filter(!is.na(Brecha))
p_brecha <- ggplot(df_brecha, aes(x = Año, y = Brecha,
color = Indicador, group = Indicador)) +
geom_hline(yintercept = 0, color = "#9CA3AF", linewidth = 0.8, linetype = "dashed") +
geom_line(linewidth = 1.6) +
geom_point(size = 3, shape = 21, fill = "white", stroke = 1.5) +
# Nota de legibilidad: los 3 tonos de azul originales eran poco distinguibles
# entre si. Se usan 3 colores de alto contraste dentro de la paleta corporativa
# extendida (navy / naranja / verde) para que cada serie se identifique sin
# depender del tooltip interactivo.
scale_color_manual(
values = c(TGP = AZUL_PRINCIPAL, TO = VERDE, TD = NARANJA),
name = "Indicador"
) +
scale_y_continuous(labels = scales::label_percent(scale = 1, suffix = " pp")) +
scale_x_continuous(breaks = seq(2010, 2026, by = 2)) +
labs(title = "Brecha de Género (Hombre − Mujer)",
subtitle = "Diferencia en puntos porcentuales — promedio anual",
x = "Año", y = "Brecha (pp)",
caption = "Fuente: DANE — GEIH") +
tema_corporativo
ggplotly(p_brecha, tooltip = c("x", "y", "colour")) |>
layout(paper_bgcolor = FONDO_APP, plot_bgcolor = "#FFFFFF",
legend = list(orientation = "h", x = 0.3, y = -0.2)) |>
centrar_grafico()Diagnóstico del gráfico — Figura 10
Tipo de gráfico: líneas múltiples con línea de referencia en cero (serie de tiempo de una variable derivada: la brecha).
¿Por qué este tipo de gráfico? La Figura 9 solo muestra un año; para responder si las brechas de género se han reducido o ampliado con el tiempo, se necesita una serie histórica. En lugar de graficar las tasas de hombres y mujeres por separado (lo que obligaría al lector a calcular la diferencia mentalmente), se grafica directamente la brecha ya calculada (hombre − mujer), con una línea horizontal en cero como referencia de “brecha nula”. Esto simplifica la lectura y hace evidente si la desigualdad aumenta, disminuye o se revierte.
Lectura diagnóstica: una línea que se acerca a cero indica reducción de la brecha; si TD se ubica en valores negativos, significa que la desocupación femenina supera a la masculina; el cruce eventual de una serie por la línea de cero marcaría un cambio de signo en la desigualdad de ese indicador.
# CORRECCIÓN: estos 4 objetos (df_gen_evol, etiquetas_indicador, color_sexo_evol,
# label_sexo_evol) se usaban mas abajo pero nunca se habian creado, lo que
# impedía que este gráfico se generara. Se construyen aquí a partir de
# df_gen_anual y reutilizando color_sexo / label_sexo ya calculados en el
# chunk de la Figura 9.
df_gen_evol <- df_gen_anual |>
filter(Indicador %in% c("TO", "TD"))
etiquetas_indicador <- c(
TO = "Tasa de Ocupación (TO)",
TD = "Tasa de Desocupación (TD)"
)
color_sexo_evol <- color_sexo
label_sexo_evol <- label_sexo
p_gen_evol <- ggplot(df_gen_evol,
aes(x = Año, y = Valor, color = `SEXO + TOTAL`,
group = `SEXO + TOTAL`)) +
geom_line(linewidth = 1.1) +
geom_point(size = 1.8) +
facet_wrap(~ Indicador, ncol = 1, scales = "free_y",
labeller = labeller(Indicador = etiquetas_indicador)) +
scale_color_manual(values = color_sexo_evol, name = "Género",
labels = label_sexo_evol) +
scale_x_continuous(breaks = scales::pretty_breaks(n = 8)) +
scale_y_continuous(labels = scales::label_percent(scale = 1, suffix = "%"),
expand = expansion(mult = c(0.08, 0.12))) +
labs(title = "Evolución de la Tasa de Ocupación y Desocupación por Género",
subtitle = paste0("Colombia, ", min(df_gen_evol$Año), "–", max(df_gen_evol$Año)),
x = NULL, y = "(%)",
caption = "Fuente: DANE — GEIH") +
tema_corporativo +
theme(strip.background = element_rect(fill = AZUL_PRINCIPAL),
strip.text = element_text(color = "#FFFFFF", face = "bold",
margin = margin(t = 6, b = 6)),
panel.spacing.y = unit(1.4, "lines"),
legend.position = "bottom")
ggplotly(p_gen_evol, tooltip = c("x", "y", "colour")) |>
layout(paper_bgcolor = FONDO_APP, plot_bgcolor = "#FFFFFF",
legend = list(orientation = "h", x = 0.3, y = -0.15),
margin = list(t = 60, b = 40)) |>
centrar_grafico()Diagnóstico del gráfico — Figura 11
Tipo de gráfico: líneas por género, en paneles separados (facetas) para TO y TD.
¿Por qué este tipo de gráfico? TO y TD se dejan en
paneles independientes (en lugar de una sola gráfica
con las 4 líneas juntas) porque cada indicador tiene una magnitud y un
comportamiento distintos; mezclarlos en un solo eje Y comprimiría las
variaciones de uno de los dos y dificultaría ver los detalles de ambas
series (scales = "free_y" permite que cada panel use su
propia escala). Dentro de cada panel, el color por género permite
comparar directamente hombres y mujeres para ese indicador
específico.
Lectura diagnóstica: el panel superior (TO) muestra el nivel de empleabilidad de cada género a lo largo del tiempo; el panel inferior (TD) permite observar si la brecha de desempleo entre géneros se mantiene, crece o se cierra en los años más recientes, complementando la lectura agregada (brecha) de la Figura 10 con el detalle de cada serie por separado.
Hallazgos principales sobre brechas de género (2025):
La Tasa Global de Participación (TGP) evidencia la brecha más amplia entre hombres y mujeres: 76.8% (hombres) vs. 52.8% (mujeres) — una diferencia de 24 pp. Los hombres participan activamente en mayor proporción, aunque la brecha ha tendido a reducirse en el período analizado.
La Tasa de Desocupación es 11.4% en mujeres vs. 7% en hombres (4.4 pp de diferencia), lo que indica que las mujeres que participan en el mercado laboral enfrentan mayores dificultades para encontrar empleo.
El COVID-19 afectó de manera diferencial por género: la Tasa de Desocupación femenina registró un incremento proporcionalmente mayor, producto de la concentración de mujeres en sectores de servicios y trabajo informal.
A pesar de los avances, las brechas en TGP y TO persisten, lo que señala barreras estructurales (trabajo no remunerado del hogar, segregación sectorial, discriminación salarial) que trascienden la dinámica macroeconómica.
modelo_lm <- lm(FuerzaTrabajo ~ SalarioMinimo, data = df_smlv)
r_cuadrado <- round(summary(modelo_lm)$r.squared, 4)
pearson_r <- round(cor(df_smlv$SalarioMinimo, df_smlv$FuerzaTrabajo,
method = "pearson"), 4)
spearman_r <- round(cor(df_smlv$SalarioMinimo, df_smlv$FuerzaTrabajo,
method = "spearman"), 4)
pendiente <- round(coef(modelo_lm)[2], 6)
intercepto <- round(coef(modelo_lm)[1], 2)df_smlv_plot <- df_smlv |>
mutate(FT_miles = FuerzaTrabajo / 1000,
SMLV_miles = SalarioMinimo / 1000)
fit_line <- data.frame(
SalarioMinimo = seq(min(df_smlv_plot$SalarioMinimo),
max(df_smlv_plot$SalarioMinimo),
length.out = 200)
)
fit_line$FuerzaTrabajo <- predict(modelo_lm, newdata = fit_line)
fit_line <- fit_line |>
mutate(FT_miles = FuerzaTrabajo / 1000,
SMLV_miles = SalarioMinimo / 1000)
p_smlv <- ggplot(df_smlv_plot, aes(x = SMLV_miles, y = FT_miles)) +
# Intervalo de confianza
geom_ribbon(data = fit_line,
aes(ymin = FT_miles * 0.985, ymax = FT_miles * 1.015),
fill = AZUL_MUY_CLARO, alpha = 0.4) +
# Línea de tendencia
geom_line(data = fit_line, aes(x = SMLV_miles, y = FT_miles),
color = AZUL_PRINCIPAL, linewidth = 1.5, linetype = "dashed") +
# Puntos
geom_point(aes(color = AÑOS), size = 5, alpha = 0.9,
shape = 21, stroke = 1.5, fill = AZUL_DESTACADOS) +
# Etiquetas de año
geom_text(aes(label = AÑOS), hjust = -0.3, vjust = 0.4,
size = 3.2, color = "white") +
# Anotación R²
annotate("label", x = min(df_smlv_plot$SMLV_miles) * 1.05,
y = max(df_smlv_plot$FT_miles) * 0.98,
label = paste0("R² = ", r_cuadrado, "\nr = ", pearson_r),
hjust = 0, fill = "#FFFFFF", color = AZUL_PRINCIPAL,
label.size = 0.5, size = 3.8, fontface = "bold") +
scale_color_gradient(low = AZUL_CLARO, high = AZUL_PRINCIPAL,
name = "Año") +
scale_x_continuous(labels = scales::label_dollar(prefix = "$",
suffix = "K",
scale = 1)) +
scale_y_continuous(labels = scales::label_comma(suffix = " M")) +
labs(title = "Salario Mínimo Legal Vigente vs. Fuerza de Trabajo",
subtitle = paste0("Correlación de Pearson: r = ", pearson_r,
" | R² = ", r_cuadrado),
x = "Salario Mínimo Legal Vigente (miles de COP)",
y = "Fuerza de Trabajo (millones de personas)",
caption = "Fuente: DANE — GEIH / Ministerio del Trabajo de Colombia") +
tema_corporativo +
theme(legend.position = "right")
ggplotly(p_smlv, tooltip = c("x", "y", "text")) |>
layout(paper_bgcolor = FONDO_APP, plot_bgcolor = "#FFFFFF") |>
centrar_grafico()Diagnóstico del gráfico — Figura 12
Tipo de gráfico: diagrama de dispersión con línea de regresión lineal, banda de confianza y etiquetas de año.
¿Por qué este tipo de gráfico? Es el gráfico
adecuado para evaluar visualmente una correlación entre dos
variables continuas (SMLV y Fuerza de Trabajo). La línea
discontinua no es decorativa: representa el modelo de regresión lineal
ajustado (lm), y la banda sombreada comunica la
incertidumbre alrededor de esa línea. Etiquetar cada punto con su año
permite además leer la dirección temporal de la relación, algo que un
scatter plot genérico no ofrece.
Lectura diagnóstica: el coeficiente R² anotado directamente en el gráfico cuantifica qué proporción de la variación de la Fuerza de Trabajo es explicada linealmente por el SMLV; la cercanía de los puntos a la línea indica qué tan fuerte es esa asociación, mientras que los puntos más alejados señalan años donde otros factores (demográficos, económicos) pesaron más que el salario mínimo.
df_smlv_resid <- df_smlv |>
mutate(
Predicho = predict(modelo_lm),
Residuo = FuerzaTrabajo - Predicho,
Color_res = ifelse(Residuo >= 0, "Positivo", "Negativo")
)
# Determinar unidad de los residuos según escala de FuerzaTrabajo
max_ft <- max(abs(df_smlv$FuerzaTrabajo), na.rm = TRUE)
unidad_resid <- if (max_ft > 1e6) "personas" else if (max_ft > 1e3) "miles de personas" else "unidades"
p_resid <- ggplot(df_smlv_resid, aes(x = factor(AÑOS), y = Residuo,
fill = Color_res)) +
geom_col(width = 0.7) +
geom_hline(yintercept = 0, color = TEXTO, linewidth = 0.8) +
geom_text(aes(label = scales::comma(round(Residuo, 0)),
vjust = ifelse(Residuo >= 0, -0.4, 1.3)),
size = 2.9, color = TEXTO) +
scale_fill_manual(values = c(Positivo = AZUL_DESTACADOS, Negativo = NARANJA),
name = "Residuo") +
labs(title = "Residuos del Modelo de Regresión Lineal",
subtitle = paste0("Ŷ = ", scales::comma(round(intercepto, 0)),
" + ", round(pendiente * 1000, 4),
" × SMLV (miles de COP)"),
x = "Año", y = paste0("Residuo (", unidad_resid, ")"),
caption = "Fuente: elaboración propia con datos DANE") +
tema_corporativo +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
ggplotly(p_resid, tooltip = c("x", "y", "fill")) |>
layout(paper_bgcolor = FONDO_APP, plot_bgcolor = "#FFFFFF") |>
centrar_grafico()Diagnóstico del gráfico — Figura 13
Tipo de gráfico: barras de residuos con línea base en cero (diagnóstico de modelo de regresión).
¿Por qué este tipo de gráfico? Este gráfico no describe los datos originales sino la calidad del ajuste del modelo de la Figura 12: el residuo es la diferencia entre el valor observado y el valor predicho por la regresión. Las barras divergentes (positivas/negativas respecto a cero) son el estándar en diagnóstico de regresión porque permiten detectar de inmediato patrones no aleatorios en los errores (por ejemplo, residuos que crecen con el tiempo), lo cual indicaría que el modelo lineal no captura toda la relación.
Lectura diagnóstica: si los residuos se distribuyen sin un patrón sistemático alrededor de cero, el ajuste lineal es razonable; si se observan agrupaciones de residuos del mismo signo en años consecutivos (por ejemplo, alrededor de 2020), esto sugiere que un choque externo (la pandemia) no fue capturado por el modelo y que la relación SMLV–Fuerza de Trabajo podría no ser puramente lineal en todo el período.
Con base en el análisis de los cinco módulos desarrollados, se sintetizan las siguientes conclusiones:
1. Mercado Laboral Nacional: Colombia registró avances en la reducción del desempleo durante la última década. La Tasa de Desocupación pasó de 12% en 2010 a 8.9% en 2025, con el pico pandémico de 16.7% en 2020. La recuperación post-COVID ha sido parcial, y persisten niveles de informalidad y subempleo.
2. Heterogeneidad Territorial: Las diferencias entre ciudades son sustanciales (17.3 pp de brecha entre Quibdó y Bucaramanga), lo que demanda políticas diferenciadas por región que atiendan las particularidades productivas y demográficas de cada área metropolitana.
3. Pobreza Monetaria: La tendencia decreciente (41% en 2012 → 36.5% en 2019) fue interrumpida por la pandemia, que elevó la tasa al 43.1% en 2020. Al 2025 la tasa se recuperó a 28%, aunque persiste un núcleo de pobreza estructural.
4. Brechas de Género: En 2025, la TGP masculina supera a la femenina en 24 pp, y la TD femenina supera a la masculina en 4.4 pp. Las brechas se han reducido lentamente, pero su persistencia señala barreras sistémicas. que requieren intervención específica.
5. SMLV y Fuerza Laboral: La correlación de Pearson (r = 0.9647, R² = 0.9307) entre el SMLV y la Fuerza de Trabajo refuerza la importancia del salario mínimo como mecanismo de inclusión económica, aunque su efecto debe analizarse en conjunto con el comportamiento demográfico y el ciclo económico.
A partir de los hallazgos del análisis, se formulan las siguientes recomendaciones de política pública y de investigación:
R1. Fortalecer los sistemas de protección laboral: Diseñar mecanismos anticíclicos que amortigüen el impacto de choques externos sobre el empleo, especialmente en sectores con alta informalidad.
R2. Políticas territoriales diferenciadas: Implementar estrategias de fomento al empleo adaptadas a las realidades de cada ciudad/región, priorizando las que exhiben mayor Tasa de Desocupación estructural.
R3. Programas focalizados de reducción de la pobreza: Complementar el crecimiento económico con transferencias condicionadas y acceso a servicios sociales para el núcleo de pobreza estructural que no se moviliza con el ciclo productivo.
R4. Equidad de género en el mercado laboral: Fortalecer políticas de corresponsabilidad en el cuidado, ampliar el acceso a guarderías, y promover la equidad salarial para reducir las brechas en TGP y TO.
R5. Monitoreo continuo de la relación SMLV–empleo: Profundizar el análisis econométrico de la relación entre salario mínimo, informalidad y empleo, incorporando controles por inflación, productividad y composición sectorial.
R6. Ampliar la desagregación de los datos: Incorporar en análisis futuros las dimensiones étnica, etaria y por nivel educativo, que permitan identificar poblaciones en situación de mayor vulnerabilidad socioeconómica.
Análisis de Evolución Socioeconómica
en Colombia
Informe generado con R Markdown — SENA
Datos: DANE – Gran Encuesta Integrada de Hogares (GEIH)
02 de julio
de 2026