En este taller trabajamos con la matriz insumo-producto de Chile para el año 2023, publicada por el Banco Central en su versión de 12 actividades. El archivo original, 2023_MIP_12x12.xlsx, contiene tres cuadros: la matriz de insumo-producto (cuadro 1), la matriz de coeficientes directos (cuadro 2) y la inversa de Leontief (cuadro 3). Los cuadros 2 y 3 nos permiten comprobar que lo que calculamos coincide con lo que publica el Banco Central.

Las partes marcadas [en clase] se desarrollan en la clase. Las marcadas [lectura] quedan para ejecutar después en el propio equipo.

La referencia para la formulación es Miller, R. y Blair, P. (2009), Input-Output Analysis: Foundations and Extensions, 2.ª ed., Cambridge University Press, capítulos 2 y 4 y apéndice 2.2.


Lectura de los datos

# Recordar, fijar directorio de trabajo en RStudio: Session > Set Working Directory > To Source File Location.
archivo_c1 <- "2023_MIP_12x12_cuadro1.csv"   # matriz de insumo-producto
archivo_c2 <- "2023_MIP_12x12_cuadro2.csv"   # coeficientes directos oficiales
archivo_c3 <- "2023_MIP_12x12_cuadro3.csv"   # inversa de Leontief oficial

# Los archivos usan coma como separador y punto decimal, al margen de la configuración regional del equipo
leer <- function(archivo) read.csv(archivo, sep = ",", dec = ".", header = TRUE,
                                   row.names = 1, check.names = FALSE, encoding = "UTF-8")

Parte 1: Estructura de la tabla [en clase]

El cuadro 1 sigue la estructura de la tabla 2.1 de Miller y Blair. Las transacciones \(z_{ij}\) registran únicamente insumos de origen nacional. Los insumos importados aparecen en una fila aparte, dentro del bloque de insumos primarios, junto con los impuestos sobre productos, los derechos de importación y el valor agregado.

Antes de leer nada hay que saber cómo está organizado el cuadro 1. En 2023_MIP_12x12_cuadro1.csv las doce primeras filas son las actividades vendedoras; sus doce primeras columnas forman \(\mathbf{Z}\), y las siguientes traen los componentes de la demanda final (consumo de hogares, IPSFL, gobierno, formación bruta de capital fijo, variación de existencias, exportaciones) y la producción a precio básico. Debajo vienen las filas de insumos primarios (importaciones cif, impuestos sobre productos, derechos de importación, valor agregado), los componentes del valor agregado (remuneraciones, excedente bruto de explotación, impuestos netos sobre la producción) y la producción por columna.

n <- 12
actividades <- c("Agro-silvícola y pesca", "Minería", "Manufactura", "EGA y desechos",
                 "Construcción", "Comercio, hoteles y rest.", "Transporte y comunic.",
                 "Interm. financiera", "Inmobiliarios y vivienda", "Serv. empresariales",
                 "Serv. personales", "Admin. pública")

cuadro1 <- leer(archivo_c1)
dim(cuadro1)                                   # 20 filas x 19 columnas
#> [1] 20 19
rownames(cuadro1)[1:12]
#>  [1] "Agro-silvicola y pesca"    "Mineria"                  
#>  [3] "Manufactura"               "EGA y desechos"           
#>  [5] "Construccion"              "Comercio, hoteles y rest."
#>  [7] "Transporte y comunic."     "Interm. financiera"       
#>  [9] "Inmobiliarios y vivienda"  "Serv. empresariales"      
#> [11] "Serv. personales"          "Admin. publica"
# Transacciones intermedias: doce primeras filas y columnas
Z <- as.matrix(cuadro1[1:12, 1:12])

# Demanda final por componente y total; producción por fila
fd <- as.matrix(cuadro1[1:12, c("consumo_hogares", "consumo_ipsfl", "consumo_gobierno",
                                 "fbcf", "variacion_existencias", "exportaciones")])
colnames(fd) <- c("hogares", "ipsfl", "gobierno", "fbcf", "existencias", "exportaciones")
f <- rowSums(fd)
x <- cuadro1[1:12, "produccion"]

# Insumos primarios y producción por columna (filas inferiores del cuadro)
primario <- function(nombre) as.numeric(cuadro1[nombre, 1:12])
importaciones  <- primario("importaciones_cif")
imp_productos  <- primario("impuestos_sobre_productos")
derechos       <- primario("derechos_importacion")
va             <- primario("valor_agregado")
remuneraciones <- primario("remuneraciones")
x_col          <- primario("produccion")
primarios <- importaciones + imp_productos + derechos + va   # insumos primarios totales

dimnames(Z) <- list(actividades, actividades)
rownames(fd) <- actividades
names(x) <- names(f) <- names(va) <- names(primarios) <- actividades

