Uncertainty quantification (tsbootstrap.uq)

The uncertainty-quantification surface is also re-exported at the top level, so from tsbootstrap import EnbPIEnsemble works alongside from tsbootstrap.uq import EnbPIEnsemble. scikit-learn (the uq extra) is imported lazily inside the out-of-bag path, so importing these names on a core-only install is safe; it is required only when an EnbPI ensemble is fitted.

Note

forecast_intervals() currently supports the AR model only and raises MethodConfigError for ARIMA or VAR. Out-of-sample forecast intervals for ARIMA and VAR are tracked on the roadmap.

Uncertainty quantification built on the bootstrap.

Two task-appropriate paths (see the v0.2.0 design notes):

  • In-sample / out-of-sample regression, EnbPIEnsemble is a MAPIE-style fit/predict object: it bootstraps the row indices, fits a clone of the estimator per resample, records the out-of-bag ensemble residuals (Xu & Xie 2021), and retains the fitted clones so intervals can be produced for new X. The half-width comes from a chosen calibrator over the residual buffer, static_halfwidths() (global quantile), sliding_window_halfwidths() (time-local EnbPI), or the drift-adaptive aci_halfwidths() / nexcp_quantile(). enbpi_intervals() and fit_predict_oob() are thin wrappers for the simple in-sample, static-width path.

  • Forecasting, forecast_intervals() simulates the fitted model forward and takes empirical path quantiles over the horizon.

These carry honest, assumption-appropriate coverage claims: approximate / asymptotic under temporal dependence, not finite-sample distribution-free.

class tsbootstrap.uq.EnbPIEnsemble[source]

Bases: object

Fit/predict EnbPI ensemble: retain the bootstrap clones, calibrate on demand.

fit bootstraps the row indices with an observation-resampling method, fits a clone of estimator on each in-bag resample, and computes the out-of-bag ensemble prediction per row (the mean over the replicates in which the row was held out) and the out-of-bag absolute residuals |y - oob_pred|. The residuals are the raw calibration scores, decoupled from any particular calibrator.

predict_interval then centers an interval at the out-of-bag prediction (in sample) or the retained-clone ensemble mean (out of sample) and applies the chosen calibrator to the residual buffer to get the half-width. Coverage is approximately 1 - alpha under a strong-mixing condition (Xu & Xie 2021), not finite-sample distribution-free.

fit(estimator: _SklearnLike, X: object, y: object, *, method: BaseMethodSpec, n_bootstraps: int = 100, random_state: int | Generator | SeedSequence | None = None, store_estimators: bool = True) EnbPIEnsemble[source]

Fit the bootstrap ensemble and record the out-of-bag calibration scores.

Parameters:
  • estimator (object) – An unfitted, order-invariant sklearn-style regressor; cloned per replicate.

  • X (array-like) – Design matrix (n, d) (1-D is treated as (n, 1)) and targets (n,).

  • y (array-like) – Design matrix (n, d) (1-D is treated as (n, 1)) and targets (n,).

  • method (object) – An observation-resampling method (IID or a block method). Recursive model methods are rejected with MethodConfigError.

  • n_bootstraps (int) – Number of bootstrap replicates.

  • random_state (object) – Seed or generator forwarded to the bootstrap.

  • store_estimators (bool) – Retain the fitted clones on the instance (default True). Required for out-of-sample predict_interval(); set False to save memory when only in-sample intervals are needed.

property oob_residuals: ndarray[tuple[int, ...], dtype[float64]]

The out-of-bag absolute residuals (calibration scores), in time order.

Raw and decoupled from calibration: every calibrator reads from this buffer.

property oob_prediction: ndarray[tuple[int, ...], dtype[float64]]

The in-sample out-of-bag ensemble prediction, one per training row.

predict_interval(X_new: object | None = None, *, alpha: float = 0.1, calibrator: Annotated[Static | SlidingWindow | ACI | NexCP | AgACI, FieldInfo(annotation=NoneType, required=True, discriminator='kind')] = Static(kind='static'), test_data: object | None = None) tuple[ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]]][source]

