mixle.inference.estimation module

Functions for estimating and validating mixle models from observed data.

Useful functions for estimating mixle ‘SequenceEncodableProbabilityDistributions’ from ‘ParameterEstimator’ objects.

class EMStep(iter, model, log_density, delta)[source]

Bases: NamedTuple

One accepted EM iteration, handed to an optimize(on_step=...) callback.

iter is 1-based; model is the current accepted model – snapshot it to checkpoint, and resume with optimize(prev_estimate=...); log_density is the training objective at this step; delta is its gain over the previous step (inf on the first iteration).

Parameters:
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

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=None, 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', schedule='full', monotone=None, track_best=None, seed=None, fused_options=None)[source]
Fit estimator to data by a generalized-EM loop, for max_its iterations or until the

objective improves by less than delta.

Each iteration re-estimates every part of the model by whatever its structure calls for – closed-form for conjugate / exponential-family leaves, gradient descent for neural leaves, coordinate descent for GLMs, responsibility-weighted EM for latent structure (mixtures, HMMs) – so a single call fits a heterogeneous tree without the caller choosing an algorithm. (The convergence objective defaults to the family-defined maximum-likelihood objective: each leaf applies its own documented estimator update, which for some families is a closed-form moment update rather than an iterative likelihood maximization, and families may apply documented numerical floors/repairs – read them back via model.numerical_repairs(). A parameter prior switches the objective to penalized-LL / MAP, and a variational model to the ELBO – see objective.)

Missing values. With estimator=None (the default) auto-inference finds the gaps and wraps the affected leaf for you: data carrying None, NaN, pd.NA or pd.NaT fits an OptionalDistribution whose missingness rate is estimated alongside the base family. When you build the estimator yourself, that wrapper is yours to add, and it must name the sentinel your data actually carries – the wrapper matches its missing_value by identity, so the None default does not accept NaN:

optimize(rows, CompositeEstimator([OptionalEstimator(GaussianEstimator(),
                                                     missing_value=float("nan")),
                                   CategoricalEstimator()]))

NaN is the spelling float arrays and numeric pandas columns use, so missing_value=float('nan') is the one that works for tabular numeric data; missing_value=None (the default) is for records that carry None. mixle.stats.marginalized() is the same wrapper with no fitted rate, but it takes a DISTRIBUTION rather than an estimator and its default sentinel is not NaN, so NaN data must spell out marginalized(dist, missing_value=float('nan')).

A native +inf/-inf gets the same auto-inference treatment as the sentinels above – fitted as its own OptionalDistribution(..., missing_value=math.inf) (one wrapper per sign present) rather than rejected – because an infinity is not itself a value most continuous families can carry, so treating it as “a measurement that comes out infinite p of the time” keeps the auto-built model a proper generative law instead of refusing to fit. This is DIFFERENT from the None/NaN/pd.NA/pd.NaT case above: those are absences by convention; an inf is a legitimate (if unusual) numeric value, so estimator=None raises a UserWarning naming the affected field(s) when it reclassifies one – catch it with warnings.catch_warnings() if your pipeline needs to notice. Passing an estimator explicitly bypasses auto-inference and gets the family’s own contract instead: a family whose support excludes inf (e.g. GaussianEstimator) raises ValueError rather than silently wrapping it.

Identifier-like columns. estimator=None auto-inference (via mixle.utils.automatic.get_estimator) also freezes a scalar column it cannot otherwise type – an unrecognized scalar type (datetime, Decimal, …), an ambiguous bool/number mix, and an identifier-like/high-cardinality column (e.g. a user id, order id, or other near-unique key) – as the empirical categorical over the values observed at fit time, held fixed by IgnoredDistribution. A value not seen at fit time then scores -inf there, the same finite-support behavior every automatically fitted categorical has (CategoricalDistribution’s default_value docstring); this is silent at fit time – no warning, unlike the +inf/-inf reclassification above – because freezing is the correct, unsurprising answer for a column of this shape, not a defect being flagged. It matters at SCORING time: a held-out or production row carrying a fresh identifier scores that field at -inf, and because log-densities sum, one such field silently drives the WHOLE model’s log_density/Model.evaluate() score to -inf even though every other field scored normally (Model.evaluate() warns rather than raising on this, precisely because it is this documented, by-design behavior rather than a scoring bug – see its docstring). mixle.propose() fits the identical policy but additionally excludes just the affected field(s) from a candidate’s held-out verification score (with a note naming them, in Model.notes) rather than voiding the whole candidate – optimize() itself does not do this rescue, so an identifier-like field’s presence is worth checking for explicitly (e.g. via model.log_density per field, or mixle.utils.automatic.get_estimator(data) inspection) before trusting a held-out score built on a model this call produced.