round(Z[, 1:4], 1)      # primeras cuatro columnas, para ver la escala
#>                           Agro-silvícola y pesca Minería Manufactura
#> Agro-silvícola y pesca                    4196.7     0.7     11469.4
#> Minería                                     19.3  4386.9      2966.5
#> Manufactura                               4823.1  3562.1     12543.2
#> EGA y desechos                             262.0  3712.1      2998.0
#> Construcción                                 1.1     3.5        12.2
#> Comercio, hoteles y rest.                  826.9  1876.5      4378.3
#> Transporte y comunic.                     1117.3  1987.8      4807.9
#> Interm. financiera                         337.2   301.8       905.5
#> Inmobiliarios y vivienda                    54.3    59.8       494.2
#> Serv. empresariales                        801.3  4949.5      3620.8
#> Serv. personales                            26.7    78.3       105.9
#> Admin. pública                              46.2   130.2       181.9
#>                           EGA y desechos
#> Agro-silvícola y pesca              39.4
#> Minería                             73.0
#> Manufactura                        455.6
#> EGA y desechos                    2066.8
#> Construcción                         1.9
#> Comercio, hoteles y rest.          274.9
#> Transporte y comunic.              556.1
#> Interm. financiera                 471.9
#> Inmobiliarios y vivienda            54.0
#> Serv. empresariales               1196.2
#> Serv. personales                    20.2
#> Admin. pública                      24.9

1.1 Las dos identidades contables

La identidad de filas, \(x_i = \sum_j z_{ij} + f_i\), se cumple sin más, porque la demanda final del cuadro también es doméstica.

La identidad de columnas se obtiene de la siguiente forma:

\[x_j = \sum_i z_{ij} + \underbrace{m_j + t_j + d_j + v_j}_{\text{insumos primarios totales, } p_j}\]

x_filas    <- rowSums(Z) + f
x_columnas <- colSums(Z) + primarios

Parte 2: Matriz de coeficientes técnicos (validación con cuadro oficial) [lectura]

\[a_{ij} = \frac{z_{ij}}{x_j}\]

Se divide por el total de la columna, es decir, por la producción del sector que compra. Como el cuadro 2 trae la matriz oficial, la calculamos y la comparamos con ella.

A <- sweep(Z, 2, x, "/")
A_oficial <- as.matrix(leer(archivo_c2)[1:12, ])
c(diferencia_maxima_vs_oficial = max(abs(A - A_oficial)))
#> diferencia_maxima_vs_oficial 
#>                  1.37945e-14
stopifnot(max(abs(A - A_oficial)) < 1e-10)

sumas_A <- colSums(A)
data.frame(actividad = actividades, suma_columna_A = round(sumas_A, 3),
           primarios_por_unidad = round(primarios / x, 3),
           va_por_unidad = round(va / x, 3), row.names = NULL)
stopifnot(all.equal(unname(sumas_A + primarios / x), rep(1, n)))

Las sumas de columna van de 0,17 en servicios inmobiliarios y de vivienda a 0,52 en agro-silvícola y pesca. La minería compra 0,39 de insumos domésticos por cada peso que produce, menos que la manufactura (0,49), la construcción (0,49) o el comercio (0,45). La columna primarios_por_unidad es el complemento exacto a uno; No es el va_por_unidad, ya que faltan las importaciones, impuestos sobre productos y derechos de importación por unidad producida.


Parte 3: La inversa de Leontief (validación con cuadro oficial) [lectura]

\[\mathbf{L} = (\mathbf{I}-\mathbf{A})^{-1}, \qquad \mathbf{x} = \mathbf{L}\,\mathbf{f}\]

I_n <- diag(n)
IA  <- I_n - A
det(IA)
#> [1] 0.20294
L <- solve(IA)
dimnames(L) <- dimnames(A)

L_oficial <- as.matrix(leer(archivo_c3)[1:12, ])
c(diferencia_maxima_vs_oficial = max(abs(L - L_oficial)))
#> diferencia_maxima_vs_oficial 
#>                  2.67009e-14
stopifnot(max(abs(L - L_oficial)) < 1e-10)
stopifnot(all.equal(as.vector(L %*% f), unname(x))) # L reproduce la producción observada
stopifnot(all.equal(IA %*% L, I_n, check.attributes = FALSE))
round(L[1:6, 1:6], 4)
#>                           Agro-silvícola y pesca Minería Manufactura
#> Agro-silvícola y pesca                    1.2601  0.0169      0.1874
#> Minería                                   0.0126  1.0941      0.0441
#> Manufactura                               0.3124  0.1060      1.2260
#> EGA y desechos                            0.0323  0.0945      0.0559
#> Construcción                              0.0018  0.0014      0.0023
#> Comercio, hoteles y rest.                 0.0741  0.0591      0.0833
#>                           EGA y desechos Construcción Comercio, hoteles y rest.
#> Agro-silvícola y pesca            0.0110       0.0401                    0.0264
#> Minería                           0.0074       0.0161                    0.0056
#> Manufactura                       0.0491       0.2539                    0.1205
#> EGA y desechos                    1.1441       0.0255                    0.0298
#> Construcción                      0.0015       1.1814                    0.0079
#> Comercio, hoteles y rest.         0.0314       0.0968                    1.1040

Parte 4: Evaluación de impacto de cambios en la demanda final [en clase]

Con la inversa calculada podemos evaluar cualquier cambio en la demanda final sobre el valor bruto de la producción, \(\mathbf{x} = \mathbf{L}\mathbf{f}\), y sobre las transacciones intermedias que ese nuevo nivel de producción exige, \(\mathbf{Z} = \mathbf{A}\,\hat{\mathbf{x}}\). Empezamos con un cambio en unidades monetarias, después escribimos una función que hace el trabajo para cualquier vector de cambios porcentuales, y la usamos en dos ejemplos y en un ejercicio de sensibilidad.