Prediction interval (lower, upper, point) for the chosen calibrator spec.

Parameters:
  • X_new (array-like, optional) – New design matrix. If None (default), returns in-sample intervals centered at the out-of-bag prediction. Otherwise the point prediction is the mean of the retained clones’ predictions on X_new (requires the ensemble to have been fitted with store_estimators=True).

  • alpha (float) – Target miscoverage; the interval target coverage is 1 - alpha.

  • calibrator (CalibratorSpec) –

    A frozen calibrator spec from tsbootstrap.uq.calibrators that decides how the residual buffer becomes interval endpoints. Every option lives on the spec, so a misspelled option fails at spec construction rather than being silently ignored:

    • Static, one global 1 - alpha quantile for every row (the default).

    • SlidingWindow, rolling 1 - alpha quantile (time-local EnbPI); window defaults to min(len, 50).

    • ACI, Adaptive Conformal Inference; needs test_data (the time-ordered realized |y_t - prediction_t|, one per row).

    • NexCP, recency-weighted quantile.

    • AgACI, Aggregated Adaptive Conformal Inference (Zaffran et al. 2022): asymmetric bounds. Needs test_data (the time-ordered SIGNED, finite y_t - prediction_t, one per row).

  • test_data (array-like, optional) – The realized runtime observation a drift-adaptive calibrator needs: the ACI scores or the AgACI signed residuals. Left None for the calibrators that read only the residual buffer (Static, SlidingWindow, NexCP). It is a runtime argument, not a spec field, because it is data rather than configuration.

Returns:

(lower, upper, point), each shape (n_rows,).

Return type:

tuple of ndarray

tsbootstrap.uq.fit_predict_oob(estimator: _SklearnLike, X: object, y: object, *, method: BaseMethodSpec, n_bootstraps: int = 100, random_state: int | Generator | SeedSequence | None = None) ndarray[tuple[int, ...], dtype[float64]][source]

Out-of-bag ensemble predictions, one per row.

Each in-bag resample fits a clone of estimator; the held-out rows are predicted and averaged per row over the replicates in which the row was out-of-bag. Rows never held out get nan.

A thin convenience wrapper over EnbPIEnsemble; use the class directly when you also need calibrated intervals or out-of-sample prediction.

tsbootstrap.uq.enbpi_intervals(estimator: _SklearnLike, X: object, y: object, *, method: BaseMethodSpec, alpha: float = 0.1, n_bootstraps: int = 100, random_state: int | Generator | SeedSequence | None = None) tuple[ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]]][source]

EnbPI prediction intervals: (lower, upper, oob_prediction).

The interval is centered at the out-of-bag ensemble prediction with half-width the 1 - alpha quantile of the out-of-bag absolute residuals. Coverage is approximately 1 - alpha under a strong-mixing condition (Xu & Xie 2021), not finite-sample distribution-free.

A thin convenience wrapper for the simple in-sample, static-width path; equivalent to EnbPIEnsemble().fit(...).predict_interval(calibrator=Static()). For time-local widths, out-of-sample prediction, or the adaptive calibrators, use EnbPIEnsemble directly.

tsbootstrap.uq.forecast_intervals(X: object, *, model: object, horizon: int, alpha: float = 0.1, n_bootstraps: int = 999, random_state: int | Generator | SeedSequence | None = None) tuple[ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]]][source]

Bootstrap forecast intervals: (lower, upper, median), each (horizon,).

The fitted model is simulated horizon steps past the data n_bootstraps times with resampled, centered innovations; the per-step quantiles form the interval.

tsbootstrap.uq.aci_halfwidths(calibration_scores: object, test_scores: object, *, alpha: float = 0.1, gamma: float = 0.05) tuple[ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]]][source]

Adaptive Conformal Inference: online-adapted interval half-widths.

