Introduction to iotables
Daniel Antal, based on the work of Jorg Beutel
2024-09-19
Source:vignettes/intro.Rmd
intro.Rmd
This introduction shows the reproducible workflow of iotables with the examples of the Eurostat Manual of Supply, Use and Input-Output Tables. by Joerg Beutel (Eurostat Manual).
This vignette uses library(tidyverse)
, more particularly
dplyr
and tidyr
, just like all analytical
functions of iotables
. Even if you do not use
tidyverse
, this packages will be installed together with
iotables
. These functions are only used in the vignette to
print the output, and they are not essential for the examples.
Germany sample files
The germany_1995
dataset is a simplified 6x6 sized SIOT
taken from the Eurostat
Manual of Supply, Use and Input-Output Tables (page 481). It is
brought to a long form similar to the Eurostat bulk files. The testthat
infrastructure of the iotables package is checking data processing
functions and analytical calculations against these published
results.
The following data processing functions select and order the data
from the Eurostat-type bulk file. Since the first version of this
package, Eurostat moved all SIOT data products to the ESA2010
vocabulary, but the manual still follows the ESA95 vocabulary. The
labels of the dataset were slightly changed to match the current
metadata names. The changes are minor and self-evident, the comparison
of the germany_1995
dataset and the Manual should cause no
misunderstandings.
germany_io <- iotable_get( labelling = "iotables" )
input_flow <- input_flow_get (
data_table = germany_io,
households = FALSE)
de_output <- primary_input_get ( germany_io, "output" )
print (de_output[c(1:4)])
#> iotables_row agriculture_group industry_group construction
#> 15 output 43910 1079446 245606
The input_flow()
function selects the first quadrant,
often called as input flow matrix, or inter-industry matrix, from the
German input-output table. The primary_input_get()
selects
on of the primary inputs, in this case, the output from the table.
Direct effects
The input coefficient matrix shows what happens in the whole domestic economy when an industry is facing additional demand, and it increases production. In the Germany example, all results are rounded to 4 digits for easier comparison with the Eurostat manual.
The input coefficients for domestic intermediates are defined in the Eurostat Manual of Supply, Use and Input-Output Tables on page 486. You can check the following results against Table 15.8 of the Eurostat manual. (Only the top-right corner of the resulting input coefficient matrix is printed for readability.)
The input_coefficient_matrix_create()
function relies on
the following equation. The numbering of the equations is the numbering
of the Eurostat Manual.
- = [recap: (43) is the same, and the same equation is (2) on page 484 with comparative results]
It checks the correct ordering of columns, and furthermore it fills up 0 values with 0.000001 to avoid division with zero.
de_input_coeff <- input_coefficient_matrix_create(
data_table = germany_io,
digits = 4)
## which is equivalent to:
de_input_coeff <- coefficient_matrix_create(
data_table = germany_io,
total = "output",
return_part = "products",
households = FALSE,
digits = 4)
print (de_input_coeff[1:3, 1:3])
#> iotables_row agriculture_group industry_group
#> 1 agriculture_group 0.0258 0.0236
#> 2 industry_group 0.1806 0.2822
#> 3 construction 0.0097 0.0068
These results are identical after similar rounding to the Table 15.6 of the Manual (on page 485.)
Similarly, the output coefficient matrix is defined in the following way:
- =
= output coefficient for domestic goods and services (i = 1, …, 6; j = 1, …, 6) \eqn{x_{ij}= flow of commodity i to sector j \eqn{x_{i} = output of sector i
#> iotables_row agriculture_group industry_group
#> 1 agriculture_group 0.0258 0.5803
#> 2 industry_group 0.0073 0.2822
#> 3 construction 0.0017 0.0299
These results are identical after similar rounding to the Table 15.7 of the Eurostat Manual of Supply, Use and Input-Output Tables on page 485. The diagonal values are the same in the input coefficient matrix and the output coefficient matrix.
The Leontief matrix is derived from Leontief equation system.
The Leontief matrix is defined as and it is created with the
leontief_matrix_create()
function.
The Leontief inverse is and it is created with the
leontief_inverse_create()
function from the
Leontief-matrix.
L_de <- leontief_matrix_create (
technology_coefficients_matrix = de_input_coeff
)
I_de <- leontief_inverse_create(de_input_coeff)
I_de_4 <- leontief_inverse_create(technology_coefficients_matrix=de_input_coeff,
digits = 4)
print (I_de_4[,1:3])
#> iotables_row agriculture_group industry_group
#> 1 industry_group 1.4155 0.5605
#> 2 construction 0.0441 1.0462
#> 3 trade_group 0.2180 0.2292
#> 4 business_services_group 0.2892 0.3237
#> 5 other_services_group 0.1089 0.1014
#> 6 total 1.1152 1.3025
You can check the Leontief matrix against Table 15.9 on page 487 of the Eurostat Manual, and the Leontief inverse against Table 15.10 on page 488. The ordering of the industries is different in the manual.
Creating indicators
Creating technical indicators
Technical indicators assume constant returns to scale and fixed relationship of all inputs to each industry. With these conditions the technical input coefficients show how much input products, labour or capital is required to produce a unit of industry output.
- = / [technical input coefficients]
The helper function primary_input_get()
selects a row
from the SIOT and brings it to a conforming form. The
input_indicator_create()
creates the vector of technical
input coefficients.
de_emp <- primary_input_get(germany_io,
primary_input = "employment_domestic_total")
de_emp_indicator <- input_indicator_create(
data_table = germany_io,
input_row = "employment_domestic_total")
vector_transpose_longer(de_emp_indicator)
#> # A tibble: 6 × 2
#> nace_r2 value
#> <chr> <dbl>
#> 1 agriculture_group 0.0250
#> 2 industry_group 0.00776
#> 3 construction 0.0132
#> 4 trade_group 0.0171
#> 5 business_services_group 0.00615
#> 6 other_services_group 0.0201
Often we want to analyse the effect of growing domestic demand on some natural units, such as employment or emissions. The only difficulty is that we need data that is aggregated / disaggregated precisely with the same industry breakup as our SIOT table.
European employment statistics have greater detail than our tables, so employment statistics must be aggregated to conform the 60 (61, 62) columns of the SIOT. There is a difference in the columns based on how national statistics offices treat imputed real estate income and household production, and trade margins. Czech SIOTs are smaller than most SIOTs because they do not have these columns and rows.
In another vignette we will show examples on how to work with these real-life data. For the sake of following the calculations, we are continuing with the simplified 1990 German data.
Creating income indicators
The input coefficients for value added are created with
input_indicator_create()
.
de_gva <- primary_input_get ( germany_io,
primary_input = "gva")
de_gva_indicator <- input_indicator_create(
data_table = germany_io,
input_row = "gva")
vector_transpose_longer(de_gva_indicator)
#> # A tibble: 6 × 2
#> nace_r2 value
#> <chr> <dbl>
#> 1 agriculture_group 0.493
#> 2 industry_group 0.366
#> 3 construction 0.471
#> 4 trade_group 0.577
#> 5 business_services_group 0.600
#> 6 other_services_group 0.717
This is equal to the equation on page 495 of the Eurostat Manual of Supply, Use and Input-Output Tables. The results above can be checked on the bottom of page 498.
- = / [input coefficients for value added]
You can create a matrix of input indicators, or direct effects on
(final) demand with direct_supply_effects_create()
. The
function by default creates input requirements for final demand. With
the code below it re-creates the Table 15.14 of the Eurostat
Manual.
direct_effects_de <- coefficient_matrix_create(
data_table = germany_io,
total = 'output',
return_part = 'primary_inputs')
direct_effects_de[1:6,1:4]
#> iotables_row agriculture_group industry_group construction
#> 7 total 0.41528126 0.482855094 0.468258104
#> 8 imports 0.06665908 0.145169837 0.054668860
#> 9 intermediate_consumption 0.50662719 0.634051171 0.529229742
#> 10 compensation_employees 0.21366431 0.274644586 0.320916427
#> 11 net_tax_production -0.04582100 0.001349766 0.003920914
#> 12 consumption_fixed_capital 0.17925302 0.059075674 0.023859352
The ‘total’ row above is labelled as Domestic goods and services in the Eurostat Manual. The table can be found on page 498.
Multipliers
Income multipliers
The SIOTs contain (with various breakups) three types of income:
Employee wages, which is usually a proxy for all household income.
Gross operating surplus, which is a form of corporate sector income.
Taxes that are the income of government.
These together make gross value added (GVA). If you are working with SIOTs that use basic prices, then GVA = GDP at producers’ prices, or basic prices.
The GVA multiplier shows the additional gross value created in the economy if demand for the industry products is growing with unity. The wage multiplier (not shown here) shows the increase in household income.
The following equation is used to work with different income effects and multipliers:
- Z = B(I-A)-1
B = vector of input coefficients for wages or GVA or taxes.
Z = direct and indirect requirements for wages (or other income)
The indicator shows that manufacturing has the lowest, and other services has the highest gross value added component. This is hardly surprising, because manufacturing needs a lot of materials and imported components. When the demand for manufacturing in the domestic economy is growing by 1 unit, the gross value added is 0.3659488.
You can check these values against the Table 15.16 of the Eurostat Manual of Supply, Use and Input-Output Tables on page 501 (row 10).
You can recreate the whole matrix, when the data data permits, with
input_multipliers_create()
as shown here. Alternatively,
you can create your own custom multipliers with
multiplier_create()
as shown in the following example.
input_reqr <- coefficient_matrix_create(
data_table = iotable_get(),
total = 'output',
return_part = 'primary_inputs')
multipliers <- input_multipliers_create(
input_requirements = input_reqr,
Im = I_de)
multipliers
#> iotables_row
#> 7 c("total", "imports", "intermediate_consumption", "compensation_employees", "net_tax_production", "consumption_fixed_capital", "os_mixed_income_net", "gva", "output", "net_tax_products", "employment_wage_salary", "employment_self_employed", "employment_domestic_total")
#> 8 c("total", "imports", "intermediate_consumption", "compensation_employees", "net_tax_production", "consumption_fixed_capital", "os_mixed_income_net", "gva", "output", "net_tax_products", "employment_wage_salary", "employment_self_employed", "employment_domestic_total")
#> 9 c("total", "imports", "intermediate_consumption", "compensation_employees", "net_tax_production", "consumption_fixed_capital", "os_mixed_income_net", "gva", "output", "net_tax_products", "employment_wage_salary", "employment_self_employed", "employment_domestic_total")
#> 10 c("total", "imports", "intermediate_consumption", "compensation_employees", "net_tax_production", "consumption_fixed_capital", "os_mixed_income_net", "gva", "output", "net_tax_products", "employment_wage_salary", "employment_self_employed", "employment_domestic_total")
#> 11 c("total", "imports", "intermediate_consumption", "compensation_employees", "net_tax_production", "consumption_fixed_capital", "os_mixed_income_net", "gva", "output", "net_tax_products", "employment_wage_salary", "employment_self_employed", "employment_domestic_total")
#> 12 c("total", "imports", "intermediate_consumption", "compensation_employees", "net_tax_production", "consumption_fixed_capital", "os_mixed_income_net", "gva", "output", "net_tax_products", "employment_wage_salary", "employment_self_employed", "employment_domestic_total")
#> 13 c("total", "imports", "intermediate_consumption", "compensation_employees", "net_tax_production", "consumption_fixed_capital", "os_mixed_income_net", "gva", "output", "net_tax_products", "employment_wage_salary", "employment_self_employed", "employment_domestic_total")
#> 14 c("total", "imports", "intermediate_consumption", "compensation_employees", "net_tax_production", "consumption_fixed_capital", "os_mixed_income_net", "gva", "output", "net_tax_products", "employment_wage_salary", "employment_self_employed", "employment_domestic_total")
#> 15 c("total", "imports", "intermediate_consumption", "compensation_employees", "net_tax_production", "consumption_fixed_capital", "os_mixed_income_net", "gva", "output", "net_tax_products", "employment_wage_salary", "employment_self_employed", "employment_domestic_total")
#> 16 c("total", "imports", "intermediate_consumption", "compensation_employees", "net_tax_production", "consumption_fixed_capital", "os_mixed_income_net", "gva", "output", "net_tax_products", "employment_wage_salary", "employment_self_employed", "employment_domestic_total")
#> 17 c("total", "imports", "intermediate_consumption", "compensation_employees", "net_tax_production", "consumption_fixed_capital", "os_mixed_income_net", "gva", "output", "net_tax_products", "employment_wage_salary", "employment_self_employed", "employment_domestic_total")
#> 18 c("total", "imports", "intermediate_consumption", "compensation_employees", "net_tax_production", "consumption_fixed_capital", "os_mixed_income_net", "gva", "output", "net_tax_products", "employment_wage_salary", "employment_self_employed", "employment_domestic_total")
#> 19 c("total", "imports", "intermediate_consumption", "compensation_employees", "net_tax_production", "consumption_fixed_capital", "os_mixed_income_net", "gva", "output", "net_tax_products", "employment_wage_salary", "employment_self_employed", "employment_domestic_total")
#> agriculture_group industry_group construction trade_group
#> 7 2.685405 2.697473 2.746360 2.773719
#> 8 2.350820 1.736823 2.960627 3.030228
#> 9 2.648481 2.546448 2.848667 2.828821
#> 10 5.228504 4.828548 4.274868 3.134768
#> 11 1.754409 -31.761313 -9.914110 -4.386767
#> 12 2.270536 5.635210 12.323323 3.589129
#> 13 2.770958 10.779995 3.440553 3.383980
#> 14 3.747840 5.325994 4.348257 3.170864
#> 15 3.190875 3.563620 3.554629 3.026047
#> 16 2.831087 9.949035 9.478301 3.608658
#> 17 4.023060 6.239150 4.299240 3.096275
#> 18 1.596012 34.019675 8.518983 3.822717
#> 19 2.665597 7.395981 4.742600 3.196316
#> business_services_group other_services_group
#> 7 2.687728 2.733341
#> 8 5.097511 2.892089
#> 9 2.850498 2.686567
#> 10 5.684347 1.967902
#> 11 -1.624052 2.014459
#> 12 2.325327 2.310132
#> 13 1.820218 2.474001
#> 14 3.051751 2.084234
#> 15 2.971231 2.254549
#> 16 4.207374 2.022875
#> 17 6.792323 2.006822
#> 18 7.413313 4.250793
#> 19 6.880557 2.149956
You can check these results against the Table 15.16 on page 501 of the Eurostat Manual. The label ‘total’ refers to domestic intermediaries. The ordering of the rows is different from the Manual.
These multipliers are Type-I multipliers. The type-I GVA multiplier shows the total effect in the domestic economy. The initial extra demand creates new orders in the backward linking industries, offers new product to build on in the forward-linking industry and creates new corporate and employee income that can be spent. Type-II multipliers will be introduced in a forthcoming vignette [not yet available.]
Employment multipliers
The E matrix contains the input coefficients for labor (created by
input_indicator_create()
). The following matrix equation
defines the employment multipliers.
- Z = E(I-A)-1
The multiplier_create()
function performs the matrix
multiplication, after handling many exceptions and problems with
real-life data, such as different missing columns and rows in the
national variations of the standard European table.
Please send a bug report on Github if you run into further real-life problems.
de_emp_indicator <- input_indicator_create (
data_table = germany_io,
input = 'employment_domestic_total')
employment_multipliers <- multiplier_create (
input_vector = de_emp_indicator,
Im = I_de,
multiplier_name = "employment_multiplier",
digits = 4 )
vector_transpose_longer(employment_multipliers,
values_to="employment_multipliers")
#> # A tibble: 6 × 2
#> nace_r2 employment_multipliers
#> <chr> <dbl>
#> 1 agriculture_group 0.0665
#> 2 industry_group 0.0574
#> 3 construction 0.0625
#> 4 trade_group 0.0548
#> 5 business_services_group 0.0423
#> 6 other_services_group 0.0431
You can check against the Eurostat Manual of Supply, Use and Input-Output Tables page 501 that these values are correct and on page 501 that the highest employment multiplier is indeed = 0.0665, the employment multiplier of agriculture.
For working with real-life, current employment data, there is a
helper function to retrieve and process Eurostat employment statistics
to a SIOT-conforming vector employment_get()
. This function
will be explained in a separate vignette.
Output multipliers
Output multipliers
and forward linkages
are
calculated with the help of output coefficients for product as defined
on p486 and p495 of the the Eurostat Manual. The Eurostat Manual uses
the definition of output at basic prices to define output
coefficients which is no longer part of SNA as of SNA2010.
- = / [also (45) output coefficients for products / intermediates].
: output of sector i
de_input_coeff <- input_coefficient_matrix_create(
data_table = iotable_get(),
digits = 4)
output_multipliers <- output_multiplier_create (input_coefficient_matrix = de_input_coeff)
vector_transpose_longer(output_multipliers,
values_to = "output_multipliers")
#> # A tibble: 6 × 2
#> nace_r2 output_multipliers
#> <chr> <dbl>
#> 1 agriculture_group 1.70
#> 2 industry_group 1.84
#> 3 construction 1.81
#> 4 trade_group 1.60
#> 5 business_services_group 1.59
#> 6 other_services_group 1.38
These multipliers can be checked against the Table 15.15 (The 8th, ‘Total’ row) on the page 500 of the Eurostat Manual.
Interindustrial linkage analysis
The backward linkages
, i.e. demand side linkages, show
how much incremental demand is created in the supplier sector when an
industry is facing increased demand, produces more, and requires more
inputs from suppliers.
Forward linkages
on the other hand show the effect of
increased production, which gives either more or cheaper supplies for
other industries that rely on the output of the given industry.
For example, when a new concert is put on stage, orders are filled for real estate, security services, catering, etc, which show in the backward linkages. The concert attracts visitors that creates new opportunities for the hotel industry in forward linkages.
Backward linkages
de_coeff <- input_coefficient_matrix_create(iotable_get(), digits = 4)
I_de <- leontief_inverse_create (de_coeff)
vector_transpose_longer(backward_linkages(I_de),
values_to = "backward_linkage_strength")
#> # A tibble: 6 × 2
#> nace_r2 backward_linkage_strength
#> <chr> <dbl>
#> 1 agriculture_group 1.70
#> 2 industry_group 1.84
#> 3 construction 1.81
#> 4 trade_group 1.60
#> 5 business_services_group 1.59
#> 6 other_services_group 1.38
You can check the results against Table 15.19 on page 506 of the Eurostat Manual.
Manufacturing has the highest backward linkages, and other services the least. An increased demand for manufacturing usually effects supplier industries. Service industry usually have a high labor input, and their main effect is increased spending of the wages earned in the services.
Forward linkages
Forward linkages show the strength of the new business opportunities when industry i starts to increase its production. Whereas backward linkages show the increased demand of the suppliers in industry i, forward linkages show the increased availability of inputs for other industries that rely on industry i as a supplier.
The forward linkages are defined as the sums of the rows in the Ghosh-inverse. The Ghosh-inverse is not explicitly named in the Eurostat Manual, but it is described in more detail in the United Nations’ similar manual Handbook on Supply and Use Tables and Input-Output Tables with Extensions and Applications (see pp 636–638).
de_out <- output_coefficient_matrix_create(
data_table = germany_io,
total = "final_demand",
digits = 4
)
ghosh_inverse_create(de_out, digits = 4)[,1:4]
#> iotables_row agriculture_group industry_group construction
#> 1 agriculture_group 1.0339 0.8612 0.0560
#> 2 industry_group 0.0117 1.4292 0.0901
#> 3 construction 0.0037 0.0839 1.0290
#> 4 trade_group 0.0103 0.2426 0.0484
#> 5 business_services_group 0.0117 0.3229 0.0888
#> 6 other_services_group 0.0042 0.0625 0.0105
The Ghosh-inverse is
where B = the output coefficient matrix.
The forward linkages are the rowwise sums of the Ghosh-inverse
forward_linkages(output_coefficient_matrix = de_out)
#> iotables_row forward_linkages
#> 1 agriculture_group 2.112754
#> 2 industry_group 1.690891
#> 3 construction 1.355896
#> 4 trade_group 1.584989
#> 5 business_services_group 2.104036
#> 6 other_services_group 1.210504
You can check the values of the forward linkages against the Table 15.20 on page 507 of the Eurostat Manual.
Environmental Impacts
At last, let’s extend the input-output system with emissions data.
For getting Eurostat’s air pollution account data, use
airpol_get()
. We have included in the package the German
emissions data from the Eurostat Manual.
data("germany_airpol")
emissions_de <- germany_airpol[, -3] %>%
vector_transpose_wider(names_from = "iotables_col",
values_from = "value")
emissions_de
#> # A tibble: 9 × 9
#> airpol agriculture_group industry_group construction trade_group
#> <chr> <int> <int> <int> <int>
#> 1 CO2 10448 558327 11194 71269
#> 2 CH4 1534 1160 1 4
#> 3 N2O 77 100 0 3
#> 4 SO2 12 1705 18 50
#> 5 NOx 62 722 64 452
#> 6 CO 43 1616 86 434
#> 7 NMVOC 20 1209 17 101
#> 8 Dust 57 165 7 34
#> 9 Total 12252 565005 11388 72347
#> # ℹ 4 more variables: business_services_group <int>,
#> # other_services_group <int>, final_consumption_households <int>,
#> # output_bp <int>
output_bp <- output_get(germany_io)
The output coefficients are created from the emission matrix with =
emission_coeffs <- germany_io %>%
supplementary_add(emissions_de) %>%
input_indicator_create(input_row = as.character(emissions_de$airpol), digits = 4)
The emissions coefficients are expressed as 1000 tons per millions of euro output (at basic prices).
emission_coeffs[-1, 1:3]
#> iotables_row agriculture_group industry_group
#> 20 CO2_indicator 0.2379 0.5172
#> 21 CH4_indicator 0.0349 0.0011
#> 22 N2O_indicator 0.0018 0.0001
#> 23 SO2_indicator 0.0003 0.0016
#> 24 NOx_indicator 0.0014 0.0007
#> 25 CO_indicator 0.0010 0.0015
#> 26 NMVOC_indicator 0.0005 0.0011
#> 27 Dust_indicator 0.0013 0.0002
#> 28 Total_indicator 0.2790 0.5234
And the multipliers (which include both the direct and indirect emissions of the industries) are created with
You can create a single multiplier with
?multiplier_create
.
multiplier_create(
input_vector = emission_coeffs[2,],
Im = I_de,
multiplier_name = "CO2_multiplier",
digits = 4 )
#> iotables_row agriculture_group industry_group construction trade_group
#> 1 CO2_multiplier 0.4185 0.7686 0.2726 0.2358
#> business_services_group other_services_group
#> 1 0.0583 0.1234
To create a tidy table of indicators of using a loop:
names(emission_coeffs)[1] <- names(I_de)[1]
emission_multipliers <- cbind (
key_column_create(names(emission_coeffs)[1],
gsub("_indicator", "_multiplier", unlist(emission_coeffs[-1,1]))),
do.call( rbind,
lapply ( 2:nrow(emission_coeffs),
function(x) equation_solve(emission_coeffs[x, ], I_de) )
) %>% as.data.frame()
)
emission_multipliers[, -1] <- round(emission_multipliers[, -1], 4)
emission_multipliers[1:3,1:4]
#> iotables_row agriculture_group industry_group construction
#> 1 CO2_multiplier 0.4185 0.7686 0.2726
#> 2 CH4_multiplier 0.0365 0.0029 0.0008
#> 3 N2O_multiplier 0.0019 0.0002 0.0001
You can check the results against the Table 15.13 of the Eurostat Manual of Supply, Use and Input-Output Tables on page 494.
Because the equation of the final demand is:
final_demand = final_consumption_households + final_consumption_government + inventory_change + gross_capital_formation + exports
we can calculate the final demand for the products of industries with creating the rowwise sums of the appropriate columns
final_demand <- rowSums(germany_io[1:6, 9:13])
And at last the emission content of the final demand is given by
where the term
is the definition of the emission multipliers.
emission_content <- as.data.frame(
round(as.matrix(emission_multipliers[1:3, -1]) %*% diag(final_demand), 0)
)
names(emission_content) <- names(emission_multipliers[,-1])
emission_content <- data.frame (
iotables_row = gsub("_multiplier", "_content", emission_multipliers[1:3,1])
) %>%
cbind(emission_content )
emission_content[,1:4]
#> iotables_row agriculture_group industry_group construction
#> 1 CO2_content 6369 476026 53447
#> 2 CH4_content 555 1796 157
#> 3 N2O_content 29 124 20
This final result can be found on the bottom of the page 494 of the Eurostat Manual of Supply, Use and Input-Output Tables.