4.1 Un cambio en unidades monetarias

Supongamos que una inversión minera eleva las exportaciones de minería en 1.000 miles de millones de pesos, alrededor del 2,2 % de las exportaciones mineras que registra el cuadro para 2023 (44.702). ¿Cuánta producción adicional hace falta, y en qué sectores?

df <- rep(0, n); names(df) <- actividades
df["Minería"] <- 1000
dx <- as.vector(L %*% df); names(dx) <- actividades

impacto <- data.frame(actividad = actividades,
                      delta_x = round(dx, 1),
                      participacion = paste0(round(100 * dx / sum(dx), 1), " %"),
                      row.names = NULL)
impacto[order(-impacto$delta_x), ]
c(efecto_directo = 1000, efecto_total = round(sum(dx), 1), multiplicador = round(sum(dx) / 1000, 4))
#> efecto_directo   efecto_total  multiplicador 
#>       1000.000       1632.000          1.632

Los 1.000 de demanda final generan 1.632 de producción: 1.094 en la propia minería (el choque más lo que la minería se compra a sí misma) y 538 repartidos entre los demás sectores, encabezados por servicios empresariales (144), manufactura (106) y EGA (94). Dos tercios del efecto quedan dentro del sector. Lo que el modelo no dice es en qué región ocurre nada de esto: la tabla es nacional, y el modelo no sabe que la mina está en Antofagasta ni dónde están sus proveedores.

4.2 La función de evaluación de impacto

Para no repetir el mismo cálculo cada vez, escribimos una función que recibe la matriz de coeficientes, la demanda final original y un vector de cambios porcentuales, y devuelve la producción y las transacciones intermedias antes y después del cambio, junto con las variaciones absolutas y porcentuales.

# Evaluación de impacto de Cambios en la Demanda Final (CDF)
#   A: matriz de coeficientes técnicos (n x n)
#   f_original: demanda final original (vector de largo n)
#   cambio_pct: vector de cambios porcentuales en f, en proporción (0,10 = +10 %; -0,10 = -10 %)
# Devuelve una lista con f y x antes y después, las variaciones, y Z antes y después.
impacto_cdf <- function(A, f_original, cambio_pct) {
  n <- nrow(A)
  stopifnot(length(f_original) == n, length(cambio_pct) == n)
  L <- solve(diag(n) - A)
  f_nuevo <- f_original * (1 + cambio_pct) # 1. nueva demanda final
  x_o <- as.vector(L %*% f_original)       # 2. producción antes 
  x_n <- as.vector(L %*% f_nuevo)          # 3. producción después
  Z_o <- A %*% diag(x_o)  # 4. transacciones intermedias antes: Z = A diag(x)
  Z_n <- A %*% diag(x_n)  # 4. transacciones intermedias después: Z = A diag(x)
  nombres <- rownames(A)
  names(x_o) <- names(x_n) <- names(f_nuevo) <- nombres
  dimnames(Z_o) <- dimnames(Z_n) <- list(nombres, nombres)
  list(f_original = f_original, f_nuevo = f_nuevo,
       x_original = x_o, x_nuevo = x_n,
       delta_x = x_n - x_o, delta_x_pct = 100 * (x_n / x_o - 1),
       Z_original = Z_o, Z_nuevo = Z_n)
}

# Comprobación: con cambio cero, la función reproduce exactamente la tabla
sin_cambio <- impacto_cdf(A, f, rep(0, n))
stopifnot(all.equal(unname(sin_cambio$x_nuevo), unname(x)),
          all.equal(unname(sin_cambio$Z_nuevo), unname(Z)))

4.3 Ejemplo 1: la demanda final de minería crece 10 %

cambio_1 <- rep(0, n); cambio_1[2] <- 0.10
ej1 <- impacto_cdf(A, f, cambio_1)

data.frame(actividad = actividades,
           x_antes = round(ej1$x_original, 0), x_despues = round(ej1$x_nuevo, 0),
           delta = round(ej1$delta_x, 0), delta_pct = round(ej1$delta_x_pct, 2), row.names = NULL)
c(delta_f_mineria = round(ej1$f_nuevo[2] - f[2], 0),
  delta_x_total = round(sum(ej1$delta_x), 0),
  multiplicador_implicito = round(sum(ej1$delta_x) / (ej1$f_nuevo[2] - f[2]), 4))
#>         delta_f_mineria.Minería                   delta_x_total 
#>                        4551.000                        7427.000 
#> multiplicador_implicito.Minería 
#>                           1.632

Un alza de 10 % en la demanda final de minería, 4.551 miles de millones, eleva la producción nacional en 7.427: 9,3 % en la propia minería, 2,5 % en EGA, 1,6 % en servicios empresariales y menos de 1 % en los demás. La minería no sube 10 % porque parte de su producción atiende demanda intermedia, que no cambió. El multiplicador implícito vuelve a ser 1,632, el mismo de la parte 3. No podía ser de otro modo: el modelo es lineal y el multiplicador no depende del tamaño del choque.

4.4 Ejemplo 2: una contramedida que no compensa