DataFrames. optimize and fit take a pandas DataFrame or Series directly; the row-level stats API does not. mixle.stats.seq_encode consumes RECORDS and refuses a frame (“expected a sequence of 2-tuples, got DataFrame”) – converting is the caller’s job, in one call: mixle.data.dataframe_records(df) for the records, or mixle.data.seq_encode_dataframe(df, model=...), which is the frame-shaped counterpart of seq_encode. A frame’s gaps are canonicalized on the way in by what each column HOLDS – NaN for a column of numbers, None for anything else – so df and df.convert_dtypes() fit models carrying the same missing_value, and each model scores the other frame.

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 ParameterEstimator is used as-is; a distribution prototype (any ProbabilityDistribution) is coerced to its matching estimator via proto.estimator() so you build the model shape only once; None infers an estimator from raw data (mixle.utils.automatic.get_estimator). Inferring from rows that do not all carry the same number of fields is ambiguous between a table with a malformed row and variable-length sequence data, so it is decided on the arity evidence rather than guessed: an overwhelmingly dominant arity raises ContractError naming the offending row, a bare majority is fitted as a sequence and warns that it did, and widely spread arities are fitted as a sequence in silence. Pass mixle.utils.automatic.get_estimator(data, ragged='sequence') as the estimator to demand the sequence reading outright.

  • 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 abs(old_loglikelihood - new_loglikelihood) < delta or iterations == max_its. delta=None requests a fixed max_its iteration count by disabling this convergence test – but it does NOT disable the separate acceptance gate every iteration still passes through (a proposed step that does not improve the objective, or produces a non-finite one, is rejected and ends the loop regardless of delta). That rejection can still cut a delta=None run short of max_its, from ordinary float noise near a fixed point; a UserWarning discloses it when it happens (compare fit_provenance().iterations against max_iterations to check yourself instead).

  • 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. This is a statistical knob, not an execution detail: the initialization is the estimator’s answer on the drawn subsample, and for latent models and for families whose documented update is approximate rather than an exact likelihood ascent (e.g. Weibull, GeneralizedExtremeValue, WrappedCauchy) the accepted EM trajectory – and therefore the returned parameters – depends on that start. In the extreme, such a family’s very first update can fail the monotone acceptance gate, and the fit then returns the initialization itself (fit_provenance() reports converged=False with iterations below the cap). init_p=1.0 initializes from the estimator’s answer on all the data.

  • rng (RandomState) – RandomState used to set seed for initializing EM algorithm. None resolves to a FIXED seed, so the NumPy-driven parts of an un-seeded optimize/fit (initialization, EM, subsampling) are deterministic by default; pass your own RandomState when you WANT different initializations across calls (e.g. hand-rolled restarts). Torch-backed leaves are the deliberate exception: modules that consume torch’s global RNG (dropout, VAE reparameterization draws, minibatch shuffling) follow torch’s own default non-determinism – call torch.manual_seed yourself when a torch-backed fit must be exactly reproducible. An integer is accepted and coerced to RandomState(rng). Mutually exclusive with seed.

  • 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 | None) – Stream for per-iteration EM progress lines. Defaults to None (quiet, so the library does not spam stdout in normal use); pass out=sys.stdout to watch convergence.

  • 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. For exact-sufficient-statistic leaves the chunk statistics combine exactly, so chunking changes only float summation order. Chunking also changes WHICH rows the init_p initialization subsample draws, however, so for the initialization-sensitive families described under init_p a different num_chunks can change the fitted parameters, not just the execution plan – measured at the percent level on Weibull/GEV/WrappedCauchy fits. When varying it, compare fit_provenance().final_objective (or hold the start fixed with init_p=1.0).

  • 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' or np.float64. Pass 'auto' to let mixle.engines.auto_precision choose 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 resources or placement is 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 for backend='dask'. The default is the CPU count capped at the number of observations; an explicit value is used as given (capped only at the number of observations), so a value far above the core count spawns that many processes and fails slowly at the worker setup timeout rather than promptly. Keep it at or below the core count.

  • 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, CompiledEM) or any callable (enc, estimator, model) -> model to use in place of the standard exact E/M step. None uses 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 maximum likelihood ('mle'). 'mle' is the family-defined maximum-likelihood objective: what is guaranteed is each leaf family’s documented estimator update – exact MLE for exponential-family leaves, a documented closed-form moment update for families whose class docstring says so – and families may apply documented numerical floors/repairs, reported on the fitted model via numerical_repairs(). Pass 'mle' / 'map' / 'vb' to force a specific objective. fit accepts 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_ll is ignored for 'map'/'vb'.)

  • monotone (Optional[bool]) –

    Outer-objective acceptance policy. None (default) uses strict generalized-EM acceptance for immutable closed-form updates and best-seen selection for mutable neural or variational/approximate updates. In best-seen mode finite downhill steps may be traversed, but the returned model (including mutable module parameters) is restored to the best selected-objective value observed. Pass True to reject the first decreasing step, or False to permit a non-monotone trajectory explicitly.

    Convergence contract (worklist Q5.4; pinned by em_convergence_contract_test): under strict acceptance the accepted-round objectives are non-decreasing within tolerance and – bounded above by the estimator variance floors – the objective sequence converges; limit-point stationarity is the classical EM/GEM theory per family. Under best-seen selection the guarantee is the best visited iterate; a neural leaf fit with lr_decay in (0.5, 1] additionally follows a Robbins–Monro step schedule (the condition stochastic-approximation EM analyses require). A non-finite objective is never accepted and never becomes the convergence reference.

  • track_best (Optional[bool]) – Whether to restore the best outer-objective state seen. None (default) does so except when an estimator explicitly declares a surrogate fitting objective, such as NCE; observed density is not a valid selector until such a model is normalized, so its final finite update is returned. Pass a boolean to override selection.

  • 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 with prev_estimate=. Called on every iteration regardless of print_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. A pandas DataFrame is converted to the same flat records first (honoring fields), so a table gets the same structure inference whether it arrives as a DataFrame or as a list of row tuples. 'off' restores the unconditional historical behavior. Only consulted when estimator is None and no prev_estimate/init_estimator/strategy/enc_data is supplied.

  • schedule (str) – 'full' (default) performs exact full-tree EM every round and automatically uses whole-model or component-level compiled kernels when the local model is eligible. 'auto' additionally engages the block-coordinate-ascent scheduler (mixle.inference.block_em) when selective work is expected to win: after one full bootstrap sweep, components are ranked by their last observed complete-data Q gain per measured whole-block cost, and only the highest-value ones within a per-round budget are re-estimated. Inactive component scores are cached while their parameters remain unchanged. This is a scheduling choice: observed likelihood is transactionally gated non-decreasing every round, and when there is no useful ranking to do (e.g. every component looks equally worth updating) the scheduler degenerates to doing exactly what 'full' does. Only engaged when the model is a local-backend MixtureDistribution/ MixtureEstimator MLE/MAP fit with no explicit strategy/engine/resources/ placement – anything else silently falls back to 'full' (never an error, never a behavior change beyond scheduling).

  • seed (Optional[int]) – Integer seed for initializing the EM algorithm – shorthand for rng=RandomState(seed), matching the seed= argument the samplers and the other entry points take. Mutually exclusive with rng (passing both raises TypeError).

  • fused_options (Optional[dict]) – Tuning knobs for the fused compiled kernels, applied when the fit runs on a fused engine (an explicit fused engine= or the auto-fusion gate). Recognized keys: parallel (bool – force the chunk-parallel kernels on or off, overriding the observation-count auto-gate; results are bit-stable either way), lse_bits (int – opt SCORING into quantized log-sum-exp with a ~2**-bits relative bound; E-steps always stay exact), and lse_span (float, default 24.0 – the clipped LSE exponent range used with lse_bits). Unknown keys raise ValueError. Ignored (with the same validation) when the fit resolves to a non-fused path.