Parameters:
  • calibration_scores (array-like, shape (m,)) – Nonconformity scores (e.g. |residual|) from the bootstrap calibration set.

  • test_scores (array-like, shape (T,)) – Realized scores |y_t - prediction_t| over the test sequence, in time order.

  • alpha (float) – Target miscoverage (interval target coverage is 1 - alpha).

  • gamma (float) – Adaptation step size. gamma = 0 recovers static conformal.

Returns:

  • halfwidths (ndarray, shape (T,)) – Interval half-width q_t to use at each step (prediction_t ± q_t).

  • alphas (ndarray, shape (T,)) – The adapted miscoverage level used at each step.

  • The update is alpha_{t+1} = alpha_t + gamma * (alpha - err_t) with

  • ``err_t = 1`` when step ``t`` is miscovered (a miss shrinks the level and widens the)

  • next interval. Coverage converges to 1 - alpha regardless of how the scores drift.

tsbootstrap.uq.nexcp_quantile(scores: object, *, alpha: float = 0.1, decay: float = 0.99) float[source]

Recency-weighted (nonexchangeable) conformal quantile of the scores.

Weights score i (0 = oldest, last = most recent) by decay ** (n - 1 - i) and returns the smallest score whose normalized weighted CDF reaches 1 - alpha. With decay = 1 this is the ordinary empirical quantile; smaller decay puts more weight on recent residuals, widening the interval when recent volatility rises.

tsbootstrap.uq.agaci_bounds(calibration_scores: object, test_residuals: object, *, alpha: float = 0.1, gammas: Sequence[float] | ndarray[tuple[int, ...], dtype[float64]] | None = None, boa_regret_constant: float = 2.2, infinite_sentinel: float | None = None, require_signed: bool = True) AgACIBounds[source]

Aggregated Adaptive Conformal Inference (AgACI): asymmetric adaptive half-widths.

Run a grid of ACI experts (one aci_halfwidths() pass per step size gamma) and aggregate their lower and upper interval endpoints with two independent Bernstein Online Aggregations under the pinball loss at tau = alpha / 2 and tau = 1 - alpha / 2. The online weights track whichever step size is currently best in pinball loss, so no single gamma has to be chosen and, unlike a large- gamma ACI expert, the aggregated interval is always finite. Section 3 of Zaffran et al. (2022) constructs AgACI exactly this way: the per-gamma ACI experts are symmetric over the absolute residuals, and the asymmetry of the final bounds comes entirely from the two independent BOA aggregations, not from the experts.

Parameters:
  • calibration_scores (array-like, shape (m,)) – The absolute out-of-bag residual buffer (e.g. EnbPIEnsemble.oob_residuals). Same role and coercion as aci_halfwidths()calibration_scores.

  • test_residuals (array-like, shape (T,)) – The SIGNED realized residuals s_t = y_t - prediction_t, time-ordered. This deliberately diverges from aci_halfwidths() (which takes absolute scores): AgACI’s two-sided pinball gradient needs the sign of each miss to load it onto the lower versus the upper bound. Must be finite; T is driven entirely by its length. The per-expert ACI pass is driven by abs(test_residuals) internally.

  • alpha (float) – Target miscoverage. Split into tau_lower = alpha / 2 and tau_upper = 1 - alpha / 2. Must be in (0, 1).

  • gammas (array-like or None) – The ACI step-size grid; each entry is one ACI expert (K = len(gammas)). All entries must be finite and non-negative. None selects DEFAULT_AGACI_GAMMAS (the K=30 grid of Zaffran et al.).

  • boa_regret_constant (float) – opera’s fixed Bernstein constant in the BOA learning-rate accumulation. Must be positive; exposed for faithfulness and pinning.

  • infinite_sentinel (float or None) – Finite clip for +inf expert half-widths (emitted when a large-gamma expert drives its level below 0, i.e. “cover everything”). None selects a deterministic, data-adaptive default min(10.0 * range_ref, 1e150) where range_ref is the larger of the finite expert half-widths and max(abs(test_residuals)) (falling back to 1.0 only for genuinely all-zero data). It scales linearly with the inputs, so agaci_bounds is scale-equivariant and the cover-everything expert stays the WIDEST at any data magnitude (a fixed floor would break that); the 1e150 cap is only an overflow guard for the squared-regret accumulator and is far beyond any real data. This default is deliberately not bit-comparable to opera’s fixed +/-1000.

  • require_signed (bool) – When True (default), test_residuals with zero strictly-negative entries on a stream of length >= 8 raises ValueError: an all-non-negative stream is the near-certain signature of a caller passing absolute scores by ACI habit, which makes the lower-bound indicator constant and biases that bound with no error. Set False for genuinely one-sided residual data.