Segunda pregunta. Supongamos que, como contramedida al alza anterior, el gobierno reduce en 10 % la demanda final de administración pública, con la expectativa de que el efecto neto sobre la producción sea pequeño. ¿Está en lo correcto?

cambio_2 <- cambio_1; cambio_2[12] <- -0.10
ej2 <- impacto_cdf(A, f, cambio_2)
c(delta_f_admin_publica = round(ej2$f_nuevo[12] - f[12], 0),
  delta_x_total_ejemplo_1 = round(sum(ej1$delta_x), 0),
  delta_x_total_ejemplo_2 = round(sum(ej2$delta_x), 0))
#> delta_f_admin_publica.Admin. pública              delta_x_total_ejemplo_1 
#>                                -1750                                 7427 
#>              delta_x_total_ejemplo_2 
#>                                 5096
# El efecto de los dos impactos es la suma de los efectos separados (linealidad)
solo_admin <- impacto_cdf(A, f, replace(rep(0, n), 12, -0.10))
stopifnot(all.equal(ej2$delta_x, ej1$delta_x + solo_admin$delta_x))
round(cbind(solo_mineria = ej1$delta_x, solo_admin_publica = solo_admin$delta_x, ambos = ej2$delta_x)[c(2, 12, 10, 3, 6), ], 0)
#>                           solo_mineria solo_admin_publica ambos
#> Minería                           4979                 -4  4975
#> Admin. pública                      17              -1758 -1742
#> Serv. empresariales                656               -152   505
#> Manufactura                        482                -73   410
#> Comercio, hoteles y rest.          269                -52   217

No lo está. La reducción de 10 % en administración pública retira 1.750 de demanda final y 2.331 de producción (multiplicador 1,33), menos de un tercio del alza minera, y el efecto neto sigue siendo positivo: 5.096. Hay algo más que vale la pena notar en la comprobación: el efecto conjunto es exactamente la suma de los efectos por separado. En un modelo de Leontief los choques no interactúan. Es una propiedad del modelo y, al mismo tiempo, una de sus limitaciones.

4.5 Sensibilidad: un cambio de ±10 % en cada sector, uno a la vez [lectura]

Ahora recorremos los sectores de uno en uno: aplicamos un cambio de +10 % y otro de −10 % en la demanda final de cada uno, y guardamos la variación porcentual de la producción de todos los sectores. El resultado es una matriz con el sector afectado en las filas y el sector donde ocurre el impacto en las columnas.

Res_alza <- Res_baja <- matrix(NA_real_, n, n, dimnames = list(afectado = actividades, cambio_en = actividades))

for (j in 1:n) {
  cambio <- rep(0, n)
  cambio[j] <-  0.10; Res_alza[, j] <- impacto_cdf(A, f, cambio)$delta_x_pct
  cambio[j] <- -0.10; Res_baja[, j] <- impacto_cdf(A, f, cambio)$delta_x_pct
}
# Simetría: en un modelo lineal la baja es exactamente la alza con signo contrario
stopifnot(all.equal(Res_alza, -Res_baja))
round(Res_alza, 2)
#>                            cambio_en
#> afectado                    Agro-silvícola y pesca Minería Manufactura
#>   Agro-silvícola y pesca                      4.07    0.32        4.06
#>   Minería                                     0.02    9.34        0.43
#>   Manufactura                                 0.26    0.53        6.98
#>   EGA y desechos                              0.15    2.53        1.71
#>   Construcción                                0.00    0.02        0.03
#>   Comercio, hoteles y rest.                   0.09    0.41        0.67
#>   Transporte y comunic.                       0.17    0.71        1.16
#>   Interm. financiera                          0.13    0.45        0.72
#>   Inmobiliarios y vivienda                    0.03    0.15        0.28
#>   Serv. empresariales                         0.17    1.64        1.21
#>   Serv. personales                            0.00    0.03        0.03
#>   Admin. pública                              0.02    0.09        0.11
#>                            cambio_en
#> afectado                    EGA y desechos Construcción
#>   Agro-silvícola y pesca              0.02         0.50
#>   Minería                             0.01         0.09
#>   Manufactura                         0.02         0.84
#>   EGA y desechos                      2.83         0.45
#>   Construcción                        0.00         9.13
#>   Comercio, hoteles y rest.           0.02         0.45
#>   Transporte y comunic.               0.05         0.51
#>   Interm. financiera                  0.09         0.53
#>   Inmobiliarios y vivienda            0.01         0.15
#>   Serv. empresariales                 0.12         0.78
#>   Serv. personales                    0.00         0.03
#>   Admin. pública                      0.01         0.04
#>                            cambio_en
#> afectado                    Comercio, hoteles y rest. Transporte y comunic.
#>   Agro-silvícola y pesca                         0.49                  0.13
#>   Minería                                        0.05                  0.02
#>   Manufactura                                    0.58                  0.22
#>   EGA y desechos                                 0.78                  0.27
#>   Construcción                                   0.09                  0.02
#>   Comercio, hoteles y rest.                      7.52                  0.25
#>   Transporte y comunic.                          1.51                  4.96
#>   Interm. financiera                             1.11                  0.30
#>   Inmobiliarios y vivienda                       0.86                  0.18
#>   Serv. empresariales                            1.60                  0.50
#>   Serv. personales                               0.04                  0.03
#>   Admin. pública                                 0.09                  0.06
#>                            cambio_en
#> afectado                    Interm. financiera Inmobiliarios y vivienda
#>   Agro-silvícola y pesca                  0.02                     0.04
#>   Minería                                 0.01                     0.01
#>   Manufactura                             0.03                     0.07
#>   EGA y desechos                          0.09                     0.16
#>   Construcción                            0.01                     0.63
#>   Comercio, hoteles y rest.               0.05                     0.05
#>   Transporte y comunic.                   0.16                     0.07
#>   Interm. financiera                      5.57                     0.35
#>   Inmobiliarios y vivienda                0.12                     7.63
#>   Serv. empresariales                     0.46                     0.19
#>   Serv. personales                        0.01                     0.00
#>   Admin. pública                          0.01                     0.01
#>                            cambio_en
#> afectado                    Serv. empresariales Serv. personales Admin. pública
#>   Agro-silvícola y pesca                   0.02             0.25           0.08
#>   Minería                                  0.00             0.03           0.01
#>   Manufactura                              0.03             0.36           0.08
#>   EGA y desechos                           0.06             0.50           0.47
#>   Construcción                             0.01             0.04           0.01
#>   Comercio, hoteles y rest.                0.05             0.36           0.08
#>   Transporte y comunic.                    0.10             0.39           0.20
#>   Interm. financiera                       0.15             0.38           0.22
#>   Inmobiliarios y vivienda                 0.07             0.42           0.10
#>   Serv. empresariales                      2.15             0.80           0.38
#>   Serv. personales                         0.01             9.79           0.02
#>   Admin. pública                           0.01             0.04           9.54
# Efecto total sobre la producción nacional de cada choque de +10 %
efecto_total_pct <- sapply(1:n, function(j) {
  cambio <- rep(0, n); cambio[j] <- 0.10
  100 * sum(impacto_cdf(A, f, cambio)$delta_x) / sum(x)
})
efecto_total_pct
#>  [1] 0.302426 1.489710 1.934904 0.124784 1.127238 1.531488 0.649827 0.343995
#>  [9] 0.533516 0.210532 1.284029 0.467552