Returns:

the fitted model. The run behind it ended in one of

three ways – the objective gain fell below delta (a converged fit), the max_its cap was reached with the objective still improving (an unconverged fit; a UserWarning says so when delta is in force), or the family’s next update failed the monotone acceptance gate before the cap (no further progress is possible; see init_p). The receipt distinguishing them ships on the model: model.fit_provenance() reports converged, iterations, final_objective (the returned model’s objective value), and any numerical repairs.

Return type:

SequenceEncodableProbabilityDistribution

Model comparison. A fitted core distribution intentionally carries no aic()/bic() – the core cannot count free parameters exactly for every composed model. The supported paths: per-observation log-densities (model.log_density(x)) feed the paired comparison tests exported by mixle.inference (vuong_test(), clarke_test(), paired_score_difference(), compare_elpd()), and the mixle.ppl surface fits the same families with a recorded parameter dimension, giving m.aic(data) / m.bic(data) and best-first ranking via mixle.ppl.compare([m1, m2], data, by='bic').

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(). fit iterates the EM/VB update that maximizes the objective selected by objective (default 'auto'):

  • 'auto' – the prior is the single switch: 'vb' when the model exposes seq_local_elbo, 'map' when the estimator carries a parameter prior, else 'mle';

  • 'mle' – the family-defined maximum-likelihood objective on the data log-likelihood (ignores any prior in the objective). What is guaranteed is each leaf family’s documented estimator update – some families document a closed-form moment update rather than an iterative likelihood maximization – and families may apply documented numerical floors/repairs; read them back via model.numerical_repairs();

  • 'map' / 'vb' – penalized log-likelihood / ELBO obj = data term + prior term, where the data term is the observed-data LL (MAP) or local-ELBO contributions (variational), and the prior term is estimator.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 as model.get_prior(). With no prior anywhere, every objective reduces to plain EM, so fit and optimize agree for frequentist estimators. optimize accepts the same objective argument; 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.

