Realizar un análisis shift-share utilizando el empleo como variable de estudio. En este taller usamos esta variable sobre las dieciséis regiones de Chile.
Los objetivos son:
# Una sola vez, en la consola:
install.packages("ggplot2") # gráficos
install.packages("sf")
# En cada sesión, al principio del script:
library(ggplot2)
library(sf)
Fuente: OECD Data Explorer (data-explorer.oecd.org).
| Rasgo | Contenido |
|---|---|
| Variable | Empleo, medido en el lugar de trabajo |
| Unidad | Personas |
| Cobertura | Chile, 16 regiones, nivel territorial TL2 |
| Período | 2013 a 2024, anual |
| Origen | Encuesta Nacional de Empleo (ENE) |
Los datos vienen en empleo_regional_chile_largo.csv, ya
en formato long y con la misma estructura del archivo
del taller anterior: una fila por región, sector y año.
| Columna | Contenido |
|---|---|
codigo_region |
Código único territorial, texto de dos dígitos |
region |
Nombre de la región |
sector |
Actividad económica, 10 categorías |
anio |
2013 a 2024 |
valor |
Personas ocupadas |
NOTA: Para los propósitos de este taller, los datos fueron procesados previamente en términos de formato y estructura para transformarlos en el formato adecuado.
#El mismo proceso de lectura, como en el taller anterior.
d <- read.csv("empleo_regional_chile_largo.csv", encoding = "UTF-8",
colClasses = c(codigo_region = "character"))
str(d)
#> 'data.frame': 1920 obs. of 5 variables:
#> $ codigo_region: chr "01" "01" "01" "01" ...
#> $ region : chr "Tarapacá" "Tarapacá" "Tarapacá" "Tarapacá" ...
#> $ sector : chr "Actividades inmobiliarias" "Administración pública, educación y salud" "Agricultura" "Arte, entretenimiento y otros servicios" ...
#> $ anio : int 2013 2013 2013 2013 2013 2013 2013 2013 2013 2013 ...
#> $ valor : num 1122 27654 4687 9782 55388 ...
c(regiones = length(unique(d$region)),
sectores = length(unique(d$sector)),
anios = length(unique(d$anio)))
#> regiones sectores anios
#> 16 10 12
Antes de empezar el taller formalmente, es importante realizar un análisis que permita identificar el porcentaje de casillas/celdas que tienen valor cero. En el contexto de un análisis shift-share, la identificación de los ceros es crucial porque puede generar problemas para calcular tasas de crecimiento cuando el valor inicial de una casilla/celda es igual a cero.
# Cuenta el número total de observaciones o celdas que tiene la base d
c(celdas = nrow(d), nulas = sum(d$valor == 0), # cuenta cuantas observaciones son iguales a cero.
pct = round(100 * mean(d$valor == 0), 1)) # se obtiene el porcentaje de observaciones que son iguales a cero.
#> celdas nulas pct
#> 1920.0 319.0 16.6
sort(tapply(d$valor == 0, d$sector, sum), decreasing = TRUE)[1:5] # Se cuenta para cada sector cuantas observaciones tienen valor cero y se ordenan de mayor a menor (considera los primeros cinco)
#> Actividades inmobiliarias
#> 135
#> Información y comunicaciones
#> 87
#> Finanzas y seguros
#> 83
#> Agricultura
#> 13
#> Servicios profesionales y administrativos
#> 1
sort(tapply(d$valor == 0, d$region, sum), decreasing = TRUE)[1:6] # Lo mismo, pero para las regiones.
#> Ñuble Aysén Arica y Parinacota Atacama
#> 36 34 33 33
#> Magallanes Antofagasta
#> 31 25
Es importante tener en cuenta que tener ceros no significa que no exista esa actividad económica en la región. Esto podría ser el resultado de que la Encuesta Nacional de Empleo no tenga para un año específico suficientes casos para estimar el empleo para una región. Esto se podría comprobar:
subset(d, region == "Antofagasta" & sector == "Actividades inmobiliarias",
select = c(anio, valor))
#> anio valor
#> 11 2013 0.000
#> 171 2014 0.000
#> 331 2015 0.000
#> 491 2016 0.000
#> 651 2017 0.000
#> 811 2018 0.000
#> 971 2019 0.000
#> 1131 2020 0.000
#> 1291 2021 3521.215
#> 1451 2022 3980.975
#> 1611 2023 3182.894
#> 1771 2024 0.000
Es necesario tomar una decisión: Una manera de solucionar este problema y no prescindir de los sectores “problemáticos” es agregar estos sectores en uno solo. Estos tres sectores son parecidos (son servicios). Lo importante, es que es una decisión del analista y es importante declarar dicha decisión. También, hay que justificar porque esta decisión es la más adecuada.
#Vamos a definir un vector que va a agrupar a los tres sectores
juntar <- c("Actividades inmobiliarias", "Información y comunicaciones", "Finanzas y seguros")
d$sector8 <- ifelse(d$sector %in% juntar, # creamos una variable nueva llamada sector8 (nueva clasificación)
"Finanzas, inmobiliarias e información", d$sector) # si el sector pertenece al conjunto que se define en el vector juntar, lo reemplaza por la nueva categoría común. Si no, mantiene su nombre original.
d8 <- aggregate(valor ~ region + codigo_region + sector8 + anio, data = d, FUN = sum)
names(d8)[names(d8) == "sector8"] <- "sector" #agrupamos la base por región, codigo, sector reclasificado y año.
c(sectores = length(unique(d8$sector)), # Repetimos conteo de ceros.
celdas = nrow(d8),
nulas = sum(d8$valor == 0),
pct = round(100 * mean(d8$valor == 0), 1))
#> sectores celdas nulas pct
#> 8.0 1536.0 70.0 4.6
No necesariamente desaparecen los ceros, pero probablemente son menos problemáticos.
anio0 <- 2013 #Periodo inicial
anio1 <- 2023 #Periodo final
regiones <- sort(unique(d8$region)) #Regiones
actividades <- sort(unique(d8$sector)) #Sectores/Actividades
# Creamos una función para construir la matriz secre con dos insumos: datos: base y a: año.
matriz <- function(datos, a) {
M <- matrix(0, length(actividades), length(regiones), # matriz de ceros: filas sectores; regiones columnas.
dimnames = list(actividades, regiones)) # asignamos nombres.
x <- datos[datos$anio == a, ] # filtra la base y conserva los datos del año a.
for (k in seq_len(nrow(x))) M[x$sector[k], x$region[k]] <- x$valor[k] # para cada fila k (va en secuencia; observación) en la base x, identifica el sector de esta observación y la región de esta observación y obtiene el empleo correspondiente. Finalmente, ubica el empleo en la posición correcta de la matriz.
M # Devuelve la matriz secre completa.
}
V0 <- matriz(d8, anio0) # matriz secre para el año 2013
V1 <- matriz(d8, anio1) # matriz secre para el año 2023
#Aquí verificamos si las matrices cumplen con las condiciones necesarias para realizar el shift-share.
stopifnot(
dim(V0) == c(8, 16), #dimensiones
identical(dimnames(V0), dimnames(V1)), #identica estructura.
!any(is.na(V0)), !any(is.na(V1)), # si tenemos NA (valores perdidos)
all(V0 >= 0), all(V1 >= 0), #si todos son valores positivos
abs(sum(rowSums(V0)) - sum(colSums(V0))) < tol # cuadratura (empleo nacional sumando regiones sea igual al empleo nacional sumando sectores)
)
c(empleo_2013 = round(sum(V0)), empleo_2023 = round(sum(V1)))
#> empleo_2013 empleo_2023
#> 8002660 9000196
g <- (sum(V1) - sum(V0)) / sum(V0) # Tasa de crecimiento agregado del empleo
g_i <- (rowSums(V1) - rowSums(V0)) / rowSums(V0) # Tasa de crecimiento del sector/actividad
kable(data.frame(Actividad = names(sort(g_i, decreasing = TRUE)),
`g_i (%)` = round(100 * as.numeric(sort(g_i, decreasing = TRUE)), 1),
`g_i - g (pp)` = round(100 * as.numeric(sort(g_i, decreasing = TRUE) - g), 1),
check.names = FALSE),
align = "c", row.names = FALSE,
caption = paste0("Crecimiento del empleo por actividad, ", anio0, "-", anio1,
". Crecimiento agregado: ", round(100 * g, 1), " %."))
| Actividad | g_i (%) | g_i - g (pp) |
|---|---|---|
| Servicios profesionales y administrativos | 43.1 | 30.7 |
| Administración pública, educación y salud | 36.5 | 24.0 |
| Comercio, transporte y hotelería | 13.9 | 1.4 |
| Finanzas, inmobiliarias e información | 10.6 | -1.9 |
| Construcción | 4.5 | -8.0 |
| Industria | 2.6 | -9.8 |
| Arte, entretenimiento y otros servicios | -2.7 | -15.1 |
| Agricultura | -19.8 | -32.2 |
#Vamos a crear una función para calcular el shift-share. Se necesitan de dos insumos: la matriz A (periodo inicial) y la matriz B (periodo final).
descomponer <- function(A, B) {
gg <- (sum(B) - sum(A)) / sum(A) #calcula la tasa de crecimiento de la economía.
gi <- (rowSums(B) - rowSums(A)) / rowSums(A) #calcula la tasa de crecimiento de los sectores/actividades económicas
data.frame(region = colnames(A), #creamos una tabla con los resultados de la descomposición shift-share, para cada región.
V0 = colSums(A), # calcula el total del empleo en la región.
dV = colSums(B) - colSums(A), #calcula cambio total del empleo entre periodos
EN = colSums(A) * gg, # Calculamos el efecto nacional
EE = colSums(A * (gi - gg)), # Calculamos el efecto estructural
ED = colSums(B - A * (1 + gi)), # Calculamos el efecto diferencial. Forma robusta ante casillas nulas. Compruebe algebraicamente por usted mismo/a.
row.names = NULL)
}
res <- descomponer(V0, V1) #Aplicamos la función considerando las dos matrices y guardamos resultados.
res$ET <- res$EE + res$ED # Calculamos el efecto total.
res$g_j <- 100 * res$dV / res$V0 # Calculamos la tasa de crecimiento del empleo por región.
res$residuo <- res$dV - (res$EN + res$EE + res$ED) #Un control de consistencia. Para comprobar que el cálculo está bien realizado, debemos comprobar que la diferencia entre el cambio observado y la suma de los tres componentes del shift-share sean cercanos (o iguales) a cero.
#Vamos a crear una función que nos permita clasificar los resultados de acuerdo a lo planteado por Boisier (1980) y reproducido por Lira y Quiroga (2009). A partir del análisis realizado, es posible clasificar el comportamiento de las regiones y de esta manera, realizar algunas recomendaciones de política pública.
tipologia <- function(EE, ED) {
ET <- EE + ED
ifelse(ET > 0,
ifelse(EE > 0 & ED > 0, "I", ifelse(EE > 0, "II-A", "III-A")),
ifelse(EE > 0, "II-B", ifelse(ED > 0, "III-B", "IV")))
}
res$tipo <- tipologia(res$EE, res$ED)
stopifnot(
max(abs(res$residuo)) < tol,
abs(sum(res$EE)) < tol,
abs(sum(res$ED)) < tol,
abs(sum(res$EN) - sum(res$dV)) < tol
)
kable(res[order(-res$ET), c("region", "V0", "dV", "g_j", "EN", "EE", "ED", "ET", "tipo")],
row.names = FALSE, align = "c", digits = 0,
caption = "Descomposición del empleo, 2013-2023. Personas.")
| region | V0 | dV | g_j | EN | EE | ED | ET | tipo |
|---|---|---|---|---|---|---|---|---|
| Metropolitana | 3425360 | 608265 | 18 | 426973 | 81473 | 99819 | 181292 | I |
| Antofagasta | 252022 | 78712 | 31 | 31415 | 2454 | 44843 | 47298 | I |
| Tarapacá | 142012 | 41291 | 29 | 17702 | 3122 | 20467 | 23589 | I |
| Magallanes | 76308 | 16841 | 22 | 9512 | 2151 | 5178 | 7329 | I |
| Coquimbo | 316114 | 43980 | 14 | 39404 | -9133 | 13709 | 4576 | III-A |
| Arica y Parinacota | 97327 | 12905 | 13 | 12132 | -232 | 1005 | 773 | III-A |
| Aysén | 50583 | 7056 | 14 | 6305 | 291 | 460 | 751 | I |
| Atacama | 129931 | 15454 | 12 | 16196 | -1246 | 504 | -742 | III-B |
| Valparaíso | 801589 | 97701 | 12 | 99919 | 2902 | -5120 | -2217 | II-B |
| Maule | 452541 | 51918 | 11 | 56409 | -24967 | 20476 | -4491 | III-B |
| Los Ríos | 171641 | 3027 | 2 | 21395 | -5631 | -12737 | -18368 | IV |
| Ñuble | 204554 | 5932 | 3 | 25498 | -5350 | -14216 | -19565 | IV |
| Biobío | 642848 | 47789 | 7 | 80131 | -2885 | -29457 | -32342 | IV |
| O’Higgins | 416560 | 11702 | 3 | 51924 | -21896 | -18326 | -40223 | IV |
| Araucanía | 426520 | -9695 | -2 | 53166 | -15992 | -46869 | -62861 | IV |
| Los Lagos | 396750 | -35342 | -9 | 49455 | -5062 | -79736 | -84797 | IV |
Lo primero que hay que mirar es Antofagasta: crece 31 % cuando el país crece 12,5 %, con efecto estructural y diferencial ambos positivos. Es tipo I, la mejor clasificación la tipología.
La descomposición 2013–2023 compara dos fotografías en el tiempo. Sin embargo, no se sabe nada de lo que ha pasado entre esos años. Aprovechando la serie anual, es posible aplicar el shift-share utilizando cada par consecutivo.
anios <- sort(unique(d8$anio)) # obtiene todos los años de la base
lista <- lapply(seq_len(length(anios) - 1), function(k) { # Aplica la función descomponer para cada par de años consecutivos. Recorre todos los pares de años consecutivos y aplica a cada uno shift-share.
x <- descomponer(matriz(d8, anios[k]), matriz(d8, anios[k + 1]))
x$anio <- anios[k + 1]
x$tipo <- tipologia(x$EE, x$ED)
x
})
sh <- do.call(rbind, lista)
stopifnot(max(abs(sh$dV - (sh$EN + sh$EE + sh$ED))) < tol)
# ¿cuántos tipologías diferentes recorre cada región a lo largo de los 11 períodos?
sort(sapply(split(sh$tipo, sh$region), function(x) length(unique(x))), decreasing = TRUE) # Ordenamos a las regiones desde la que tuvo más cambios de tipología hasta la que presentó una trayectoria más estable.
#> Araucanía Atacama Biobío Coquimbo
#> 5 5 5 5
#> Valparaíso Antofagasta Arica y Parinacota Aysén
#> 5 4 4 4
#> Los Lagos Magallanes Metropolitana Ñuble
#> 4 4 4 4
#> Tarapacá Los Ríos Maule O'Higgins
#> 4 3 3 3
Ninguna región permanece en una sola tipología. Probablemente, El diagnóstico no es una propiedad de la región: es una propiedad de la región y del período elegido.
Podemos analizar temporalmente la trayectoria del efecto estructural y el efecto diferencial.
library(ggplot2)
ggplot(sh, aes(anio)) +
geom_hline(yintercept = 0, colour = "#b8b4ae", linewidth = 0.3) +
geom_line(aes(y = EE, colour = "Estructural"), linewidth = 0.6) +
geom_line(aes(y = ED, colour = "Diferencial"), linewidth = 0.6) +
facet_wrap(~ region, ncol = 4, scales = "free_y") +
scale_colour_manual(values = c("Estructural" = "#b1541f", "Diferencial" = "#2a78d6"),
name = NULL) +
labs(title = "Efecto Estructural y Diferencial, año a año",
subtitle = "Empleo regional de Chile, 2013-2024",
x = NULL, y = "Personas",
caption = "Datos: OCDE, Regional economy. Elaboración propia.") +
theme_minimal(base_size = 9) +
theme(panel.grid.minor = element_blank(), legend.position = "top",
strip.text = element_text(face = "bold", colour = "#1f3864"))
Es importante un análisis a la figura.
c(sd_EE = round(sd(sh$EE)), sd_ED = round(sd(sh$ED)),
razon = round(sd(sh$ED) / sd(sh$EE), 1),
pct_ED_mayor = round(100 * mean(abs(sh$ED) > abs(sh$EE))))
#> sd_EE sd_ED razon pct_ED_mayor
#> 4247.0 12229.0 2.9 86.0
# desviación agregada de cada componente, por período
agr <- aggregate(cbind(EE, ED) ~ anio, data = sh, FUN = function(v) sum(abs(v)))
cbind(agr[1], round(agr[-1]))
#> anio EE ED
#> 1 2014 24734 122016
#> 2 2015 43394 143887
#> 3 2016 22207 94247
#> 4 2017 18928 134136
#> 5 2018 21113 96067
#> 6 2019 10756 84036
#> 7 2020 42750 223896
#> 8 2021 74445 105891
#> 9 2022 27789 123234
#> 10 2023 17908 57193
#> 11 2024 12838 131393
Hasta aquí las regiones han sido una lista. Pero tambien conviene preguntarse si los resultados obedecen a si las regiones vecinas se parecen entre sí más de lo que se parecerían si los efectos se hubieran repartido al azar.
library(sf)
regiones_sf <- st_read("cartografia/regiones_chile.shp", quiet = TRUE)
cut_datos <- unique(d8[, c("codigo_region", "region")])
mapa <- merge(regiones_sf[, c("cut", "geometry")], # Unimos datos por el código CUT.
merge(cut_datos, res, by = "region"),
by.x = "cut", by.y = "codigo_region", all.x = TRUE)
stopifnot(!any(is.na(mapa$EE))) # el empalme debe ser 16 de 16
lim_x <- c(-76.5, -66.0) # Chile continental; deja fuera Rapa Nui
lim_y <- c(-56.5, -17.0)
lim <- max(abs(c(mapa$EE, mapa$ED)))
m1 <- mapa; m1$valor <- mapa$EE; m1$efecto <- "Efecto estructural"
m2 <- mapa; m2$valor <- mapa$ED; m2$efecto <- "Efecto diferencial"
mapa_largo <- rbind(m1, m2)
mapa_largo$efecto <- factor(mapa_largo$efecto,
levels = c("Efecto estructural", "Efecto diferencial"))
ggplot(mapa_largo) +
geom_sf(aes(fill = valor), colour = "white", linewidth = 0.15) +
facet_wrap(~ efecto) +
coord_sf(xlim = lim_x, ylim = lim_y, expand = FALSE) +
scale_fill_gradient2(low = "#b1541f", mid = "#f0efec", high = "#2a78d6",
midpoint = 0, limits = c(-lim, lim), name = "Personas") +
labs(title = "Los dos componentes en personas, 2013-2023",
subtitle = "La escala la fijan las regiones grandes y el resto del país se aplana",
caption = "Datos: OCDE, Regional economy. Cartografía: BCN.") +
theme_void(base_size = 11) +
theme(strip.text = element_text(size = 11, margin = margin(t = 8, b = 8)),
plot.subtitle = element_text(margin = margin(b = 6)))
NOTA: Si bien el mapa está correctamente graficado, el efecto estructural queda casi en blanco y el efecto diferencial destaca las regiones más grandes. La razón de este resultado se explica porque los componentes de la descomposición dependen del tamaño incial de la región. Por ejemplo, la región Metropolitana tiene 3,4 millones de ocupados, y la región de Aysén tiene 51 mil. La región Metropolitana siempre será más grande y se destacará más en el mapa, aunque la desviación relativa sea menor. Una solución es dividir por el empleo del año base, es decir, expresar cada componente como porcentaje del empleo inicial de su región:
mapa$EEr <- 100 * mapa$EE / mapa$V0
mapa$EDr <- 100 * mapa$ED / mapa$V0
mapa$ETr <- 100 * (mapa$EE + mapa$ED) / mapa$V0
kable(data.frame(Región = mapa$region,
`EE (%)` = round(mapa$EEr, 1),
`ED (%)` = round(mapa$EDr, 1),
`ET (%)` = round(mapa$ETr, 1),
check.names = FALSE)[order(-mapa$ETr), ],
row.names = FALSE, align = "c",
caption = "Componentes como porcentaje del empleo de 2013.")
| Región | EE (%) | ED (%) | ET (%) |
|---|---|---|---|
| Antofagasta | 1.0 | 17.8 | 18.8 |
| Tarapacá | 2.2 | 14.4 | 16.6 |
| Magallanes | 2.8 | 6.8 | 9.6 |
| Metropolitana | 2.4 | 2.9 | 5.3 |
| Aysén | 0.6 | 0.9 | 1.5 |
| Coquimbo | -2.9 | 4.3 | 1.4 |
| Arica y Parinacota | -0.2 | 1.0 | 0.8 |
| Valparaíso | 0.4 | -0.6 | -0.3 |
| Atacama | -1.0 | 0.4 | -0.6 |
| Maule | -5.5 | 4.5 | -1.0 |
| Biobío | -0.4 | -4.6 | -5.0 |
| Ñuble | -2.6 | -6.9 | -9.6 |
| O’Higgins | -5.3 | -4.4 | -9.7 |
| Los Ríos | -3.3 | -7.4 | -10.7 |
| Araucanía | -3.7 | -11.0 | -14.7 |
| Los Lagos | -1.3 | -20.1 | -21.4 |
lim2 <- max(abs(c(mapa$EEr, mapa$EDr)))
n1 <- mapa; n1$valor <- mapa$EEr; n1$efecto <- "Efecto estructural"
n2 <- mapa; n2$valor <- mapa$EDr; n2$efecto <- "Efecto diferencial"
rel_largo <- rbind(n1, n2)
rel_largo$efecto <- factor(rel_largo$efecto,
levels = c("Efecto estructural", "Efecto diferencial"))
ggplot(rel_largo) +
geom_sf(aes(fill = valor), colour = "white", linewidth = 0.15) +
facet_wrap(~ efecto) +
coord_sf(xlim = lim_x, ylim = lim_y, expand = FALSE) +
scale_fill_gradient2(low = "#b1541f", mid = "#f0efec", high = "#2a78d6",
midpoint = 0, limits = c(-lim2, lim2), name = "% del\nempleo 2013") +
labs(title = "Los dos componentes en términos relativos, 2013-2023",
subtitle = "Naranjo: por debajo del patrón nacional · Azul: por encima",
caption = "Datos: OCDE, Regional economy. Cartografía: BCN. Se recorta la vista a Chile continental.") +
theme_void(base_size = 11) +
theme(strip.text = element_text(size = 11, margin = margin(t = 8, b = 8)),
plot.subtitle = element_text(margin = margin(b = 6)))
col_tipo <- c("I" = "#1b5e9c", "II-A" = "#7fa8c9", "III-A" = "#bcd3e6",
"II-B" = "#e6c6a8", "III-B" = "#c87f45", "IV" = "#8c4a1f")
ggplot(mapa) +
geom_sf(aes(fill = tipo), colour = "white", linewidth = 0.15) +
coord_sf(xlim = lim_x, ylim = lim_y, expand = FALSE) +
scale_fill_manual(values = col_tipo, name = "Tipo",
limits = c("I", "II-A", "III-A", "II-B", "III-B", "IV")) +
labs(title = "Tipología de Boisier sobre el empleo, 2013-2023",
subtitle = "Azules: efecto total positivo · Naranjos: negativo",
caption = "Datos: OCDE, Regional economy. Cartografía: BCN.") +
theme_void(base_size = 11)
Boisier, S. (1980). Técnicas de análisis regional con información limitada. Cuaderno del ILPES N.º 27, Santiago.
Lira, L. y Quiroga, B. (2009). Técnicas de análisis regional. Serie Manuales N.º 59, CEPAL–ILPES, Santiago.
Stimson, R. J., Stough, R. R. y Roberts, B. H. (2006). Regional Economic Development: Analysis and Planning Strategy. 2.ª ed., Springer, capítulo 3.
OECD. Regions, Cities and Local Areas database, conjunto Regional economy: Employment by main economic activity — Regions. data-explorer.oecd.org · oe.cd/geostats.
Banco Central de Chile. PIB regional por actividad económica, volumen a precios del año anterior encadenado, referencia 2018.