La diagonal dice cuánto crece cada sector cuando su propia demanda final sube 10 %. Nunca llega a 10 %, porque vale \(0{,}10 \cdot (f_j/x_j)\cdot l_{jj}\): responden casi uno a uno los sectores que venden sobre todo a demanda final (minería 9,3 %, construcción 9,1 %, comercio 7,5 %) y responden poco los que venden sobre todo como insumo (EGA 2,8 %, agro-silvícola 4,1 %). Fuera de la diagonal, la columna de la minería mueve 2,5 % a EGA y menos de 2 % a cualquier otro sector. Medido sobre la producción nacional, el cambio de 10 % que más pesa es el de la manufactura (1,94 % del total), seguido del comercio (1,53 %) y la minería (1,49 %). Lo que importa aquí es el tamaño de la demanda final del sector multiplicado por su multiplicador, no el multiplicador por sí solo.


Parte 5: Visualización de los resultados [en clase]

Cuatro maneras de mirar los resultados anteriores: los multiplicadores en barras, la variación de la producción antes y después de un choque, la matriz de sensibilidad como mapa de calor, y la matriz de transacciones como superficie interactiva.

5.1 Multiplicadores de producto por actividad

par(mar = c(9, 4.5, 3, 1))
mult_producto <- colSums(L)
orden <- order(mult_producto, decreasing = TRUE)
bp <- barplot(mult_producto[orden], names.arg = actividades[orden], las = 2, cex.names = 0.8,
              col = ifelse(actividades[orden] == "Minería", "#A85C32", "#6E7F66"), border = NA,
              ylim = c(0, 2.2), ylab = "Suma de columna de L",
              main = "Multiplicador de producto por actividad, Chile 2023 (12 actividades)")
text(bp, mult_producto[orden] + 0.06, sprintf("%.2f", mult_producto[orden]), cex = 0.8)
abline(h = 1, lty = 3)

5.2 Producción antes y después del cambio

Con doce sectores de tamaños tan distintos, la producción antes y después del cambio es indistinguible en niveles. Se grafica la variación porcentual.

par(mar = c(9, 4.5, 3, 1))
bp <- barplot(ej1$delta_x_pct[orden], names.arg = actividades[orden], las = 2, cex.names = 0.8,
              col = "#41505E", border = NA, ylab = "Variación de la producción (%)",
              main = "Ejemplo 1: demanda final de minería +10 %")
text(bp, ej1$delta_x_pct[orden] + 0.3, sprintf("%.2f", ej1$delta_x_pct[orden]), cex = 0.75)

5.3 La matriz de sensibilidad como mapa de calor

library(lattice)
M <- Res_alza; diag(M) <- NA          # la diagonal domina la escala; se grafica aparte
levelplot(t(M), col.regions = colorRampPalette(c("#F7F3EC", "#C9A27E", "#A85C32"))(40),
          xlab = "Sector en el que ocurre el cambio (+10 % en su demanda final)",
          ylab = "Sector afectado", scales = list(x = list(rot = 60, cex = 0.8), y = list(cex = 0.8)),
          main = "Variación porcentual de la producción, fuera de la diagonal",
          panel = function(...) { panel.levelplot(...); panel.abline(h = 0:n + 0.5, v = 0:n + 0.5, col = "white", lwd = 0.5) })

