Fitting and comparison#
Fitting, model comparison and model-recovery studies, common to every family.
fit()fits one model class by multi-start optimisation (maximum likelihood or least squares).compare()fits several classes and ranks them by BIC or AIC.recovery()checks that the comparison selects the model that generated simulated data.fit_individuals()andcompare_individuals()fit every person separately, which tests whether one set of parameters describes everyone.
Examples
>>> from quantum_mind import fit, compare
>>> from quantum_mind.families.order_effects import QuantumOrderModel4D, BayesOrderModel
>>> data = QuantumOrderModel4D().sample(None, 500)
>>> ranking = compare([QuantumOrderModel4D, BayesOrderModel], data)
>>> ranking[0].summary()['model']
'QuantumOrderModel4D'
Classes
Result of |
|
Per-person fits of one model class, returned by |
Functions
Fit a model class to data by multi-start optimisation. |
|
Fit several model classes to the same data and rank them. |
|
Model-recovery study. |
|
Kullback-Leibler divergence. |
|
Total variation distance. |
|
Fit a model class separately to each person's data. |
|
Fit every candidate to every person and compare them. |
- class FitResult(model, loss, loglik, k, n, options=<factory>)[source]#
Bases:
objectResult of
fit().- Variables:
model (
Model) – Fitted model instance.loss (
float) – Negative log-likelihood (multinomial models) or sum of squared errors ('sse'models).loglik (
float) – Log-likelihood. For'sse'models this is the Gaussian log-likelihood with the error variance profiled out, so that AIC and BIC are comparable across models.k (
int) – Number of fitted parameters.n (
int) – Number of observations.options (
dict) – Structural options of the selected fit.
- Parameters:
- class IndividualFits(model_name, results)[source]#
Bases:
objectPer-person fits of one model class, returned by
fit_individuals().Every person has their own parameters, so group criteria are sums over people.
- Variables:
- Parameters:
- fit(model_cls, data, design=None, restarts=8, rng=None, structures=None, method='Nelder-Mead', x0=None, **options)[source]#
Fit a model class to data by multi-start optimisation.
- Parameters:
model_cls (
type) – Subclass ofModel.data (
dict) –{condition: counts}(multinomial models) or{condition: values}('sse'models).design (
iterable, optional) – Conditions passed topredict; most families acceptNonefor their default design.restarts (
int, optional) – Number of random starting points per structure.rng (
numpy.random.Generator, optional) – Random number generator for the starting points (default: seed 0, so fits are reproducible).structures (
listofdict, optional) – Discrete structural choices (for example projector ranks). Every structure is fitted and the best one kept.method (
str, optional) –scipy.optimize.minimize()method.x0 (
array_like, optional) – Unconstrained starting point for the first restart of every structure (the other restarts start at random).bootstrap()uses it to start each refit at the original estimate.**options – Fixed options passed to the model constructor.
- Returns:
FitResult– Best fit over all structures and restarts.
- compare(candidates, data, design=None, restarts=8, rng=None, criterion='bic')[source]#
Fit several model classes to the same data and rank them.
- Parameters:
candidates (
list) – Model classes, or(class, fit_kwargs)tuples.design (
iterable, optional) – Conditions passed topredict.restarts (
int, optional) – Restarts per fit.rng (
numpy.random.Generator, optional) – Random number generator.criterion (
{'bic', 'aic'}, optional) – Ranking criterion (lower is better).
- Returns:
- recovery(generators, candidates, design, n, reps=20, rng=None, criterion='bic', restarts=8)[source]#
Model-recovery study.
Data are simulated from each generating model, every candidate is fitted, and the criterion’s choice is counted. A good design selects the generating model most of the time.
- Parameters:
generators (
dict) –{name: model instance}used to simulate data.candidates (
list) – Model classes (or(class, fit_kwargs)) to compare.design (
iterable) – Conditions to simulate.n (
int) – Observations per condition.reps (
int, optional) – Simulated data sets per generator.rng (
numpy.random.Generator, optional) – Random number generator.criterion (
{'bic', 'aic'}, optional) – Selection criterion.restarts (
int, optional) – Restarts per fit.
- Returns:
dict–{generator: {candidate class name: times selected}}.
- kl(p, q)[source]#
Kullback-Leibler divergence.
- Parameters:
p (
array_like) – Probability vectors (clipped at 1e-12).q (
array_like) – Probability vectors (clipped at 1e-12).
- Returns:
float– \(\mathrm{KL}(p\,\Vert\,q) = \sum_i p_i \log(p_i / q_i)\) in nats.
- tvd(p, q)[source]#
Total variation distance.
- Parameters:
p (
array_like) – Probability vectors.q (
array_like) – Probability vectors.
- Returns:
float– \(\tfrac12 \sum_i |p_i - q_i|\), between 0 and 1.
- fit_individuals(model_cls, data_by_person, design=None, restarts=4, rng=None, **fit_kwargs)[source]#
Fit a model class separately to each person’s data.
Aggregate fitting assumes that everyone shares one set of parameters; per-person fits test that assumption.
- Parameters:
model_cls (
type) – Model class.data_by_person (
dict) –{person: data}.design (
iterable, optional) – Conditions passed topredict.restarts (
int, optional) – Restarts per fit.rng (
numpy.random.Generator, optional) – Random number generator.**fit_kwargs – Passed to
fit().
- Returns:
- Raises:
ValueError – If
data_by_personis empty.
- compare_individuals(candidates, data_by_person, design=None, restarts=4, rng=None, criterion='bic')[source]#
Fit every candidate to every person and compare them.
- Parameters:
candidates (
list) – Model classes, or(class, fit_kwargs)tuples.data_by_person (
dict) –{person: data}.design (
iterable, optional) – Conditions passed topredict.restarts (
int, optional) – Restarts per fit.rng (
numpy.random.Generator, optional) – Random number generator.criterion (
{'bic', 'aic'}, optional) – Comparison criterion (lower is better).
- Returns:
dict–'group':[(model name, group criterion)]sorted from best;'best_counts':{model name: number of people it fits best};'fits':{model name: IndividualFits}.