GVARResult#

class cultivars.multivariate.reduced_form.closed_global.GVARResult(*, endog, names, unit_names, unit_sizes, order, trend, coefficients, deterministic, contemporaneous, weights, sigma_u, resid, nobs, units)[source]#

A closed global system assembled from conditional units.

Each unit \(i\) was fitted on its own variables \(y_{it}\) with a weighted average of the other units’ variables, \(y^*_{it} = \sum_j w_{ij}\, y_{jt}\), entering as the exogenous block, so on its own it has no law of motion for the foreign variables it conditions on. Writing every unit in levels against the global vector \(x_t = (y_{1t}', \dots, y_{Nt}')'\) through its link matrix \(z_{it} = (y_{it}', y^{*\prime}_{it})' = W_i x_t\) and stacking,

\[G_0\, x_t = d_t + \sum_{l=1}^{p} G_l\, x_{t-l} + u_t, \qquad x_t = G_0^{-1} d_t + \sum_{l=1}^{p} G_0^{-1} G_l\, x_{t-l} + G_0^{-1} u_t,\]

where \(G_0\) stacks \([I, -\Lambda_{i0}] W_i\) and \(G_l\) stacks \([\Phi_{il}, \Lambda_{il}] W_i\). The inversion is the moment the system closes: individually no unit explains its foreign aggregate, jointly they all do, because one unit’s foreign variables are other units’ domestic ones. This record holds \(G_0\) as contemporaneous, the solved stack \(G_0^{-1} G_l\) as coefficients, and the rotated innovations \(G_0^{-1} u_t\) as resid.

Deliberately not a _VectorResult. Every other result in the package was estimated: it has one design matrix, one likelihood, one parameter count. This one was assembled – the units were estimated separately and then linked by an algebraic solve – so it has none of those three, and giving it hollow versions to fit the hierarchy would be worse than standing outside it. What it does have is a law of motion for every variable, which is why it carries the propagation surface the units individually refused and satisfies the closed-system contract they could not.

Note

The assembly is exact rather than approximate: substituting each unit’s link matrix into its own equations and stacking gives a square system whose solution reproduces every unit equation to machine precision, so contemporaneous @ resid.T is the stacked unit residuals and no unit’s coefficients are altered. What the assembly cannot do is make the units’ coefficients correct. A unit’s foreign aggregate contains other units’ contemporaneous variables, which the global solve makes functions of that unit’s own innovations, so least squares on a unit equation is consistent only if the aggregate is weakly exogenous for it. That is an assumption about the data, not a property of the estimator, and the bias it causes does not shrink as units are added. weak_exogeneity_test() is therefore not an optional diagnostic here – it is the condition under which everything else on this object means what it says, and the summary names any unit that fails it. Two further conventions: the global order is the deepest lag any unit uses in its levels form, with shorter units padded by zero blocks, and trend is read off the widest deterministic block among the units.

Variables:
  • endog – The global panel, all units side by side.

  • names – Global variable labels, "unit.variable".

  • unit_names – Unit labels, in global column order.

  • unit_sizes – Variables each unit contributes.

  • order – Lags of the global system.

  • trend – Deterministic specification of the global representation.

  • coefficients – (p, k, k) global autoregressive matrices.

  • deterministic – (d, k) global deterministic coefficients.

  • contemporaneous – The (k, k) linkage matrix inverted to close the system.

  • weights – The validated cross-unit weight matrix.

  • sigma_u – Covariance of the global reduced-form innovations.

  • resid – The global reduced-form innovations on the common sample.

  • nobs – Rows of the common sample.

  • units – The fitted unit results, in global column order.

See also

  • GVAR – the assembler that builds this record from fitted units and a weight matrix through solve().

  • VECMXResult – the conditional error-correction unit, the only kind whose weak-exogeneity assumption can be tested here.

  • VARXResult – the conditional levels unit, linked through the levels form it already is.

  • VARResult – the estimated closed system this record stands beside without descending from.

References

Pesaran, M. H., Schuermann, T., & Weiner, S. M. (2004). Modeling regional interdependencies using a global error-correcting macroeconometric model. Journal of Business & Economic Statistics, 22(2), 129-162.

Dees, S., di Mauro, F., Pesaran, M. H., & Smith, L. V. (2007). Exploring the international linkages of the euro area: A global VAR analysis. Journal of Applied Econometrics, 22(1), 1-38.

