Objetivos del Taller

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:

  • Construir la matriz SECRE a partir de los datos de empleo por actividades económicas.
  • Implementar la descomposición como función de dos años y aplicarla a la serie anual completa.
  • Representar los resultados obtenidos a través de mapas con el fin de conectar la interpretación con el territorio.

Paquetes que se utilizarán

# 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)

Los datos

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)

Cómo se preparó este archivo

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.

Leer el archivo

#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

Un potencial problema que es necesario atender: los ceros

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.

La matriz SECRE

La matriz

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

Calculamos las tasas de crecimiento

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), " %."))
Crecimiento del empleo por actividad, 2013-2023. Crecimiento agregado: 12.5 %.
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

La descomposición

#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.")
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 serie completa, año a año

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

Descripción espacial de los resultados

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.

Los componentes en el mapa

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)

Mapa: Efecto estructural y efecto diferencial

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.")
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)))

La tipología

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)

Referencias

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.