fit is a thin wrapper over optimize() – they share the one EM/objective loop. fit adds only the opt-in data-structure check, a Bayesian-leaning default delta (1e-6), and the exact per-iteration-scored loop (reuse_estep_ll=False). Every other optimize() keyword – engines, precision, distributed backend, on_step, the fused E-step – is accepted here too and forwarded verbatim, so reaching for a heavier knob never means switching verbs. estimator accepts the same three spellings as optimize() (estimator, distribution prototype, or None to infer from data).

Parameters:
  • data (Sequence[T] | None)

  • estimator (ParameterEstimator | ProbabilityDistribution | None)

  • max_its (int)

  • delta (float | None)

  • init_estimator (ParameterEstimator | ProbabilityDistribution | None)

  • kwargs (Any)

Return type:

SequenceEncodableProbabilityDistribution

best_of(data, vdata, est, trials, max_its, init_p, delta, rng=None, init_estimator=None, enc_data=None, enc_vdata=None, out=None, print_iter=1, reuse_estep_ll=True, objective='auto', seed=None, fused_options=None)[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 abs(old-log-likelihood - new-log-likelihood) < delta.

  • rng (RandomState) – RandomState for setting seed. An integer is coerced to RandomState(rng); None (default) resolves to the fixed default seed. Mutually exclusive with 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 optimize call – reuse the E-step likelihood for convergence instead of a separate scoring pass (see optimize). Set False to force the exact historical per-iteration scoring behavior.

  • objective (str) – Convergence/selection objective forwarded to each trial’s optimize call; 'auto' (default) selects MLE / MAP / variational Bayes from the prior (see optimize).

  • seed (Optional[int]) – Integer seed – shorthand for rng=RandomState(seed). Mutually exclusive with rng (passing both raises TypeError).

  • fused_options (Optional[dict]) – Fused-kernel tuning knobs forwarded to every trial’s optimize call – see optimize(fused_options=...) for the recognized keys.

Returns:

Tuple of log-likelihood of best fitting model and the best fitting model from number of trials.

Return type:

tuple[float, SequenceEncodableProbabilityDistribution]

constant(rho)[source]

Return a constant streaming step-size schedule.

Parameters:

rho (float)

harmonic(alpha, offset=1.0)[source]

Return rho_t = (offset + t - 1)^(-alpha) for streaming EM.

Parameters:
posterior_carry()[source]

Return the recursive-conjugate streaming mode name.

In posterior_carry mode each fitted posterior becomes the next batch’s prior, i.e. the stream performs exact recursive Bayesian updating: the conjugate posterior after batch t is fed in as the conjugate prior for batch t + 1.

Return type:

str

forgetting(rho)[source]

Return a constant forgetting / power-prior schedule for streaming Bayes.

rho in (0, 1] discounts the sufficient statistics retained from PREVIOUS batches before adding the next batch at full weight, so older evidence decays geometrically. rho=1 recovers ordinary un-forgotten accumulation.

Parameters:

rho (float)

class BayesianStreamingEstimator(estimator, mode='posterior_carry', schedule=None, model=None, init_estimator=None, init_p=0.1, rng=None, num_chunks=1)[source]

Bases: object

Streaming / 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' retains a running sufficient-statistic accumulator. Before each batch after the first, the retained OLD statistics and effective observation count are scaled by rho = schedule(step); the new batch is then added at full weight. Estimation always uses the original estimator/prior, avoiding both discounting new evidence and double-counting a carried posterior. Accumulator scaling preserves structural support metadata such as categorical bounds.

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.

Parameters:
Return type:

SequenceEncodableProbabilityDistribution

reset()[source]

Restore the original estimator, RNG state, and empty stream state.

Return type:

None