Chudik, A., & Pesaran, M. H. (2016). Theory and practice of GVAR modelling. Journal of Economic Surveys, 30(1), 165-197.

Example

A dominant unit and a satellite: the world price is a random walk, the satellite price error-corrects toward it. Each unit is fitted as a conditional error-correction model against the other, the weight matrix swaps them, and the solve closes the pair. The rotation back through the linkage matrix recovers the unit residuals exactly, and the generalized response of the satellite to a world shock climbs toward one as the gap closes:

>>> import numpy as np
>>> from cultivars.multivariate.reduced_form.error_correction import VECMX
>>> rng = np.random.default_rng(0)
>>> world, sat = np.zeros(400), np.zeros(400)
>>> for t in range(1, 400):
...     world[t] = world[t - 1] + rng.standard_normal()
...     gap = world[t - 1] - sat[t - 1]
...     sat[t] = sat[t - 1] + 0.3 * gap + 0.5 * rng.standard_normal()
>>> units = [
...     VECMX(world[:, None], sat[:, None], order=1, rank=1).fit(),
...     VECMX(sat[:, None], world[:, None], order=1, rank=1).fit(),
... ]
>>> swap = np.array([[0.0, 1.0], [1.0, 0.0]])
>>> names = ("world", "sat")
>>> res = GVAR(units, swap, variable_labels=["p", "p"], unit_names=names).solve()
>>> res.names, res.order, res.nobs
(('world.p', 'sat.p'), 1, 399)
>>> stacked = np.hstack([unit.resid[-res.nobs :] for unit in res.units])
>>> bool(np.allclose(res.contemporaneous @ res.resid.T, stacked.T))
True
>>> response = res.generalized_irf(8)[:, 1, 0]
>>> bool(response[1] > 0.25), bool(response[-1] > 0.9)
(True, True)
>>> res.exogeneity_table().metadata[2]
('Rejections', '1')

Attributes#

endog

The global panel (n, k), every unit's endog side by side in unit order.

names

Global column labels "unit.variable", built from the unit names and the labels.

unit_names

Unit labels in global column order; the keys every per-unit method accepts.

unit_sizes

Variables each unit contributes; the partition of the k global columns.

order

the deepest levels lag any unit uses.

trend

Deterministic specification of the global representation, "n", "c" or "ct".

coefficients

The (p, k, k) solved autoregressive stack \(G_0^{-1} G_l\).

deterministic

The (d, k) global deterministic coefficients, one row per deterministic term.

contemporaneous

The (k, k) linkage matrix \(G_0\) whose inverse closed the system.

weights

The validated (n_units, n_units) cross-unit weight matrix the aggregates used.

sigma_u

Covariance of the global reduced-form innovations.

resid

The (nobs, k) global innovations \(G_0^{-1} u_t\) on the common sample.

nobs

the shortest unit residual series.

units

The fitted unit results in global column order, exactly as they were passed in.

companion

The (kp, kp) companion matrix of the autoregressive block.

is_stable

Whether every companion eigenvalue lies inside the unit circle.

k_endog

Number of endogenous variables.

linkage_condition

Condition number of the contemporaneous linkage matrix.

n_units

Units the system links.

sigma_ml

Innovation covariance without the degrees-of-freedom correction.

Methods#

exogeneity_table(*[, alpha])

Run the weak-exogeneity test on every unit that supports it.

fevd([horizon])

Forecast-error variance decomposition.

forecast([steps])

Deterministic multi-step forecasts from the end of the sample.

generalized_fevd([horizon])

Variance shares from the generalized responses, normalized to sum to one.

generalized_irf([horizon, cumulative])

Pesaran-Shin impulse responses, which do not depend on variable order.

historical_decomposition()

Attribute each observation to the shocks that produced it.

identify(strategy)

Declare an identification scheme and return the structural view.

irf([horizon, orthogonalized, cumulative])

Impulse responses to a one-standard-deviation shock.

ma_representation([horizon])

Moving-average matrices Psi_0, ..., Psi_horizon.

simulate([n, seed, burn])

A fresh sample path from the fitted system.

stability_check()

Eigenvalue verdict for the companion matrix.

structural_shocks()

Residuals rotated by the inverse Cholesky impact matrix.

summary()

The estimation summary, renderable as text, HTML, or a dataframe.

unit_columns(unit)

Global column indices the named unit owns.

weak_exogeneity_test(unit)

Test that a unit's foreign aggregates ignore its disequilibria.