cultivars.multivariate.large_dim.sparse#

The sparse VAR: shrinkage by selection, and the network it draws.

Where the Bayesian family shrinks every coefficient a little, the penalized family sets most of them to exactly zero – and in a large system the zeros are the finding: which variables’ histories actually enter which equations is a directed Granger network, read straight off the support. The estimator is one problem on the standardized panel,

\[\hat A = \arg\min_A\ \tfrac{1}{2}\sum_t \bigl\lVert y_t - c - \textstyle\sum_{i=1}^{p} A_i y_{t-i} \bigr\rVert^2 + \lambda\, P(A),\]

under five penalties. The lasso \(P(A) = \sum |a_{ij}^{(l)}|\) (Basu and Michailidis, 2015) is the baseline; the adaptive lasso reweights it by a ridge pilot, \(\sum |a| / |\tilde a|\); SCAD and MCP (Nicholson-Matteson-Bien territory) unbias the large coefficients the lasso drags toward zero, solved here by local linear approximation – a short sequence of weighted lasso problems, the standard route to their oracle behavior (Zou and Li, 2008); and the lag-group penalty \(\sum_l \sqrt{k^2}\,\lVert A_l \rVert_F\) zeroes entire lag matrices, which is lag selection rather than entry selection. Each problem is solved by FISTA, warm-started down a geometric path from the level that zeroes everything. Deterministic terms are never penalized, and everything is standardized internally so one penalty level means the same thing in every equation.

Two commitments shape the surface. First, the penalty level, when unstated, is chosen by rolling-origin one-step forecast cross-validation with refitting at every origin – genuine out-of-sample errors, the scheme the sparse-VAR literature settled on – and its two consequences are stated rather than hidden: prediction-optimal levels keep more variables than the true support (the lasso especially; the nonconvex penalties are the remedy when the support itself is the object), and the path and its errors are kept on the result so the choice can be read rather than trusted. Second, inference after selection is a genuinely unsolved problem at this generality, so no likelihood, criteria or standard errors are reported – the result refuses to decorate selected coefficients with intervals that ignore the selection, and the summary says why.

The result satisfies the closed-system contract, so a fitted sparse VAR feeds the structural layer and Spillover directly – estimating connectedness among a hundred banks with a lasso VAR is exactly the Demirer-Diebold-Liu-Yilmaz pipeline.

Layout. SparseVAR validates the specification on _SparseVectorAutoRegressionModel in _internals, whose _fit_sparse standardizes, builds the geometric path from the zeroing level, solves each level through _solve_penalized – the lasso and group penalties directly, the adaptive lasso with ridge-pilot weights, SCAD and MCP through _nonconvex_weights and a reweighted pass – on _fista_penalized from _internals._solvers, selects by rolling origin, and packs a _VectorSparseFit. SparseVARResult takes the summary from _SummaryMixin and computes ma_representation and granger_adjacency itself. The penalty names are Penalty. The second-stage precision network is graphical; the shrinkage alternatives are bayesian and gibbs.

References

Basu, S., & Michailidis, G. (2015). Regularized estimation in sparse high-dimensional time series models. Annals of Statistics, 43(4), 1535-1567.

Nicholson, W. B., Matteson, D. S., & Bien, J. (2017). VARX-L: Structured regularization for large vector autoregressions with exogenous variables. International Journal of Forecasting, 33(3), 627-651.

Zou, H., & Li, R. (2008). One-step sparse estimates in nonconcave penalized likelihood models. Annals of Statistics, 36(4), 1509-1533.

Demirer, M., Diebold, F. X., Liu, L., & Yilmaz, K. (2018). Estimating global bank network connectedness. Journal of Applied Econometrics, 33(1), 1-15.

Example

A six-variable VAR(1) with two cross links, under the lasso and MCP: both recover the support, MCP with far fewer survivors, and the result feeds the spillover table directly:

>>> import numpy as np
>>> from cultivars.multivariate.large_dim.spillover import Spillover
>>> rng = np.random.default_rng(0)
>>> k, n = 6, 300
>>> first = 0.5 * np.eye(k)
>>> first[1, 0], first[3, 2] = 0.3, -0.3
>>> y = np.zeros((n, k))
>>> for t in range(1, n):
...     y[t] = first @ y[t - 1] + rng.standard_normal(k)
>>> lasso = SparseVAR(y, order=1).fit(penalty="lasso")
>>> mcp = SparseVAR(y, order=1).fit(penalty="mcp")
>>> truth = [(1, 0), (3, 2)]
>>> for res in (lasso, mcp):
...     edges = res.granger_adjacency(threshold=0.15)
...     print([(i, j) for i in range(k) for j in range(k) if edges[i, j]] == truth)
True
True
>>> bool(mcp.n_nonzero <= lasso.n_nonzero / 2)
True
>>> table = Spillover(mcp, horizon=10).compute()
>>> table.names == mcp.names, bool(0.0 <= table.total <= 100.0)
(True, True)

Classes#

SparseVAR

Penalized VAR: lasso, adaptive lasso, SCAD, MCP, or lag-group.

SparseVARResult

A fitted sparse VAR: the coefficients that survived, and the zeros.