Quickstart¶
This quickstart fits a heterogeneous record model with mixle.stats and
mixle.inference.optimize. It scores new rows, samples from the fitted
distribution, and inspects the fitted object’s capabilities.
Install¶
pip install mixle
From a repository checkout:
pip install -e .
Data Shape¶
One observation is a Python tuple:
(segment, value, count_sequence)
Example:
("steady", 11.8, [3, 4, 2])
The fields are intentionally mixed:
segmentis categorical;valueis real-valued;count_sequenceis a variable-length sequence of counts.
Make Synthetic Rows¶
import numpy as np
def make_rows(n=240, seed=0):
rng = np.random.RandomState(seed)
rows = []
for _ in range(n):
bursty = rng.rand() < 0.45
segment = "bursty" if bursty else "steady"
value = float(rng.normal(18.0 if bursty else 8.0, 2.0 if bursty else 1.0))
length = int(rng.choice([2, 3, 4]))
rate = 9.0 if bursty else 3.0
counts = [int(x) for x in rng.poisson(rate, size=length)]
rows.append((segment, value, counts))
return rows
rows = make_rows()
Build the Model Shape¶
The estimator has the same shape as one observation. A mixture adds a latent cluster over the whole row.
from mixle.stats import (
CategoricalEstimator,
CompositeEstimator,
GaussianEstimator,
MixtureEstimator,
PoissonEstimator,
SequenceEstimator,
)
def row_component():
return CompositeEstimator(
(
CategoricalEstimator(),
GaussianEstimator(),
SequenceEstimator(
PoissonEstimator(),
len_estimator=CategoricalEstimator(),
),
)
)
estimator = MixtureEstimator([row_component(), row_component()])
Read this literally:
CategoricalEstimatorfitssegment.GaussianEstimatorfitsvalue.SequenceEstimator(PoissonEstimator())fits a variable-length list of counts.CompositeEstimatorjoins those fields into one row-level model.MixtureEstimatorlearns two latent row types.
Fit¶
from mixle.inference import optimize
model = optimize(rows, estimator, max_its=80, out=None)
The result is a fitted distribution. It can score rows, sample rows, and expose
capabilities through mixle.describe.
Score Rows¶
ordinary = rows[0]
unusual = ("steady", 24.0, [18, 21, 19])
print(model.log_density(ordinary))
print(model.log_density(unusual))
Both scores are log probabilities. The unusual row should score poorly because
its label says steady while its value and counts look more like the
bursty cluster.
Sample¶
samples = model.sampler(seed=0).sample(3)
print(samples)
Sampling is part of the distribution contract. Use an explicit seed whenever a notebook, test, or article needs reproducible output.
Inspect Capabilities¶
import mixle
print(mixle.describe(model))
print(mixle.capabilities(model))
This habit matters. Not every fitted object can enumerate, condition, marginalize, expose exact densities, run on every backend, or produce latent posteriors. Capability inspection is the honest way to find out.
Use a Prototype Distribution¶
When you know the model family, pass a prototype distribution. Mixle derives the matching estimator from that shape.
from mixle.stats import GaussianDistribution, MixtureDistribution
values = [row[1] for row in rows]
proto = MixtureDistribution(
[GaussianDistribution(8.0, 1.0), GaussianDistribution(18.0, 4.0)],
[0.5, 0.5],
)
value_model = optimize(values, proto, prev_estimate=proto, out=None)
Passing proto as the second argument tells optimize what to fit.
Passing it as prev_estimate also uses those parameter values as the
starting estimate, which is usually what you want for a mixture example.
Infer a First Estimator¶
For exploratory work, Mixle can propose an estimator shape from data:
from mixle.utils.automatic import get_estimator
inferred = get_estimator(rows)
inferred_model = optimize(rows, inferred, max_its=40, out=None)
Treat the inferred shape as a starting point. Inspect it, compare it on held-out data, and replace pieces when the automatic guess does not match the domain.
Create a Certified Artifact¶
When the fit should carry an explicit certificate and optional post-fit checks,
use create after the core workflow is clear:
from mixle.inference import create
artifact = create(rows, calibrate=0.2, quantify_uq=True, seed=0)
print(artifact.guarantee)
print(artifact.is_calibrated())
create still delegates to the same fitting machinery. It adds an artifact
boundary: estimation certificate, optional calibration, optional UQ, and
provenance including row counts and exchangeability diagnostics.
Optional: Neural And Task Layers¶
Use the neural and LLM-facing layers when the task genuinely calls for them:
shared embeddings across language-model experts, exact neural density leaves,
local students distilled from expensive teachers, or calibrated LLM abstention.
Those workflows carry extra dependency and validation requirements, so keep the
first model in mixle.stats unless the data shape demands otherwise. See
Neural and LLM Models, Task Distillation, and Uncertainty after the
core distribution workflow above is clear.