bai_perron#

cultivars.diagnostics.breaks.bai_perron(endog, exog=None, *, trend='c', max_breaks=5, trimming=0.15, criterion='bic', alpha=0.05, n_draws=5000, grid=2000, seed=None)[source]#

Bai-Perron estimation of multiple breaks in a linear regression.

The regression \(y_t = x_t^\top \beta_j + u_t\) is allowed a different \(\beta_j\) on each of \(m + 1\) segments, every coefficient breaking at once. The sum of squared residuals of every admissible segment, one of at least trimming times the sample and never fewer than \(q + 1\) observations, is tabled once, and the global least-squares partition for each \(m\) up to max_breaks follows by dynamic programming over that table, which is what makes the search over \(\binom{T}{m}\) partitions affordable. The number of breaks is then chosen three ways, all kept on the record, one reported. BIC and the Liu-Wu-Zidek criterion penalize the partition sequence, with \(p_m = (m + 1) q + m\) parameters; LWZ’s penalty grows as \((\ln T)^{2.1}\) rather than \(\ln T\), which is why the authors found it less prone to over-fitting. The sequential procedure starts from no break and, given the \(l\)-break partition, computes on each segment the largest single-break F statistic,

\[\sup F(l + 1 \mid l) = \max_{\text{segments}} \max_{\tau} \frac{S_{\text{seg}} - S_{\text{split}}(\tau)} {S_{\text{split}}(\tau) / (n_{\text{seg}} - 2q)},\]

tests \(l\) against \(l + 1\) with it, and stops at the first non-rejection at alpha. Because the maximum is over \(l + 1\) independent segments, its p-value follows from the single-break sup-Wald limit \(G\) simulated at the trimming as \(1 - G(x)^{l + 1}\), and its critical values are the quantiles of \(G\) at \((1 - \alpha)^{1 / (l + 1)}\).

Parameters:
  • endog (ArrayLike) – The target, (T,).

  • exog (ArrayLike | None) – Regressors (T, k) or (T,), or None.

  • trend (str) – Deterministic terms, "n", "c" or "ct", placed before the regressors in the design.

  • max_breaks (int) – Largest number of breaks considered; at least one.

  • trimming (float) – Minimum segment length as a fraction of the sample, in (0, 0.5); 0.15 is Bai and Perron’s default.

  • criterion (str) – Which selection to report: "bic", "lwz" or "sequential".

  • alpha (float) – Level of the sequential tests, in (0, 1).

  • n_draws (int) – Limit-process paths for the sequential p-values, at least 500.

  • grid (int) – Points on which each path is simulated, at least 100.

  • seed (int | Generator | None) – Seed or generator for the limit simulation.

Return type:

MultipleBreakTest

Returns:

The MultipleBreakTest, with the partition, SSR, BIC and LWZ for every count and the sequential tests taken.

Raises:
  • SpecificationError – If the criterion, trend, trimming, level, or counts are unusable, or if max_breaks + 1 segments of the minimum length do not fit the sample.

  • DimensionError – If the regressors do not align with the target.

  • NumericalError – If a value is not finite or the design is rank deficient.

Note

The sequential F statistic here normalizes by the split segment’s own residual sum, with n_seg - 2q degrees of freedom, rather than by the full-sample residual sum of the \(l + 1\)-break model as in Bai and Perron’s Section 4; the two agree asymptotically and the segment form keeps each step a self-contained single-break test. Serial correlation and heteroskedasticity in \(u_t\) are not corrected for: include the lags the dynamics call for in exog, or read the selection as descriptive. The sequential tests are run under every criterion, so criterion="bic" still pays for the limit simulation; n_draws is the lever if that matters.

See also

  • MultipleBreakTest – the record, with the summary table over counts.

  • sup_wald() – the single-break test with the same limit, when one break is the hypothesis.

  • cusum() – a boundary test that needs no count of breaks.

References

Bai, J., & Perron, P. (1998). Estimating and testing linear models with multiple structural changes. Econometrica, 66(1), 47-78.

Bai, J., & Perron, P. (2003). Computation and analysis of multiple structural change models. Journal of Applied Econometrics, 18(1), 1-22.

Liu, J., Wu, S., & Zidek, J. V. (1997). On segmented multivariate regression. Statistica Sinica, 7(2), 497-525.

Example

One mean shift at observation 100. BIC, LWZ, and the sequential procedure agree on one break at the right date:

>>> import numpy as np
>>> rng = np.random.default_rng(0)
>>> y = np.concatenate([rng.standard_normal(100), 2.0 + rng.standard_normal(100)])
>>> bai_perron(y, max_breaks=3, seed=0)
MultipleBreakTest(n_breaks=1, break_indices=(100,), criterion='bic', nobs=200)
>>> bai_perron(y, max_breaks=3, criterion="lwz", seed=0).n_breaks
1
>>> test = bai_perron(y, max_breaks=2, criterion="sequential", seed=0)
>>> test.n_breaks, [t.name for t in test.sequential]
(1, ['sup F(1 | 0)', 'sup F(2 | 1)'])
>>> test.sequential[0].pvalue, bool(test.sequential[1].pvalue > 0.05)
(0.0, True)

Too many breaks for the sample at the requested trimming is refused rather than silently capped:

>>> bai_perron(y, max_breaks=10)
Traceback (most recent call last):
    ...
cultivars.exceptions.SpecificationError: 10 breaks with segments of at least 30 ...