Returns:

Named tuple (lower, upper), each shape (T,), float64, non-negative, and finite. The interval at step t is [prediction_t - lower[t], prediction_t + upper[t]]. BOTH fields are load-bearing, unlike aci_halfwidths()’ diagnostic second element.

Return type:

AgACIBounds

Notes

Coverage: AgACI carries a regret/efficiency guarantee (via BOA it is asymptotically no worse in pinball loss than the best fixed-gamma expert in the grid, with O(sqrt(T log K)) regret) but NO finite-T or asymptotic coverage certificate: aggregating the two endpoints breaks the bounded-level-excursion argument that gives single ACI its long-run coverage guarantee. Empirically it keeps marginal coverage close to 1 - alpha while producing shorter, always-finite intervals. Do not read this as a guarantee of 1 - alpha coverage.

Interval crossing is structurally impossible: every lower expert offset -q_k <= 0 and every upper offset +q_k >= 0, and a convex BOA combination preserves the sign, so lower and upper are both non-negative and the interval never crosses.

A deliberate fidelity divergence from the R source: when alpha_t >= 1 an ACI expert returns q = 0 (a finite confident expert) where the R source emits the absolute empty interval (0, 0); here that feeds BOA as a finite expert, not the +inf sentinel path. Non-bit-comparable to opera in that rare regime.

References

Zaffran, M., Feron, O., Goude, Y., Josse, J., and Dieuleveut, A. (2022). Adaptive Conformal Predictions for Time Series. Proceedings of the 39th International Conference on Machine Learning (ICML), PMLR 162, pp. 25834-25866.

Wintenberger, O. (2017). Optimal learning with Bernstein Online Aggregation. Machine Learning 106(1), pp. 119-141.

Gibbs, I. and Candes, E. (2021). Adaptive Conformal Inference Under Distribution Shift. Advances in Neural Information Processing Systems 34.

class tsbootstrap.uq.AgACIBounds(lower: NDArray[np.float64], upper: NDArray[np.float64])[source]

Bases: NamedTuple

The two load-bearing asymmetric half-widths AgACI produces per step.

Unlike aci_halfwidths(), whose second return element is a discardable diagnostic, BOTH fields here are load-bearing: the interval at step t is [prediction_t - lower[t], prediction_t + upper[t]]. Destructuring away either field (hw, _ = agaci_bounds(...)) is a bug, not an idiom.

lower: ndarray[tuple[int, ...], dtype[float64]]

Alias for field number 0

upper: ndarray[tuple[int, ...], dtype[float64]]

Alias for field number 1

tsbootstrap.uq.static_halfwidths(residuals: ndarray[tuple[int, ...], dtype[float64]], n_rows: int, *, alpha: float = 0.1) ndarray[tuple[int, ...], dtype[float64]][source]

Constant half-width: the global 1 - alpha quantile, broadcast to n_rows.

Parameters:
  • residuals (ndarray, shape (m,)) – Time-ordered out-of-bag absolute residuals (the calibration scores).

  • n_rows (int) – Number of prediction rows to emit a width for.

  • alpha (float) – Target miscoverage; the interval target coverage is 1 - alpha.

Returns:

The same scalar 1 - alpha quantile repeated for every row.

Return type:

ndarray, shape (n_rows,)

