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.
# 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")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
#> [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
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}\]
\[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)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.
\[\mathbf{L} = (\mathbf{I}-\mathbf{A})^{-1}, \qquad \mathbf{x} = \mathbf{L}\,\mathbf{f}\]
#> [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
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.
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.
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)))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.
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.
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.
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.
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)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)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.
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))))\[\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)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.
#> condicion_suficiente maxima_suma_columna
#> 1.0000 0.5213
#> [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
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.
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)
comparacionc(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
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")#> 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é.
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), ]\[\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).