El mapa de calor muestra de un vistazo que las columnas de manufactura y comercio son las que más mueven al resto, y que las filas de EGA y de servicios empresariales son las que más responden a cambios ajenos, porque venden insumos a casi todos.

5.4 La matriz de transacciones como superficie interactiva

En la salida HTML esta superficie es interactiva. En la escala original la minería y la manufactura aplastan al resto, así que se grafica el logaritmo de las transacciones, más uno para las celdas nulas.

library(plotly)
plot_ly(z = ~log10(1 + Z), x = actividades, y = actividades, colors = "YlOrRd") %>%
  add_surface(contours = list(z = list(show = TRUE, usecolormap = TRUE, project = list(z = TRUE)))) %>%
  layout(title = "log10(1 + z_ij): transacciones intermedias domésticas, Chile 2023",
         scene = list(xaxis = list(title = "Compra (j)"), yaxis = list(title = "Vende (i)"),
                      zaxis = list(title = "log10(1 + z)"),
                      camera = list(eye = list(x = 1.8, y = 0.9, z = 0.8))))

Parte 6: La serie de potencias sobre la tabla real [lectura]

\[\Delta\mathbf{x} = \Delta\mathbf{f} + \mathbf{A}\Delta\mathbf{f} + \mathbf{A}^2\Delta\mathbf{f} + \cdots\]

n_rondas <- 7
rondas <- matrix(NA_real_, n, n_rondas + 1, dimnames = list(actividades, paste0("r", 0:n_rondas)))
rondas[, 1] <- df
for (k in 1:n_rondas) rondas[, k + 1] <- A %*% rondas[, k]
suma_ronda <- colSums(rondas); acumulado <- cumsum(suma_ronda); pct <- acumulado / sum(dx)

data.frame(ronda = 0:n_rondas, suma = round(suma_ronda, 2), acumulado = round(acumulado, 2),
           pct_del_total = round(100 * pct, 2), row.names = NULL)
stopifnot(1 - pct[n_rondas + 1] < 0.01)

Tres rondas capturan el 97,8 % del efecto total y siete dejan fuera seis centésimas de punto porcentual. La velocidad depende de las sumas de columna de \(\mathbf{A}\), que aquí van de 0,17 a 0,52: la serie converge más rápido cuanto menos compra cada sector por unidad producida, y en la tabla chilena ningún sector gasta más de la mitad de su producción en insumos domésticos.


Parte 7: Hawkins-Simon sobre la tabla real [lectura]

c(condicion_suficiente = all(sumas_A < 1), maxima_suma_columna = round(max(sumas_A), 4))
#> condicion_suficiente  maxima_suma_columna 
#>               1.0000               0.5213
menores <- sapply(1:n, function(k) det(IA[1:k, 1:k, drop = FALSE]))
round(menores, 4)
#>  [1] 0.8252 0.7573 0.6283 0.5508 0.4669 0.4297 0.3516 0.2523 0.2485 0.2134
#> [11] 0.2039 0.2029
stopifnot(all(menores > 0), all(L >= 0))

Los doce menores principales dominantes son positivos y van bajando desde 0,83 hasta el determinante completo, 0,20. La inversa es no negativa, como corresponde a una economía viable. De hecho, todos los elementos de \(\mathbf{L}\) son estrictamente positivos: a 12 actividades no hay un par de sectores sin conexión, directa o indirecta.


Parte 8: El modelo cerrado respecto de los hogares, con los datos del cuadro [en clase, versión breve]

La tabla trae los dos vectores que necesitamos para cerrar el modelo: la fila de remuneraciones de asalariados, que es la venta de trabajo de los hogares a cada sector, y la columna de consumo de hogares, que son sus compras a cada sector. Con la notación de Miller y Blair (sección 2.5):

\[h_R = \left[\frac{z_{n+1,j}}{x_j}\right],\qquad h_C = \left[\frac{z_{i,n+1}}{x_{n+1}}\right],\qquad \bar{\mathbf{A}} = \begin{pmatrix}\mathbf{A} & h_C\\ h_R & h\end{pmatrix}\]

consumo <- fd[, "hogares"]
x_h <- sum(remuneraciones)      # ingreso de los hogares medido por remuneraciones
h_R <- remuneraciones / x
h_C <- consumo / x_h
h   <- 0
c(consumo_hogares_total = round(sum(consumo), 1), remuneraciones_total = round(x_h, 1),
  suma_h_C = round(sum(h_C), 4))
#> consumo_hogares_total  remuneraciones_total              suma_h_C 
#>           128493.3000           114601.6000                1.1212

Aquí aparece un problema de medición. El consumo de los hogares (128.493) supera a las remuneraciones (114.602), porque los hogares también reciben ingreso mixto, rentas de la propiedad y transferencias que el cuadro no separa. Si medimos \(x_{n+1}\) solo con remuneraciones, la columna \(h_C\) suma 1,12: cada peso de salario «genera» 1,12 pesos de consumo doméstico. La condición suficiente de Hawkins-Simon falla en esa columna, así que hay que mirar la condición necesaria.

