pmcprg.diagnostics¶
Goodness-of-fit and inference diagnostics, independent of any specific model class: each utility takes raw NumPy arrays (and optionally a CDF callable) and returns a typed result object.
Multivariate Kolmogorov-Smirnov test¶
Naaman (2021)'s finite-sample extension.
mks_1samp ¶
mks_1samp(sample: ndarray, cdf: Callable[[ndarray], float], *, alpha: float = 0.05, asymptotic: bool = False) -> MKSResult
One-sample multivariate KS test.
Test H0: sample is drawn from the distribution whose CDF is
cdf.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sample
|
ndarray
|
|
required |
cdf
|
Callable[[ndarray], float]
|
|
required |
alpha
|
float
|
|
0.05
|
asymptotic
|
bool — use the asymptotic critical value (tighter, but
|
|
False
|
Returns:
| Type | Description |
|---|---|
MKSResult — see :class:`MKSResult`.
|
|
mks_2samp ¶
mks_2samp(sample_a: ndarray, sample_b: ndarray, *, alpha: float = 0.05, asymptotic: bool = False) -> MKSResult
Two-sample multivariate KS test.
Test H0: sample_a and sample_b share the same distribution.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sample_a
|
np.ndarray, shape ``(N_a, d)`` and ``(N_b, d)``.
|
Must have the same trailing dimension. 1-D arrays are reshaped
to |
required |
sample_b
|
np.ndarray, shape ``(N_a, d)`` and ``(N_b, d)``.
|
Must have the same trailing dimension. 1-D arrays are reshaped
to |
required |
alpha
|
float
|
|
0.05
|
asymptotic
|
float
|
|
0.05
|
Returns:
| Type | Description |
|---|---|
MKSResult — see :class:`MKSResult`.
|
|
mks_test ¶
mks_test(sample: ndarray, other: ndarray | None = None, cdf: Callable[[ndarray], float] | None = None, *, alpha: float = 0.05, asymptotic: bool = False) -> MKSResult
Dispatch to :func:mks_1samp or :func:mks_2samp.
Exactly one of other / cdf must be provided.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sample
|
see :func:`mks_1samp` and :func:`mks_2samp`.
|
|
required |
other
|
see :func:`mks_1samp` and :func:`mks_2samp`.
|
|
required |
cdf
|
see :func:`mks_1samp` and :func:`mks_2samp`.
|
|
required |
alpha
|
float
|
|
0.05
|
asymptotic
|
float
|
|
0.05
|
Returns:
| Type | Description |
|---|---|
MKSResult.
|
|
MKSResult
dataclass
¶
MKSResult(statistic: float, critical_value: float, alpha: float, reject: bool, n_samples_x: int, n_samples_y: int | None, dim: int, asymptotic: bool)
Typed result of a multivariate Kolmogorov-Smirnov test.
Fields
statistic : float — the KS statistic (max absolute deviation).
critical_value : float — the critical value at significance level
:attr:alpha. Computed under the finite-sample
bound (default) or the asymptotic approximation
(asymptotic=True).
alpha : float — the significance level used.
reject : bool — True if statistic > critical_value
(H0 rejected at level α).
n_samples_x : int — size of the (first) sample.
n_samples_y : int | None — size of the second sample (None for
the one-sample test).
dim : int — observation dimensionality.
asymptotic : bool — whether the critical value uses the
asymptotic approximation.
Parametric bootstrap¶
Model-level calibration of any post-fit statistic — resampling whole series from the fitted model, needed because a tabulated critical value is wrong on a fitted model (estimated reference, dependent observations, per-state samples that are assigned rather than given).
parametric_bootstrap ¶
parametric_bootstrap(model, Y, statistic: Callable[[Any, ndarray, Generator], Mapping[Hashable, float]], *, B: int = 200, seed: int = 0, max_len: int | None = None, progress_cb: Callable[[int, int, float, str], None] | None = None, simulate_fn: Callable[..., tuple] | None = None, n_jobs: int | None = None) -> dict[Hashable, BootstrapResult]
Calibrate statistic against series simulated from model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
PMCModel
|
The fitted model. It is both what is being tested and what generates the null — see the module docstring on what that means for the hypothesis actually being tested. |
required |
Y
|
array - like
|
The observations, shape |
required |
statistic
|
callable
|
|
required |
B
|
int
|
Replicates. Cost is linear in |
200
|
max_len
|
int
|
Cap on the series length. Above it a contiguous prefix is used, and replicates are simulated at that same length so calibration is untouched — what is lost is sample size, not validity. Contiguous because thinning would destroy the serial dependence the bootstrap exists to absorb. |
None
|
progress_cb
|
callable
|
|
None
|
simulate_fn
|
callable
|
Defaults to :func: |
None
|
n_jobs
|
int
|
|
None
|
Returns:
| Type | Description |
|---|---|
dict mapping each key returned by ``statistic`` to a
|
|
class:`BootstrapResult`. Keys seen only in replicates and never in the
|
|
observed pass are dropped: there is nothing to compare them to.
|
|
BootstrapResult
dataclass
¶
BootstrapResult(observed: float, p_value: float, n_valid: int, B: int, n_series: int)
One statistic's observed value and its bootstrap p-value.
Fields
observed : float — the statistic on the real data.
p_value : float — (1 + #{T_b ≥ T_obs}) / (n_valid + 1), the exactly
valid Monte-Carlo p-value (Davison & Hinkley 1997, ch. 4; Phipson & Smyth 2010): it can never be 0, and the
smallest reportable value is 1/(B + 1). NaN when no
replicate landed.
n_valid : int — replicates that produced a finite value. Report it:
a p-value resting on 12 of 200 draws is not the same claim as
one resting on 200, and the difference is invisible in the
number itself.
B : int — replicates requested.
n_series : int — length of the series actually used, which may be
shorter than the input (see max_len).
Smooth tests (Neyman)¶
Legendre-polynomial components of a fitted margin's goodness of fit — one component per kind of departure (location, dispersion, asymmetry, tails).
neyman_components ¶
neyman_components(sample, cdf=None, *, order: int = 4) -> NeymanResult
Smooth-test components of sample against cdf.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sample
|
array-like, shape ``(n,)``
|
The observations. One-dimensional: the construction rests on the probability integral transform, which has no direct multivariate analogue here. |
required |
cdf
|
callable
|
Vectorised CDF of the reference distribution. Pass |
None
|
order
|
int
|
Number of components, at most 4 — beyond |
4
|
Returns:
| Type | Description |
|---|---|
NeymanResult
|
|
neyman_test ¶
neyman_test(p_values, *, alpha: float = 0.05) -> tuple[float, int]
Combine per-component p-values into one verdict, paying multiplicity.
p_values are the bootstrap p-values of V_j², in component order.
Returns (corrected_p, index) where index is the 1-based position
of the component that drove it.
Bonferroni, not the omnibus Σ V_j². Both hold their level; measured
over 200 datasets per alternative, Bonferroni rejects a Student-t margin
at 0.338 against the omnibus's 0.180 and a skew-normal one at 0.480
against 0.290. Concentrating on one component and paying a factor of four
beats spreading over four degrees of freedom, because a real margin is
usually wrong in one way.
Reporting the uncorrected minimum would take the level from 0.05 to 0.175 — measured on the same datasets. The factor is not optional.
NeymanResult
dataclass
¶
NeymanResult(components: ndarray, squares: ndarray, n: int, component: str = '', index: int = 0)
Components of a smooth test, and the multiplicity-corrected verdict.
Fields
components : np.ndarray — the signed V_j, asymptotically N(0, 1)
under a fully specified null; with an estimated margin the
null law changes (Kallenberg & Ledwina 1997), which is why
the package calibrates them by parametric_bootstrap.
squares : np.ndarray — V_j², the per-component statistics.
n : int — sample size the components were computed on.
component : str — name of the largest component: where the margin
departs, which a single p-value cannot say.
index : int — its 1-based position.
Read the signed components, not only the largest. A single name is a
summary and summaries mislead: heavy tails show up as V₂ negative
and V₄ positive, because extra mass in the extremes comes with a
hollowed-out shoulder. Taking the argmax alone would label that
"dispersion" and lose half the diagnosis.
COMPONENT_NAMES
module-attribute
¶
COMPONENT_NAMES = ('location', 'dispersion', 'asymmetry', 'tail weight')
Copula-family comparison (Vuong / Clarke)¶
Is a copula family choice significant? Weighted Vuong (1989) and Clarke (2007) tests with a HAC variance, over all pairs of a candidate set, and over every pair of states after an ICE run.
vuong_test ¶
vuong_test(logc_a, logc_b, weights=None, *, k_a: float = 1, k_b: float = 1, correction: str = 'none', alpha: float = 0.05, bandwidth: int | str = 'auto', n_eff: str = 'sum', names: tuple[str, str] = ('A', 'B'), ranks: bool = False, uv=None, dm_du=None, dm_dv=None, pretest_omega2: bool = False) -> ComparisonResult
Weighted Vuong (1989) test of family A against family B.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
logc_a
|
pointwise log-densities ``log c_A(u_n, v_n; θ̂_A)`` and
|
|
required |
logc_b
|
pointwise log-densities ``log c_A(u_n, v_n; θ̂_A)`` and
|
|
required |
weights
|
|
None
|
|
k_a
|
float
|
|
1
|
k_b
|
float
|
|
1
|
correction
|
str
|
|
'none'
|
alpha
|
float
|
|
0.05
|
bandwidth
|
int | str
|
|
'auto'
|
n_eff
|
str
|
|
'sum'
|
names
|
tuple[str, str]
|
|
('A', 'B')
|
ranks
|
bool
|
|
False
|
uv
|
required when ``ranks=True`` — the pseudo-observations
|
|
None
|
dm_du
|
required when ``ranks=True`` — the pseudo-observations
|
|
None
|
dm_dv
|
required when ``ranks=True`` — the pseudo-observations
|
|
None
|
pretest_omega2
|
run Vuong's (1989) ``H0: ω² = 0`` pre-test (see
|
|
False
|
Returns:
| Type | Description |
|---|---|
ComparisonResult — ``Z = √n_eff (m̄_w − K/n_eff) / σ̂``, two-sided normal
|
|
p-value, decision ``"A"`` / ``"B"`` / ``"tie"``. See the module docstring
|
|
for the variance, the corrections and the caveats (margins estimated,
|
|
Chen & Fan 2006; overlapping families).
|
|
clarke_test ¶
clarke_test(logc_a, logc_b, weights=None, *, k_a: float = 1, k_b: float = 1, correction: str = 'none', alpha: float = 0.05, bandwidth: int | str = 'auto', n_eff: str = 'sum', method: str = 'auto', names: tuple[str, str] = ('A', 'B')) -> ComparisonResult
Weighted distribution-free sign test of Clarke (2007).
H₀: median(m_n) = 0, with the corrected differences
m_n − K / n_eff (Clarke 2007). Points whose corrected
difference is exactly zero carry no sign and are dropped, as in the
classical sign test.
Takes the same parameters as :func:vuong_test, plus method.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
method
|
``"exact"`` — binomial ``B ~ Bin(N, 1/2)`` on the weighted count
|
|
'auto'
|
Notes
The binomial law assumes independent signs: with serially dependent pairs (ICE) use the default HAC.
comparison_matrix ¶
comparison_matrix(log_densities: Mapping[str, ndarray], weights=None, *, n_params: Mapping[str, float] | None = None, test: str = 'vuong', correction: str = 'none', alpha: float = 0.05, bandwidth: int | str = 'auto', n_eff: str = 'sum', **test_kwargs) -> ComparisonMatrix
Pairwise tests between all families of a candidate set.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
log_densities
|
``{name: log c_name(u_n, v_n; θ̂_name)}``, every array on
|
|
required |
weights
|
|
None
|
|
n_params
|
Mapping[str, float] | None
|
|
None
|
test
|
str
|
|
'vuong'
|
**test_kwargs
|
forwarded to the test.
|
|
{}
|
Notes
Each unordered pair is tested once; the lower triangle is the swapped result, so the matrix is exactly antisymmetric.
confidence_set ¶
confidence_set(log_densities: Mapping[str, ndarray], weights=None, *, n_params: Mapping[str, float] | None = None, best: str | None = None, scores: Mapping[str, float] | None = None, test: str = 'vuong', correction: str = 'none', alpha: float = 0.05, adjust: str | None = None, bandwidth: int | str = 'auto', n_eff: str = 'sum', **test_kwargs) -> ConfidenceSet
Families not significantly worse than the best one.
The reference best is, by default, the family with the highest
scores — or, without scores, the highest corrected weighted
log-likelihood Σ w log c − K (the ranking of AIC for
correction="akaike", of BIC for "schwarz"). Every other family
F is tested against it; F is excluded only when the test
significantly prefers best (p ≤ alpha after adjust and a
statistic of the sign favouring best). The rest are retained: they
are statistically tied with the best, or better than it under the test
(possible when best comes from a non-likelihood score).
adjust (None, "holm", "bonferroni") corrects the m − 1
p-values for multiplicity. This is a set of pairwise comparisons with one
reference, not the model confidence set of Hansen, Lunde & Nason (2011).
ice_pair_comparisons ¶
ice_pair_comparisons(model, Y, xi=None, *, candidates: Sequence[str] | None = None, criterion: str | None = None, test: str = 'vuong', correction: str | None = None, alpha: float = 0.05, adjust: str | None = None, bandwidth: int | str = 'auto', n_eff: str = 'sum', pairs: Sequence[tuple[int, int]] | None = None, **test_kwargs) -> dict[tuple[int, int], PairComparison]
Is the copula family ICE selected for each pair of states significant?
For every pair (i, j) this rebuilds the weighted sample the ICE
M-step fits the copula c_ij on — (F_ij(y_n), F_ji(y_{n+1})) with
weight ξ_n(i, j) (DerrodePieczynski_CSDA2013 Eq. 12), the CDFs clipped
as in pmcprg.pmc.ice._m_step — refits every candidate with the M-step's own
weighted MLE (ice._fit_copula_params), scores it with the ICE
criterion (ice._SCORE_FN), and compares the candidates with
:func:vuong_test or :func:clarke_test.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
|
required | |
Y
|
|
required | |
xi
|
|
None
|
|
candidates
|
copula SHORT_NAMEs; ``None`` uses the ICE configuration of
|
|
None
|
criterion
|
str | None
|
|
None
|
test
|
str
|
|
'vuong'
|
correction
|
``None`` takes the one consistent with ``criterion``
|
|
None
|
alpha
|
see :func:`confidence_set`.
|
|
0.05
|
adjust
|
see :func:`confidence_set`.
|
|
0.05
|
bandwidth
|
see :func:`confidence_set`.
|
|
0.05
|
n_eff
|
see :func:`confidence_set`.
|
|
0.05
|
pairs
|
Sequence[tuple[int, int]] | None
|
|
None
|
Returns:
| Type | Description |
|---|---|
``{(i, j): PairComparison}``. ``tied_with_runner_up`` answers the
|
|
question "is the selected family significantly better than the next
|
|
one?". Nothing in ``model`` is modified.
|
|
Notes
selected is the criterion's choice on this sample; it equals the
model's family when ICE stopped at convergence (the returned model then
produced ξ), and may differ after max_iter iterations. The test
ignores the estimation of the margins and of ξ (Chen & Fan 2006;
see the module docstring).
ComparisonMatrix
dataclass
¶
ComparisonMatrix(names: list[str], statistic: ndarray, p_value: ndarray, decision: list[list[str]], results: dict[tuple[str, str], ComparisonResult], test: str, alpha: float, correction: str)
All pairwise comparisons of a candidate set.
statistic[a, b] is the statistic of names[a] against names[b]
(antisymmetric, 0 on the diagonal); p_value is symmetric (1 on the
diagonal); decision[a][b] is the preferred family's name, "tie" or
"undetermined" ("—" on the diagonal). results[(A, B)] holds
the :class:ComparisonResult for every ordered pair A ≠ B.
ComparisonResult
dataclass
¶
ComparisonResult(test: str, names: tuple[str, str], statistic: float, p_value: float, alpha: float, decision: str, method: str, estimate: float, penalty: float, sd: float, n_eff: float, sum_weights: float, bandwidth: int, correction: str, n_eff_kind: str, count: float = math.nan, n_trials: float = math.nan, ranks: bool = False, omega2: 'Omega2Test | None' = None)
Outcome of one pairwise test of family A against family B.
Attributes:
| Name | Type | Description |
|---|---|---|
test |
``"vuong"`` or ``"clarke"``.
|
|
names |
``(name_A, name_B)``.
|
|
statistic |
standardised statistic, ``> 0`` favours ``A``. For Clarke's
|
exact test, |
p_value |
two-sided p-value.
|
|
alpha |
level of the decision.
|
|
decision |
``"A"``, ``"B"``, ``"tie"`` or ``"undetermined"``.
|
|
method |
``"normal"``, ``"exact"`` (binomial), ``"infinite"`` (one
|
likelihood is |
estimate |
Vuong — weighted mean ``m̄_w`` of the *uncorrected*
|
differences (nat per unit weight); Clarke — weighted share of positive corrected differences. |
penalty |
total correction ``K`` subtracted from ``Σ w m``.
|
|
sd |
long-run standard deviation ``σ̂`` (NaN when undefined).
|
|
n_eff |
effective sample size (``Σw`` or Kish).
|
|
sum_weights |
``Σ w`` over the points that entered the test.
|
|
bandwidth |
HAC lag truncation ``L`` actually used.
|
|
correction, n_eff_kind |
the options used.
|
|
count, n_trials |
Clarke only — weighted count of positive differences and
|
weighted number of non-zero differences. |
ranks |
Vuong only — whether the Chen & Fan (2006) rank-margin
|
correction was applied (see :func: |
omega2 |
Vuong only, when ``pretest_omega2=True`` — the
|
:class: |
ConfidenceSet
dataclass
¶
ConfidenceSet(best: str, members: list[str], excluded: list[str], scores: dict[str, float], comparisons: dict[str, ComparisonResult], p_adjusted: dict[str, float], alpha: float, adjust: str | None, test: str, correction: str)
Families not significantly worse than a reference family.
Attributes:
| Name | Type | Description |
|---|---|---|
best |
the reference family (kept by construction).
|
|
members |
retained families, reference first, then by decreasing score.
|
|
excluded |
families significantly worse than ``best``.
|
|
scores |
the score used for the ordering (corrected weighted
|
log-likelihood, or the caller's scores). |
comparisons |
``{name: test(best, name)}`` for every other family.
|
|
p_adjusted |
the p-values after ``adjust`` (equal to the raw ones when
|
|
PairComparison
dataclass
¶
PairComparison(pair: tuple[int, int], model_family: str, selected: str, runner_up: str | None, criterion: str, scores: dict[str, float], log_likelihood: dict[str, float], params: dict[str, dict], n_params: dict[str, int], sum_weights: float, matrix: ComparisonMatrix | None, vs_runner_up: ComparisonResult | None, confidence_set: ConfidenceSet | None, failed: list[str] = list(), log_densities: dict[str, ndarray] = dict(), weights: ndarray | None = None)
Family comparison for one pair of states (i, j) of a fitted chain.
Attributes:
| Name | Type | Description |
|---|---|---|
pair |
``(i, j)``.
|
|
model_family |
the family the fitted model carries for the pair.
|
|
selected |
the family the ICE criterion selects on this weighted
|
sample (what the next M-step would keep; equal to
|
runner_up |
second family by the criterion (``None`` with a single
|
usable candidate). |
criterion |
the ICE selection criterion used for the ranking.
|
|
scores |
criterion score of every candidate (higher is better).
|
|
log_likelihood |
``Σ ξ log c`` of every candidate at its fitted parameters.
|
|
params |
fitted parameters of every candidate.
|
|
n_params |
parameter count of every candidate.
|
|
sum_weights |
``Σ_n ξ_n(i, j)``.
|
|
matrix |
:class:`ComparisonMatrix` over the usable candidates.
|
|
vs_runner_up |
``test(selected, runner_up)``.
|
|
confidence_set |
families not significantly worse than ``selected``.
|
|
failed |
candidates whose fitted copula could not be evaluated.
|
|
log_densities |
``{family: log c(u_n, v_n)}`` at the fitted parameters, on
|
the |
weights |
``ξ_n(i, j)``, shape ``(N − 1,)``.
|
|
tied_with_runner_up
property
¶
tied_with_runner_up: bool
True when the selected family is not significantly better than
the runner-up (False when there is no runner-up).
Radial symmetry and exchangeability screens¶
Cramér-von Mises statistics on the empirical copula against its radial reflection / its transpose, calibrated by a parametric (Gaussian-surrogate) bootstrap. Unweighted only.
radial_symmetry_test ¶
radial_symmetry_test(x: ndarray, y: ndarray, *, B: int = 200, seed: int = 0, alpha: float = 0.05, weights=None, bootstrap: str = 'parametric', multiplier: str = 'normal', block_length: int | str = 'auto', block_kernel: str = 'bartlett', n_jobs: int | None = None) -> RadialSymmetryResult
Test H0: the copula of (x, y) is radially symmetric (FR-10).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
ndarray
|
|
required |
y
|
ndarray
|
|
required |
B
|
int
|
|
200
|
seed
|
int
|
|
0
|
alpha
|
float
|
|
0.05
|
weights
|
|
None
|
|
bootstrap
|
str
|
|
'parametric'
|
multiplier
|
``'normal'`` (default) or ``'rademacher'`` — the i.i.d.
|
|
'normal'
|
block_length
|
the dependence length ``ℓ`` of the multiplier sequence,
|
|
'auto'
|
block_kernel
|
``'bartlett'`` (default) or ``'parzen'``, the smoothing
|
|
'bartlett'
|
n_jobs
|
int | None
|
|
None
|
Returns:
| Type | Description |
|---|---|
RadialSymmetryResult.
|
|
radial_symmetry_statistic ¶
radial_symmetry_statistic(u: ndarray, v: ndarray) -> float
T_n of the module docstring, from pseudo-observations already in [0, 1].
Unlike :func:radial_symmetry_test, this does not rank-transform its
input: pass pseudo-observations, not raw data, so that a bootstrap
replicate (already uniform-margined by construction) and the observed
sample are put through the identical computation.
RadialSymmetryResult
dataclass
¶
RadialSymmetryResult(statistic: float, p_value: float, reject: bool, alpha: float, n: int, tau_hat: float, B: int, n_valid: int, bootstrap: str = 'parametric', block_length: int = 1)
Typed result of :func:radial_symmetry_test.
Fields
statistic : float — the Cramér–von Mises statistic T_n (see module
docstring). NaN when n < MIN_N.
p_value : float — bootstrap Monte-Carlo p-value, never exactly 0
(Davison & Hinkley 1997). NaN when no replicate is available.
reject : bool — p_value < alpha (H0 = "radially symmetric").
False whenever p_value is NaN.
alpha : float — significance level used for reject.
n : int — number of pairs the statistic was computed on.
tau_hat : float — Kendall's τ of the sample. For bootstrap='parametric'
it is also the calibrating Gaussian surrogate's only fitted
parameter; for bootstrap='multiplier' it is reported for
diagnostics only (the multiplier bootstrap fits nothing).
B : int — bootstrap replicates requested.
n_valid : int — replicates that produced a finite statistic.
bootstrap : str — 'parametric' (default), 'multiplier' or
'dependent-multiplier', the calibration method actually
used — see the module docstring.
block_length : int — the multiplier dependence length ℓ actually used
(FR-5). Always 1 for the two other methods, and 1 for
'dependent-multiplier' means it coincided with the
i.i.d. one; report it, since the whole question FR-5 raises
is how much the answer moves with ℓ.
exchangeability_test ¶
exchangeability_test(x: ndarray, y: ndarray, *, B: int = 200, seed: int = 0, alpha: float = 0.05, weights=None, bootstrap: str = 'parametric', multiplier: str = 'normal', block_length: int | str = 'auto', block_kernel: str = 'bartlett', n_jobs: int | None = None) -> ExchangeabilityResult
Test H0: the copula of (x, y) is exchangeable, C(u,v) = C(v,u) (FR-10).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
ndarray
|
|
required |
y
|
ndarray
|
|
required |
B
|
int
|
|
200
|
seed
|
int
|
|
0
|
alpha
|
float
|
|
0.05
|
weights
|
|
None
|
|
bootstrap
|
str
|
|
'parametric'
|
multiplier
|
``'normal'`` (default) or ``'rademacher'`` — the i.i.d.
|
|
'normal'
|
block_length
|
the dependence length ``ℓ`` of the multiplier sequence,
|
|
'auto'
|
block_kernel
|
``'bartlett'`` (default) or ``'parzen'``; only used by
|
|
'bartlett'
|
n_jobs
|
int | None
|
|
None
|
Returns:
| Type | Description |
|---|---|
ExchangeabilityResult.
|
|
exchangeability_statistic ¶
exchangeability_statistic(u: ndarray, v: ndarray) -> float
T_n of the module docstring, from pseudo-observations already in [0, 1].
Unlike :func:exchangeability_test, this does not rank-transform its
input: pass pseudo-observations, not raw data, so that a bootstrap
replicate (already uniform-margined by construction) and the observed
sample are put through the identical computation.
ExchangeabilityResult
dataclass
¶
ExchangeabilityResult(statistic: float, p_value: float, reject: bool, alpha: float, n: int, tau_hat: float, B: int, n_valid: int, bootstrap: str = 'parametric', block_length: int = 1)
Typed result of :func:exchangeability_test.
Fields
statistic : float — the Cramér–von Mises statistic T_n (see module
docstring). NaN when n < MIN_N.
p_value : float — parametric-bootstrap Monte-Carlo p-value, never
exactly 0 (Davison & Hinkley 1997). NaN when no replicate
produced a finite statistic.
reject : bool — p_value < alpha (H0 = "exchangeable", i.e.
C(u, v) = C(v, u)). False whenever p_value is NaN.
alpha : float — significance level used for reject.
n : int — number of pairs the statistic was computed on.
tau_hat : float — Kendall's τ of the sample. For bootstrap='parametric'
it is also the calibrating Gaussian surrogate's only fitted
parameter; for bootstrap='multiplier' it is reported for
diagnostics only (the multiplier bootstrap fits nothing).
B : int — bootstrap replicates requested.
n_valid : int — replicates that produced a finite statistic.
bootstrap : str — 'parametric' (default), 'multiplier' or
'dependent-multiplier', the calibration method actually
used — see the module docstring.
block_length : int — the multiplier dependence length ℓ actually used
(FR-5); always 1 for the two other methods.
Rosenblatt goodness-of-fit¶
Reduces "does (x, y) follow C_theta?" to "is (u, h(v|u))
independent-uniform on the square?", tested by a Cramér-von Mises statistic
against Pi(u, v) = u*v, calibrated by a parametric bootstrap that refits
theta on every replicate.
rosenblatt_gof_test ¶
rosenblatt_gof_test(x: ndarray, y: ndarray, family_cls, *, method: str = 'tau', B: int = 200, seed: int = 0, alpha: float = 0.05, weights=None, bootstrap: str = 'parametric', multiplier: str = 'normal', block_length: int | str = 'auto', block_kernel: str = 'bartlett', n_jobs: int | None = None) -> RosenblattGoFResult
Test H0: (x, y) is drawn from family_cls (FR-10, Rosenblatt).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
ndarray
|
|
required |
y
|
ndarray
|
|
required |
family_cls
|
a ``CopulaVirt`` subclass (e.g. ``CopulaGaussian``) — the
|
|
required |
method
|
str
|
|
'tau'
|
B
|
int
|
|
200
|
seed
|
int
|
|
0
|
alpha
|
float
|
|
0.05
|
weights
|
|
None
|
|
bootstrap
|
str
|
|
'parametric'
|
multiplier
|
``'normal'`` (default) or ``'rademacher'`` — the i.i.d.
|
|
'normal'
|
block_length
|
the dependence length ``ℓ`` of the multiplier sequence,
|
|
'auto'
|
block_kernel
|
``'bartlett'`` (default) or ``'parzen'``; only used by
|
|
'bartlett'
|
n_jobs
|
int | None
|
|
None
|
Returns:
| Type | Description |
|---|---|
RosenblattGoFResult.
|
|
rosenblatt_transform ¶
rosenblatt_transform(u: ndarray, v: ndarray, copula) -> tuple[np.ndarray, np.ndarray]
Rosenblatt transform (Û, V̂) = (û, h(v̂|û)) of pseudo-observations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
u
|
ndarray
|
|
required |
v
|
ndarray
|
|
required |
copula
|
a fitted ``CopulaVirt`` instance — ``h(v|u)`` is
|
|
required |
Returns:
| Type | Description |
|---|---|
(U, V) : both shape ``(n,)``, clipped to ``[EPS, 1-EPS]`` (``h`` can
|
return exactly 0 or 1 at the boundary of a one-sided family, e.g. Clayton; the CvM statistic below only needs values inside the open square). |
rosenblatt_statistic ¶
rosenblatt_statistic(U: ndarray, V: ndarray) -> float
S_n of the module docstring, from an already-transformed sample.
S_n = n · mean_i [Ĝ_n(Û_i, V̂_i) − Û_i·V̂_i]², the Cramér–von Mises
distance between the empirical CDF of (U, V) and the independent
uniform reference Π(u, v) = u·v, evaluated at the sample's own
points (as :func:pmcprg.diagnostics.radial_symmetry.radial_symmetry_statistic
evaluates its own CvM statistic).
RosenblattGoFResult
dataclass
¶
RosenblattGoFResult(statistic: float, p_value: float, reject: bool, alpha: float, n: int, family: str, tau_hat: float, B: int, n_valid: int, bootstrap: str = 'parametric', block_length: int = 1)
Typed result of :func:rosenblatt_gof_test.
Fields
statistic : float — the Cramér–von Mises statistic S_n (see module
docstring). NaN when n < MIN_N.
p_value : float — parametric-bootstrap Monte-Carlo p-value, never
exactly 0 (Davison & Hinkley 1997). NaN when no replicate
produced a finite statistic.
reject : bool — p_value < alpha (H0 = "the data follow the
fitted family"). False whenever p_value is NaN.
alpha : float — significance level used for reject.
n : int — number of pairs the statistic was computed on.
family : str — family_cls.__name__ of the candidate copula.
tau_hat : float — τ of the family fitted to the observed data.
B : int — bootstrap replicates requested.
n_valid : int — replicates that produced a finite statistic (a fit
or a Rosenblatt transform can fail on a degenerate
replicate; such replicates are dropped, not counted as 0).
For bootstrap='multiplier' no replicate is dropped.
bootstrap : str — 'parametric' (default), 'multiplier' or
'dependent-multiplier', the calibration method actually
used — see the module docstring.
block_length : int — the multiplier dependence length ℓ actually used
(FR-5); always 1 for the two other methods.
Pseudo-observations¶
Pseudo-observations and margin samples of a fitted chain, for state margins
f_i and for the pair margins f_ij of a general PMC.
copula_pseudo_obs ¶
copula_pseudo_obs(F, xi, i: int, j: int, sel=None)
Weighted pseudo-observations of the copula c_ij
(DerrodePieczynski_CSDA2013 Eq. 12).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
F
|
|
required | |
xi
|
(or one-hot draws). |
required | |
i
|
int
|
|
required |
j
|
int
|
|
required |
sel
|
optional indices ``n`` of the transitions to keep (a thinning
|
stride, a window); all |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
uv |
``(M, 2)`` — ``(F_ij(y_n), F_ji(y_{n+1}))``.
|
|
w |
``(M,)`` — ``ξ_n(i, j)``.
|
|
margin_cdfs ¶
margin_cdfs(model, Y, *, clip=CDF_CLIP, broadcast: bool = False) -> np.ndarray
F[n, i, j] = F_ij(y_n) for every observation and every pair.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
|
required | |
Y
|
|
required | |
clip
|
|
CDF_CLIP
|
|
broadcast
|
state margins only. ``False`` (default) returns a writable
|
|
False
|
Returns:
| Type | Description |
|---|---|
np.ndarray, shape ``(N, K, K)``, float64.
|
|
For state margins only K CDFs are evaluated and ``F[:, i, j]`` is the
|
|
vector ``F_i(Y)`` for every ``j``; for pair margins K² are evaluated.
|
|
Clipping is element-wise, so clipping the K state vectors before
|
|
broadcasting them gives the floats of clipping the broadcast array.
|
|
margin_pit_dual ¶
margin_pit_dual(F, xi, i: int, j: int)
Weighted probability integral transform of the pair margin f_ij.
Dual view (DerrodePieczynski_CSDA2013 Eq. 12): f_ij is the left margin of the
pair (i, j) and the right margin of the pair (j, i), so it accounts for
u = F_ij(y_n)with weightξ_n(i, j),n = 0 … N−2;u = F_ij(y_{n+1})with weightξ_n(j, i),n = 0 … N−2.
Under the model, P(x_n=i, x_{n+1}=j, y_n ∈ dy) = p_ij f_ij(y) dy and
P(x_n=j, x_{n+1}=i, y_{n+1} ∈ dy) = p_ji f_ij(y) dy (DerrodePieczynski_CSDA2013
Eqs. 12–13, symmetric p), so the ξ-weighted empirical CDF of u is uniform in
expectation when f_ij is right. Returned as one
sample of length 2(N−1), left view first. Summed over all pairs the
weights total 2(N−1): every observation is counted once as a left
and once as a right observation, except the two ends.
For a state model (F[:, i, j] = F_i) the dual view of (i, j) is a
subset of the state-i sample; summing its weights over j gives
γ_n(i) on the left view and γ_{n+1}(i) on the right one.
Returns:
| Name | Type | Description |
|---|---|---|
u |
``(2(N−1),)``
|
|
w |
``(2(N−1),)``
|
|
margin_keys ¶
margin_keys(model) -> list
Keys of the distinct margins of model, in a stable order.
[0, …, K−1] for state margins, [(0, 0), (0, 1), …, (K−1, K−1)] for
pair margins. model.margin(*key) (or model.margin(key) for an
integer key) returns the corresponding density.
margin_sample ¶
margin_sample(Y, labels, key)
Observations a margin accounts for under one label path.
key = k(state marginf_k):Y[labels == k].key = (i, j)(pair marginf_ij): the hard-label dual view,{y_n : (x_n, x_{n+1}) = (i, j)}followed by{y_{n+1} : (x_n, x_{n+1}) = (j, i)}. With one-hotξthis is exactly the sample :func:margin_pit_dualweights.
labels is any path — the true labels, a posterior draw, the MPM path.
Dependent-multiplier bootstrap¶
Serially dependent multipliers for the bootstrap of a copula functional on a Markov chain (audit FR-5) — an i.i.d. multiplier bootstrap under-covers because consecutive pairs share an observation.
draw_multipliers ¶
draw_multipliers(n: int, B: int, rng: Generator, law: str = 'normal', *, block_length: int = 1, kernel: str = 'bartlett') -> np.ndarray
(n, B) multipliers, mean 0, variance 1, ℓ-dependent in n.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n
|
int
|
|
required |
B
|
int
|
|
required |
rng
|
Generator
|
|
required |
law
|
str
|
|
'normal'
|
block_length
|
``ℓ ≥ 1``. ``1`` returns the i.i.d. draw itself.
|
|
1
|
kernel
|
str
|
|
'bartlett'
|
auto_block_length ¶
auto_block_length(u: ndarray, v: ndarray, *, kernel: str = 'bartlett', grid: tuple[float, ...] = (0.25, 0.5, 0.75), max_block: int | None = None) -> int
Newey & West (1994) plug-in ℓ for a bivariate sequence in (0,1)².
ℓ = 1 + median_{(a,b) ∈ grid²} L_NW(1{u_i ≤ a, v_i ≤ b} − C_n(a, b))
for kernel='bartlett', where L_NW is
:func:pmcprg.diagnostics.model_selection.newey_west_bandwidth — the
package's existing HAC bandwidth rule, reused rather than duplicated
because ℓ = L + 1 is an exact identity for this kernel (module
docstring). For kernel='parzen' the same target dependence length
L + 1 is converted to that kernel's ℓ, whose autocorrelation
reaches 2ℓ - 2: ℓ = ⌈(L + 2)/2⌉.
u, v must be in time order — the whole point is that row i is
observation i of the chain. Returns at least 1, at most
max_block (default n // 4).
multiplier_weights ¶
multiplier_weights(block_length: int, kernel: str = 'bartlett') -> np.ndarray
Weights w of the moving average, normalised so Σ w_k² = 1.
block_length = 1 returns array([1.0]) for every kernel, which is
what makes the dependent bootstrap reduce to the i.i.d. one exactly.
"bartlett": ℓ equal weights ℓ^{-1/2} (a rectangular window,
whose self-convolution is the Bartlett kernel — module docstring).
"parzen": 2ℓ-1 weights ∝ Parzen(k/ℓ), |k| ≤ ℓ-1.
multiplier_autocorrelation ¶
multiplier_autocorrelation(block_length: int, kernel: str = 'bartlett') -> np.ndarray
[ρ(0), ρ(1), …] of the sequence, ρ(h) = Σ_k w_k w_{k+h}.
Returned for h = 0 … m-1 (m = len(w)); ρ(h) = 0 beyond. For
kernel="bartlett" this is exactly 1 − h/ℓ.