tsbootstrap.uq.sliding_window_halfwidths(residuals: ndarray[tuple[int, ...], dtype[float64]], n_rows: int, *, alpha: float = 0.1, window: int | None = None) ndarray[tuple[int, ...], dtype[float64]][source]

Time-local half-widths: a rolling 1 - alpha quantile of the residuals.

For row t the width is the 1 - alpha quantile of the most recent window residuals ending at t (the trailing window shrinks at the start of the series, where fewer residuals are available). The width therefore widens in high-volatility stretches and tightens in calm ones, which is the defining time-local mechanism of EnbPI (Xu & Xie 2021) and the static calibrator’s missing piece.

Parameters:
  • residuals (ndarray, shape (m,)) – Time-ordered out-of-bag absolute residuals (the calibration scores).

  • n_rows (int) – Number of prediction rows to emit a width for. Each row t uses the window of residuals ending at min(t, m - 1), so out-of-sample rows beyond the calibration set reuse the final trailing window.

  • alpha (float) – Target miscoverage; the interval target coverage is 1 - alpha.

  • window (int, optional) – Trailing window length. Defaults to min(len(residuals), 50).

Returns:

Per-row half-width; non-constant whenever local volatility varies.

Return type:

ndarray, shape (n_rows,)

class tsbootstrap.uq.BaseCalibratorSpec[source]

Bases: BaseModel

Open base for every calibrator spec: immutable, hashable, strict about options.

Third-party calibrators subclass this, declare a unique kind Literal, and register a function with register_calibrator(); predict_interval() then dispatches to them exactly like a built-in. Runtime safety comes from the registry, which raises for an unregistered spec.

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class tsbootstrap.uq.Static(*, kind: Literal['static'] = 'static')[source]

Bases: BaseCalibratorSpec

One global 1 - alpha quantile, the same half-width for every row (original EnbPI).

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class tsbootstrap.uq.SlidingWindow(*, kind: Literal['sliding_window'] = 'sliding_window', window: Annotated[int | None, Ge(ge=1)] = None)[source]

Bases: BaseCalibratorSpec

Rolling 1 - alpha quantile over a trailing window (time-local EnbPI, Xu and Xie 2021).

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class tsbootstrap.uq.ACI(*, kind: Literal['aci'] = 'aci', gamma: float = 0.05)[source]

Bases: BaseCalibratorSpec

Adaptive Conformal Inference (Gibbs and Candes 2021): online-adapted quantile level.

Requires the realized test scores as test_data; gamma is the adaptation step size (gamma = 0 recovers static conformal).

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class tsbootstrap.uq.NexCP(*, kind: Literal['nexcp'] = 'nexcp', decay: float = 0.99)[source]

Bases: BaseCalibratorSpec

Nonexchangeable conformal prediction (Barber et al. 2023): a recency-weighted quantile.

decay in (0, 1] weights recent residuals more heavily; decay = 1 recovers the ordinary empirical quantile.

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class tsbootstrap.uq.AgACI(*, kind: Literal['agaci'] = 'agaci', gammas: tuple[float, ...] | None = None, require_signed: bool = True, boa_regret_constant: float = 2.2, infinite_sentinel: float | None = None)[source]

Bases: BaseCalibratorSpec

Aggregated Adaptive Conformal Inference (Zaffran et al. 2022): asymmetric adaptive bounds.

Aggregates a grid of ACI experts with Bernstein Online Aggregation, so no single step size has to be chosen. Requires the SIGNED realized residuals as test_data. The fields mirror agaci_bounds() one-to-one; gammas=None selects the K=30 grid of the paper.

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

tsbootstrap.uq.percentile_interval(statistics: ndarray[tuple[int, ...], dtype[float64]], *, alpha: float = 0.05) tuple[ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]]][source]

Percentile interval: the alpha/2 and 1 - alpha/2 replicate quantiles.

Parameters:
  • statistics (ndarray, shape (B,) or (B, k)) – Bootstrap replicate statistics, one row per replicate.

  • alpha (float) – Target miscoverage; the interval target coverage is 1 - alpha.

