Personalised human models#
Personalised human models: start from the population, adapt to each person.
Fitting one model to everyone’s answers assumes that people are alike; fitting each person separately needs thousands of answers (see example 11). Partial pooling sits in between: the population’s spread of parameters becomes a prior, and each person’s parameters are the maximum a posteriori (MAP) estimate
in the unconstrained parameter space of the model (see quantum_mind.core.Param.to_free()). With few
answers the estimate stays near the population; with many it follows the person. A robot can therefore
personalise its human model from the first few interactions without over-fitting.
PopulationPrior: mean and covariance of the free parameters, estimated from per-person fits (empirical Bayes) or set by hand.fit_map(): MAP fit of one model class to one person’s data.PersonalisedHumanModel: keeps each person’s answer counts and their personalised model, either as a MAP point estimate or, withmethod='online', as a full posterior updated after every answer (OnlinePersonModelstarted from the population prior), so the robot also knows how sure it is about this person.
Examples
>>> import numpy as np
>>> from quantum_mind.families.order_effects import BayesOrderModel
>>> from quantum_mind.applications.personalisation import PopulationPrior, fit_map
>>> prior = PopulationPrior(BayesOrderModel, mean=[0.0, 0.0, 0.0], cov=np.eye(3) * 0.5)
>>> few = {'AB': np.array([3, 0, 0, 1]), 'BA': np.array([2, 1, 0, 1])}
>>> r = fit_map(BayesOrderModel, few, prior)
>>> 0.5 < r.model.pA < 0.9 # pulled toward the population mean 0.5
True
Classes
Gaussian prior on a model's free (unconstrained) parameters. |
|
Per-person human models with partial pooling. |
Functions
Maximum a posteriori fit of one person's data under a population prior. |
|
Convenience: fit every person by maximum likelihood and build the empirical-Bayes prior. |
- class PopulationPrior(model_cls, mean, cov)[source]#
Bases:
objectGaussian prior on a model’s free (unconstrained) parameters.
- Parameters:
model_cls (
type) – Model class whosefree_params()the prior describes.mean (
array_like) – Prior mean in the free space.cov (
array_like) – Prior covariance (positive definite).
- classmethod from_fits(fits, shrink=0.01)[source]#
Empirical-Bayes prior from per-person fits.
- Parameters:
fits (
sequenceofFitResult) – Maximum-likelihood fits of the same model class to different people (for examplefit_individuals(...).results.values()).shrink (
float, optional) – Added to the covariance diagonal so it stays invertible with few people.
- Returns:
- online(n_particles=500, design=None, rng=None, **options)[source]#
A per-person posterior that starts from this prior.
- Parameters:
n_particles (
int, optional) – Number of parameter samples.design (
iterable, optional) – Design passed topredict.rng (
numpy.random.Generator, optional) – Random number generator.**options – Structural options of the model.
- Returns:
OnlinePersonModel
- class PersonalisedHumanModel(model_cls, prior, design=None, outcomes=4, method='map', n_particles=300)[source]#
Bases:
objectPer-person human models with partial pooling.
- Parameters:
model_cls (
type) – Model class (for exampleQuantumOrderModel4D).prior (
PopulationPrior) – Population prior; build it withPopulationPrior.from_fits()from earlier people.design (
iterable, optional) – Conditions.outcomes (
int, optional) – Number of outcome cells per condition (4 for two yes/no questions).method (
{'map', 'online'}, optional) –'map'refits a MAP estimate after every answer;'online'keeps a particle posterior per person (faster per answer, and givescredible_interval()).n_particles (
int, optional) – Particles per person formethod='online'.
Examples
>>> svc = PersonalisedHumanModel(BayesOrderModel, prior) >>> svc.add('alice', 'AB', [1, 0]) >>> svc.predict('alice')['AB']
- model(person)[source]#
The person’s model (the population mean model for a new person).
- Parameters:
person (
hashable)- Returns:
Model
- predict(person, design=None)[source]#
Predicted answer distribution for one person.
- Parameters:
person (
hashable)design (
iterable, optional)
- Returns:
- credible_interval(person, name, level=0.9)[source]#
Posterior interval of one of a person’s parameters (
method='online'only).- Parameters:
- Returns:
- Raises:
ValueError – If the model keeps MAP estimates, or the person has not answered yet.
- fit_map(model_cls, data, prior, design=None, restarts=4, rng=None, **options)[source]#
Maximum a posteriori fit of one person’s data under a population prior.
- Parameters:
model_cls (
type) – Model class (multinomial loss).data (
dict) – The person’s answer counts.prior (
PopulationPrior) – Prior on the free parameters.design (
iterable, optional) – Conditions passed topredict.restarts (
int, optional) – Random restarts (the first start is the prior mean).rng (
numpy.random.Generator, optional)**options – Structural options of the model.
- Returns:
FitResult–lossis the negative log posterior;loglikthe log-likelihood at the MAP estimate.
- population_prior(model_cls, data_by_person, design=None, restarts=4, rng=None)[source]#
Convenience: fit every person by maximum likelihood and build the empirical-Bayes prior.
- Parameters:
model_cls (
type)data_by_person (
dict) –{person: data}.design (
iterable, optional)restarts (
int, optional)rng (
numpy.random.Generator, optional)
- Returns: