FactorSVResult#
- class cultivars.multivariate.large_dim.factor_volatility.FactorSVResult(*, panel, series_names, loading_draws, factor_draws, h_factor_draws, h_idio_draws, mu_factor_draws, phi_factor_draws, sigma2_factor_draws, mu_idio_draws, phi_idio_draws, sigma2_idio_draws, means, n_draws, n_burn, thin)[source]
Bases:
_SummaryMixin,_ConvergenceMixinThe posterior of a factor stochastic-volatility model.
The model is
\[y_t = \Lambda f_t + \varepsilon_t, \qquad f_t \sim N\bigl(0, H_t\bigr), \quad \varepsilon_t \sim N\bigl(0, D_t\bigr),\]with \(H_t = \operatorname{diag}(e^{h_{1t}}, \ldots, e^{h_{rt}})\) and \(D_t = \operatorname{diag}(e^{\eta_{1t}}, \ldots, e^{\eta_{kt}})\), every log variance a latent AR(1),
\[h_{j,t+1} = \mu_j + \phi_j (h_{jt} - \mu_j) + \sigma_j \xi_{jt},\]so the conditional covariance \(\Sigma_t = \Lambda H_t \Lambda' + D_t\) moves through \(k + r\) volatility paths and one loading matrix. Identification is the triangular convention: \(\Lambda\) is lower triangular with a unit diagonal in its leading \(r\) rows, so factor \(j\) is scaled and signed by series \(j\). The sampler is an exact Gibbs scheme – factors one Gaussian per period, loadings one weighted regression per row, every log-variance path and its three parameters by the Kim-Shephard-Chib mixture blocks – and what comes back is the posterior: the record stores the retained draws of every unknown, and the point summaries (
loadings,factors, the conditional covariance and correlation, the communalities) are posterior means computed from them on demand.Note
Every
*_drawsfield shares the kept-draw axisS, which is whatconvergencefrom_ConvergenceMixinassesses. The fixed loadings (the unit diagonal and the zeros above it) never move and are reported as such rather than flagged. The chain is a plain Gibbs sampler without the Kastner, Fruehwirth-Schnatter and Lopes (2017) interweaving, so loadings and factor scales mix slowly and the volatility paths have low effective sample sizes at short runs; thin and lengthen accordingly, and readconvergencebefore the point summaries. The series means are removed before sampling and kept inmeans;panelis the raw input.- Variables:
panel – The observed
(nobs, k)panel.series_names – One label per series.
loading_draws –
(S, k, r)posterior draws of the loading matrix.factor_draws –
(S, T, r)posterior draws of the factor paths.h_factor_draws –
(S, T, r)posterior draws of the factor log variances.h_idio_draws –
(S, T, k)posterior draws of the idiosyncratic log variances.mu_factor_draws –
(S, r)factor log-variance means.phi_factor_draws –
(S, r)factor log-variance persistences.sigma2_factor_draws –
(S, r)factor log-variance innovation variances.mu_idio_draws –
(S, k)idiosyncratic log-variance means.phi_idio_draws –
(S, k)idiosyncratic persistences.sigma2_idio_draws –
(S, k)idiosyncratic innovation variances.means –
(k,)series means removed before sampling.n_draws – Total sampler iterations.
n_burn – Burn-in discarded.
thin – Post-burn thinning.
See also
References
Pitt, M. K., & Shephard, N. (1999). Time-varying covariances: A factor stochastic volatility approach. In Bayesian Statistics 6 (pp. 547-570). Oxford University Press.
Chib, S., Nardari, F., & Shephard, N. (2006). Analysis of high dimensional multivariate stochastic volatility models. Journal of Econometrics, 134(2), 341-371.
Kastner, G., Fruehwirth-Schnatter, S., & Lopes, H. F. (2017). Efficient Bayesian inference for multivariate factor stochastic volatility models. Journal of Computational and Graphical Statistics, 26(4), 905-917.
Example
One factor with a persistent log variance, loaded onto five series with decreasing weights; the posterior recovers the loadings, the factor path and its volatility:
>>> import numpy as np >>> rng = np.random.default_rng(0) >>> n, k = 300, 5 >>> h = np.zeros(n) >>> for t in range(1, n): ... h[t] = 0.95 * h[t - 1] + 0.3 * rng.standard_normal() >>> f = np.exp(h / 2) * rng.standard_normal(n) >>> lam = np.array([1.0, 0.8, 0.6, 0.4, 0.2]) >>> y = np.outer(f, lam) + 0.5 * rng.standard_normal((n, k)) >>> res = FactorSV(y, n_factors=1).fit(n_draws=300, n_burn=100, seed=0) >>> res.n_series, res.n_factors, res.nobs, res.n_kept (5, 1, 300, 200) >>> np.round(res.loadings[:, 0], 1) array([1. , 0.8, 0.6, 0.4, 0.2]) >>> bool(np.corrcoef(res.factors[:, 0], f)[0, 1] > 0.9) True >>> bool(np.corrcoef(res.h_factor_draws.mean(axis=0)[:, 0], h)[0, 1] > 0.7) True