Returns:

lower, upper – The two-sided percentile bounds (0-d arrays for a scalar statistic). The quantiles use numpy’s linear interpolation.

Return type:

ndarray, shape statistics.shape[1:]

tsbootstrap.uq.basic_interval(statistics: ndarray[tuple[int, ...], dtype[float64]], theta_hat: ndarray[tuple[int, ...], dtype[float64]], *, alpha: float = 0.05) tuple[ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]]][source]

Basic (reflected-percentile) interval around the point estimate.

The percentile interval is reflected through theta_hat: lower = 2 * theta_hat - q_hi and upper = 2 * theta_hat - q_lo, where q_lo and q_hi are the alpha/2 and 1 - alpha/2 replicate quantiles. This corrects the percentile interval’s bias when the replicate distribution is shifted relative to theta_hat.

Parameters:
  • statistics (ndarray, shape (B,) or (B, k)) – Bootstrap replicate statistics, one row per replicate.

  • theta_hat (ndarray, shape statistics.shape[1:]) – The statistic evaluated on the original series.

  • alpha (float) – Target miscoverage; the interval target coverage is 1 - alpha.

Returns:

lower, upper – The two-sided basic-interval bounds.

Return type:

ndarray, shape statistics.shape[1:]

tsbootstrap.uq.jackknife_statistics(x: ndarray[tuple[int, ...], dtype[float64]], statistic: Callable[[ndarray[tuple[int, ...], dtype[floating]], ndarray[tuple[int, ...], dtype[int32]] | None], object]) ndarray[tuple[int, ...], dtype[float64]][source]

Delete-one jackknife: the statistic recomputed on each leave-one-row-out sample.

Parameters:
  • x (ndarray, shape (n,) or (n, d)) – The original observations, one row per observation.

  • statistic (callable (values, indices) -> scalar | array) – The reducer to recompute on each leave-one-out sample. It is called with indices=None (the helper operates on a raw array with no resampling provenance), matching the bootstrap_reduce() contract.

Returns:

The n leave-one-out statistics stacked along axis 0.

Return type:

ndarray, shape (n,) or (n, k)

tsbootstrap.uq.block_jackknife_se(values: ndarray[tuple[int, ...], dtype[floating]], statistic: Callable[[ndarray[tuple[int, ...], dtype[floating]], ndarray[tuple[int, ...], dtype[int32]] | None], object], *, block_length: int, indices: ndarray[tuple[int, ...], dtype[int32]] | None = None) ndarray[tuple[int, ...], dtype[float64]][source]

Delete-a-group (block) jackknife standard error, Kunsch 1989.

The rows are split into g = n // block_length non-overlapping blocks; the statistic is recomputed with each block deleted, and the standard error is sqrt((g - 1) / g * sum_j (theta_(j) - mean_j)^2). Deleting whole blocks rather than single rows keeps the estimate consistent under temporal dependence. With block_length=1 this reduces exactly to the classic delete-one jackknife variance.

Parameters:
  • values (ndarray, shape (n,) or (n, d)) – The observations, one row per observation.

  • statistic (callable (values, indices) -> scalar | array) – The reducer to recompute on each block-deleted sample.

  • block_length (int) – Number of consecutive rows per deleted block.

  • indices (ndarray of int32, shape (n,), optional) – Original-observation indices to slice in lockstep with values: when supplied, the same block of rows is removed from indices and passed to statistic alongside the deleted-block values. None (the default) passes None to the reducer.

Returns:

The block-jackknife standard error per statistic component.

Return type:

ndarray, shape () or (k,)

tsbootstrap.uq.studentized_interval(statistics: ndarray[tuple[int, ...], dtype[float64]], se_statistics: ndarray[tuple[int, ...], dtype[float64]], theta_hat: ndarray[tuple[int, ...], dtype[float64]], se_hat: ndarray[tuple[int, ...], dtype[float64]], *, alpha: float = 0.05) tuple[ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]]][source]

