3. Reading Model Outputs

Important

The following assumes that an equilibrium has already been solved. It only focuses on how to read and explore the resulting iamax outputs.

3.1. General principle

Once an equilibrium has been solved, users naturally want to explore the data generated by the model. Here is a minimal procedure to do so.

_

The main idea is simple: the economic outputs are returned as pandas.DataFrame instances. For example, you can directly inspect variables such as

ms.input_values
ms.markets_rents
ms.deflators_lpaasche

Most economic variables also come with two companion variables, whose names are obtained by suffixing the variable name with _grates or _drates.

ms.input_values_grates   # growth rates of input_values
ms.input_values_drates   # arbitrary input_values's companion data

3.2. Identifiers

The indexing logic is always the same. Each variable is a table whose rows and columns are identified by identifiers.

_

In the example documentation, each identifier is a 3-part coordinate such as

('n', 'd', 'e')

You can think of this as “region / type / sector”, although the exact meaning and number depends on the data you provided iamax with.

Even row or column vectors are stored as full pandas.DataFrame instances. When one side of the table is not economically meaningful, iamax uses the universal selector '*' (see UNIV_SYM). So a column vector still has columns like

('*', '*', '*')

and a row vector still has an index like

('*', '*', '*')

Said differently, all outputs can be read as tables, even when their mathematical shape is closer to \(1 \times |\mathcal{I}|\), \(|\mathcal{I}| \times 1\), or \(|\mathcal{I}| \times |\mathcal{I}|\).

3.3. Minimal setup

A useful habit is to slice these objects with pandas.IndexSlice, here shortened to i.

import pandas as pd
import iamax as im

i = pd.IndexSlice

Using the same example file and sheet names as in the documentation, an MSystem can be instanced as follows.

ms = im.MSystem(
    "examples/ut(KLEM-BRICS-202006)@sol.xlsx",
    sheets_names=dict(
        mappings="entities",
        input_values="i-vals",
        contrib_taxes="c-txs",
        markets_rents="nos",
        sales_taxes_totals="s-txs-tot",
        sales_taxes_exorates="¬%(s-txs)",
        specific_margins="sp-mgs",
        producer_gross_prices="av-p-prices",
    ),
    year=2010,
)
ms.frames_as_denseap = False

For your own model, only the file path, the sheet names, and often the year argument — used to specify the calibration year — would change.

Note

In the following examples, at least one requested item is put in square brackets when slicing, for example ['e', 'o'], [2010], or even ['*']. This tells pandas: “please keep returning a table”. Without this, pandas may sometimes simplify the result too much and return a single value or a thinner object, which can be confusing.

3.4. Examples

3.4.1. Row vector, cross-section mode

Here markets_rents is a row vector: its meaningful identifiers are on the columns, while the row side is the universal '*'.

>>> ms.frames_as_tseries = False
>>> ms.markets_rents.loc[i[['*'], '*', '*'], i['n', 'd', ['e', 'o']]]
              n
              d
              e         o
* * *  15404.71  26352.29

This reads the market rents for the domestic sectors e and o.

The same selection can be applied to the companion variables.

3.4.2. Row vector, time-series mode

When frames_as_tseries is True, the year is added as the first level of the index. The columns remain unchanged.

>>> ms.frames_as_tseries = True
>>> ms.markets_rents.loc[i[[2010], ['*'], '*', '*'], i['n', 'd', ['e', 'o']]]
                   n
                   d
                   e         o
year
2010 * * *  15404.71  26352.29

The only difference with the previous example is the extra [2010] (or :) at the beginning of the row selector.

3.4.3. Column vector, cross-section mode

Here deflators_lpaasche is a column vector: its meaningful identifiers are on the index, while the column side is the universal '*'.

>>> ms.frames_as_tseries = False
>>> ms.deflators_lpaasche.loc[i['n', 'd', ['c', 'g', 'i']], i[['*'], '*', '*']]
         *
         *
         *
n d c  1.0
    g  1.0
    i  1.0

This reads lagged Paasche deflators for domestic consumption, government, and investment sectors.

Again, the companion variables follow the same structure.

3.4.4. Column vector, time-series mode

In time-series mode, the year is again added as the first index level.

>>> ms.frames_as_tseries = True
>>> ms.deflators_lpaasche.loc[i[[2015], 'n', 'd', ['c', 'g', 'i']], i[['*'], '*', '*']]
              *
              *
              *
year
2010 n d c  1.0
         g  1.0
         i  1.0

3.4.5. Square matrix, cross-section mode

Here input_values is a square matrix: both rows and columns have meaningful identifiers.

>>> ms.frames_as_tseries = False
>>> ms.input_values.loc[i['n', 'm', ['e', 'o']], i['n', 'a', ['e', 'o']]]
              n
              a
              e         o
n m e  1.30e+06  0.00e+00
    o  0.00e+00  8.93e+06

This reads the values of imported energy and composite goods used by domestic activity sectors e and o.

The companion variables follow the same structure.

3.4.6. Square matrix, time-series mode

For a matrix in time-series mode, the year is added only to the index, not to the columns.

>>> ms.frames_as_tseries = True
>>> ms.input_values.loc[i[:, 'n', 'm', ['e', 'o']], i['n', 'a', ['e', 'o']]]
                   n
                   a
                   e         o
year
2010 n m e  1.30e+06  0.00e+00
         o  0.00e+00  8.93e+06
>>> ms.input_values.loc[i[[2010], 'n', 'm', ['e', 'o']], i['n', 'a', ['e', 'o']]]
                   n
                   a
                   e         o
year
2010 n m e  1.30e+06  0.00e+00
         o  0.00e+00  8.93e+06

3.5. In summary

Setting

ms.frames_as_tseries = False

returns one cross-section, while setting

ms.frames_as_tseries = True

returns a time series where year becomes the first level of the index.

_

The most important thing to remember is that all these outputs are ordinary pandas.DataFrame instances. Once you know whether the variable is a row vector, a column vector, or a matrix, the same .loc[i[...], i[...]] logic applies everywhere.

More generally, pandas.DataFrame is a very standard Python object: the internet and online AI assistants are full of explanations on how to inspect, manipulate, read from disk, and write to disk the content of a pandas.DataFrame.