A_bar <- rbind(cbind(A, h_C), c(h_R, h))
dimnames(A_bar) <- list(c(actividades, "Hogares"), c(actividades, "Hogares"))
round(colSums(A_bar), 3)
#>    Agro-silvícola y pesca                   Minería               Manufactura 
#>                     0.642                     0.478                     0.591 
#>            EGA y desechos              Construcción Comercio, hoteles y rest. 
#>                     0.404                     0.713                     0.738 
#>     Transporte y comunic.        Interm. financiera  Inmobiliarios y vivienda 
#>                     0.594                     0.774                     0.202 
#>       Serv. empresariales          Serv. personales            Admin. pública 
#>                     0.585                     0.779                     0.782 
#>                   Hogares 
#>                     1.121
IA_bar <- diag(n + 1) - A_bar
menores_bar <- sapply(1:(n + 1), function(k) det(IA_bar[1:k, 1:k, drop = FALSE]))
c(todos_positivos = all(menores_bar > 0), det_completo = round(det(IA_bar), 4),
  radio_espectral = round(max(Mod(eigen(A_bar)$values)), 4))
#> todos_positivos    det_completo radio_espectral 
#>          1.0000          0.1196          0.7279
L_bar <- solve(IA_bar)
stopifnot(all(menores_bar > 0), all(L_bar > 0))

# Control: L_bar f_bar reproduce (x; x_h) con la demanda final restante f* = f - consumo
f_est <- f - consumo
x_bar <- as.vector(L_bar %*% c(f_est, 0))
stopifnot(all.equal(x_bar, c(unname(x), x_h)))

# El mismo cambio minero en los dos modelos
dx_cerrado <- as.vector(L_bar %*% c(df, 0)); names(dx_cerrado) <- c(actividades, "Ingreso hogares")
comparacion <- data.frame(actividad = c(actividades, "Ingreso hogares", "Suma sectores"),
                          abierto = c(round(dx, 1), NA, round(sum(dx), 1)),
                          cerrado = c(round(dx_cerrado, 1), round(sum(dx_cerrado[1:n]), 1)), row.names = NULL)
comparacion
c(multiplicador_abierto = round(sum(dx) / 1000, 4), multiplicador_cerrado = round(sum(dx_cerrado[1:n]) / 1000, 4))
#> multiplicador_abierto multiplicador_cerrado 
#>                1.6320                2.2533

La condición necesaria se cumple: los trece menores son positivos y el radio espectral de \(\bar{\mathbf{A}}\) es 0,73. El modelo cerrado existe y su inversa es positiva aunque una columna sume más que uno. El mismo cambio de 1.000 en minería pasa de 1.632 a 2.253 de producción, más 343 de ingreso adicional para los hogares. Quien más gana con el cierre es comercio, hoteles y restaurantes (de 59 a 186), que vende poco a la minería y mucho a los hogares. Le siguen la manufactura (de 106 a 219) y los servicios inmobiliarios y de vivienda (de 9 a 81), que en el modelo abierto apenas aparecían.

El supuesto que estamos imponiendo tiene dos partes. Se congela la canasta de consumo, como en cualquier cierre, y además se atribuye a los salarios todo el consumo, que en realidad también se financia con otros ingresos. Con \(h_C\) sumando 1,12, el modelo cerrado con remuneraciones sobreestima el efecto inducido. Una alternativa razonable es escalar \(h_C\) para que sume uno, lo que equivale a suponer que todo el salario se gasta con la canasta observada (o a una propensión menor, si se quiere descontar ahorro e impuestos). Con ese ajuste el multiplicador cerrado baja de 2,25 a 2,15. Cómo se mide \(x_{n+1}\) es una decisión del analista y hay que dejarla por escrito.

# Ejercicio resuelto: h_C escalada para que sume uno (todo el salario se consume con la canasta observada)
h_C_alt <- h_C * (x_h / sum(consumo))
A_bar_alt <- rbind(cbind(A, h_C_alt), c(h_R, h))
L_bar_alt <- solve(diag(n + 1) - A_bar_alt)
dx_alt <- as.vector(L_bar_alt %*% c(df, 0))
c(suma_h_C_alt = round(sum(h_C_alt), 4), multiplicador_cerrado_alt = round(sum(dx_alt[1:n]) / 1000, 4))
#>              suma_h_C_alt multiplicador_cerrado_alt 
#>                    1.0000                    2.1474

8.1 Comparación visual de los multiplicadores abierto y cerrado

Para ver cuánto pesa el consumo de los hogares en el resultado, comparamos los multiplicadores de producto del sistema abierto con los del cerrado, en sus dos versiones.

# Suma de columna de L_bar sobre las filas de los 12 sectores (producción), sin la fila de hogares (ingreso)
MP <- rbind(Abierto = mult_producto,
            Cerrado_MB = colSums(L_bar[1:n, 1:n]),
            Cerrado_escalado = colSums(L_bar_alt[1:n, 1:n]))
colnames(MP) <- actividades
par(mar = c(9, 4.5, 3, 1))
barplot(MP[, orden], beside = TRUE, las = 2, cex.names = 0.8, border = NA,
        col = c("#6E7F66", "#A85C32", "#C9A27E"), ylim = c(0, max(MP) * 1.15),
        ylab = "Multiplicador de producto", legend.text = TRUE,
        args.legend = list(x = "topright", bty = "n", cex = 0.85),
        main = "Multiplicadores de producto: sistema abierto frente a sistema cerrado")