Studentized (bootstrap-t) interval from per-replicate standard errors.

Each replicate is pivoted to t_b = (theta_b - theta_hat) / se_b; the interval inverts the pivot, lower = theta_hat - t_{1 - alpha/2} * se_hat and upper = theta_hat - t_{alpha/2} * se_hat. The pivot’s upper quantile therefore sets the lower bound (the minus sign flips the orientation), which is what makes the interval second-order correct for smooth statistics when se_b and se_hat are dependence-aware (e.g. block_jackknife_se()).

Parameters:
  • statistics (ndarray, shape (B,) or (B, k)) – Bootstrap replicate statistics.

  • se_statistics (ndarray, same shape as statistics) – The per-replicate standard error of each statistic.

  • theta_hat (ndarray, shape statistics.shape[1:]) – The statistic on the original series.

  • se_hat (ndarray, shape statistics.shape[1:]) – The standard error of theta_hat on the original series.

  • alpha (float) – Target miscoverage; the interval target coverage is 1 - alpha.

Returns:

lower, upper – The two-sided studentized bounds.

Return type:

ndarray, shape statistics.shape[1:]

Raises:

ValueError – If any per-replicate or point standard error is zero (the pivot is undefined).

tsbootstrap.uq.jackknife_acceleration(x: ndarray[tuple[int, ...], dtype[float64]], statistic: Callable[[ndarray[tuple[int, ...], dtype[floating]], ndarray[tuple[int, ...], dtype[int32]] | None], object]) ndarray[tuple[int, ...], dtype[float64]][source]

Efron’s BCa acceleration constant from the delete-one jackknife.

The acceleration is a = sum(d_i^3) / (6 * (sum(d_i^2))^{3/2}) with d_i = mean(theta_jack) - theta_(i) the centred leave-one-out statistics (Efron 1987). It measures the skewness of the statistic’s sampling distribution. Where the denominator is zero (a constant jackknife, e.g. a degenerate sample) the acceleration is defined as zero.

Parameters:
  • x (ndarray, shape (n,) or (n, d)) – The original observations, one row per observation.

  • statistic (callable (values, indices) -> scalar | array) – The reducer whose acceleration is estimated.

Returns:

The acceleration per statistic component.

Return type:

ndarray, shape () or (k,)

tsbootstrap.uq.bca_interval(statistics: ndarray[tuple[int, ...], dtype[float64]], theta_hat: ndarray[tuple[int, ...], dtype[float64]], acceleration: ndarray[tuple[int, ...], dtype[float64]], *, alpha: float = 0.05) tuple[ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]]][source]

Bias-corrected and accelerated (BCa) interval, Efron 1987.

The two endpoint probability levels are adjusted for median bias (the bias-correction z0) and skewness (the acceleration) before reading the replicate quantiles. z0 comes from the tie-adjusted fraction of replicates below theta_hat, p0 = (#{theta_b < theta_hat} + 0.5 * #{theta_b == theta_hat}) / B. With z0 = 0 and acceleration = 0 the interval reduces exactly to percentile_interval().

This function is method-agnostic pure math: it takes a precomputed acceleration. The jackknife acceleration (jackknife_acceleration()) is defined under independent sampling, so restricting BCa to the IID method spec is an orchestrator-level concern, not enforced here.

Parameters:
  • statistics (ndarray, shape (B,) or (B, k)) – Bootstrap replicate statistics.

  • theta_hat (ndarray, shape statistics.shape[1:]) – The statistic on the original series.

  • acceleration (ndarray, shape statistics.shape[1:]) – The precomputed acceleration constant per component.

  • alpha (float) – Target miscoverage; the interval target coverage is 1 - alpha.

Returns:

lower, upper – The two-sided BCa bounds.

Return type:

ndarray, shape statistics.shape[1:]

Raises:

ValueError – If the bias-correction fraction p0 is 0 or 1 for any component (z0 is infinite, so BCa is degenerate).

tsbootstrap.uq.conf_int(X: object, statistic: str | tuple[str, float] | Callable[[ndarray[tuple[int, ...], dtype[floating]], ndarray[tuple[int, ...], dtype[int32]] | None], object], *, method: BaseMethodSpec, kind: Literal['percentile', 'basic', 'studentized', 'bca'] = 'percentile', alpha: float = 0.05, n_bootstraps: int = 999, random_state: int | Generator | SeedSequence | None = None, backend: Literal['numpy', 'compiled'] = 'numpy', se_statistic: Callable[[ndarray[tuple[int, ...], dtype[floating]], ndarray[tuple[int, ...], dtype[int32]] | None], object] | None = None, se_block_length: int | None = None) tuple[ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]]][source]

