mixle.inference package¶
The inference concern — fit a model and quantify its parameters.
One home for turning data into a fitted/posterior model. Every entry point is the same idea — infer parameters from data — and differs only in what it requires of its input:
closed-form conjugate Bayes (
conjugate_posterior) — needs aConjugateUpdatablefamily;MLE / EM / MAP (
fit/optimize/run_em) — needs anEstimatorfor the model;sampling-based inference (
nuts/advi) — needs a sampleable / differentiable target (a log-density callable, or a model that can be sampled). This is exactly why it belongs here and not in a separate package: it is inference under a capability precondition on the target, nothing more.
Everything physically lives in this package: the estimation / EM / fit / objectives / Fisher machinery
(mixle.inference.{estimation,em,fit,objectives,fisher}), the MCMC samplers (mixle.inference.mcmc),
the engine-agnostic NUTS/ADVI target facade (mixle.inference.target + .backends + .diagnostics).
Conjugate Bayes is re-exported from its canonical home mixle.stats.bayes. mixle.infer remains as
a deprecated shim onto this package.
These imports are eager and cycle-free: the machinery’s only mixle.stats dependency is the compute
layer (mixle.stats.compute.{pdist,sequence}), never the mixle.stats package surface — the
vectorized seq_* drivers were moved out of mixle.stats.__init__ into compute.sequence for
exactly this reason.
- class Explanation(total, parts=<factory>, responsibilities=None, component=None)[source]
Bases:
objectExact additive attribution of
log p(x)(plus the latent posterior for mixtures).- Parameters:
- total: float
- explain(model, x)[source]
Exact per-part attribution of
model.log_density(x)(see module docstring).
- class InterventionalNetwork(net, interventions)[source]
Bases:
objectA Bayesian network under
do(...): sample and summarize the post-intervention world.- sample(size=1, *, seed=None)[source]
Ancestral sampling with the intervened fields clamped (their factors are never consulted).
- expectation(field, *, n=4000, seed=0)[source]
Monte-Carlo
E[field | do(...)]for a numeric field.
- average_causal_effect(net, treatment, a, b, outcome, *, n=4000, seed=0)[source]
E[outcome | do(treatment=a)] - E[outcome | do(treatment=b)](numeric outcome).
- counterfactual(net, observed, interventions)[source]
What THIS observed record would have been under the intervention (abduction-action-prediction).
Per Pearl’s three steps, walked in topological order:
abduction – a linear-Gaussian field’s exogenous noise is point-identified from the row: its residual
eps = observed - coef @ parents_observed;action – intervened fields take their
dovalues;prediction – the SAME residual replays through the counterfactual parents:
cf = coef @ parents_cf + eps.
Honest boundaries: (1) a field that is not linear-Gaussian keeps its observed value only while its parents are unchanged under the intervention (that much IS identified); if its parents change, its exogenous noise cannot be recovered from one observation and this raises — use
average_causal_effect()for the population answer instead of a guessed individual one. (2) The counterfactual is relative to the network’s DAG as given: purely observational structure learning cannot orient Markov-equivalent edges (x -> y and y -> x fit equally well), so if the causal direction matters, assert it from domain knowledge rather than trusting the learned arrow.
- do(net, interventions)[source]
Return the network under Pearl’s
dooperator (see module docstring).
- class Forecast(mean, lo, hi, level, state_probs, samples=None)[source]
Bases:
objectPer-step predictive summaries plus the state-marginal trajectory.
- mean: Any
- lo: Any
- hi: Any
- level: float
- state_probs: ndarray
- samples: Any = None
- forecast(model, history, horizon, *, level=0.9, n=4000, seed=0, keep_samples=False)[source]
Forecast
horizonsteps beyondhistoryunder a fitted HMM.- Parameters:
model (Any) – a fitted
HiddenMarkovModelDistribution(any emission family with a sampler).history (Any) – the observed sequence to condition on (one sequence).
horizon (int) – number of future steps to predict.
level (float) – central-interval mass (0.9 -> the 5%..95% band).
n (int) – Monte-Carlo draws per step for the emission quantiles (state marginals are exact).
seed (int) – reproducibility.
keep_samples (bool) – also return the raw
(H, n)predictive draws (scalar emissions only).
- Return type:
Forecast
- class ParameterEstimator[source]
-
Estimates a distribution from accumulated sufficient statistics.
accumulator_factory() supplies accumulators that gather sufficient statistics of type SS, and estimate(nobs, suff_stat) maps those statistics (plus optional regularization configured on the estimator) to a new distribution.
- to_dict()[source]
Return a safe JSON-compatible representation of this estimator.
- classmethod from_dict(payload)[source]
Reconstruct an estimator from
to_dictoutput.
- to_json(**kwargs)[source]
Serialize this estimator as safe strict JSON.
- classmethod from_json(text)[source]
Deserialize an estimator from
to_jsonoutput.- Parameters:
text (str)
- Return type:
ParameterEstimator
- abstractmethod estimate(nobs, suff_stat)[source]
- Parameters:
nobs (float | None)
suff_stat (SS)
- Return type:
SequenceEncodableProbabilityDistribution
- abstractmethod accumulator_factory()[source]
- Return type:
StatisticAccumulatorFactory
- resident_accumulation_supported()[source]
Return whether engine-resident (fixed-width) sufficient statistics suffice for
estimate.Most exponential-family M-steps consume only the resident sufficient statistics, so the default is
True. Estimators whose M-step needs more than that (e.g. a full count histogram for the negative-binomial dispersion solve) override this toFalseso stacked/generated kernels fall back to the host accumulator, keeping every backend’s fixed point identical.- Return type:
- get_prior()[source]
Return the parameter prior configured on this estimator, if any.
The unified estimation contract treats the prior as the single regularization concept:
Nonegives maximum likelihood, a conjugate prior gives the Bayesian posterior update insideestimate. The default reads thepriorattribute (Nonewhen unset).- Return type:
ProbabilityDistribution | None
- model_log_density(model)[source]
Return the prior log-density of
model’s parameters (the ELBO global term).Used by the variational/MAP objective in
fit. The default is0.0(no prior); conjugate estimators override this to evaluate their prior at the model’s parameters, mapping to the prior’s parameterization first.- Parameters:
model (ProbabilityDistribution)
- Return type:
- estimate(data, estimator, prev_estimate=None)[source]
Perform E-step in EM algorithm by iterating over all observations in ‘data’.
Arg estimator must be consistent with prev_estimate. That is, prev_estimate must be an estimate that could be obtained from estimator.
Data must type consistent with estimator and prev_estimate.
Returns the next iteration of EM algorithm by iterating over each observation of data. See seq_estimate() for a more computationally efficient implementation.
- Parameters:
data (Union[Sequence[T], pyspark.rdd.RDD]) – Sequence of iid observations of data type consistent with ‘estimator’ and/or ‘prev_estimate’.
estimator (ParameterEstimator) – Model to be estimated from ‘data’.
prev_estimate (Optional[SequenceEncodableProbabilityDistribution]) – Previous estimate of EM algorithm. Must be included for distributions that require initialization.
- Returns:
SequenceEncodableProbabilityDistribution object.
- Return type:
SequenceEncodableProbabilityDistribution
- initialize(data, estimator, rng, p=0.1)[source]
Randomly initialize a model corresponding to ParameterEstimator for iid observations data.
Note: ParameterEstimator must be of data type T, matching the input data.
This function sequentially iterates over the entire data set ‘data’, repeatedly calling initialize() method of the SequenceEncodableStatisticAccumulator object created from ‘estimator’. Data points are weighted 0 or 1 with probability p.
Seq_initialize() is much more efficient, and should produce the same initialized model for the same data sets.
- Parameters:
data (Union[Sequence[T], pyspark.rdd.RDD]) – Set of iid observations compatible with ‘estimator’.
estimator (ParameterEstimator) – ParameterEstimator object for desired model to be estimated from data.
rng (RandomState) – RandomState object for setting seed.
p (float) – Proportion of data to randomly sample for initializing model.
- Returns:
SequenceEncodableProbabilityDistribution object consistent with ‘estimator’.
- Return type:
SequenceEncodableProbabilityDistribution
- seq_estimate(enc_data, estimator, prev_estimate)[source]
Perform vectorized E-step in EM algorithm for encoded sequence of observations in ‘enc_data’.
Arg estimator must be consistent with prev_estimate. That is, prev_estimate must be an estimate that could be obtained from estimator.
Arg enc_data must type consistent with estimator and prev_estimate (result of seq_encode() call).
Returns the next iteration of EM algorithm with vectorized calls to “seq_update()” of the corresponding SequenceEncodableStatsiticAccumulator objects.
- Parameters:
enc_data (Union[List[Tuple[int, T]], 'pyspark.rdd.RDD']) – Sequence encoded data of format matching output of seq_encode() function.
estimator (ParameterEstimator) – Model to be estimated from ‘enc_data’.
prev_estimate (SequenceEncodableProbabilityDistribution) – Previous estimate of EM algorithm.
- Returns:
SequenceEncodableProbabilityDistribution object.
- Return type:
T_D
- seq_initialize(enc_data, estimator, rng, p=0.1)[source]
- Vectorized initialization of a model corresponding to ParameterEstimator for encoded sequences of iid data
observations.
Arg enc_data must type consistent with estimator (result of seq_encode() call). Arg estimator must be of data type consistent with encoded sequence data type in ‘enc_data’.
Vectorized initialization of SequenceEncodableProbabilityDistribution corresponding to ‘estimator’ from enc_data. Observations in the encoded sequence enc_data are kept with probability p.
This functions relies on calls to SequenceEncodableStatisticAccumulator.seq_initialize(), which is a vectorized initialization of the SequenceEncodableStatisticAccumulator object.
This method should produce the same initialized model as a call to initialize() if the data sets are the same.
- Parameters:
enc_data (Union[List[Tuple[int, T]], 'pyspark.rdd.RDD']) – Sequence encoded data of format matching output of seq_encode() function.
estimator (ParameterEstimator) – Model to be estimated from ‘enc_data’.
rng (RandomState) – RandomState object for setting seed.
p (float) – Proportion of data to randomly sample for initializing model.
- Returns:
SequenceEncodableProbabilityDistribution object consistent with ‘estimator’.
- Return type:
SequenceEncodableProbabilityDistribution
- optimize(data, estimator=None, max_its=10, delta=1.0e-9, init_estimator=None, init_p=0.1, rng=None, prev_estimate=None, vdata=None, enc_data=None, enc_vdata=None, out=sys.stdout, print_iter=1, num_chunks=1, engine=None, precision=None, fields=None, resources=None, placement=None, sub_chunks=1, chunk_size=None, backend='local', num_workers=None, client=None, comm=None, root=0, root_only=False, strategy=None, reuse_estep_ll=True, objective='auto', on_step=None, structure='auto')[source]
- Estimation of ‘estimator’ via EM algorithm for max_its iterations or until
new_loglikelihood - old_loglikelihood < delta.
- Parameters:
data (Optional[List[T]]) – List of data type T containing observed data. Must be compatible with data type of estimator.
estimator (ParameterEstimator | ProbabilityDistribution | None) – What to fit. A
ParameterEstimatoris used as-is; a distribution prototype (anyProbabilityDistribution) is coerced to its matching estimator viaproto.estimator()so you build the model shape only once;Noneinfers an estimator from rawdata(mixle.utils.automatic.get_estimator).max_its (int) – Maximum number of EM iterations to be performed. Default value is 10 iterations.
delta (Optional[float]) – Stopping criteria for EM algorithm used if max_its is not set: Iterate until |old_loglikelihood - new_loglikelihood| < delta or iterations == max_its.
init_estimator (Optional[ParameterEstimator]) – ParameterEstimator to used to initialize EM algorithm parameters. If None, estimator is used. Must be consistent with estimator.
init_p (float) – Value in (0.0,1.0] for randomizing the proportion of data points used in initialization.
rng (RandomState) – RandomState used to set seed for initializing EM algorithm.
vdata (Optional[Sequence[T]]) – Optional validation set.
prev_estimate (Optional[SeqeuenceEncodableProbabilityDistribution]) – Optional model estimate used from prior fitting. Must be consistent with estimator.
enc_data (Optional[List[Tuple[int, E]]]) – Optional encoded data of form List[Tuple[int, E]]. Formed from data if None.
enc_vdata (Optional[List[Tuple[int, E0]]]) – Optional sequence encoded validation set.
out (IO) – IO stream to write out iterations of EM algorithm. Pass out=None to silence all output.
print_iter (int) – Print the log-likelihood difference every print_iter iterations; the final converged iteration is always reported. Pass print_iter=0 to suppress the periodic lines (keeping only the converged line), or out=None to silence entirely.
num_chunks (int) – Number of chunks for encoded data.
engine (Optional[Any]) – Optional ComputeEngine for local kernel scoring/accumulation. Distributed engine placement is intentionally deferred to the orchestrator/planner layer.
precision (Optional[Any]) – Optional floating-point precision such as
'float32'ornp.float64. Pass'auto'to letmixle.engines.auto_precisionchoose from the data and engine: float32 only on a GPU torch engine with well-conditioned numeric data, else float64. Pass'minimal'for the data-aware CPU allocator (mixle.inference.precision_plan): it inspects the data magnitude and the model’s leaf families/conditioning and runs the reduced float32 fused kernel where verified safe (accumulation stays float64), else float64 – the “preserve accuracy with minimal compute” default for local fits.fields (Optional[Any]) – DataFrame column/field selection. A single field yields scalar observations; several fields yield tuple observations unless the estimator/model is record-shaped, in which case dict records are produced by source column name.
resources (Optional[Any]) – Optional planner resources. When supplied with raw data, optimize encodes through the shared encoded-data factory so placement, sub-chunks, and per-shard engines use the orchestrator contract.
placement (Optional[Any]) – Optional explicit placement produced by
mixle.utils.parallel.planner.plan.sub_chunks (int) – Number of sub-chunks per placement shard when
resourcesorplacementis supplied.chunk_size (Optional[int]) – Approximate chunk size for ordinary local sequence encoding.
backend (str) – Encoded-data backend for raw data.
'local'keeps the historical local encoding unless resources/placement are supplied;'mp'and'mpi'use the shared encoded-data factory.num_workers (Optional[int]) – Worker count for
backend='mp'and optional partition count hint forbackend='dask'.client (Optional[Any]) – Existing dask.distributed client for
backend='dask'. If omitted, the dask backend uses an active default client or starts a local threaded client.comm (Optional[Any]) – MPI communicator for
backend='mpi'.root (int) – MPI root rank for
backend='mpi'.root_only (bool) – MPI root-only data mode for
backend='mpi'.strategy (Optional[Any]) – Optional EM strategy from
mixle.inference.em(e.g.AnnealedEM,HardEM,MonteCarloEM) or any callable(enc, estimator, model) -> modelto use in place of the standard exact E/M step.Noneuses the standard step.reuse_estep_ll (bool) – Default True. Reuse the data log-likelihood computed during the E-step (the posterior normalizer / forward pass / variational ELBO) for convergence instead of running a separate scoring pass each iteration – typically ~1.5-2x faster per iteration for latent models (mixtures, HMMs and variants, topic models, associations, IBP, …) on the default local engine. Convergence then lags by one iteration (same fixed point) and the best-likelihood model is returned; fixed-iteration fits (delta=None) are identical to the standard loop. Automatically falls back to the standard loop for engines/strategies/ distributed backends or models that can’t report the LL (no slowdown there). Set False to force the exact historical per-iteration scoring behavior.
objective (str) – Convergence/selection objective.
'auto'(default) makes the prior the single switch – a model exposing a variational ELBO (seq_local_elbo) is fit by variational Bayes ('vb'), an estimator carrying a parameter prior by penalized log-likelihood ('map'), and everything else by plain maximum likelihood ('mle'). Pass'mle'/'map'/'vb'to force a specific objective.fitaccepts the same argument; both share this resolution so a Bayesian estimator is fit on the correct objective regardless of the verb used. (Only'mle'is compatible with the fused E-step shortcut;reuse_estep_llis ignored for'map'/'vb'.)on_step (Optional[Callable[[EMStep], None]]) – Optional per-iteration callback receiving an
EMStep(iter, model, log_density, delta)for the accepted model. Use it to checkpoint a long run – e.g.on_step=registry.checkpointer('run', every=5)– and resume withprev_estimate=. Called on every iteration regardless ofprint_iter.structure (str) –
'auto'(default) makes the tagline literal for flat tuple records fit with no estimator: the cross-field dependency graph is discovered (mixle.inference.learn_bayesian_network()) and returned WHEN it beats the independent composite by BIC — otherwise (no edges, non-record data, or any failure) the historical automatic-composite path proceeds untouched.'off'restores the unconditional historical behavior. Only consulted whenestimatorisNoneand noprev_estimate/init_estimator/strategy/enc_datais supplied.
- Returns:
- SequenceEncodableProbabilityDistribution corresponding to estimator when stopping criteria of EM algorithm
is met.
- Return type:
SequenceEncodableProbabilityDistribution
- jit_seq_log_density(model, engine=None)[source]
Return a
JittedScorer: the whole-tree log-density ofmodelcompiled to one XLA program.jit_seq_log_density(model)(data)is bit-identical tomodel.seq_log_density(encode(data))but runs as a singlejax.jitXLA program over the entire composite tree – fast for repeated scoring of a fixed model. Requires the JAX optional extra and that every leaf inmodeldeclares JAX support (raisesEngineNotSupportedError-style errors from the engine layer otherwise).
- jit_em_mixture(model, data, *, max_its=100, engine=None)[source]
Fit a finite mixture of same-family scalar exponential-family leaves by EM, with the ENTIRE EM loop (every E-step + closed-form weighted M-step iteration) compiled to ONE
jax.jitXLA program vialax.scan– the parameters are traced inputs threaded through the loop on-device, so there is no per-iteration recompile and no per-iteration host sync. This is roadmap A2 bullet 1 (“repeated EM iterations run as one XLA program”) realized literally.modelis the initial mixture (its components seed the EM); supported leaves: Gaussian, Poisson, Exponential. Runs a fixedmax_itsiterations (no host-side early stop – that is the point: the loop stays on-device). Returns a fittedMixtureDistribution, bit-close to the host EM from the same start (it is the same EM update). RaisesNotImplementedErrorfor unsupported structure.SPEED – measured, honest: the payoff is GPU/TPU and large scale, where XLA parallelizes the E-step over millions of points and many components. On an Apple M4 GPU (via jax-metal) this kernel runs ~21x faster than mixle’s vectorized NumPy EM (K=10, N=1e6, 50 iters: 156 ms vs 3254 ms) with identical estimates, and ~12x faster than the same jitted loop on CPU. On CPU it is *not* a speedup – mixle’s host EM is already vectorized NumPy (+ a fused path) and a long sequential
scanof small steps loses to it (~0.1-0.8x for K up to 40). So: GPU -> big win, CPU -> use the host EM. (The CPU win from A2 is the single-pass scoring jit,jit_seq_log_density(), ~8x.) Note: jax-metal is version-pinned – the GPU result above used Python 3.11 + jax/jaxlib 0.4.34 + jax-metal 0.1.1; newer jaxlib emits StableHLO that jax-metal 0.1.1 cannot compile.
- class JittedScorer(model, engine=None)[source]
Bases:
objectA
jax.jit-compiled whole-tree log-density scorer for a fixed model.Calling the scorer encodes
data, runs the engine-neutralbackend_seq_log_densityover the whole model tree on the JAX engine underjax.jit, and returns host log-densities. The compiled program is cached and reused across calls with the same data shape.- Parameters:
model (Any)
engine (Any)
- laplace_posterior(model, data, *, eps=1e-4, ridge=1e-6)[source]
Laplace posterior over
model’s parameters from a finite-difference Hessian of its ownseq_log_density– works for ANY model whose parameters_flatten()covers (the scalar exponential-family leaves,CompositeandMixture, recursively), conjugate or not, with no per-model inference code.modelshould be the fitted (MLE/MAP) model – its parameters are the Laplace mode. Returns aLaplacePosterioryou can.sample()(a fitted model per draw).
- class LaplacePosterior(mode_model, u_mode, cov, rebuild)[source]
Bases:
objectGaussian Laplace posterior over a model’s parameters (in the unconstrained space), with draws rebuilt back into fitted models.
mean_modelis the mode;covthe unconstrained covariance.
- collapse_mixture(mixture)[source]
Moment-match a mixture onto a single distribution, in closed form (exact for Gaussians).
Returns the Gaussian minimizing
KL(mixture || Gaussian)– its mean and covariance are the mixture’s overall mean and covariance (law of total variance). This is the exact, sample-free counterpart tomixle.ops.project(mixture, GaussianDistribution(...).estimator()).
- reduce_mixture(mixture, n_components, *, method='runnalls')[source]
Reduce a Gaussian mixture to
n_componentsby greedily merging the least-costly pair (Runnalls).Repeatedly merges the two components whose merge costs the least KL (
_runnalls_cost()) untiln_componentsremain. Every merge is moment-preserving, so the reduced mixture has the same overall mean and covariance as the original – only higher moments are lost. Returns a mixture of the same kind as the input (aGaussianMixtureDistributionfor multivariate input).
- moment_project(teacher, target=None, *, exact=True, **sampling_kw)[source]
Project
teacheronto a smaller student – exactly when possible, else by sampling.If
teacheris a Gaussian mixture andtargetisNone(or a single Gaussian family), the projection is the closed-formcollapse_mixture()– no samples, machine-precision. Otherwise (or whenexact=False) it delegates tomixle.ops.project(), the sampling M-projection ontotarget’s family. This gives one entry point that is exact where the structure allows and honest (sampling, clearly) where it does not.
- gaussian_kl(p, q)[source]
KL(p || q)between two Gaussians (uni- or multivariate), in nats. Accepts distributions.0.5[ tr(Σq⁻¹ Σp) + (μq-μp)ᵀ Σq⁻¹ (μq-μp) - d + ln(det Σq / det Σp) ]– the analytic Gaussian KL.
- fisher_merge(estimates, fishers=None)[source]
Fisher-weighted merge of parameter estimates – the closed-form Laplace-posterior combination.
Given estimates
θ_i(each a flat parameter vector) and their Fisher informationF_i, returnsθ* = (Σ F_i)⁻¹ (Σ F_i θ_i)– the point that maximizes the sum of the local Laplace log-posteriorsΣ_i -½(θ-θ_i)ᵀ F_i (θ-θ_i). This is Matena & Raffel Fisher merging (diagonalF) and, in general, the precision-weighted mean; for Gaussians it coincides with the product-of-experts mean. No gradient steps – a single linear solve.- Parameters:
estimates (Any) – sequence of parameter vectors
θ_i(each shape(p,)), or a stack(m, p).fishers (Any) – per-estimate Fisher information. Each may be a scalar/1-D vector (diagonal Fisher, per-coordinate precision) or a
(p, p)matrix (full Fisher).Noneuses unit Fisher (a plain average). A single value is broadcast to every estimate.
- Returns:
The merged parameter vector
θ*of shape(p,).- Return type:
- fit(data, estimator=None, max_its=10, delta=1.0e-6, init_estimator=None, **kwargs)[source]
Fit a model in the Bayesian (variational / MAP) sense, returning the posterior-bearing model.
This is the posterior-returning counterpart of
optimize().fititerates the EM/VB update that maximizes the objective selected byobjective(default'auto'):'auto'– the prior is the single switch:'vb'when the model exposesseq_local_elbo,'map'when the estimator carries a parameter prior, else'mle';'mle'– plain data log-likelihood (ignores any prior in the objective);'map'/'vb'– penalized log-likelihood / ELBOobj = data term + prior term, where the data term is the observed-data LL (MAP) or local-ELBO contributions (variational), and the prior term isestimator.model_log_density(model).
Convergence is checked on the chosen objective, so under
'map'/'vb'the prior is part of the stopping rule and conjugate updates never decrease it. The returned model carries its conjugate posterior forward asmodel.get_prior(). With no prior anywhere, every objective reduces to plain EM, sofitandoptimizeagree for frequentist estimators.optimizeaccepts the sameobjectiveargument; the two share this resolution so a Bayesian estimator is fit correctly regardless of which verb the caller reaches for.Args otherwise mirror
optimize()(local encoded path). Returns the model with the best validation log-likelihood seen during the run.fitis a thin wrapper overoptimize()– they share the one EM/objective loop.fitadds only the opt-in data-structure check, a Bayesian-leaning defaultdelta(1e-6), and the exact per-iteration-scored loop (reuse_estep_ll=False). Every otheroptimize()keyword – engines, precision, distributedbackend,on_step, the fused E-step – is accepted here too and forwarded verbatim, so reaching for a heavier knob never means switching verbs.estimatoraccepts the same three spellings asoptimize()(estimator, distribution prototype, orNoneto infer from data).
- class EMStep(iter, model, log_density, delta)[source]
Bases:
NamedTupleOne accepted EM iteration, handed to an
optimize(on_step=...)callback.iteris 1-based;modelis the current accepted model – snapshot it to checkpoint, and resume withoptimize(prev_estimate=...);log_densityis the training objective at this step;deltais its gain over the previous step (infon the first iteration).- iter: int
Alias for field number 0
- model: Any
Alias for field number 1
- log_density: float
Alias for field number 2
- delta: float
Alias for field number 3
- best_of(data, vdata, est, trials, max_its, init_p, delta, rng, init_estimator=None, enc_data=None, enc_vdata=None, out=sys.stdout, print_iter=1, reuse_estep_ll=True, objective='auto')[source]
- Performs EM algorithm for trials-number of randomized initial conditions. Returns the best model fit in terms of
maximum log-likelihood value from validation data.
- Parameters:
data (Optional[List[T]]) – List of data of type T. If None is given, enc_data must be provided as List[Tuple[int, enc_data_type]].
vdata (Optional[Sequence[T]]) – Optional validation set.
est (ParameterEstimator) – ParameterEstimator for model to be estimated.
trials (int) – Integer number >= 1, of randomized initial conditions to perform EM algorithm for.
max_its (int) – Integer value >=1, sets the maximum number of iterations of EM to be performed as stopping criteria.
init_p (float) – Value in (0.0,1.0] for randomizing the proportion of data points used in initialization.
delta (float) – Stopping criteria for EM when |old-log-likelihood - new-log-likelihood| < delta.
rng (RandomState) – RandomState for setting seed.
init_estimator (Optional[ParameterEstimator]) – Optional ParameterEstimator used for fitting.
enc_data (Optional[List[Tuple[int, E]]]) – Optional encoded data, if provided data need not be provided. If None, enc_data is set from data.
enc_vdata (Optional[List[Tuple[int, E0]]]) – Optional sequence encoded validation set.
out (I0) – Text output stream.
print_iter (int) – Print iterations (i.e. log-likelihood difference) every print_iter-iterations.
reuse_estep_ll (bool) – Default True. Forwarded to each trial’s
optimizecall – reuse the E-step likelihood for convergence instead of a separate scoring pass (seeoptimize). Set False to force the exact historical per-iteration scoring behavior.objective (str) – Convergence/selection objective forwarded to each trial’s
optimizecall;'auto'(default) selects MLE / MAP / variational Bayes from the prior (seeoptimize).
- Returns:
Tuple of log-likelihood of best fitting model and the best fitting model from number of trials.
- Return type:
- run_em(enc_data, estimator, initial_model, strategy=None, max_its=10, delta=1.0e-9, engine=None, objective=None, max_iter=None)[source]
Run an EM-family strategy until convergence or
max_its.objectivetakes the same values asoptimize():None(MLE), a selection string ('auto'/'mle'/'map'/'vb'), or a readymodel -> floatcallable.max_itsis the canonical iteration-cap spelling (matchingoptimize/fit/best_of);max_iteris accepted as a back-compat alias and overridesmax_itswhen given.- Parameters:
- Return type:
SequenceEncodableProbabilityDistribution
- class EMStrategy(*args, **kwargs)[source]
Bases:
ProtocolStructural contract for an EM-family strategy consumed by
run_em().Every strategy object in this module (
StandardEM,PosteriorTransformEM,AnnealedEM, …) satisfies this Protocol structurally by exposing astep(...) -> EMStepResultmethod.run_emand_em_step_fndispatch on it polymorphically; membership is decided byisinstance().
- class StreamingEstimator(estimator, schedule=None, model=None, init_estimator=None, init_p=0.1, rng=None, encoder=None, num_chunks=1)[source]
Bases:
_StreamingBaseDecay-mode online estimator built from accumulator scaling and M-steps.
- Parameters:
estimator (ParameterEstimator)
model (SequenceEncodableProbabilityDistribution | None)
init_estimator (ParameterEstimator | None)
init_p (float)
rng (RandomState | None)
num_chunks (int)
- class IncrementalEstimator(estimator, model=None, init_estimator=None, init_p=0.1, rng=None, encoder=None, num_chunks=1)[source]
Bases:
_StreamingBaseNeal-Hinton style incremental EM over replaceable data chunks.
Each chunk contributes a sufficient-statistic payload computed under the current model. Revisiting a chunk subtracts that chunk’s previous payload, adds the new payload, and runs the ordinary estimator M-step on the pooled statistics. No distribution-specific estimation code lives here; the class only uses
scale(-1),combine(), andestimate().- Parameters:
estimator (ParameterEstimator)
model (SequenceEncodableProbabilityDistribution | None)
init_estimator (ParameterEstimator | None)
init_p (float)
rng (RandomState | None)
num_chunks (int)
- update(data=None, *, enc_data=None, chunk_id=None)[source]
Replace one chunk contribution and return the updated model.
chunk_idis keyword-only so this matchesStreamingEstimator.update()’s(data, *, enc_data)shape across the streaming surface; it is required (aNonechunk_idraises) because the Neal-Hinton update keys each batch’s contribution by it.
- chunk_value(chunk_id)[source]
Return a copy of one stored chunk contribution.
- Parameters:
chunk_id (Any)
- reset()[source]
Drop all chunk contributions and fitted model state.
- Return type:
None
- class BayesianStreamingEstimator(estimator, mode='posterior_carry', schedule=None, model=None, init_estimator=None, init_p=0.1, rng=None, num_chunks=1)[source]
Bases:
objectStreaming / recursive-Bayes driver over the mixle.stats estimator protocol.
mode='posterior_carry'(the default) performs exact recursive conjugate updating: each fitted posterior is carried forward as the next batch’s prior by rebuilding the estimator from the fitted model (model.estimator()returns an estimator whose prior is the model’s posterior).mode='forgetting'applies a power-prior step: the current batch’s accumulated sufficient statistics are scaled byrho = schedule(step)(via the accumulator’sscale, which preserves structural support metadata such as a categorical’smin_val) before the ordinary conjugateestimatecall, and the batch’s contribution tonobsis scaled to match.The public surface is
BayesianStreamingEstimator(estimator, mode=..., schedule=...)plus.update(data=None, enc_data=None)and.reset().- Parameters:
estimator (ParameterEstimator)
mode (str | None)
schedule (Any | None)
model (SequenceEncodableProbabilityDistribution | None)
init_estimator (ParameterEstimator | None)
init_p (float)
rng (RandomState | None)
num_chunks (int)
- update(data=None, enc_data=None)[source]
Consume one batch and return the updated posterior-bearing model.
- reset()[source]
Drop the current model and stream counters.
- Return type:
None
- bayes_action(posterior, loss, actions, *, n=2000, seed=0, cvar_alpha=0.1, quantiles=(0.05, 0.5, 0.95))[source]
Pick the Bayes action:
argmin_a E_{draw ~ posterior}[ loss(a, draw) ].- Parameters:
posterior (Any) – any object exposing
samples(n, rng)– e.g.mixle.inference.posterior(model, data, over=...)(parameter, latent, or predictive).loss (Callable[[Any, Any], float]) –
loss(action, draw) -> float(or a numpy-vectorizedloss(action, draws) -> array).actions (Sequence[Any]) – the finite candidate-action set to minimise over.
n (int) – number of posterior draws for the Monte-Carlo expectation.
seed (int) – RNG seed for the posterior draw (reproducible).
cvar_alpha (float) – tail mass for the CVaR / VaR of the chosen action (0.1 -> worst 10%).
quantiles (Sequence[float]) – loss quantiles to report per action.
- Returns:
{action, action_index, expected_loss, risk_profile, alternatives}– the chosen action, its expected loss, its tail-risk profile, and the expected loss of every candidate.- Raises:
ValueError – if
actionsis empty.CapabilityError – if
posteriordoes not expose thesamples(n, rng)contract.
- Return type:
- class RiskProfile(expected_loss, cvar, cvar_alpha, var, quantiles, std)[source]
Bases:
objectThe tail-risk summary of a single action’s posterior loss distribution.
- Parameters:
- expected_loss: float
- cvar: float
- cvar_alpha: float
- var: float
- std: float
- certify(model, *, escape_tested=False, penalized=False)[source]
Return the
EstimationCertificatefor a fitted model (or distribution prototype).Walks the model’s block structure and classifies each block’s estimation method + guarantee from its capability signals – no fitting is done here, only inspection. Pass
escape_tested=Truewhen the fit ran saddle-escape restarts (mixle.Model.fit()sets this automatically), which upgrades EM blocks fromSTATIONARYtoSTATIONARY_ESCAPE_TESTED.Pass
penalized(a reason string, or True) when the fit optimized a PENALIZED objective – soft constraints, conservation/PINN residual factors, potentials (E2). The optimum is then of the penalized surrogate, NOT the likelihood, so no block may claim more than STATIONARY however clean its own solver is: every stronger block is downgraded with the penalty named in its reason.
- plan_estimation(model, *, escape_tested=False)[source]
Alias for
certify()– the pre-fit planning view over a distribution prototype.
- schedule(model, *, escape_tested=False)[source]
Plan the block-coordinate estimation schedule for
model(planner v2, A3).Built from the same block classification as
certify(): EM blocks make the schedule a loop (E-step + per-block M-steps, repeated until convergence); without a latent block every block is one independent pass. Gradient blocks appear as explicitgradientpasses with their pool placement, so the schedule is also the offload plan for the hybrid case.
- class EstimationSchedule(passes=<factory>, latent=False)[source]
Bases:
objectThe block-coordinate schedule planner v2 produces (A3): ordered passes + the loop structure.
A fully-factorized model schedules one independent pass per block (no loop). A latent model schedules the EM loop explicitly: an E-step over the latent, then one M-step pass PER BLOCK per round – each M-step named with its own method, so the schedule shows exactly where the closed forms live inside the iteration (and which pass, if any, is the gradient block a pool would take).
- passes: list[SchedulePass]
- latent: bool = False
- property per_round: list[SchedulePass]
- property gradient_passes: list[SchedulePass]
- class SchedulePass(order, kind, block, method, placement, repeat)[source]
Bases:
objectOne pass of the estimation schedule: what runs, on which block, how, where, and how often.
- order: int
- kind: str
- block: str
- method: str
- placement: str
- repeat: str
- class EstimationCertificate(guarantee, blocks=<factory>, escape_tested=False)[source]
Bases:
objectThe auditable proof of how a model was (or would be) estimated: per-block plans + the aggregate.
guaranteeis the minimum over blocks.why_not_adamsummarizes where gradient optimization was used and why those blocks could not use a stronger closed-form or convex route.- guarantee: Guarantee
- blocks: list[BlockPlan]
- escape_tested: bool = False
- property gradient_blocks: list[BlockPlan]
- property closed_form_blocks: list[BlockPlan]
- why_not_adam()[source]
The audit: which blocks needed gradient descent and why – everything else got a stronger method.
- Return type:
- class BlockPlan(name, kind, method, guarantee, gradient, placement, reason)[source]
Bases:
objectThe estimation plan for one block of a model: which method ran and how strong its guarantee is.
- Parameters:
- name: str
- kind: str
- method: str
- guarantee: Guarantee
- gradient: bool
- placement: str
- reason: str
- class Guarantee(*values)[source]
Bases:
IntEnumHow strong the solution to an estimation block is, as an ordered ladder (higher = stronger).
- HEURISTIC = 1
- STATIONARY = 2
- STATIONARY_ESCAPE_TESTED = 3
- GLOBAL = 4
- GLOBAL_UNIQUE = 5
- property label: str
- uq(thing, data=None, *, alpha=0.1, equivalent=None)[source]
Quantify the uncertainty of
thing, choosing the method from whatthingis.- Parameters:
thing (Any) – a fitted mixle model, a torch module / point-predictor callable (or a list of them for a deep ensemble), or an LLM-style callable that maps a prompt to a generation.
data (Any) – for a mixle model, the fitting data (builds the Laplace posterior); for a point predictor,
(X_cal, y_cal)calibration data; for an LLM, optional example prompts used to calibrate an abstention threshold.alpha (float) – target miscoverage / abstention level (
1 - alphacoverage).equivalent (Callable[[Any, Any], bool] | None) – for the LLM path, an optional meaning-equivalence predicate over generations (default: exact string match after stripping).
- Returns:
A
UQResultexposing the method-appropriate accessors and its own calibration numbers.- Return type:
UQResult
- class UQResult(kind, method, payload)[source]
Bases:
objectThe uncertainty of a predictor, with the method that produced it and receipts to check it.
- kind: str
- method: str
- sample_models(n=200, *, seed=None)[source]
nfitted models drawn from the parameter posterior (epistemic ensemble).
- credible_interval(readout, alpha=0.1, *, n=400, seed=0)[source]
A
1-alphacredible interval onreadout(model)over the parameter posterior.
- interval(x, alpha=None)[source]
Calibrated prediction interval(s) at
x.alphaoverrides the calibrated level.
- epistemic_std(x)[source]
Ensemble disagreement (std across members) at
x– 0.0 for a single predictor.
- semantic_entropy(prompt, *, n=8)[source]
Entropy (nats) over the meaning classes of
nsampled generations forprompt.
- confident(prompt, *, n=8, max_entropy=None)[source]
True when semantic entropy is below the threshold – else the model disagrees with itself.
- calibration_report(model, data)[source]
The calibration of
modelon held-outdata(see module docstring).datashould be data the model was NOT fitted on – calibration measured on the training set is optimistic. Runs the PIT test when the model has a scalar predictive CDF; always reports the held-out mean log-density.
- class CalibrationReport(n, mean_log_density, pit_error=None, pit_histogram=None, bins=10, method='', note='')[source]
Bases:
objectWhether a fitted model’s uncertainty is calibrated on held-out data.
pit_erroris the total-variation distance of the PIT histogram from uniform (0 = perfectly calibrated). It has a finite-sample floor ~``sqrt(bins/n)`` even for a perfect model, sois_calibrated()judges against that floor rather than a fixed constant.- Parameters:
- n: int
- mean_log_density: float
- bins: int = 10
- method: str = ''
- note: str = ''
- noise_floor()[source]
The PIT-error a perfectly calibrated model would show at this sample size (sampling noise).
- Return type:
- is_calibrated(tol=None)[source]
True when the PIT error is within tolerance. Default tol = 2.5x the finite-sample noise floor (so genuine miscalibration, not sampling noise, is what fails). Unknown -> False, conservatively.
- plan_placement(certificate, pool=None, *, telemetry=None)[source]
Decide local vs pool for every block of a certified fit (see module docstring).
Closed-form / convex / EM blocks always stay local. A gradient (
pool_eligible) block goes to the pool only whenpool.availableand its estimated work clearspool.flop_threshold_tflop; otherwise it stays local too. Each decision carries a priced reason, and (with a pool) aplacementtelemetry event is emitted per block.- Parameters:
certificate (EstimationCertificate)
pool (PoolSpec | None)
telemetry (Any)
- Return type:
PlacementPlan
- class PlacementPlan(placements=<factory>, pool_spec=None)[source]
Bases:
objectThe full local-vs-pool plan for a model’s blocks, derived from its certificate + a PoolSpec.
- Parameters:
placements (list[BlockPlacement])
pool_spec (PoolSpec | None)
- placements: list[BlockPlacement]
- pool_spec: PoolSpec | None = None
- property pool_blocks: list[BlockPlacement]
- property local_blocks: list[BlockPlacement]
- property est_pool_cost: float
- class BlockPlacement(name, kind, placement, reason, est_tflop=0.0, est_cost=0.0)[source]
Bases:
objectWhere one block runs and why: ‘local’ or ‘pool’, with the priced justification.
- name: str
- kind: str
- placement: str
- reason: str
- est_tflop: float = 0.0
- est_cost: float = 0.0
- class PoolSpec(available=False, cost_per_hour=0.5, flop_threshold_tflop=1.0, pool_speedup=10.0)[source]
Bases:
objectWhat the shared GPU pool offers, and when offloading is worth it.
available: is a pool configured at all (else everything is local).cost_per_hour: the pool’s price.flop_threshold: the estimated work (in TFLOP) below which the round-trip is not worth it – small gradient blocks stay local.local_tflops/ pool speedup drive the estimate.- Parameters:
- available: bool = False
- cost_per_hour: float = 0.5
- flop_threshold_tflop: float = 1.0
- pool_speedup: float = 10.0
- learn_placement_policy(rows, static_policy, *, cost_key='cost', k=8, min_neighbors=4)[source]
Learn a placement policy from telemetry
(features, choice, outcome)rows (see module docstring).static_policymaps a feature dict to a choice and is the fall-back when history is too thin.cost_keynames the outcome field to minimize (default"cost"). Feature standardization and the neighbor index are built from the rows;LearnedPolicy.decide()andevaluatefollow.
- class LearnedPolicy(keys, vecs, choices, costs, static, mean=<factory>, scale=<factory>, k=8, min_neighbors=4, margin=0.02)[source]
Bases:
objectA history-based placement policy that defers to a static teacher where it lacks evidence.
- Parameters:
- vecs: ndarray
- costs: ndarray
- mean: ndarray
- scale: ndarray
- k: int = 8
- min_neighbors: int = 4
- margin: float = 0.02
- decide(features)[source]
Return
(choice, learned)– the learned pick when confident, else the static fallback.
- learn_action_policy(rows, static_scorer=None, *, value_key='value', k=8, min_neighbors=4)[source]
Learn a reasoner acquisition policy from
routetelemetry(features, kind, outcome)rows.static_scoreris the fall-back when history is thin (defaultmixle.substrate.act.score_action()).value_keynames the outcome field to MAXIMIZE (default"value"– did the action yield evidence). Returns aLearnedAcquisitionusable directly asinvestigate(..., scorer=policy).
- class LearnedAcquisition(keys, vecs, values, static, mean=<factory>, scale=<factory>, k=8, min_neighbors=4)[source]
Bases:
objectA history-based action scorer for the reasoner: learns which actions pay off, else defers.
Drop-in for
mixle.substrate.act.score_action()(call it asscorer=policyininvestigate). Fromroutetelemetry – each row a fired action’s(features={kind,cost,overlap}, value)– it estimates the expected yield of an action in a query’s feature region and scores ityield / cost. Where nearby history is too thin, it FALLS BACK to the static lexical scorer: the same never-worse discipline asLearnedPolicy, now on the reasoner’s acquisition decisions (J3).- Parameters:
- vecs: ndarray
- values: ndarray
- mean: ndarray
- scale: ndarray
- k: int = 8
- min_neighbors: int = 4
- learn_schedule_policy(rows, static_policy, *, latency_key='latency', k=8, min_neighbors=4)[source]
Learned pool scheduling (J4): when work is pool-eligible, learn WHERE/WHEN it actually runs fastest.
The same never-worse shape as placement, keyed on realized LATENCY instead of dollar cost: rows are
(features, choice, outcome)where features describe the moment (queue depth, job size, local load), choice is the scheduling decision (“run_local” / “queue_pool” / “defer”), and the outcome’slatencyis what the decision actually cost in wall-clock. Where nearby history is thin, the returned policy defers to the static scheduler.
- meta_improve(rows, static_policy, *, cost_key='cost', holdout_frac=0.3, seed=0, k=8, min_neighbors=4)[source]
The meta-improve loop (J5): learn from telemetry, PROMOTE only on a never-worse holdout receipt.
Splits the telemetry into train/holdout, learns a policy on the train slice, and evaluates it against the static policy on the HELD-OUT decisions (realized cost, the same currency the platform pays). The learned policy is promoted iff its held-out mean cost is <= the static policy’s – the receipt is returned either way, so a non-promotion is auditable, not silent. Returns:
{promoted, policy, receipt: {learned_mean_cost, static_mean_cost, deferred_fraction, n}}
policyis the learned policy when promoted, else the static one wrapped for the same call shape – callers can always use the result’s policy and get never-worse behavior by construction.
- simulate(model)[source]
Package a fitted
modelas aSimulator(see module docstring).- Parameters:
model (Any)
- Return type:
Simulator
- class Simulator(model)[source]
Bases:
objectA fitted model packaged as a data generator, runnable under a baseline or named scenarios.
- Parameters:
model (Any)
- scenario(name, interventions)[source]
Register a named intervention scenario (requires a learned Bayesian network to apply).
- run(n=100, *, scenario=None, interventions=None, seed=0)[source]
Generate
nsynthetic records under the baseline, a registeredscenario, or ad-hocinterventions.
- outcome_mean(field_index, *, scenario=None, n=2000, seed=0)[source]
The mean of a numeric field under a scenario – the quantity to compare across conditions.
- class Scenario(name, interventions=<factory>)[source]
Bases:
objectA named simulation condition: which fields are clamped to which values (an intervention).
- name: str
- synthesize(source, *, label=None, verify=None, n=100, max_tries=None, seed=0)[source]
Build a verified dataset of
naccepted rows from a generativesource(see module docstring).sourceis a fitted model (sampled), a list of real inputs (a generator is inferred over them), or a callable draw function.label(optional) is the teacher applied to each input.verify(optional) acceptsverify(x)orverify(x, label)and gates each row – rejected rows are resampled up tomax_triestotal draws. The verifier is attached to the returnedDatasetso consumers canrecheck()independently.
- class Dataset(inputs, labels=None, verify=None, acceptance_rate=1.0, n_rejected=0, provenance=<factory>)[source]
Bases:
objectA verified synthetic dataset: inputs, optional labels, and the verifier that vouched for them.
- Parameters:
- acceptance_rate: float = 1.0
- n_rejected: int = 0
- pairs()[source]
(input, label)pairs – raises if the dataset is unlabeled.
- create(data, *, budget=None, device=None, calibrate=None, quantify_uq=False, max_its=25, seed=0)[source]
Create a certified model from
data(see module docstring).datais a list of records/scalars.calibrate(a fraction in (0,1)) reserves a holdout for a PIT calibration check.quantify_uq=Trueattaches an auto-selected UQ handle.budget/device(any object; recorded verbatim) constrain the fit toward a smaller model. Returns aCreatedModelbundling the fit, its certificate, and the requested post-conditions.
- class CreatedModel(model, certificate, strategy, calibration=None, uq=None, provenance=<factory>)[source]
Bases:
objectA certified model artifact: the fitted model plus its guarantees and provenance.
- Parameters:
- model: Any
- certificate: Any
- strategy: str
- property guarantee: Any
The aggregate estimation guarantee (MIN over blocks) – the artifact’s headline claim.
- skill(name, obj, *, description='', tags=(), call=None, provenance=None, registry=None)[source]
Package
obj(a fitted model, aCreatedModel, or a function) as a reusableSkilland register it (see module docstring).The estimation certificate is inherited from
obj.certificatewhen present (so a certified model yields a certified skill).calloverrides how the skill is invoked; otherwise a model verb (predict/__call__/sampler) is used. The skill is added toregistry(or the process default) and returned.
- class Skill(name, call, description='', tags=(), certificate=None, provenance=<factory>)[source]
Bases:
objectA named, described, provenanced callable derived from a fitted artifact (or a plain function).
- Parameters:
- name: str
- description: str = ''
- class SkillRegistry[source]
Bases:
objectA findable collection of skills – register once, retrieve by name or by query.
- add(sk)[source]
- Parameters:
sk (Skill)
- Return type:
Skill
- find(query, k=5)[source]
The best
kskills forqueryby lexical overlap (highest score first, ties by name).
- best(query)[source]
The single best-matching skill for
query(or None if nothing overlaps).- Parameters:
query (str)
- Return type:
Skill | None
- index(substrate)[source]
Mirror every skill into a
Substratefor embedding-grade recall.The registry’s own
findis a lexical matcher; when a corpus grows past that, index the skills asartifactitems and retrieve through the substrate instead. Returns the item ids.
- default_registry()[source]
The process-wide default registry
skill()writes to when noregistryis given.- Return type:
SkillRegistry
- posterior(model, data=None, *, over='predictive', prior=None, method='auto', **kwargs)[source]
Build the
Posteriorofmodelover the requested variables.- Parameters:
model (Any) – a fitted mixle distribution (or a latent-variable model for
over='latent').data (Any) – observations – required for
over='params'and forover='latent'(thexthe latent posterior conditions on); ignored for plug-inover='predictive'.over (str) –
'latent'->q(z | x)(needs thelatent_posteriorcapability);'params'->q(theta | data);'predictive'-> draws of new data.prior (Any) – prior over parameters for
over='params'(seeconjugate_posterior/sample_parameter_posterior).method (str) – for
over='params'–'auto'(conjugate when the family supports it, else MCMC),'conjugate', or'mcmc'.**kwargs (Any) – forwarded to
sample_parameter_posteriorfor the MCMC path (sampler,steps…).
- Returns:
A
Posterior– aLatentPosterior,ParameterPosterior, orPredictivePosterior.- Return type:
Posterior
- class ParameterPosterior(draw_one, draw_many, *, mean_fn=None, chain=None, kind='')[source]
Bases:
Posteriorq(theta | data)over a model family’s parameters – exact (conjugate) or MCMC.Built by
posterior(model, data, over="params"); the exact-vs-MCMC distinction is hidden behind the sharedPosteriorinterface. A singlesample()returns one parameter set, andsamples()returnsnof them;mean()andinterval()summarize the posterior.- Parameters:
- classmethod from_conjugate(cp)[source]
Wrap a closed-form
ConjugatePosterior(each draw is a parameter dict).- Parameters:
cp (ConjugatePosterior)
- Return type:
ParameterPosterior
- classmethod from_mcmc(result)[source]
Wrap an MCMC
MCMCResult; draws resample the retained chain, summaries use it directly.- Parameters:
result (Any)
- Return type:
ParameterPosterior
- sample(rng=None)[source]
One parameter draw from the posterior.
- samples(n, rng=None)[source]
nparameter draws (a dict of length-narrays for conjugate; a list for MCMC).
- class PredictivePosterior(draw_one, draw_many)[source]
Bases:
PosteriorThe posterior-predictive: draws of new data from a fitted model.
plug_in()wraps a single fitted model’s sampler.from_parameter_posterior()integrates parameter uncertainty – each predictive draw first samplestheta ~ q(theta | data), rebuilds the model, then draws data – so the spread reflects both sampling and parameter uncertainty.- Parameters:
draw_one (Callable[[Any], Any])
draw_many (Callable[[int, Any], Any])
- classmethod plug_in(model)[source]
Plug-in predictive: draw new data from
modelat its fitted parameters.- Parameters:
model (Any)
- Return type:
PredictivePosterior
- classmethod from_parameter_posterior(param_post, build)[source]
Posterior-predictive integrating parameter uncertainty.
buildmaps one parameter draw (the objectParameterPosterior.sample()returns) to a distribution; each predictive draw rebuilds the model from a freshthetaand samples it.
- record_fit(model, data, *, seed, estimator=None)[source]
Record a
ReproReceiptfor a model fitted ondatawithseed(see module docstring).
- verify_reproducible(estimator, data, receipt, *, seed=None, max_its=25)[source]
Refit
estimatorondataand check the fit reproducesreceipt(data + parameters).Returns
{reproducible, data_matches, params_match, refit_fingerprint}.reproducibleis True iff BOTH the data fingerprint and the refit’s parameter fingerprint match the receipt – i.e. the exact fit can be recovered from the recorded recipe.seeddefaults to the receipt’s seed.
- class ReproReceipt(data_fingerprint, n, seed, estimator, param_fingerprint)[source]
Bases:
objectThe recipe to re-derive a fit: data + seed + estimator, plus the parameter fingerprint to check.
- data_fingerprint: str
- n: int
- seed: int
- estimator: str
- param_fingerprint: str
- matches_data(data)[source]
Whether
datais the exact dataset this fit was recorded on.
- data_fingerprint(data, *, ndigits=_NDIGITS)[source]
A stable hash of a training dataset (order-sensitive; floats rounded) – identifies the exact input.
- param_fingerprint(model, *, ndigits=_NDIGITS)[source]
A stable hash of a fitted model’s parameters, via its
to_jsonstate (floats rounded).
- class BeliefState[source]
Bases:
ABCA distribution over a latent, exposing a uniform query + update interface.
Realizations answer where they are defined:
mean(),cov(),var(),sd(),entropy(),interval(),sample(),marginal(), and – the point of a belief state –update(), which returns a new belief conditioned on fresh evidence.- abstractmethod entropy()[source]
The differential/Shannon entropy
H[q](nats) – watch it shrink as evidence arrives.- Return type:
- abstractmethod sample(n=1, rng=None)[source]
Draw
nlatent samples from the belief.
- abstractmethod update(*args, **kwargs)[source]
Return a new belief conditioned on fresh evidence (the assimilation step).
- interval(level=0.9)[source]
Per-coordinate central credible interval at
level– an(d, 2)array of[lo, hi].
- class GaussianBelief(mean, cov)[source]
Bases:
BeliefStateA multivariate-Gaussian belief
N(mean, cov)over a continuous latent.Evidence is a linear-Gaussian observation
y = H z + noise,noise ~ N(0, R);update()applies the exact Kalman measurement update (Joseph form, so the covariance stays symmetric positive-definite).fuse()combines two beliefs about the same latent as a product of Gaussian experts.condition()does noiseless Gaussian conditioning on a coordinate subset.- Parameters:
mean (Any)
cov (Any)
- property dim: int
- entropy()[source]
The differential/Shannon entropy
H[q](nats) – watch it shrink as evidence arrives.- Return type:
- interval(level=0.9)[source]
Per-coordinate central credible interval at
level– an(d, 2)array of[lo, hi].
- sample(n=1, rng=None)[source]
Draw
nlatent samples from the belief.
- update(H, y, R)[source]
Kalman measurement update: condition on
y = H z + noise,noise ~ N(0, R).
- fuse(other)[source]
Product-of-experts fusion of two beliefs about the same latent (cross-modal fusion).
Equivalent to conditioning
selfonothertreated as a direct Gaussian observation (H = I,R = other.cov), so it reuses the exact Kalman update.- Parameters:
other (GaussianBelief)
- Return type:
GaussianBelief
- condition(indices, values)[source]
Noiseless Gaussian conditioning: fix latent coordinates
indicestovalues.Returns the belief over the remaining coordinates. This is the exact
R -> 0limit of an observation that reads off those coordinates.
- as_belief(obj, node=None)[source]
Adapt any object exposing
mean/cov(aFieldPosteriornode, a fitted Gaussian, aParameterPosterior) into aGaussianBelief.nodeis forwarded when the source is node-addressable (e.g.FieldPosterior.mean(node)/.cov(node)); otherwisemean/covare called with no argument.
- class UncertaintyDecomposition(total, aleatoric, epistemic, kind)[source]
Bases:
objectA predictive uncertainty split into
aleatoric+epistemic(summing tototal).kindis"entropy"(values in nats) or"variance"(values in the outcome’s squared units). Each field is a scalar for a single query point, or an array over query points.- total: ndarray
- aleatoric: ndarray
- epistemic: ndarray
- kind: str
- property fraction_epistemic: ndarray
Share of the total uncertainty that is epistemic (reducible by more data), in
[0, 1].
- item()[source]
Collapse size-1 arrays to Python floats (convenience for single-point decompositions).
- Return type:
UncertaintyDecomposition
- decompose_uncertainty(*, probs=None, means=None, variances=None)[source]
Front door: decompose a predictive into aleatoric + epistemic uncertainty.
Pass exactly one representation of the per-member predictive:
probs=(M, ..., K)– categorical predictives -> BALD entropy split (decompose_entropy());means=(M, ...)(with optionalvariances=(M, ...)) – continuous predictives -> law-of-total-variance split (decompose_variance()).
To decompose a fitted model’s parameter uncertainty, build the members first with
posterior_ensemble()(thenpredictive_distribution()for the discrete case).
- decompose_entropy(member_probs)[source]
BALD entropy split of a discrete predictive.
- Parameters:
member_probs (Any) – array
(M, ..., K)–Mposterior draws / ensemble members, each a categorical predictive overKoutcomes (optionally batched over query points in the middle axes). Rows need not be normalized; each is renormalized over the last axis.- Returns:
An
UncertaintyDecompositionwithkind="entropy"(nats).epistemicis the mutual informationH(mean) - mean Hand is clamped to>= 0(it is non-negative in exact arithmetic; the clamp only removes tiny floating-point negatives).- Return type:
UncertaintyDecomposition
- decompose_variance(member_means, member_vars=None)[source]
Law-of-total-variance split of a continuous predictive.
- Parameters:
member_means (Any) – array
(M, ...)– each member’s predictive meanE[y | theta_m].member_vars (Any) – array
(M, ...)– each member’s predictive varianceVar[y | theta_m]. IfNone, aleatoric noise is taken as zero (members are point predictors) and the decomposition reports only the epistemic spread of the means.
- Returns:
aleatoric = mean_m Var_m,epistemic = Var_m(mean_m),totaltheir sum.- Return type:
An
UncertaintyDecompositionwithkind="variance"
- predictive_distribution(members, support)[source]
Evaluate an iterable of fitted distributions over a discrete
support->(M, K)probs.Each member’s
log_densityis evaluated at every point ofsupportand softmax-normalized over the support, giving one categorical row per member. Feed the result todecompose_entropy().
- posterior_ensemble(param_post, build, n=200, rng=None)[source]
Materialize
nmodels from a parameter posterior – an ensemble representingq(theta|data).buildmaps one parameter draw (whateverParameterPosterior.sample()returns) to a fitted distribution, mirroringfrom_parameter_posterior(). The returned list is the “members” the decomposition integrates over – so epistemic uncertainty here is genuine parameter uncertainty, not just ensemble disagreement.
- class Clustering(representatives, probs, labels)[source]
Bases:
objectSamples grouped into equivalence classes:
representatives, classprobs, per-samplelabels.- probs: ndarray
- labels: ndarray
- cluster_samples(samples, equivalent=None)[source]
Group
samplesinto equivalence classes underequivalent(default exact==).For discrete draws whose surface form varies but meaning does not – e.g. LLM generations (“Paris”, “It’s Paris.”, “The capital is Paris”) – pass a semantic
equivalent(embedding similarity, an entailment check, normalized match). Greedy single-linkage against each cluster’s first member; returns the class distribution and per-sample assignments.
- marginalize_meaning(items, equivalent=None, *, log_probs=None, weights=None)[source]
The distribution over meanings = the string distribution marginalized over each meaning class.
A generative model puts probability on strings; a meaning is an equivalence class of strings (
equivalentdecides sameness). The probability of a meaningcis the pushforward under the quotient – you sum the string probabilities over the class:P(c) = sum_{s in c} P(s). This returns that marginal (as aClustering,probs=P(c)).How the per-string probability enters:
log_probs– the model’s sequence log-probabilitieslog P(s)for each item; classes are combined bylogsumexp(exact marginalization, numerically stable). Use this when the items are distinct strings whose probabilities you know – it corrects the counting form’s hidden “every string in a class is equiprobable” assumption.weights– explicit non-negative masses per item (summed within class).neither – uniform mass, i.e. counting:
P(c) = count_c / N. For i.i.d. samples from the model this is the unbiased Monte-Carlo estimate of the same marginal.
- semantic_entropy(samples, equivalent=None, *, log_probs=None, weights=None)[source]
Entropy (nats) over the meaning classes of
samples– the model’s predictive uncertainty.Sample a stochastic generator (an LLM at temperature)
ntimes, marginalize the string distribution over meaning classes (marginalize_meaning()), and take the entropy of that marginal. High semantic entropy means the model disagrees with itself about what the answer is (a hallucination signal), as opposed to merely phrasing one answer many ways (which collapses to low entropy). Passlog_probs(the sequence log-likelihoods) to marginalize with the actual string probabilities rather than by sample counting. Feed the clusters’ per-member distributions todecompose_entropy()for an epistemic/aleatoric split.
- reliability_curve(prob, outcome, *, bins=10, strategy='uniform', ci=False, n_boot=1000, ci_level=0.95, seed=0)[source]
Reliability diagram: observed frequency vs mean forecast probability, per bin.
Bins the forecasts, then within each bin compares the mean predicted probability to the observed event frequency. A perfectly calibrated forecaster lies on the diagonal
observed == predicted.- Parameters:
prob (ndarray) –
(n,)predicted probabilities of the positive class (or top-label confidences).outcome (ndarray) –
(n,)0/1 outcomes (or correctness indicators).bins (int) – number of bins.
strategy (str) –
"uniform"(equal-width) or"quantile"(equal-count) bins.ci (bool) – if True attach a percentile bootstrap band on the observed frequency in each bin.
n_boot (int) – bootstrap resamples when
ciis True.ci_level (float) – central probability of the bootstrap band (e.g. 0.95).
seed (int | RandomState | None) – RNG seed for the bootstrap.
- Returns:
{'mean_pred', 'obs_freq', 'count', 'bin_edges'}(one entry per non-empty bin), plus'obs_lo'/'obs_hi'whenciis True.- Return type:
- expected_calibration_error(prob, outcome, *, bins=10, strategy='uniform', norm='l1', ci=False, n_boot=1000, ci_level=0.95, seed=0)[source]
Expected Calibration Error: count-weighted average gap between confidence and accuracy.
ECE = sum_b (n_b / n) |obs_b - pred_b|over bins (norm='l2'uses the squared gap, square- rooted). Zero is perfect calibration. For multiclass classifiers reduce withtop_label_confidence()first.- Parameters:
prob (ndarray) –
(n,)predicted probabilities / confidences.outcome (ndarray) –
(n,)0/1 outcomes / correctness indicators.bins (int) – number of bins.
strategy (str) –
"uniform"or"quantile"binning.norm (str) –
"l1"(mean absolute gap) or"l2"(root mean squared gap).ci (bool) – if True also return a percentile bootstrap interval.
n_boot (int) – bootstrap controls.
ci_level (float) – bootstrap controls.
seed (int | RandomState | None) – bootstrap controls.
- Returns:
The ECE (float), or
(ece, lo, hi)whenciis True.- Return type:
- maximum_calibration_error(prob, outcome, *, bins=10, strategy='uniform')[source]
Maximum Calibration Error: the worst per-bin gap
max_b |obs_b - pred_b|.Unlike
expected_calibration_error()this is not count-weighted, so it surfaces a small but badly-miscalibrated region that the average would hide.
- top_label_confidence(prob, labels)[source]
Reduce a multiclass classifier to the (confidence, correct) top-label calibration problem.
- Parameters:
- Returns:
the max predicted probability per row and a 0/1 indicator of whether that argmax class was the true label. Feed these to
reliability_curve()/expected_calibration_error().- Return type:
(confidence, correct)
- class ProbabilityCalibrator(method='isotonic')[source]
Bases:
objectMap raw scores to calibrated probabilities – fit against binary outcomes.
A raw score (a model’s confidence, a self-consistency fraction, a token likelihood) need not be a probability of anything: it can be monotone-but-miscalibrated, or have no relationship to the outcome at all. This learns the transform
score -> P(outcome = 1 | score)from labeled data, so the output is a probability of the event you calibrated against.method="isotonic"– monotone, non-parametric (pool-adjacent-violators). Assumes higher score => not-lower probability; flexible, needs enough calibration points.method="platt"– logisticsigmoid(a * score + b). Two parameters, robust on little data, but assumes a sigmoidal relationship.
A near-flat fitted curve is itself the finding: it means the raw score carried little information about the outcome (its “likelihood” was unrelated to the event).
- Parameters:
method (str)
- fit(scores, outcomes)[source]
Fit the score->probability map on
scoreswith binaryoutcomes(0/1).
- calibrate_probabilities(scores, outcomes, *, method='isotonic')[source]
Fit a
ProbabilityCalibratormappingscorestoP(outcome=1 | score).
- pit_values(y, cdf)[source]
Probability Integral Transform values
u_i = F_i(y_i).Under a calibrated continuous predictive distribution the PIT values are Uniform(0, 1). Pass either the precomputed CDF values
F_i(y_i)or a callablecdf(y) -> F(y).
- pit_ensemble(y, forecasts, *, randomize=True, seed=0)[source]
Rank-based PIT from a finite predictive ensemble.
u_iis the fraction of ensemble members<= y_i. Withrandomize=Trueties are broken by a uniform jitter within the rank gap, which makes the PIT exactly Uniform(0, 1) under calibration even for discrete ensembles (the randomized PIT of Czado et al. 2009).
- pit_histogram(pit, *, bins=10)[source]
Histogram of PIT values with the uniform reference level.
- pit_calibration_error(pit, *, bins=10)[source]
Calibration error of a PIT histogram: mean absolute deviation from uniform mass.
sum_b |count_b/n - 1/bins|– 0 when the PIT histogram is perfectly flat (calibrated), larger when it is U-shaped (under-dispersed) or humped (over-dispersed).
- interval_coverage(lower, upper, y)[source]
Empirical coverage and mean width of a set of prediction intervals.
- Parameters:
- Returns:
{'coverage', 'mean_width'}– the fraction ofyinside[lower, upper]and the mean interval width. Comparecoverageto the nominal level the interval was built for.- Return type:
- coverage_curve(forecasts, y, *, levels=None)[source]
Empirical-vs-nominal coverage of central intervals across a grid of nominal levels.
For each nominal central level
cthe per-observation central interval[quantile((1-c)/2), quantile((1+c)/2)]is read off the predictive ensemble and its empirical coverage is measured. A calibrated forecast traces the diagonalempirical == nominal; bowing below the diagonal means the intervals are too narrow (over-confident).
- bonferroni(pvals, *, alpha=0.05)[source]
Bonferroni single-step FWER control: adjusted
p_i = min(1, m p_i).The simplest and most conservative correction; always valid regardless of dependence.
- holm(pvals, *, alpha=0.05)[source]
Holm step-down FWER control – uniformly more powerful than Bonferroni, equally valid.
Sorts p-values ascending and applies the running factor
m - kwith a cumulative maximum so the adjusted values stay monotone.
- hochberg(pvals, *, alpha=0.05)[source]
Hochberg step-up FWER control (valid under independence / positive dependence).
Same per-step factor as Holm but applied step-up (from the largest p-value down), giving more rejections; requires the independence/PRDS assumption that Holm does not.
- benjamini_hochberg(pvals, *, alpha=0.05)[source]
Benjamini–Hochberg FDR control; adjusted values are q-values.
Controls the expected false-discovery proportion at
alphaunder independence or positive regression dependence (PRDS). The standard choice for screening many hypotheses.
- benjamini_yekutieli(pvals, *, alpha=0.05)[source]
Benjamini–Yekutieli FDR control, valid under arbitrary dependence.
Like
benjamini_hochberg()but inflated by the harmonic factorc(m) = sum_{i=1}^m 1/i, so it holds for any dependence structure at the cost of power.
- adjust_pvalues(pvals, *, method='bh', alpha=0.05)[source]
Unified dispatcher over the correction methods.
- Parameters:
- Returns:
{'reject', 'pvals_adjusted', 'n_reject', 'alpha'}.- Return type:
- fisher_combine(pvals)[source]
Fisher’s method: combine independent p-values via
-2 sum log p ~ chi^2_{2k}.Sensitive to a few very small p-values. For combining evidence for the same hypothesis across independent tests.
- stouffer_combine(pvals, *, weights=None)[source]
Stouffer’s Z method: combine p-values on the z-scale, optionally weighted.
Z = sum w_i Phi^{-1}(1 - p_i) / sqrt(sum w_i^2). Weights let more-precise studies (e.g. larger samples) count more; equal weights recover the unweighted combination.
- tippett_combine(pvals)[source]
Tippett’s method (Sidak min-p): combined
p = 1 - (1 - min p)^k.Most powerful when a single strong signal exists among the tests.
- bootstrap(data, statistic, *, n_boot=2000, method='bca', ci_level=0.95, seed=0, groups=None, clusters=None, block_length=None, m=None)[source]
Bootstrap confidence interval for
statistic(data).- Parameters:
data (Any) – a single array (resampled along axis 0) or a tuple of arrays sharing their first axis (the statistic is then called as
statistic(*parts)).statistic (Callable[[...], Any]) – maps the data to a scalar or fixed-length vector.
n_boot (int) – number of bootstrap resamples.
method (str) –
"percentile","basic"(pivotal), or"bca"(bias-corrected & accelerated)."bca"is only second-order accurate for plain i.i.d. resampling; withgroups/clusters/block_length/mset it falls back to"percentile".ci_level (float) – central probability of the interval.
seed (int | RandomState | None) – RNG seed.
groups (ndarray | None) –
(n,)labels for stratified resampling (resample within each group).clusters (ndarray | None) –
(n,)labels for cluster resampling (resample whole clusters with replacement).block_length (int | None) – moving-block length for serially dependent (time-series) data.
m (int | None) – subsample size for m-out-of-n subsampling (without replacement).
- Returns:
A
BootstrapResult.- Return type:
BootstrapResult
- class BootstrapResult(estimate, ci_low, ci_high, distribution, method, ci_level, standard_error)[source]
Bases:
objectResult of a
bootstrap()call.- Parameters:
- estimate
the statistic on the original data (scalar or vector).
- Type:
- ci_low / ci_high
confidence-interval endpoints (same shape as
estimate).
- distribution
(n_boot, ...)array of bootstrap replicates.- Type:
- method
the interval method used.
- Type:
- ci_level
the central probability of the interval.
- Type:
- standard_error
bootstrap standard error (std of the replicates).
- Type:
- estimate: ndarray
- ci_low: ndarray
- ci_high: ndarray
- distribution: ndarray
- method: str
- ci_level: float
- standard_error: ndarray
- block_bootstrap(data, statistic, block_length, *, n_boot=2000, ci_level=0.95, seed=0)[source]
Moving-block bootstrap for serially dependent (time-series) data.
Convenience wrapper over
bootstrap()withblock_lengthset: resamples contiguous blocks so within-block autocorrelation is preserved. Chooseblock_lengthon the order of the series’ correlation length.
- wild_bootstrap(fitted, residuals, statistic, *, n_boot=2000, kind='rademacher', ci_level=0.95, seed=0)[source]
Wild (residual-multiplier) bootstrap, robust to heteroscedasticity.
Builds synthetic responses
y* = fitted + residual * vwherevare mean-zero, unit-variance two-point multipliers drawn independently per observation, then recomputes the statistic on eachy*. Because each residual keeps its own magnitude, the procedure preserves heteroscedasticity that an i.i.d. residual resample would destroy.- Parameters:
fitted (ndarray) –
(n,)fitted values from the model.residuals (ndarray) –
(n,)residualsy - fitted.statistic (Callable[[ndarray], Any]) – maps a synthetic response vector
y*to a scalar or vector (e.g. refit and return coefficients).n_boot (int) – number of resamples.
kind (str) –
"rademacher"(v in {-1, +1}) or"mammen"(Mammen’s two-point distribution).ci_level (float) – central probability of the percentile interval.
seed (int | RandomState | None) – RNG seed.
- Returns:
A
BootstrapResult(percentile interval).- Return type:
BootstrapResult
- permutation_test(x, y, *, statistic=None, n_perm=10000, alternative='two-sided', paired=False, stratify=None, seed=0, exact_max=10000)[source]
Two-sample permutation test for an arbitrary statistic under a sharp null.
Under the null that the two samples are exchangeable, the labels can be shuffled freely; the statistic’s permutation distribution is the reference. For
two-sidedthe statistic is centered at zero by construction (difference statistics) and compared on absolute value.- Parameters:
x (ndarray) – the two samples (1-D). For
paired=Truethey must have equal length and pairing is preserved by sign-flipping the within-pair differences.y (ndarray) – the two samples (1-D). For
paired=Truethey must have equal length and pairing is preserved by sign-flipping the within-pair differences.statistic (Callable[[ndarray, ndarray], float] | None) –
f(x, y) -> float; defaults to the difference in means. Forpairedit is applied to(differences, zeros)so the default reduces to the mean paired difference.n_perm (int) – number of random rearrangements (ignored if the exact set is enumerated).
alternative (str) –
"two-sided","greater", or"less".paired (bool) – paired (sign-flip) permutation instead of label shuffling.
stratify (ndarray | None) –
(n,)group labels (concatenated x-then-y) for restricted permutation – labels are shuffled only within each group, preserving group structure.seed (int | RandomState | None) – RNG seed.
exact_max (int) – if the number of distinct rearrangements is
<= exact_maxthey are enumerated for an exact p-value.
- Returns:
A
PermutationResult.- Return type:
PermutationResult
- class PermutationResult(statistic, pvalue, null_distribution, n_perm, exact, alternative)[source]
Bases:
objectResult of a
permutation_test().- Parameters:
- statistic
the observed test statistic.
- Type:
- pvalue
the (one- or two-sided) p-value.
- Type:
- null_distribution
the statistic under each sampled/enumerated rearrangement.
- Type:
- n_perm
number of rearrangements used.
- Type:
- exact
True if the full permutation set was enumerated.
- Type:
- alternative
the alternative hypothesis.
- Type:
- statistic: float
- pvalue: float
- null_distribution: ndarray
- n_perm: int
- exact: bool
- alternative: str
- sandwich_covariance(scores, bread, *, clusters=None, n_params=None, small_sample=True)[source]
Generic sandwich covariance
B M B'from per-observation scores and the bread.- Parameters:
scores (ndarray) –
(n, p)per-observation contributions to the estimating equation (for OLS thei-th row isx_i * e_i; for a GLM the score of observationi).bread (ndarray) –
(p, p)inverse sensitivityB(e.g.(X'X)^{-1}for OLS, the inverse negative Hessian / inverse Fisher for an M-estimator).clusters (ndarray | None) – optional
(n,)cluster labels; scores are summed within cluster before forming the meat (the robust-to-within-cluster-correlation meat). If None, observations are independent.n_params (int | None) – number of estimated parameters for the small-sample correction (defaults to
p).small_sample (bool) – apply the usual finite-sample correction (
n/(n-p)for independent data,G/(G-1) * (n-1)/(n-p)for clustered).
- Returns:
The
(p, p)robust covariance matrix.- Return type:
- ols_robust_covariance(x, residuals, *, hc='hc1')[source]
Heteroscedasticity-consistent (White) covariance for OLS coefficients.
Cov = (X'X)^{-1} ( sum_i w_i x_i x_i' ) (X'X)^{-1}where the per-observation weightw_iis the squared residual, optionally adjusted for leverageh_ii:hc0:e_i^2(White’s original; biased down in small samples).hc1:e_i^2 * n/(n-p)(degrees-of-freedom correction; the common default).hc2:e_i^2 / (1 - h_ii).hc3:e_i^2 / (1 - h_ii)^2(best small-sample behaviour; ~jackknife).
- cluster_robust_covariance(x, residuals, clusters, *, small_sample=True)[source]
Cluster-robust (one-way or multi-way) covariance for OLS coefficients.
Allows arbitrary correlation within clusters while assuming independence across them. Pass one label array for one-way clustering, or a list/tuple of label arrays for multi-way clustering, which uses the Cameron–Gelbach–Miller inclusion–exclusion
V_A + V_B - V_{A∩B}(two-way) and its higher-way generalisation.- Parameters:
- Returns:
The
(p, p)cluster-robust covariance matrix.- Return type:
- newey_west_covariance(x, residuals, *, lags=None, small_sample=True)[source]
Newey–West HAC covariance for OLS coefficients (serially correlated errors).
Heteroscedasticity- and autocorrelation-consistent: the meat is the long-run covariance of the scores
s_t = x_t e_t, estimated with Bartlett (triangular) weights so it stays positive semi-definite:S = Gamma_0 + sum_{l=1}^{L} (1 - l/(L+1)) (Gamma_l + Gamma_l’), Gamma_l = sum_t s_t s_{t-l}’.
Rows of
x(andresiduals) are assumed to be in time order.- Parameters:
- Returns:
The
(p, p)HAC covariance matrix.- Return type:
- robust_standard_errors(cov)[source]
Standard errors
sqrt(diag(cov))from a covariance matrix.
- glm(x, y, *, family='gaussian', link=None, offset=None, weights=None, max_iter=100, tol=1e-8, robust=False)[source]
Fit a generalized linear model by iteratively reweighted least squares.
- Parameters:
x (ndarray) –
(n, p)design matrix (include an intercept column explicitly if wanted).y (ndarray) –
(n,)response (counts, 0/1 or proportions, positive reals, … per the family).family (str | Family) –
"gaussian","binomial","poisson","gamma","inverse_gaussian","negativebinomial", or aFamily.link (str | None) – link name; defaults to the family’s canonical link.
offset (ndarray | None) –
(n,)known additive term on the linear-predictor scale (e.g.logexposure).weights (ndarray | None) –
(n,)prior weights.max_iter (int) – IRLS controls (convergence on the relative deviance change).
tol (float) – IRLS controls (convergence on the relative deviance change).
robust (bool) – if True report Huber–White sandwich standard errors instead of model-based ones.
- Returns:
A
GLMResult.- Return type:
GLMResult
- class GLMResult(coef, se, fitted, deviance, dispersion, log_likelihood, n_iter, family, link, cov, _link=None)[source]
Bases:
objectFitted GLM.
- Parameters:
- coef
(p,)coefficient estimates.- Type:
- se
(p,)standard errors (model-based, or robust if requested).- Type:
- fitted
(n,)fitted meansmu.- Type:
- deviance
residual deviance.
- Type:
- dispersion
estimated/assumed dispersion
phi.- Type:
- log_likelihood
maximised log-likelihood.
- Type:
- n_iter
IRLS iterations to convergence.
- Type:
- family / link
names.
- cov
(p, p)coefficient covariance.- Type:
- coef: ndarray
- se: ndarray
- fitted: ndarray
- deviance: float
- dispersion: float
- log_likelihood: float
- n_iter: int
- family: str
- link: str
- cov: ndarray
- predict(x, *, offset=None)[source]
Predict the mean response
muat new design rowsx.
- property aic: float
- property bic: float
- class Family(name, variance, canonical, unit_deviance, estimate_dispersion, extra=1.0)[source]
Bases:
objectAn exponential-family error model: variance function, canonical link, deviance, dispersion.
- Parameters:
- name: str
- canonical: str
- estimate_dispersion: bool
- extra: float = 1.0
- ridge_regression(x, y, alpha=1.0, *, fit_intercept=True)[source]
Ridge (L2-penalised) linear regression in closed form.
Minimises
||y - X b||^2 + alpha ||b||^2; the intercept (if fitted) is not penalised.
- elastic_net(x, y, alpha=1.0, l1_ratio=0.5, *, fit_intercept=True, max_iter=1000, tol=1e-7)[source]
Elastic-net linear regression by cyclic coordinate descent.
Minimises
(1/2n) ||y - X b||^2 + alpha ( l1_ratio ||b||_1 + (1 - l1_ratio)/2 ||b||^2 ).l1_ratio = 1is the lasso (sparse),l1_ratio = 0is ridge.
- lasso(x, y, alpha=1.0, **kw)[source]
Lasso (L1) linear regression –
elastic_net()withl1_ratio = 1.
- class PenalizedResult(coef, intercept, alpha, l1_ratio, n_iter)[source]
Bases:
objectFitted penalized linear regression.
- coef
(p,)coefficients (excluding the intercept).- Type:
- intercept
fitted intercept.
- Type:
- alpha
overall penalty strength.
- Type:
- l1_ratio
elastic-net mixing (1 = lasso, 0 = ridge).
- Type:
- n_iter
coordinate-descent iterations (0 for the closed-form ridge).
- Type:
- coef: ndarray
- intercept: float
- alpha: float
- l1_ratio: float
- n_iter: int
- robust_regression(x, y, *, method='huber', c=None, max_iter=100, tol=1e-8)[source]
Robust (M-estimator) linear regression by IRLS with a robust scale.
Down-weights observations with large residuals so a few outliers cannot dominate the fit.
huberuses the Huber weight (tuningc = 1.345for 95% Gaussian efficiency);tukeyuses the redescending Tukey biweight (c = 4.685), which rejects gross outliers entirely.
- quantile_regression(x, y, tau=0.5, *, max_iter=200, tol=1e-7, eps=1e-6)[source]
Linear quantile regression: the conditional
tau-quantile by IRLS on the check loss.Minimises the pinball loss
sum rho_tau(y - X b)via iteratively reweighted least squares with weightstau / |r|for positive residuals and(1 - tau) / |r|for negative ones (a smoothed Newton scheme;epsfloors|r|for stability).
- class RegressionFit(coef, fitted, scale, n_iter)[source]
Bases:
objectCoefficients + fitted values from
robust_regression()/quantile_regression().- coef: ndarray
- fitted: ndarray
- scale: float
- n_iter: int
- kaplan_meier(time, event=None, *, ci_level=0.95)[source]
Kaplan–Meier product-limit estimate of the survival function
S(t).- Parameters:
- Returns:
{'time', 'survival', 'se', 'ci_low', 'ci_high', 'at_risk', 'n_events', 'median'}.- Return type:
- nelson_aalen(time, event=None)[source]
Nelson–Aalen estimate of the cumulative hazard
H(t) = sum d_i / Y_i.
- cox_ph(x, time, event, *, start=None, strata=None, ties='efron', max_iter=50, tol=1e-9)[source]
Cox proportional-hazards regression by Newton–Raphson on the partial likelihood.
The hazard is
h(t | x) = h0(t) exp(x' beta); only the ordering of event times enters, so the baselineh0is left unspecified (semi-parametric). Time-varying covariates are supported through the counting-process form: passstartso each row is an at-risk interval(start, stop](a subject contributes several rows), and the risk set at an event time is every interval covering it.- Parameters:
x (ndarray) –
(n, p)covariates (no intercept – it is absorbed into the baseline).time (ndarray) –
(n,)event/censoring times (the interval stop times).event (ndarray) –
(n,)1 = event, 0 = censored.start (ndarray | None) – optional
(n,)interval start times for time-varying covariates / left truncation.strata (ndarray | None) – optional
(n,)labels; each stratum gets its own baseline hazard (coefficients shared).ties (str) –
"efron"(default, more accurate) or"breslow"tie handling.max_iter (int) – Newton controls.
tol (float) – Newton controls.
- Returns:
A
CoxResult.- Return type:
CoxResult
- class CoxResult(coef, se, cov, loglik, baseline_time, baseline_cumhaz, concordance, n_iter)[source]
Bases:
objectFitted Cox proportional-hazards model.
- Parameters:
- coef
(p,)log-hazard-ratio coefficients.- Type:
- se
(p,)standard errors (inverse observed information).- Type:
- cov
(p, p)covariance.- Type:
- loglik
maximised partial log-likelihood.
- Type:
- baseline_time / baseline_cumhaz
Breslow baseline cumulative hazard.
- concordance
Harrell’s C-index.
- Type:
- n_iter
Newton iterations.
- Type:
- coef: ndarray
- se: ndarray
- cov: ndarray
- loglik: float
- baseline_time: ndarray
- baseline_cumhaz: ndarray
- concordance: float
- n_iter: int
- to_person_period(time, event, covariates=None)[source]
Expand right-censored durations into a person-period (long) array for discrete-time models.
Each subject contributes one row per discrete period they were at risk; the binary outcome is 1 in the period the event occurred and 0 otherwise. Integer
timeis the number of periods observed.
- discrete_time_hazard(x, outcome, *, link='cloglog', offset=None)[source]
Discrete-time hazard model: a binary GLM on the person-period array.
Fit on the long-format data from
to_person_period()(the designxtypically holds period indicators / a time trend plus covariates).clogloggives the grouped-proportional-hazards (interval-censored Cox) interpretation;logitgives the proportional-odds hazard.
- aalen_johansen(time, event, *, causes=None)[source]
Aalen–Johansen cumulative incidence functions for competing risks.
With several mutually exclusive event types, the cause-specific CIF
F_k(t)is the probability of failing from causekby timetaccounting for the competing causes (it is not1 - KMon the cause, which overstates incidence).- Parameters:
- Returns:
{'time', 'cif': {cause: array}, 'overall_survival'}.- Return type:
- aalen_additive(x, time, event, *, intercept=True)[source]
Aalen’s additive-hazards regression: cumulative regression functions
B(t).Models
h(t | x) = b0(t) + sum_j x_j b_j(t)with time-varying additive effects. At each event time the incrementdBis the least-squares solution over the risk set; the cumulativeB(t)(returned) has interpretable slopes – a risingB_jmeans covariatejadds hazard.
- frailty_cox(x, time, event, groups, *, max_iter=50, tol=1e-5, ties='breslow')[source]
Shared gamma-frailty Cox model for clustered survival, by EM.
Subjects in the same group share an unobserved frailty
w_g ~ Gamma(1/theta, 1/theta)(mean 1, variancetheta) that multiplies the hazard, capturing within-group correlation. The E-step takes the posterior-mean frailties; the M-step refits Cox withlog w_gas an offset and updatestheta.theta -> 0indicates no detectable clustering.
- class FrailtyCoxResult(coef, se, theta, frailties, groups, n_iter=0)[source]
Bases:
objectShared gamma-frailty Cox result.
- Parameters:
- coef / se
fixed-effect log-hazard-ratios and standard errors.
- theta
estimated frailty variance (0 means no clustering signal).
- Type:
- frailties
posterior mean random effect per group.
- Type:
- groups
group labels aligned to
frailties.- Type:
- n_iter
EM iterations.
- Type:
- coef: ndarray
- se: ndarray
- theta: float
- frailties: ndarray
- groups: ndarray
- n_iter: int = 0
- ordinal_regression(x, y, *, link='logit', max_iter=200)[source]
Fit a cumulative-link ordinal regression (ordered logit / probit) by maximum likelihood.
- class OrdinalResult(coef, thresholds, se, log_likelihood, link, n_categories)[source]
Bases:
objectFitted ordinal (cumulative-link) regression.
- Parameters:
- coef
(p,)slope coefficients (positivebeta_jraises the latent score, shifting mass toward higher categories).- Type:
- thresholds
(K-1,)ordered cut pointsalpha.- Type:
- se
(p,)standard errors forcoef.- Type:
- log_likelihood
maximised log-likelihood.
- Type:
- link
"logit"or"probit".- Type:
- n_categories
number of ordered categories
K.- Type:
- coef: ndarray
- thresholds: ndarray
- se: ndarray
- log_likelihood: float
- link: str
- n_categories: int
- predict_proba(x)[source]
Per-category probabilities
(n, K)at design rowsx.
- concordance_summary(x, y)[source]
All pairwise concordance measures between two ordinal variables.
- kendall_tau(x, y)[source]
Kendall’s tau-b rank correlation (tie-corrected) between two ordinal variables.
- goodman_kruskal_gamma(x, y)[source]
Goodman–Kruskal gamma:
(C - D) / (C + D)ignoring ties.
- somers_d(x, y, *, dependent='y')[source]
Somers’ D, the asymmetric rank association treating
dependentas the response.
- mann_whitney_u(x, y, *, alternative='two-sided', use_continuity=True)[source]
Mann-Whitney U / Wilcoxon rank-sum test for two independent samples.
Tests whether
xis stochastically greater/less thany. Uses mid-ranks for ties, the tie-corrected normal approximation, and (default) a continuity correction.alternativeis'two-sided','greater'(x > y), or'less'. The rank-biserial correlation2*U1/(n1 n2) - 1is reported as the effect size.
- class MannWhitneyResult(statistic: 'float', statistic2: 'float', zscore: 'float', pvalue: 'float', rank_biserial: 'float', alternative: 'str')[source]
Bases:
object- Parameters:
- statistic: float
- statistic2: float
- zscore: float
- pvalue: float
- rank_biserial: float
- alternative: str
- wilcoxon_signed_rank(x, y=None, *, alternative='two-sided', zero_method='wilcox', correction=False)[source]
Wilcoxon signed-rank test for paired samples (or one sample vs 0).
Ranks
|d|ford = x - y(mid-ranks for ties), splits into positive / negative rank sums, and uses the tie-corrected normal approximation.zero_method='wilcox'drops zero differences (and their ranks);'pratt'keeps them in the ranking but drops them from the sums. The matched-pairs rank-biserial correlation is reported as the effect size.
- class WilcoxonResult(statistic: 'float', zscore: 'float', pvalue: 'float', rank_biserial: 'float', alternative: 'str')[source]
Bases:
object- statistic: float
- zscore: float
- pvalue: float
- rank_biserial: float
- alternative: str
- sign_test(x, y=None, *, alternative='two-sided')[source]
Sign test for paired samples (or one sample vs 0): exact binomial test on the signs of
x - y.Only the directions of the differences are used (ties dropped), so it is maximally robust but less powerful than the signed-rank test.
extracarriesn_positiveandn(non-zero pairs).
- kruskal_wallis(*samples)[source]
Kruskal-Wallis H test: the rank-based k-sample generalization of Mann-Whitney (one-way ANOVA).
Tie-corrected H with a chi-square(k-1) reference.
extracarriesdfand theepsilon_squaredeffect size(H - k + 1)/(N - k).- Parameters:
samples (Any)
- Return type:
TestResult
- friedman_test(*measurements)[source]
Friedman test for k related samples (repeated measures): the rank-based repeated-measures ANOVA.
Pass each treatment as a separate equal-length array (one value per block). Ranks within each block, tie-corrects, and uses a chi-square(k-1) reference.
extracarriesdfand Kendall’sWconcordance effect size.- Parameters:
measurements (Any)
- Return type:
TestResult
- brunner_munzel(x, y, *, alternative='two-sided', distribution='t')[source]
Brunner-Munzel test: the generalized Wilcoxon test that does NOT assume equal variances/shapes.
Tests the stochastic-equality null
P(x < y) + 0.5 P(x = y) = 1/2.distribution='t'uses a Satterthwaite t reference (recommended for small samples);'normal'the normal approximation. Reports the estimated relative effectp_hat = P(x < y) + 0.5 P(x = y)inextra.
- mood_median_test(*samples, ties='below')[source]
Mood’s median test: chi-square test that k samples share a common median.
Cross-tabulates each observation as above / (at-or-below) the pooled grand median and runs a chi-square test of independence on the resulting 2xk table.
extracarries thegrand_median.
- dunn_test(*samples, p_adjust='holm')[source]
Dunn’s post-hoc test: all pairwise rank-mean comparisons after a Kruskal-Wallis rejection.
Uses the pooled-rank z statistic with the shared tie-corrected variance, and adjusts the pairwise p-values by
'holm','bonferroni', or'none'.
- class DunnResult(comparisons, zscores, pvalues, p_adjust)[source]
Bases:
objectPost-hoc Dunn pairwise comparisons after Kruskal-Wallis.
- zscores: ndarray
- pvalues: ndarray
- p_adjust: str
- jonckheere_terpstra(*samples, alternative='increasing')[source]
Jonckheere-Terpstra test for an ORDERED alternative across independent samples.
More powerful than Kruskal-Wallis when the groups are expected to shift monotonically in the given order.
alternative='increasing'/'decreasing'/'two-sided'. Uses the tie-corrected normal approximation of the J statistic (sum of pairwise Mann-Whitney counts over ordered pairs).
- page_trend_test(*measurements, decreasing=False)[source]
Page’s trend test for an ORDERED alternative in repeated measures.
Like Friedman but for a pre-specified ordering of the k treatments (the columns, in order). Tests
L = sum_j j * R_jagainst the normal approximation. Setdecreasing=Trueto predict the reverse ordering.extracarries the z-score.
- ks_1samp(x, cdf, *, alternative='two-sided')[source]
One-sample Kolmogorov-Smirnov goodness-of-fit test against a fully-specified
cdfcallable.
- ks_2samp(x, y, *, alternative='two-sided')[source]
Two-sample Kolmogorov-Smirnov test: max gap between the two empirical CDFs (asymptotic p).
- runs_test(x, *, cutoff='median')[source]
Wald-Wolfowitz runs test for randomness of a binary/dichotomized sequence.
Dichotomizes
xabout its median (or a supplied numericcutoff) and tests whether the run count departs from what independence predicts (too few runs => clustering/trend; too many => over-alternation). Normal approximation, two-sided.extracarries the run count and z-score.
- cliffs_delta(x, y)[source]
Cliff’s delta effect size in [-1, 1]:
P(x > y) - P(x < y)(rank-based, ties count as 0).
- class TestResult(statistic, pvalue, extra=<factory>)[source]
Bases:
objectGeneric statistic + p-value result;
extracarries test-specific fields (effect size, df, …).- statistic: float
- pvalue: float
- deming_regression(x, y, variance_ratio=1.0)[source]
Errors-in-variables (Deming) regression of
yonxwhen both are noisy.- Parameters:
x – paired measurements; both may carry error.
y – paired measurements; both may carry error.
variance_ratio (float) –
var(e_y) / var(e_x)– the ratio of output to input noise variance.1.0is total least squares (orthogonal regression); a large value -> ordinary least squares (no input error); a small value -> inverse regression (predictor dominated by error).
- Returns:
A
DemingFitwith the unbiasedslope/interceptand the recovered latentx*.- Return type:
DemingFit
- class DemingFit(slope, intercept, variance_ratio, x, y)[source]
Bases:
objectResult of
deming_regression(): slope/intercept plus the recovered latent predictor values.
- simex(fit_fn, x, y, sigma_u, *, lambdas=None, n_sims=100, extrapolation='quadratic', seed=0)[source]
SIMEX: simulation–extrapolation correction for a predictor measured with known error.
When a predictor
xis observed asx = x* + uwithu ~ N(0, sigma_u^2), naive estimates are biased (attenuation). SIMEX adds further noise of variancelambda sigma_u^2for a grid oflambda >= 0, refits at each level (averaging overn_simsnoise draws), then extrapolates the estimate back tolambda = -1(zero measurement error). Works for any estimator returning a parameter vector.- Parameters:
fit_fn (Callable[[ndarray, ndarray], ndarray]) –
f(x, y) -> thetareturning the parameter vector for (possibly multi-column)x.x (ndarray) –
(n,)or(n, p)error-prone predictor(s).y (ndarray) –
(n,)response.sigma_u (float | ndarray) – measurement-error standard deviation (scalar, or per-column for matrix
x).lambdas (ndarray | None) – extra-noise levels (defaults to
0, 0.5, 1.0, 1.5, 2.0).n_sims (int) – noise replications per level.
extrapolation (str) –
"quadratic"or"linear"extrapolant inlambda.seed (int | RandomState | None) – RNG seed.
- Returns:
{'estimate', 'naive', 'lambdas', 'curve'}– the SIMEX-corrected parameter vector, the naivelambda=0estimate, and the per-level averaged estimates.- Return type:
- propagate_uncertainty(func, samples, *, quantiles=(0.025, 0.5, 0.975))[source]
Monte-Carlo propagation of an uncertainty set through an arbitrary functional.
Pushes input draws (a posterior sample, a bootstrap set, any uncertainty representation) through
funcand summarises the output distribution – the general “what is the uncertainty ofg(theta)?” operation.funcmay be vectorised (accept the whole(n, ...)array) or act on a single draw; both are detected.- Parameters:
- Returns:
{'mean', 'std', 'quantiles', 'levels', 'samples'}over the propagated outputs.- Return type:
- paired_score_difference(scores_a, scores_b, *, lower_is_better=True, ci_level=0.95)[source]
Mean paired held-out score difference with a CI and a paired t-test.
- Parameters:
scores_a (ndarray) –
(n,)per-observation held-out scores for the two models (same observations, same order).scores_b (ndarray) –
(n,)per-observation held-out scores for the two models (same observations, same order).lower_is_better (bool) – True for losses/scores (CRPS, log loss, pinball); False for higher-is-better metrics.
ci_level (float) – confidence level for the interval on the mean difference.
- Returns:
{'mean_diff', 'se', 'ci_low', 'ci_high', 't', 'p_value', 'favored'}wheremean_diffismean(a - b)andfavoredis'A'/'B'/'tie'at the given level.- Return type:
- vuong_test(loglik_a, loglik_b, *, k_a=0, k_b=0, correction='none')[source]
Vuong’s test for non-nested model selection.
Compares two models by their pointwise log-likelihoods. Under the null that both are equally close to the truth, the statistic
sqrt(n) * mean(m) / sd(m)(withm_i = ll_a_i - ll_b_i, minus an optional complexity correction) is asymptotically standard normal. A large positive value favors A.- Parameters:
loglik_a (ndarray) –
(n,)pointwise log-likelihoods of the two (non-nested) models.loglik_b (ndarray) –
(n,)pointwise log-likelihoods of the two (non-nested) models.k_a (int) – parameter counts, used only if
correctionis set.k_b (int) – parameter counts, used only if
correctionis set.correction (str) –
"none","aic"(subtractk_a - k_b), or"bic"(subtract(k_a - k_b) log n / 2) from the log-likelihood ratio.
- Returns:
{'statistic', 'p_value', 'favored'}.- Return type:
- clarke_test(loglik_a, loglik_b, *, k_a=0, k_b=0, correction='none')[source]
Clarke’s distribution-free paired sign test for non-nested models.
Counts how often model A’s pointwise log-likelihood beats B’s; under the null this count is
Binomial(n, 0.5). More robust thanvuong_test()when the per-observation log-ratio is heavy-tailed or skewed (where the normal approximation behind Vuong fails).
- compare_elpd(pointwise_a, pointwise_b)[source]
Compare two models’ expected log pointwise predictive density (LOO/WAIC).
Takes the per-observation
elpdcontributions (thepointwisearrays returned bymixle.ppl.diagnostics.psis_loo()/waic) and returns the elpd difference with the standard error of the pointwise difference – the honest SE for model comparison (a difference within ~2 SE of zero is not decisive).
- split_conformal(cal_pred, cal_y, test_pred, *, alpha=0.1, side='two-sided')[source]
Split (inductive) conformal interval from a calibration set.
- Parameters:
cal_pred (ndarray) –
(n,)model predictions on the calibration set.cal_y (ndarray) –
(n,)calibration responses.test_pred (ndarray) –
(m,)predictions at the test points.alpha (float) – miscoverage level (
1 - alphacoverage).side (str) –
"two-sided"(|y - yhat|score),"upper"(one-sided upper bound), or"lower"(one-sided lower bound).
- Returns:
(lower, upper)arrays of lengthm(an unbounded side is-inf/+inf).- Return type:
- jackknife_plus(x, y, fit_predict, x_test, *, alpha=0.1)[source]
Jackknife+ intervals (leave-one-out), using all data for both fitting and calibration.
For each training point
ithe model is refit withouti;R_i = |y_i - mu_{-i}(x_i)|is the LOO residual andmu_{-i}(x)the LOO prediction at a test point. The interval aggregatesmu_{-i}(x) -/+ R_iacrossi(Barber et al. 2021), giving ~``1 - 2 alpha`` worst-case and ~``1 - alpha`` typical coverage without a data split. Costsnrefits.
- cv_plus(x, y, fit_predict, x_test, *, alpha=0.1, n_folds=10, seed=0)[source]
CV+ intervals: the K-fold analogue of
jackknife_plus()(onlyn_foldsrefits).Each point’s residual uses the model trained on the other folds, and the test prediction uses the same out-of-fold model. Much cheaper than Jackknife+ with nearly the same guarantee.
- mondrian_conformal(cal_pred, cal_y, cal_groups, test_pred, test_groups, *, alpha=0.1)[source]
Mondrian (group-conditional) split conformal: a separate quantile per group.
Calibrates the conformal quantile within each group (taxonomy), so coverage holds conditional on the group rather than only marginally – the fix when error scale varies across known subpopulations.
- Parameters:
cal_pred (ndarray) – calibration predictions, responses, and group labels.
cal_y (ndarray) – calibration predictions, responses, and group labels.
cal_groups (ndarray) – calibration predictions, responses, and group labels.
test_pred (ndarray) – test predictions and their group labels.
test_groups (ndarray) – test predictions and their group labels.
alpha (float) – miscoverage level.
- Returns:
(lower, upper)arrays of lengthlen(test_pred).- Return type:
- weighted_conformal(cal_pred, cal_y, test_pred, weights, *, alpha=0.1, test_weight=1.0)[source]
Covariate-shift-weighted split conformal (Tibshirani et al. 2019).
Under covariate shift the calibration and test inputs follow different distributions; reweighting the calibration scores by the likelihood ratio
w(x) = p_test(x)/p_train(x)restores coverage. Uses the weighted empirical quantile of the calibration scores (each test point shares the sametest_weightfor its own potential score).- Parameters:
cal_pred (ndarray) – calibration predictions and responses.
cal_y (ndarray) – calibration predictions and responses.
test_pred (ndarray) –
(m,)test predictions.weights (ndarray) –
(n,)likelihood-ratio weights for the calibration points (need not be normalised).alpha (float) – miscoverage level.
test_weight (float) – the weight assigned to a test point (usually the mean test/train ratio;
1.0when weights are self-normalised around the test density).
- Returns:
(lower, upper)arrays of lengthm(a symmetric interval per test point).- Return type:
- conformal_label_threshold(cal_prob_true, *, alpha=0.1)[source]
Calibrate the LAC (least-ambiguous set-valued classifier) score threshold for
1 - alphacoverage.The nonconformity score of a calibration point is
1 - p_model[true_class]– which needs the model’s class scores to rank well, not to be a true probability (the whole point: a softmax over a ReLU net is not a describable random process, but conformal still gives a finite-sample coverage guarantee from how those scores behave on held-out, exchangeable data). Returns the conformal quantileqhatof the calibration scores; a class is admitted at test time iff1 - p[c] <= qhat(seeconformal_label_sets()).- Parameters:
- Returns:
qhat– the score threshold (+infwhennis too small for the requestedalpha).- Return type:
- conformal_label_sets(cal_prob_true, test_prob, *, alpha=0.1, qhat=None)[source]
Split-conformal prediction sets for a classifier: distribution-free
1 - alphalabel coverage.Calibrates a LAC threshold (
conformal_label_threshold()) on the held-out true-class scores, then admits every class whose score clears it. The returned boolean mask has guaranteed marginal coverage: the true label is in the set with probability>= 1 - alpha. A singleton set is a confident prediction; an empty or multi-label set is an honest “I’m not sure” – the signal a cost-aware cascade escalates on.- Parameters:
cal_prob_true (ndarray) –
(n,)score assigned to the true class of each calibration point.test_prob (ndarray) –
(m, K)model class scores at the test points (rows need not sum to 1).alpha (float) – miscoverage level.
qhat (float | None) – a precomputed threshold (e.g. from an earlier calibration); recomputed if
None.
- Returns:
(sets, qhat)–setsis an(m, K)boolean mask,qhatthe threshold used.- Return type:
- learn_structure(data, *, field_estimators=None, min_gain=0.0, max_levels=64, n_bins=4, max_its=30)[source]
Discover the dependency forest for heterogeneous
dataand return the fitted joint model.Any field can be a parent: a discrete one conditions directly, a continuous one is quantile-binned into
n_binsconditioning levels (so a real can drive a count, a category, or another real). Scores every(parent -> child)pair bydependency_gain(), greedily builds a maximum-gain acyclic forest (each field at most one parent), and fits each factor. Falls back to independent marginals where no dependence clearsmin_gain– never worse than a composite, much better when structure exists. This is “automatic inference for composable models of heterogeneous data” made real.
- learn_mixture_structure(data, n_components, *, restarts=3, max_iter=15, seed=0, min_gain=0.0, n_bins=4, max_its=30)[source]
Fit a
MixtureOfDependencyTreesby hard EM – discover clusters AND each cluster’s dependency graph.Each iteration re-learns a dependency forest per cluster on its currently-assigned points (M-step), then reassigns every record to its most-probable cluster (E-step), until assignments stabilize. Runs
restartsrandom initializations and returns the highest-likelihood fit. Empty/tiny clusters are re-seeded so a component never collapses.
- learn_bayesian_network(data, *, max_parents=2, min_gain=0.0, max_its=30, weights=None)[source]
Discover a heterogeneous DAG for
dataand return the fitted network.Each field greedily gains up to
max_parentsparents by BIC-penalized conditional likelihood, keeping the graph acyclic. Continuous children become conditional-linear-Gaussian factors (regression on continuous + one-hot discrete parents); discrete/count children condition on the joint config of their discrete parents, or become GLM nodes when a driver is continuous. Withweights(soft-EM responsibilities), every factor fit and the BIC search itself are responsibility-weighted, with effective sample sizesum(weights).
- learn_mixture_bayesian_network(data, n_components, *, restarts=3, max_iter=12, seed=0, max_parents=2, min_gain=0.0, max_its=30, em='hard')[source]
Fit a
MixtureOfBayesianNetworksby EM – discover clusters AND each cluster’s DAG.em="hard"(default): each iteration re-learns a network per cluster on its assigned points and reassigns every record to its most-probable cluster, until assignments stabilize.em="soft": proper EM – every record contributes to EVERY cluster with its responsibility, each component’s structure search and factor fits are responsibility-weighted (learn_bayesian_network(weights=)), and convergence is on the observed-data log-likelihood; boundary points shape both clusters instead of whipsawing between them. Both run from the same restarts (k-means-seeded + random); best final log-likelihood wins. Starved clusters are re-seeded (hard) / responsibility-floored (soft).
- select_mixture_components(data, k_values=(1, 2, 3, 4), *, em='hard', seed=0, **kwargs)[source]
Model selection over the number of clusters by BIC.
Fits
learn_bayesian_network()fork=1andlearn_mixture_bayesian_network()for each largerk, scores each bybayesian_network_bic(), and returns(best_model, report)wherereport = {"k": chosen, "bic": {k: score, ...}}. BIC’sn_params log npenalty is what stops a mixture of per-cluster DAGs from always preferring more clusters.
- bayesian_network_bic(model, data)[source]
BIC (lower is better) for a fitted network or mixture:
-2 LL + n_params log n.
- learn_structure_embedded(data, *, text_fields='auto', n_clusters=8, embed_dim=16, seed=0, max_parents=2, **embed_kw)[source]
Discover cross-field structure where some fields are free text (see module docstring).
- Parameters:
data (Sequence[tuple]) – flat tuple records; text fields may hold arbitrary strings.
text_fields (Sequence[int] | str) – which field indices to embed, or
"auto"– every string-valued field with too many distinct values to be a categorical.n_clusters (int) – number of representative clusters surfaced by
describe()(interpretability only; the model uses the full embedding vector, not a cluster code).embed_dim (int) – embedding dimension for
mixle.represent.fit_embedder()– the vector node’s dim.**embed_kw (Any) – forwarded to
fit_embedder(epochs,hidden,feature_dim, …).seed (int)
max_parents (int)
**embed_kw
- Return type:
EmbeddedStructureModel
- class EmbeddedStructureModel(net, codecs)[source]
Bases:
objectA discovered dependency graph over records whose text fields ride in as embedding VECTORS.
- encode_record(x)[source]
The record with each text field replaced by its embedding vector.
- class HeterogeneousBayesianNetwork(factors)[source]
Bases:
objectA DAG joint over a heterogeneous record:
log p(x) = sum_i log P(x_i | parents(i))over fitted factors.- Parameters:
factors (Sequence[Any])
- class MixtureOfBayesianNetworks(components, weights)[source]
Bases:
objectA latent mixture whose components each carry their own heterogeneous DAG (regression edges and all).
The fullest form of the moat: it discovers the clustering and each cluster’s cross-field graphical model, so the slope of one field on another (or the whole dependency graph) can differ between clusters – which a single network cannot represent.
log p(x) = logsumexp_k(log w_k + log p_k(x))overHeterogeneousBayesianNetworkcomponents. Fit bylearn_mixture_bayesian_network().- Parameters:
components (Sequence[HeterogeneousBayesianNetwork])
weights (Sequence[float])
- property n_components: int
- dependency_gain(parent, child, child_estimator, *, max_its=30, penalty='bic')[source]
Description-length gain (nats) of modeling
childconditioned on a discreteparentvs. independently.Fits the marginal
P(child)and the conditionalP(child | parent)(a child model per parent value) on the same data and returnsLL_cond - LL_marginalminus a complexity penalty for the extra parameters (BIC:0.5 * (levels - 1) * k * ln n). Positive means the dependence is worth modeling. This is a model-based dependency test – it works across any pair of families, unlike a same-type MI estimate.
- class DependencyTreeDistribution(parents, factors, binners=None)[source]
Bases:
objectA directed-forest joint over a heterogeneous record: each field is a marginal or a conditional on its parent.
log_density(record) = sum_root log P(f_root) + sum_child log P(f_child | f_parent). The dependence aCompositeDistributionassumes away is modeled here as per-parent-value conditionals – while it still scores, samples, and composes like any mixle distribution.- Parameters:
parents (Sequence[int | None])
factors (Sequence[Any])
binners (Sequence[Any] | None)
- class MixtureOfDependencyTrees(components, weights)[source]
Bases:
objectA latent mixture whose components each carry their own discovered dependency structure.
log p(x) = logsumexp_k ( log w_k + log p_k(x) )where eachp_kis aDependencyTreeDistribution. This is the deep form of the tagline: it discovers both the clustering and the within-cluster cross-field dependence – so the same category can map to different reals in different clusters, which neither a single dependency tree (one relationship) nor a mixture of independent composites (no within-cluster dependence) can represent. Fit bylearn_mixture_structure().- Parameters:
components (Sequence[DependencyTreeDistribution])
weights (Sequence[float])
- responsibilities(data)[source]
Posterior
p(component | record)for each record – the E-step and a soft cluster assignment.
- property n_components: int
- kfold(n, n_splits=5, *, shuffle=False, seed=0)[source]
Standard k-fold split of
nrows.- Parameters:
n (int) – number of observations.
n_splits (int) – number of folds
k(each row is in exactly one test fold).shuffle (bool) – shuffle the row order before splitting (use for i.i.d. data; leave False to keep contiguous folds, i.e.
blocked_kfold()).seed (int | RandomState | None) – RNG seed when
shuffleis True.
- Returns:
k(train_index, test_index)pairs.- Return type:
- blocked_kfold(n, n_splits=5)[source]
Contiguous-block k-fold (no shuffle) for serially dependent data.
Identical to
kfold()withshuffle=False; named separately because keeping blocks contiguous is the point for time series, not an incidental default.
- leave_one_out(n)[source]
Leave-one-out CV:
nfolds, each holding out a single observation.
- stratified_kfold(y, n_splits=5, *, shuffle=True, seed=0)[source]
Stratified k-fold preserving class proportions in every fold.
Distributes each class’s indices across the folds so that class frequencies in each test fold mirror the overall frequencies – important for imbalanced classification.
- Parameters:
y (ndarray) –
(n,)class labels.n_splits (int) – number of folds.
shuffle (bool) – shuffle within each class before round-robin assignment.
seed (int | RandomState | None) – RNG seed when
shuffleis True.
- Returns:
n_splits(train_index, test_index)pairs.- Return type:
- leave_one_group_out(groups)[source]
Leave-one-group-out CV: one fold per distinct group held out entirely.
- group_kfold(groups, n_splits=5)[source]
Group k-fold: partition groups into
kfolds so no group spans train and test.Greedily assigns whole groups (largest first) to the currently-smallest fold, balancing fold sizes while keeping each group intact – the right scheme for repeated measures when there are more groups than folds.
- time_series_split(n, n_splits=5, *, gap=0, max_train_size=None)[source]
Forward-chaining time-series CV: train always precedes test (expanding window).
The series is cut into
n_splits + 1contiguous blocks; folditests on blocki+1and trains on everything strictly before it. Agap(buffer) drops thegappoints just before each test block from the training set so leakage through short-range autocorrelation is avoided.- Parameters:
- Returns:
n_splits(train_index, test_index)pairs.- Return type:
- purged_kfold(n, n_splits=5, *, embargo=0)[source]
Purged/embargoed blocked k-fold (a.k.a. buffered CV).
Contiguous test blocks, but the
embargoobservations on each side of a test block are removed from the training set, so no training point sits within the autocorrelation reach of a test point. The standard guard for serially dependent data when you still want every block to serve as a test fold (cf. de Prado 2018).
- spatial_block_kfold(coords, n_splits=5, *, block_size=None, n_side=None, seed=0)[source]
Spatial-block k-fold: hold out contiguous spatial blocks, not scattered points.
Partitions space into a regular grid of blocks and assigns whole blocks to folds at random, so a test point’s spatial neighbours are held out with it rather than leaking into training. This is the right scheme for geostatistical / spatially autocorrelated data.
- Parameters:
coords (ndarray) –
(n, d)spatial coordinates (typicallyd = 2).n_splits (int) – number of folds.
block_size (float | None) – grid-cell width in coordinate units; if None it is derived from
n_side.n_side (int | None) – number of grid cells per axis; defaults so there are comfortably more blocks than folds.
seed (int | RandomState | None) – RNG seed for assigning blocks to folds.
- Returns:
n_splits(train_index, test_index)pairs.- Return type:
- nested_kfold(n, *, outer_splits=5, inner_splits=4, shuffle=False, seed=0)[source]
Nested k-fold: an inner CV (for tuning) inside each outer fold (for evaluation).
The outer loop estimates generalisation; the inner loop selects hyper-parameters using only the outer-training data, so the reported score is not optimistically biased by tuning on the test set.
- Parameters:
- Returns:
A list of
NestedFold; inner folds index the original array.- Return type:
list[NestedFold]
- class NestedFold(train, test, inner)[source]
Bases:
objectOne outer fold of
nested_kfold().- train
outer training indices (used to build the inner CV).
- Type:
- test
outer test indices (held out for the final, untuned-on evaluation).
- Type:
- inner
inner
(train_index, test_index)folds, indexing into the original array (not intotrain), so they can be applied directly.- Type:
- train: ndarray
- test: ndarray
- log_score(prob, *, mean=True)[source]
Logarithmic score (log loss)
-log p(y)of the probability assigned to the outcome.The log score is local (it depends only on the density at the realised value) and strictly proper. Pass the predictive probability/density evaluated at the observed outcome.
- Parameters:
prob (ndarray) – array of predictive probabilities (or densities) at the realised outcomes. Values are clipped away from zero before the log so a single zero-probability event yields a large but finite penalty rather than
inf.mean (bool) – if True (default) return the mean log loss; otherwise the per-observation vector.
- Returns:
Mean log loss (float) or the per-observation array.
- Return type:
- brier_score(prob, outcome, *, mean=True)[source]
Brier score (mean squared error of probabilistic classification).
For binary forecasts pass 1-D
prob(predicted probability of the positive class) and 0/1outcome. ForK-class forecasts passprobshaped(n, K)andoutcomeeither as integer class labels (lengthn) or as a one-hot(n, K)matrix; the multiclass score sums the squared error across classes, so it ranges in[0, 2].- Parameters:
- Returns:
Mean Brier score (float) or the per-observation array.
- Return type:
- brier_decomposition(prob, outcome, *, bins=10)[source]
Murphy’s reliability–resolution–uncertainty decomposition of the (binary) Brier score.
Bins the forecast probabilities into
binsequal-width bins on[0, 1]and computesBrier = reliability - resolution + uncertainty,
where reliability (lower is better) is the mean squared gap between forecast probability and observed frequency within a bin, resolution (higher is better) is how far bin frequencies move from the base rate, and uncertainty is the base-rate variance
p_bar (1 - p_bar)(a property of the data, not the forecaster).- Parameters:
- Returns:
{'reliability', 'resolution', 'uncertainty', 'brier'}. The identityreliability - resolution + uncertainty == brierholds up to binning of the score’s in-bin variance term.- Return type:
- crps_ensemble(forecasts, y, *, fair=False, mean=True)[source]
Continuous Ranked Probability Score from a finite predictive ensemble (sample).
Uses the energy form
CRPS = E|X - y| - 1/2 E|X - X'|estimated from the ensemble draws. The CRPS generalises absolute error to distributional forecasts (a point forecast recovers|x-y|) and is reported in the same units asy.- Parameters:
forecasts (ndarray) – predictive draws. Either
(n, m)(mdraws for each ofnobservations) or(m,)for a single observation. Ragged ensembles are not supported – pad or call per observation.y (ndarray) –
(n,)realised values (or a scalar for the(m,)case).fair (bool) – if True use the unbiased
1/(m(m-1))spread estimator (the “fair”/almost-unbiased CRPS); if False (default) the standard1/m^2estimator.mean (bool) – if True return the mean CRPS; otherwise the per-observation vector.
- Returns:
Mean CRPS (float) or the per-observation array.
- Return type:
- crps_gaussian(mu, sigma, y, *, mean=True)[source]
Closed-form CRPS for a Gaussian predictive distribution
N(mu, sigma^2).CRPS = sigma * [ z (2 Phi(z) - 1) + 2 phi(z) - 1/sqrt(pi) ]withz = (y - mu) / sigma(Gneiting & Raftery 2007). Exact, so it is the right reference when the forecast is Gaussian.- Parameters:
- Returns:
Mean CRPS (float) or the per-observation array.
- Return type:
- interval_score(lower, upper, y, alpha, *, mean=True)[source]
Winkler interval score for a central
(1 - alpha)prediction interval.IS = (u - l) + (2/alpha)(l - y) 1[y < l] + (2/alpha)(y - u) 1[y > u](Gneiting & Raftery 2007). It rewards narrow intervals but penalises misses by2/alphatimes the shortfall, so at matched nominal coverage the tighter, better-placed interval scores lower. This is the proper way to rank interval methods (conformal, quantile-regression, GP credible bands) head to head.- Parameters:
- Returns:
Mean interval score (float) or the per-observation array.
- Return type:
- winkler_score(lower, upper, y, alpha, *, mean=True)[source]
Alias for
interval_score()(the score is due to Winkler 1972).
- pinball_loss(pred, y, tau, *, mean=True)[source]
Pinball (quantile / check) loss for a quantile forecast.
rho_tau(u) = max(tau * u, (tau - 1) * u)withu = y - pred; its expectation is minimised by the truetau-quantile, so it is the proper score for quantile forecasts and the loss that quantile regression and conformalised quantiles optimise.- Parameters:
pred (ndarray) – predicted
tau-quantiles, shape(n,)(single level) or(n, q)(several levels, one per column oftau).y (ndarray) –
(n,)realised values.tau (float | ndarray) – quantile level(s) in
(0, 1)– a scalar for(n,)pred, or a length-qarray matching the columns of a(n, q)pred.mean (bool) – if True return the mean over all entries; otherwise the per-observation (or per-observation-per-level) array.
- Returns:
Mean pinball loss (float) or the per-observation array.
- Return type:
- energy_score(forecasts, y, *, fair=False, mean=True)[source]
Energy score: the multivariate generalisation of CRPS for vector-valued forecasts.
ES = E||X - y|| - 1/2 E||X - X'||with Euclidean norms; for scalaryit equalscrps_ensemble().- Parameters:
forecasts (ndarray) – predictive draws shaped
(n, m, d)(md-vectors per observation) or(m, d)for a single observation.y (ndarray) –
(n, d)realised vectors (or(d,)for the single-observation case).fair (bool) – use the unbiased
1/(m(m-1))spread estimator if True.mean (bool) – if True return the mean; otherwise the per-observation vector.
- Returns:
Mean energy score (float) or the per-observation array.
- Return type:
- skill_score(score, reference, *, perfect=0.0)[source]
Skill score: fractional improvement of
scoreover areferencescore.skill = (reference - score) / (reference - perfect)– 1 means the forecast hit the perfect score, 0 means it only matched the reference (e.g. climatology), and negative means it did worse than the reference. Works for any negatively-oriented score (lower is better) such as those above.- Parameters:
- Returns:
The skill score (float);
nanif the reference already equals the perfect score.- Return type:
- select_best(candidates, *, score, lower_is_better=False, conformal_alpha=None)[source]
Score each candidate and return the best, the verifier-based test-time-compute selector.
- Parameters:
candidates (Any) – an iterable of candidate objects (anything
scoreaccepts).score (Callable[[Any], float]) – a verifier
score(candidate) -> float; the winner maximizes it (or minimizes it whenlower_is_better).lower_is_better (bool) – if
True, the winner is the candidate with the smallest score.conformal_alpha (float | None) – optional miscoverage level in
(0, 1). When given, the result’sconfidentflag reports whether the winner’s lead over the runner-up exceeds a conformal/bootstrap band at confidence1 - conformal_alpha(az-scaled estimate of the score spread).None(default) leavesconfidentunset.
- Returns:
A
SelectionResult. It is also subscriptable (result["best"]), so callers may treat it as a small dict with keysbest,best_index,scores,confident.- Raises:
ValueError – if
candidatesis empty, orconformal_alphais outside(0, 1).- Return type:
SelectionResult
- class SelectionResult(best, best_index, scores, confident=None, margin=None, band=None, _extras=<factory>)[source]
Bases:
objectResult of a
select_best()call.- Parameters:
- best
the winning candidate (the actual object, not its index).
- Type:
Any
- best_index
the position of the winner in the input
candidates.- Type:
- scores
per-candidate scores in input order (a numpy float array).
- Type:
- confident
whether the winner’s lead clears the conformal band —
Nonewhen noconformal_alphawas supplied.- Type:
bool | None
- margin
the winner’s lead over the runner-up (in score units, always
>= 0);Nonewhen there is a single candidate.- Type:
float | None
- band
the conformal/bootstrap band the margin was compared against —
Nonewhen noconformal_alphawas supplied or there is a single candidate.- Type:
float | None
- best: Any
- best_index: int
- scores: ndarray
- class ConjugateUpdatable[source]
Bases:
PredicateCapabilityHas a closed-form conjugate Bayesian update (the top tier of the inference ladder).
supports(x, ConjugateUpdatable)is True iffconjugate_posterior(x, data)returns an exact closed-form posterior; otherwise Bayesian inference falls back to the numerical fitters (MAP / Laplace / MCMC / VI). Detection is the singleconjugate_posteriorregistry.
- conjugate_posterior(dist, data, prior=None, weights=None)[source]
Closed-form conjugate posterior over the parameters of
distgivendata.Every supported family returns a closed-form, full-Bayesian posterior: exact parameter samples, marginal likelihood, posterior mean / point estimate, and a posterior predictive. For families with a multi-parameter likelihood whose conjugate is conditional (Gamma, InverseGamma, InverseGaussian, Pareto, NegativeBinomial, vonMises), the non-target parameter (shape / location / scale / number-of-trials / concentration) is taken as known from
dist– exactly as a Binomial’s number of trials is. Families with no closed-form conjugate (full Beta, full Gamma, LogSeries, …) raise a clear error rather than returning a partial answer.- Parameters:
dist – A mixle likelihood distribution instance whose type selects the conjugate family.
data – A sequence of observations of the kind
distscores.prior (dict | None) – Optional dict of conjugate-prior hyperparameters (family specific).
Noneuses a weak proper prior.weights (ndarray | None) – Optional per-observation weights (e.g. EM responsibilities).
- Returns:
A
ConjugatePosteriorexposingmean,sample,point_estimate,log_marginal_likelihood,posterior_predictiveandsummary.- Return type:
ConjugatePosterior
- mixture_conjugate_posterior(dist, data, priors, prior_weights=None, weights=None)[source]
Posterior under a prior that is a mixture of conjugate priors (Diaconis-Ylvisaker).
- Parameters:
dist – The likelihood distribution (must map to a closed-form conjugate realiser, since the reweighting needs each component’s marginal likelihood).
data – The observations.
priors (list[dict]) – One hyperparameter dict per mixture component (same keys
conjugate_posterior()accepts for this family).prior_weights (ndarray | None) – Prior mixing weights
w_m(default uniform); normalised internally.weights (ndarray | None) – Optional per-observation weights.
- Returns:
the exact posterior, again a mixture of conjugate posteriors with weights
w'_m proportional to w_m * Z_m.- Return type:
A
MixtureConjugatePosterior
- is_conjugate_family(dist)[source]
Return whether
dist(instance or type) has a closed-form conjugate posterior.Single source of truth: membership in the
conjugate_posteriorbuilder registry. This is the family-level capability — “can this distribution be updated in closed form?” — distinct from the instance-levelhas_conj_priorflag (whether a conjugate prior is currently attached for the MAP path). Backsmixle.capability.ConjugateUpdatableandProbabilityDistribution.has_conjugate_prior().
- class ConjugatePosterior[source]
Bases:
objectBase class for a closed-form conjugate posterior over a likelihood’s parameters.
Subclasses provide the family-specific hyperparameters and the four capabilities:
mean(the posterior mean of the parameters),sample(exact draws of the parameters),point_estimate(a fitted distribution at the posterior mean),log_marginal_likelihood(the evidence of the observed data under the prior), andposterior_predictive(the distribution of a new draw).- family: str = 'conjugate'
- log_base: float = 0.0
- sample(n=1, rng=None)[source]
- Parameters:
n (int)
rng (RandomState | None)
- Return type:
- sampler(seed=None)[source]
Return a sampler exposing the standard
obj.sampler(seed).sample(size)API.Mirrors the distribution sampling convention so conjugate posteriors read the same way as every other mixle object; here each draw is a parameter set from the posterior.
size=Nonereturns one parameter set (scalars),size=na dict of length-narrays. The explicit-rng formsample(n, rng)remains available.- Parameters:
seed (int | None)
- Return type:
ConjugatePosteriorSampler
- point_estimate()[source]
- posterior_predictive()[source]
- class MixtureConjugatePosterior(components, post_weights, prior_weights, comp_log_evidence)[source]
Bases:
ConjugatePosteriorPosterior under a prior that is itself a mixture of conjugate priors.
Diaconis-Ylvisaker (1979): if the prior is
sum_m w_m * pi_m(theta)with eachpi_mconjugate to the likelihood, the posterior is again a mixture of the component conjugate posteriors,sum_m w'_m * pi_m^post(theta), with the mixing weights reweighted by each component’s marginal likelihoodZ_m:w’_m proportional to w_m * Z_m.
Everything stays closed-form, so a prior can be multimodal (e.g. “the rate is near 1 OR near 10”) or robust (a heavy-tailed prior as a mixture of conjugates) without losing exact inference.
- Parameters:
components (list[ConjugatePosterior])
- family: str = 'MixtureOfConjugates'
- components: list[ConjugatePosterior]
- sample(n=1, rng=None)[source]
- Parameters:
n (int)
rng (RandomState | None)
- Return type:
- point_estimate()[source]
The maximum-a-posteriori component’s point estimate (the dominant conjugate mode).
- posterior_predictive()[source]
A mixle MixtureDistribution of the component predictives, weighted by the posterior weights.
- class FisherView(dist, estimator=None)[source]
Bases:
objectAccumulator-backed Fisher-geometry view of a distribution.
- Parameters:
dist (Any) – mixle.stats or mixle.bstats distribution.
estimator (Any | None) – Optional estimator. When omitted, dist.estimator() is used.
Notes
The generic encoded-data path obtains per-row statistics by replaying seq_update with one-hot weights. That keeps the interface compatible with existing encoders, but it is a correctness fallback rather than a high-performance implementation. Important families should override to_fisher() with direct seq_expected_statistics kernels.
- structured_statistics(x, estimate=None, weight=1.0)[source]
Structured sufficient stats for one observation.
For latent-variable distributions, this is the posterior-expected complete-data sufficient statistic under estimate (or this view’s distribution when estimate is omitted).
- expected_structured_statistics(x, estimate=None, weight=1.0)[source]
- sufficient_statistics(x, estimate=None, vectorizer=None)[source]
- expected_sufficient_statistics(x, estimate=None, vectorizer=None)[source]
- seq_structured_statistics(enc_data, estimate=None)[source]
Structured per-row stats from encoded data.
This generic implementation is intentionally conservative and may be slow for large data. It exists so every encoder-compatible model has a correct baseline.
- statistics_matrix(data=None, enc_data=None, estimate=None, vectorizer=None, fit=True)[source]
Return an n x d matrix of per-observation sufficient statistics.
- expected_statistics_matrix(data=None, enc_data=None, estimate=None, vectorizer=None, fit=True)[source]
- seq_expected_statistics(enc_data, estimate=None, vectorizer=None, fit=True)[source]
- mean_statistics(stats=None, **kwargs)[source]
- score_center(stats=None, **kwargs)[source]
- fisher_information(stats=None, diagonal=False, ridge=1.0e-8, **kwargs)[source]
Empirical Fisher approximation from per-observation statistic vectors.
- fisher_vectors(stats=None, metric='diagonal', center=None, fisher=None, ridge=1.0e-8, **kwargs)[source]
Return centered/whitened sufficient-statistic vectors.
metric=’identity’ returns centered statistics, ‘diagonal’ divides by per-coordinate Fisher standard deviations, and ‘full’ applies an empirical full-matrix whitening transform.
- observed_fisher_information(stats=None, diagonal=False, center=None, ridge=1.0e-8, **kwargs)[source]
Observed Fisher estimate from score vectors for observed data.
For latent models the statistic rows are posterior-expected complete-data sufficient statistics, so centering them by their model expectation gives observed score vectors. Their covariance is the observed Fisher metric used by Fisher-vector embeddings. If a model center is unavailable, this falls back to the empirical mean.
- observed_fisher_vectors(stats=None, metric='diagonal', center=None, fisher=None, ridge=1.0e-8, **kwargs)[source]
- fisher_vector(x, estimate=None, metric='diagonal', center=None, fisher=None, vectorizer=None, ridge=1.0e-8)[source]
- class FixedFisherView(dist, labels)[source]
Bases:
FisherViewDistribution-specific Fisher view with fixed vector coordinates.
- Parameters:
dist (Any)
labels (Sequence[Path])
- structured_statistics(x, estimate=None, weight=1.0)[source]
Structured sufficient stats for one observation.
For latent-variable distributions, this is the posterior-expected complete-data sufficient statistic under estimate (or this view’s distribution when estimate is omitted).
- sufficient_statistics(x, estimate=None, vectorizer=None)[source]
- seq_structured_statistics(enc_data, estimate=None)[source]
Structured per-row stats from encoded data.
This generic implementation is intentionally conservative and may be slow for large data. It exists so every encoder-compatible model has a correct baseline.
- statistics_matrix(data=None, enc_data=None, estimate=None, vectorizer=None, fit=True)[source]
Return an n x d matrix of per-observation sufficient statistics.
- mean_statistics(stats=None, model=True, **kwargs)[source]
- fisher_information(stats=None, diagonal=False, ridge=1.0e-8, **kwargs)[source]
Empirical Fisher approximation from per-observation statistic vectors.
- fisher_vectors(stats=None, metric='diagonal', center=None, fisher=None, ridge=1.0e-8, **kwargs)[source]
Return centered/whitened sufficient-statistic vectors.
metric=’identity’ returns centered statistics, ‘diagonal’ divides by per-coordinate Fisher standard deviations, and ‘full’ applies an empirical full-matrix whitening transform.
- to_fisher(dist, **kwargs)[source]
Return a FisherView for
distvia its ownto_fisherhook.Fisher views are co-located with each distribution: a distribution owns its view by overriding
ProbabilityDistribution.to_fisher. This module keeps only the shared base machinery (FisherView/FixedFisherView/SufficientStatisticVectorizer and the reusable CountFisherView / EmpiricalMetricFixedFisherView helpers) plus_legacy_to_fisher(), the type-name dispatch for families not yet migrated to a per-file hook (and the generic fallback).
- nuts(target, *, backend='auto', dim=None, init=None, num_samples=1000, warmup=1000, chains=1, mass=1.0, target_accept=0.8, max_tree_depth=10, thin=1, rng=None, parallel=None, **backend_kwargs)[source]
No-U-Turn Sampler over an arbitrary log-target, dispatched to a registered engine.
The
targetcontract depends on the backend (the kinds cannot be auto-converted across autodiff systems):numpy/numba: a fusedvalue_and_grad(theta) -> (logp, grad)(njit-jitted fornumba). The caller supplies the (analytic) gradient.torch/jax: a scalarlogp(theta); the backend buildsvalue_and_gradby autodiff (torch.func/ NumPyro).
- Parameters:
target (Callable[[...], Any]) – the log-target, per the contract above.
backend (str) –
"auto"(default), or one ofavailable_backends()."auto"honors an explicit choice elsewhere, otherwise prefers the always-presentnumpypath for a plain numpyvalue_and_grad; passbackend="numba"to run an@njittarget,"jax"/"torch"for an autodiff scalarlogp.dim (int | None) – parameter dimension. Required unless
initis given.init (Any) – initial state, shape
(dim,)or(chains, dim)for per-chain starts. Defaults to zeros. A 1-Dinitis reused (jittered after the first) across chains.num_samples (int) – retained post-warmup draws per chain.
warmup (int) – step-size adaptation / burn-in iterations per chain.
chains (int) – number of independent chains (>= 2 to get a meaningful R-hat).
mass (Any) – forwarded to the sampler.
target_accept (float) – forwarded to the sampler.
max_tree_depth (int) – forwarded to the sampler.
thin (int) – forwarded to the sampler.
rng (RandomState | int | None) – seed / RandomState for reproducibility.
parallel (bool | str | None) – run the
chainsindependent chains concurrently.None/False(default) runs them in the backend’s usual single call;"thread"uses a thread pool (real speedup for thenumba/torchbackends, whose inner loops release the GIL);Trueor"process"uses a process pool (real speedup for the pure-numpybackend; requires a picklabletarget). Ignored for thejaxbackend, which already vectorizes chains internally. Each chain still gets an independent seed, so results are valid multi-chain draws (R-hat / ESS across chains).**backend_kwargs (Any) – forwarded to the chosen backend (e.g.
compile=,device=fortorch;chain_method=forjax).
- Returns:
NutsResultwith pooledsamples(chains*draws, d), per-chainchains(chains, draws, d), per-dimensionrhatandess, the total target-evaluation count, the adaptedstep_size, andextra={"backend": name}.- Return type:
NutsResult
- nuts_torch(logp, *, dim=None, init=None, num_samples=1000, warmup=1000, chains=1, mass=1.0, target_accept=0.8, max_tree_depth=10, thin=1, rng=None, compile=True, dtype=None, device=None)[source]
Torch-native NUTS over a torch scalar
logp(theta) -> Tensor[()](GPU / large autodiff targets).The whole leapfrog/tree runs in torch tensors with a
torch.compile``d ``value_and_grad(no numpy round-trip / graph re-trace per gradient). Same multi-chain interface andNutsResultasnuts(). Also registered as the"torch"backend.Performance note (be deliberate about when to use this): on CPU this is typically slower than the numpy
nuts()(per-op torch dispatch + host syncs in the tree dominate when the target is cheap). Its value is GPU (device=) and large autodiff targets. For CPU work prefer the numpy backend, numba (analytic gradient), or the jax/NumPyro backend (XLA, vectorized multi-chain). Chains run in a Python loop (per-chain latency).
- advi(target_batch, u0, s0, *, samples=1000, mc=16, steps=2000, lr=0.05, batch_size=None, family='meanfield', alpha=1.0, rng=None)[source]
Automatic-differentiation VI over a user batched torch target.
- Parameters:
target_batch (Callable[[Any], Any]) –
target_batch(U: Tensor(B, d)) -> Tensor(B,)returning the (unnormalized) joint log-target for each ofBparameter draws. The caller owns any data minibatching/rescaling inside this callable;batch_sizehere is unused unless the caller wires it in (kept for signature parity with the internal ADVI).u0 – initial variational mean and (marginal) scale in the unconstrained space.
s0 – initial variational mean and (marginal) scale in the unconstrained space.
samples (int) – number of posterior draws to return.
mc (int) – Monte-Carlo samples per step, optimizer steps, Adam learning rate.
steps (int) – Monte-Carlo samples per step, optimizer steps, Adam learning rate.
lr (float) – Monte-Carlo samples per step, optimizer steps, Adam learning rate.
family (str) –
'meanfield'(diagonal) or'fullrank'(Cholesky covariance).alpha (float) – Renyi/tilted objective exponent (
1.0= standard KL-ELBO).rng (RandomState | int | None) – seed / RandomState.
batch_size (int | None)
- Returns:
AdviResultwithsamples(samples, d)drawn from the fitted Gaussian q (in the same spacetarget_batchconsumes), plus the fittedmeanandscale.- Return type:
AdviResult
- class NutsResult(samples, chains, rhat, ess, num_target_evals, step_size, extra=<factory>)[source]
Bases:
objectDraws and diagnostics from a multi-chain
nuts()run.samplesis(chains * draws, d)pooled draws;chainsis(n_chains, draws, d).- Parameters:
- samples: ndarray
- chains: ndarray
- rhat: ndarray
- ess: ndarray
- num_target_evals: int
- step_size: float
- extra: dict
- class AdviResult(samples, mean, scale, objective=None)[source]
Bases:
objectResult of
advi(): posterior draws plus the fitted variational parameters.- samples: ndarray
- mean: ndarray
- scale: ndarray
- rhat(chains)[source]
Gelman-Rubin potential scale reduction factor (R-hat) per parameter dimension.
R-hat compares the variance between chains to the variance within chains. Values near 1.0 indicate the chains have mixed and are sampling a common target; values above ~1.01-1.1 flag non-convergence. Standard multi-chain check (Gelman & Rubin 1992).
- ess(samples, max_lag=None)[source]
Effective sample size per parameter from positive autocorrelation lags.
Accepts a single chain
(n_draws,)/(n_draws, d)or a stack of chains(n_chains, n_draws, d)(the chains are pooled into one autocorrelation estimate after centering each chain by its own mean). Uses the initial-positive-sequence truncation (Geyer): sum autocorrelations until the first non-positive lag.
- split_rhat(chains)[source]
Rank-normalized split-R-hat (Vehtari et al. 2021) – the robust, recommended R-hat.
Splits each chain in half (doubling the chain count, so within-chain non-stationarity is caught), rank-normalizes the pooled draws (robust to heavy tails / non-normality), then applies the Gelman-Rubin R-hat. Convergence is typically declared at
< 1.01.
- folded_split_rhat(chains)[source]
Folded rank-normalized split-R-hat (Vehtari et al. 2021): split-R-hat on
|x - median(x)|.The plain
split_rhat()compares chain locations; folding about the median makes it compare chain scales/tails, catching the case where chains share a mean but differ in spread. Use together withsplit_rhat()(orrhat_max()).
- rhat_max(chains)[source]
The recommended convergence R-hat:
max(split_rhat, folded_split_rhat)(Vehtari et al. 2021).A single number that flags non-convergence in either the location (bulk) or the scale (folded) of the chains; declare convergence at
< 1.01.
- mcse_mean(chains)[source]
Monte Carlo standard error of the posterior mean:
sd(x) / sqrt(ESS)per parameter.The sampling error in the estimated mean from autocorrelated draws – the posterior standard deviation deflated by the (autocorrelation-based) effective sample size of the raw chains.
- geweke_z(chain, first=0.1, last=0.5)[source]
Geweke convergence z-score comparing the start and end of a single chain (per parameter).
Tests stationarity within one chain (Geweke 1992): if the chain has converged, the mean of its first
firstfraction and its lastlastfraction agree, so the z-statistic(mean_a - mean_b) / sqrt(se_a^2 + se_b^2)– with autocorrelation-adjusted standard errors (the segment variance divided by its effective sample size) – is approximately standard normal.|z| < 2indicates convergence; a large|z|flags a chain still drifting. Returns one z per parameter. Complements the multi-chainsplit_rhat().
- mcmc_summary(chains)[source]
Per-parameter posterior + convergence summary (the ArviZ-style
summarytable).Returns one dict per parameter with the posterior
mean/sdand 5/50/95% quantiles, plus the recommended convergence diagnostics:r_hat(=rhat_max(), the max of the bulk and folded rank-normalized split-R-hats),ess_bulk,ess_tail, andmcse_mean(Vehtari et al. 2021). Declare convergence atr_hat < 1.01withess_bulk/ess_tailcomfortably in the hundreds.
- ess_bulk(chains)[source]
Bulk effective sample size: ESS of the rank-normalized split chains (mixing in the distribution body).
- ess_tail(chains, prob=0.05)[source]
Tail effective sample size: the smaller ESS of the lower-/upper-
probtail indicators.Tail quantiles mix more slowly than the bulk; tail-ESS is
min(ESS[1(x <= q_prob)], ESS[1(x >= q_{1-prob})])over the split chains (Vehtari et al. 2021), surfacing poor tail exploration that bulk-ESS misses.
- available_backends()[source]
Return the names of registered backends whose engine is importable, in registration order.
- class InferenceBackend(name, available, target_kind, nuts)[source]
Bases:
objectA registered inference engine: a name, an availability probe, a target contract, a sampler.
- Parameters:
- name: str
- available: Callable[[], bool]
- target_kind: str
- nuts: Callable[..., NutsResult]
- register_inference_backend(backend)[source]
Register (or replace) an inference backend under
backend.name.- Parameters:
backend (InferenceBackend)
- Return type:
None
- class EventStudyResult(effect, se, z, p_value, ci, treated_mean, treated_se, control_mean, control_se, tau2_treated, n_treated, n_control, shrunk_treated)[source]
Bases:
objectPooled influence estimate.
effectis the DiD ATT (treated minus control) when a control exists.- Parameters:
- effect: float
- se: float
- z: float
- p_value: float
- treated_mean: float
- treated_se: float
- tau2_treated: float
- n_treated: int
- n_control: int
- shrunk_treated: ndarray
- gaussian_effect(pre, post)[source]
Per-subject mean shift and its (Welch) sampling variance from pre/post activity samples.
- poisson_lograte_effect(k_pre, t_pre, k_post, t_post)[source]
Per-subject log activity-rate shift
log(rate_post) - log(rate_pre)for event counts over windows.k_*are event counts,t_*the window durations (or exposures). Uses a Haldane 0.5 correction so zero-count windows are finite; variance is the delta-method log-rate variance1/k_post + 1/k_pre.
- hierarchical_event_study(treated_effects, treated_vars, control_effects=None, control_vars=None, *, alpha=0.05)[source]
Pool per-subject effects into a population influence estimate (DiD if a control group is given).
*_effects/*_varsare the per-subject shifts and their variances from stage 1. With a control group the reportedeffectistreated_mean - control_mean– the difference-in-differences ATT.
- tipping_drift(result)[source]
Sensitivity bound: the unmeasured differential drift that would explain the effect away.
Within-subject DiD is unbiased only if, absent treatment, treated and control would have drifted equally. This returns the differential drift
delta(in effect units) that nullifies the estimate (= effect) and the value that pushes the 95% CI through zero – so a reader can judge whether a confound that large is plausible. Larger = more robust.- Parameters:
result (EventStudyResult)
- Return type:
Subpackages¶
Submodules¶
- mixle.inference.backends module
- mixle.inference.bayesian_network module
- mixle.inference.belief module
- mixle.inference.blackbox module
- mixle.inference.block_gibbs module
- mixle.inference.calibrate_fit module
- mixle.inference.calibration module
- mixle.inference.causal module
- mixle.inference.conformal module
- mixle.inference.create module
- mixle.inference.cross_validation module
- mixle.inference.decision module
- mixle.inference.diagnostics module
- mixle.inference.em module
- mixle.inference.errors_in_variables module
- mixle.inference.estimation module
- mixle.inference.event_study module
- mixle.inference.explain module
- mixle.inference.fisher module
- mixle.inference.forecast module
- mixle.inference.fusion_policy module
- mixle.inference.glm module
- mixle.inference.gradient_fit module
- mixle.inference.heterogeneous_executor module
- mixle.inference.jit module
- mixle.inference.model_comparison module
- mixle.inference.mpi_executor module
- mixle.inference.multiple_testing module
- mixle.inference.nonparametric module
- mixle.inference.objectives module
- mixle.inference.orchestration module
- mixle.inference.ordinal module
- mixle.inference.placement module
- mixle.inference.planning module
- mixle.inference.posterior module
- mixle.inference.precision_plan module
- mixle.inference.priors module
- mixle.inference.project module
- mixle.inference.reproduce module
- mixle.inference.resampling module
- mixle.inference.robust module
- mixle.inference.scoring module
- mixle.inference.select module
- mixle.inference.simulate module
- mixle.inference.skill module
- mixle.inference.spark_executor module
- mixle.inference.streaming module
- mixle.inference.structure module
- mixle.inference.survival module
- mixle.inference.synthesize module
- mixle.inference.target module
- mixle.inference.uncertainty module
- mixle.inference.uq module