round(MP[, orden], 3)
#>                  Agro-silvícola y pesca Construcción Manufactura
#> Abierto                           1.947        1.863       1.856
#> Cerrado_MB                        2.792        3.077       2.621
#> Cerrado_escalado                  2.648        2.870       2.490
#>                  Interm. financiera Comercio, hoteles y rest.
#> Abierto                       1.818                     1.727
#> Cerrado_MB                    3.364                     3.090
#> Cerrado_escalado              3.100                     2.857
#>                  Transporte y comunic. Minería EGA y desechos
#> Abierto                          1.640   1.632          1.482
#> Cerrado_MB                       2.686   2.253          2.067
#> Cerrado_escalado                 2.507   2.147          1.967
#>                  Serv. empresariales Serv. personales Admin. pública
#> Abierto                        1.418            1.357          1.332
#> Cerrado_MB                     2.702            3.322          3.309
#> Cerrado_escalado               2.483            2.987          2.972
#>                  Inmobiliarios y vivienda
#> Abierto                             1.301
#> Cerrado_MB                          1.590
#> Cerrado_escalado                    1.541

El cierre eleva todos los multiplicadores, pero no por igual. Los sectores con mayor contenido salarial por peso producido (administración pública, servicios personales, servicios empresariales) son los que más crecen, porque son los que más ingreso inyectan a los hogares por unidad de cambio. La minería pasa de 1,63 a 2,25. El orden de los sectores cambia, y un estudio de impacto tiene que decidir cuál de los dos órdenes reporta y por qué.

8.2 Sensibilidad en el sistema cerrado [lectura]

Repetimos el recorrido de la parte 4.5 sobre \(\bar{\mathbf{A}}\) y comparamos, sector por sector, el efecto total sobre la producción de un choque de +10 % en la demanda final en los dos sistemas.

A_bar_sin_nombres <- A_bar; rownames(A_bar_sin_nombres) <- colnames(A_bar_sin_nombres) <- c(actividades, "Hogares")
f_bar_o <- c(f_est, 0)
efecto_abierto <- efecto_cerrado <- numeric(n)
for (j in 1:n) {
  cambio <- rep(0, n); cambio[j] <- 0.10
  efecto_abierto[j] <- sum(impacto_cdf(A, f, cambio)$delta_x)
  cambio_bar <- rep(0, n + 1); cambio_bar[j] <- 0.10 * f[j] / f_est[j]   # el mismo monto, sobre f*
  efecto_cerrado[j] <- sum(impacto_cdf(A_bar_sin_nombres, f_bar_o, cambio_bar)$delta_x[1:n])
}
comparacion_sens <- data.frame(choque_en = actividades,
                               delta_x_abierto = round(efecto_abierto, 0),
                               delta_x_cerrado = round(efecto_cerrado, 0),
                               razon = round(efecto_cerrado / efecto_abierto, 3), row.names = NULL)
comparacion_sens[order(-comparacion_sens$razon), ]
stopifnot(all(efecto_cerrado > efecto_abierto))

Parte 9: El modelo de precios, con insumos primarios totales [lectura]

\[\tilde{\mathbf{p}} = (\mathbf{I}-\mathbf{A}')^{-1}\mathbf{v}_c = \mathbf{L}'\,\mathbf{v}_c\]

Con una matriz doméstica, el vector que reproduce precios unitarios en el año base es el de insumos primarios totales por unidad, \(p_j/x_j\), porque es el que cierra la identidad de columnas (parte 1). Con el valor agregado solo, los precios base quedan por debajo de uno.

v_c_primarios <- primarios / x
v_c_solo_va   <- va / x
p_base_primarios <- as.vector(t(L) %*% v_c_primarios)
p_base_solo_va   <- as.vector(t(L) %*% v_c_solo_va)
data.frame(actividad = actividades, p_base_con_primarios = round(p_base_primarios, 6),
           p_base_solo_va = round(p_base_solo_va, 4), row.names = NULL)
stopifnot(all.equal(p_base_primarios, rep(1, n)))

# Escenario: +10 % en el costo de los insumos primarios de EGA (energía, gas, agua)
v_c1 <- v_c_primarios; v_c1[4] <- v_c1[4] * 1.10
p_1 <- as.vector(t(L) %*% v_c1)
data.frame(actividad = actividades, precio_indice = round(p_1, 4),
           variacion = paste0(round(100 * (p_1 - 1), 2), " %"), row.names = NULL)[order(-p_1), ]

Con insumos primarios totales los doce precios base valen exactamente uno; con valor agregado solo quedan entre 0,68 y 0,87, y lo que falta es el contenido importado y los impuestos que el valor agregado no cubre. En el escenario, un alza de 10 % en los costos primarios de EGA sube su propio precio 7,9 %: 6,9 puntos vienen del alza directa sobre el 69 % del costo que son insumos primarios, y el resto de que EGA se compra a sí misma 0,12 por peso producido. El alza se transmite sobre todo a la minería (0,65 %) y a la manufactura (0,39 %); el resto de la economía se mueve menos de un tercio de punto. La minería es el sector más expuesto a un choque de costos energéticos porque es el que más EGA compra por peso producido (0,070).