Bootstrap confidence interval for a statistic of one series, in one call.

Runs a single bootstrap_reduce() pass with method and reads the requested interval from the replicate statistics. To reuse an existing run instead, call the interval functions directly on its statistics array (e.g. percentile_interval(result.statistics)).

Parameters:
  • X (array-like, shape (n,) or (n, d)) – The observed series (any input bootstrap() accepts).

  • statistic (str, (“quantile”, q) tuple, or callable (values, indices) -> theta) – The statistic to bootstrap. Built-in names ("mean", "var", "std") are required for backend="compiled".

  • method (BaseMethodSpec) – Any method spec. BCa additionally requires IID (see below).

  • kind ({"percentile", "basic", "studentized", "bca"}) – The interval family. studentized computes a dependence-aware per-replicate standard error via block_jackknife_se() (or se_statistic); bca is available for the IID spec only, because its jackknife acceleration is defined under independent sampling (Efron 1987; for dependent data use studentized, the second-order-correct route of Gotze and Kunsch 1996).

  • alpha (float) – Target miscoverage; the interval targets 1 - alpha coverage.

  • n_bootstraps (int) – Number of bootstrap replicates.

  • random_state (int, Generator, SeedSequence, or None) – Seeding, with the library’s per-replicate determinism contract.

  • backend ({"numpy", "compiled"}) – "compiled" accelerates percentile/basic with a built-in string statistic; studentized/bca need Python callables per replicate and raise a typed error under the compiled backend.

  • se_statistic (callable, optional) – Override for the per-replicate standard-error estimator (studentized only).

  • se_block_length (int, optional) – Override for the block-jackknife block length (studentized only).

Returns:

lower, upper, point – Interval bounds and the statistic on the original series, each shaped like one replicate’s statistic (0-d for a scalar statistic).

Return type:

ndarray

tsbootstrap.uq.conf_int_panel(panel: object, statistic: str | tuple[str, float] | Callable[[ndarray[tuple[int, ...], dtype[floating]], ndarray[tuple[int, ...], dtype[int32]] | None], object], *, method: BaseMethodSpec, indptr: object | None = None, kind: Literal['percentile', 'basic', 'studentized'] = 'percentile', alpha: float = 0.05, n_bootstraps: int = 999, random_state: int | Generator | SeedSequence | None = None, backend: Literal['numpy', 'compiled'] = 'numpy', se_statistic: Callable[[ndarray[tuple[int, ...], dtype[floating]], ndarray[tuple[int, ...], dtype[int32]] | None], object] | None = None, se_block_length: int | None = None) tuple[ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[float64]]][source]

Per-series bootstrap confidence intervals over a ragged panel, in one pass.

The panel counterpart of conf_int(), built on bootstrap_reduce_panel() (observation-resampling methods only, matching that function’s contract). Returns arrays with a leading num_series axis.

BCa is not offered for panels: it is gated to IID data at the single-series level and a per-series jackknife acceleration sweep is deliberately out of scope. The studentized kind requires an explicit block length (either se_block_length or an integer block length on the method spec): replicate reducers see one series at a time without its identity, so a per-series automatic block length cannot be resolved honestly, and one Politis-White fit on a mixed panel would be statistically arbitrary.