axiom

A model of your own · step 4 of 5

Fit it

How does a hand-built model reach a backend?

Straight at one. A backend takes the model and a mapping from column name to array — there is no Panel in this path, because a ModelSpec names its own columns and that is all the backend needs.

The parameters come back under the names you declared. Checking them against a truth you control is the only honest way to know a hand-built model is right, which is why simulating from it first is worth the ten minutes it costs.

step 4
import numpy as np
from axiom.infer import LaplaceBackend

# data from a world we control, so the answer can be checked
TRUE = {"alpha": 41.0, "beta": 12.0, "k": 260.0, "sigma": 2.0}
rng = np.random.default_rng(3)
x = rng.uniform(0.0, 900.0, 600)
y = (TRUE["alpha"] + TRUE["beta"] * (1 - np.exp(-x / TRUE["k"]))
     + rng.normal(0.0, TRUE["sigma"], x.size))

posterior = LaplaceBackend().sample(
    model, {"spend": x, "footfall": y},
    draws=800, tune=0, chains=4, seed=0,
)

print(f"{'parameter':10s}{'fitted':>10}{'truth':>10}")
for name in ("alpha", "beta", "k", "sigma"):
    got = float(posterior.flat(name).mean())
    print(f"{name:10s}{got:>10.2f}{TRUE[name]:>10.2f}")
what it printed
parameter     fitted     truth
alpha          40.45     41.00
beta           12.42     12.00
k             238.27    260.00
sigma           1.99      2.00

Every line above was captured by running this code at build time. The steps share one namespace, so the code on this page is the code you would type after the steps before it.