Models

BaseModel

The BaseModel class is the basis for every other model.

class evidently.BaseModel(trial_func=None, par_names=[], pars=[], par_descriptions=None, n_traces=1, max_time=5.0, dt=0.001, stimuli=None, bounds=None, name='Base Accumulator model')[source]

Bases: object

Base class for accumulator models. This class doesn’t do anything by itself, but all other model classes should inherit from it.

describe_parameters()[source]

Pretty-prints the values of model.par_descriptions.

do_dataset(n=50, pars=None, max_time=None)[source]
Simulate a dataset from the model.

This is the most important function in the package.

Parameters
  • n – Number of trials to simulate.

  • pars (list or array) –

    A list of model paramters.
    If missing, defaults to model.pars
    See model.trial_func? or model model.describe_parameters() for more information.

  • max_time (int or float) – How many seconds to simulate? Defaults to model.max_time

Returns

tuple containing:

  • X (pandas.DataFrame): A data frame of the n simulated accumulator trajectories over time.

    • Columns indicate the time, in seconds.

    • If model has only a single accumulator, the index indicates the simulation number.

    • If model has multiple accumulators, indices indicate sim. number, and accumulator number.

    • If trial-by-trial inputs are provided, indices indicate input number, and sim. number. This feature is not implemented yet.

  • responses (np.ndarray): +/-1 if upper/lower threshold crossed, 0 otherwise.

  • rts (np.ndarray): Time of threshold crossing, in seconds, or np.NaN

Return type

(pandas.DataFrame, array, array)

Classic Models

Drift Diffusion

class evidently.Diffusion(pars=[], par_names=['t0', 'v', 'z', 'a', 'c'], max_time=5.0, dt=0.001, bounds=None)[source]

Bases: evidently.base.BaseModel

The classic Drift Diffusion model.

This model has five free parameters.

  • t0: Onset of evidence accumulation (seconds)

  • v: Drift rate after t0.

  • z: Starting point.

  • a: Threshold.

  • c: Noise standard devitation.

The model equation is

x_{t+1} = x_{t} + dt * input_{t} + sqrt(dt) * ε;
x_{0} = z * a
ε ~ Normal(0, c);
input_{t} = where(t > t0, v, 0)
Response:
+1 if x > a;
-1 if x < -a;
0 otherwise

Notes

Like most models in evidently, this model is overparameterised, so that if you were to multiply the parameters v, z, a, and c by the same value the model simulations do not change. This means if you’re attempting to fit this model to real data you’ll need to fix one of these values. By convention, c is usually fixed to c=1, although some older papers use c=0.1.

The starting point parameter, z, is measured in units of the threshold a. This means that a starting point of z = 0.5 means the accumulator starts halfway to the upper boundary, where ever that might be. This is the case for all models with a starting point parameter.

Wald (One-boundary) Diffusion

class evidently.Wald(pars=[], par_names=['t0', 'v', 'z', 'a', 'c'], max_time=5.0, dt=0.001, bounds=None)[source]

Bases: evidently.base.BaseModel

The Wald Diffusion model.

This model is identical to the Drift Diffusion model (evidently.models.Diffusion), except that there is no lower response boundary, and so only one response is possible.

This model has five free parameters.

  • t0: Onset of evidence accumulation (seconds)

  • v: Drift rate after t0.

  • z: Starting point.

  • a: Threshold.

  • c: Noise standard devitation.

The model equation is

x_{t+1} = x_{t} + dt * input_{t} + sqrt(dt) * ε;
x_{0} = z * a
ε ~ Normal(0, c);
input_{t} = v if t > t0, 0 otherwise;
Response: +1 if x > a

Notes

See evidently.models.Diffusion.

Simple Race Model

class evidently.Race(pars=[], par_names=['t1', 'v1', 'z1', 'c1', 't2', 'v2', 'z2', 'c2', 'a'], max_time=5.0, dt=0.001, bounds=None)[source]

Bases: evidently.base.BaseModel

The classic Race model.

This model has nine parameters (!), where x1 is accumulator #1, x2 is accumulator #2:

  • t1: Onset of evidence accumulation (seconds) for x1

  • v1: Drift rate for x1

  • z1: Starting point for x1

  • c1: Noise for x1

  • t2: Onset of evidence accumulation (seconds) for x2

  • v2: Drift rate for x2

  • z2: Starting point for x2

  • c2: Noise for x2

  • a: Threshold.

The model equation for each accumulator is

x_{t+1} = x_{t} + dt * input_{t} + sqrt(dt) * ε;
x_{0} = z * a
ε ~ Normal(0, c);
input_{t} = where(time > t, v, 0)

The first accumulator to cross threshold, a, produces a response. Both accumulators use the same threshold, but can differ in their starting points. It is suggested that you keep a=1 and vary the other parameters.

Notes

This model is extremely overparameterised, and cannot be fit to real data without fixing the value of several parameters!

Hierarchical Models

Hierarchical Diffusion

class evidently.HDiffusion(pars=[], par_names=['m_t0', 'm_v', 'm_z', 'm_a', 's_t0', 's_v', 's_z', 's_a', 'c'], max_time=5.0, dt=0.001, bounds=None)[source]

Bases: evidently.base.BaseModel

The Hierarchical Drift Diffusion model.

This model is based on evidently.models.Diffusion, but instead of setting every parameter to a fixed value, it takes a mean and standard deviation for each parameter, and randomly varies parameters across trials.

Parameters:

  • m_t0 : Mean of Onset of evidence accumulation (seconds)

  • m_v : Mean of Drift rate after t0.

  • m_z : Mean of Starting point.

  • m_a : Mean of Threshold.

  • s_t0 : SD of t0 (Gamma distribution)

  • s_v : SD of v (Normal distribution)

  • s_z : SD of z (Normal distribution)

  • s_a : SD of a (Gamma distribution)

  • c : Noise standard devitation.

As in the standard drift diffusion, the model equation is

x_{t+1} = x_{t} + dt * input_{t} + sqrt(dt) * ε;
x_{0} = z * a
ε ~ Normal(0, c);
input_{t} = v if t > t0, 0 otherwise;
Response:
+1 if x > a
-1 ix x < -a
0 otherwise

The difference is that each parameter is now drawn randomly from a distribution:

t0 ~ Gamma*(m_t0, s_t0);
v ~ Normal(m_v, s_v);
z ~ Normal(m_z, s_z);
a ~ Gamma*(m_a, s_a);

Gamma*(m, s) denotes random samples from a Gamma distribution with mean m and standard deviation s. See evidently.utils.random_gamma for details. We use the Gamma distribution for parameters that must be positive.

Notes

Although we do not allow the noise parameter c to vary across trials here, it might be interesting to do so.

class evidently.HWald(pars=[], par_names=['m_t0', 'm_v', 'm_z', 'm_a', 's_t0', 's_v', 's_z', 's_a', 'c'], max_time=5.0, dt=0.001, bounds=None)[source]

Bases: evidently.base.BaseModel

The Hierarchical Wald Diffusion model.

All details are the same as evidently.models.HDiffusion, except there is no lower response boundary.

See also evidently.models.Diffusion and evidently.models.Wald.

Others

class evidently.models.Schurger(pars=[], par_names=['t0', 'v', 'k', 'z', 'a', 'c'], max_time=12.0, dt=0.001, bounds=None)[source]

Bases: evidently.base.BaseModel

Single-accumulator model with leak, used as a model for self-initiated actions.

This model has 6 free parameters:

  • t0: Start time of input (seconds)

  • v: Strength of input

  • k: Decay

  • z: Starting point

  • a: Threshold

  • c: Noise

Note that this implementation has t0 and z parameters that do no feature in the original version. These should be set to 0 to recover the original implementation.

The model equation is

x_{t+1} = x_{t} + dt * (input_{t} - k * x{t-1}) * ε;
x_{0} = z * a
ε ~ Normal(0, c*sqrt(dt));
input_{t} = where(t > t0, v, 0)
Response:
+1 if x > a;
0 otherwise

Notes

The noise parameter c=0.1 in the original paper.

Schurger, A., Sitt, J. D., & Dehaene, S. (2012). An accumulator model for spontaneous neural activity prior to self-initiated movement. Proceedings of the National Academy of Sciences, 109(42), E2904-E2913.

Visualisation Functions

Warning: This documentation is patchy and incomplete.

evidently.viz.configure_mpl()[source]

Configures global matplotlib settings to better defaults

sns.set_style(‘whitegrid’)
mpl.rcParams[‘font.size’] = 20
mpl.rcParams[‘axes.titlesize’] = ‘medium’
mpl.rcParams[‘axes.labelsize’] = ‘medium’
mpl.rcParams[‘xtick.labelsize’] = ‘medium’
mpl.rcParams[‘ytick.labelsize’] = ‘medium’
mpl.rcParams[‘legend.fontsize’] = ‘medium’
mpl.rcParams[‘figure.titlesize’] = ‘medium’
mpl.rcParams[‘figure.figsize’] = (8, 6)
mpl.rcParams[‘axes.spines.right’] = False
mpl.rcParams[‘axes.spines.top’] = False
mpl.rcParams[‘axes.edgecolor’] = ‘k’
mpl.rcParams[‘svg.fonttype’] = ‘none’
evidently.viz.plot_X_diff(Xs)[source]
evidently.viz.plot_Xs(Xs, colours=['g', 'b'], labels=['One', 'Two'])[source]
evidently.viz.plot_kde(x, *args, **kwargs)[source]
evidently.viz.plot_trace_mean(model, X=None, n=100, ax=None, label=None)[source]

Plot mean and SD of accumulator traces. This function creates a basic plot, that should be augmented for visualising specific models.

Parameters
  • model – The model object.

  • X – Model simulations generated by model.do_dataset(). If None, simulated from the model object.

  • n – Number of traces to plot/simulate.

  • ax – Axis to plot to. If None, a new figure is created.

Returns

The figure axis.

Return type

ax

evidently.viz.plot_traces(model, X=None, responses=None, rts=None, n=50, ax=None, threshold=None, terminate=False, show_mean=True, label=None, alpha=0.1, color='b')[source]

Plot mean and SD of accumulator traces. This function creates a basic plot, that should be augmented for visualising specific models.

Parameters
  • model – The model object.

  • responses, rts (X,) – Model simulations generated by model.do_dataset(). If None, simulated from the model object.

  • n – Number of traces to plot/simulate.

  • ax – Axis to plot to. If None, a new figure is created.

Returns

The figure axis.

Return type

ax

evidently.viz.quickplot(X, n=20, times=None)[source]
evidently.viz.setup_ddm_plot(model, ax=None, time_range=None, threshold=None)[source]

Set up background for a two-boundary DDM plot

evidently.viz.setup_race_plot(model, ax=None, time_range=None, threshold=None)[source]

Set up background for a Race plot

evidently.viz.setup_schurger_figure()[source]
evidently.viz.strip_ytick_labs()[source]
evidently.viz.visualise_model(model, model_type='ddm', measure='means', n=None, threshold=None)[source]

Produces a full 3 panel overview of common models

evidently.viz.visualise_schurger(model, n=100, rp_duration=3)[source]

Utility Functions

Warning: This documentation is patchy and incomplete.

evidently.utils.clone_column[source]

[a,b,c] -> [[a,b,c], [a,b,c], …, [a,b,c]]

evidently.utils.do_dataset_no_stimuli(model, n: int, *args, **kwargs)[source]

Simulate a dataset for a model that does not take trial-by-trial inputs.

Parameters
  • model – pycumulate.AccumulatorModel object

  • n – number of repititions to simulate

  • arguments get passed to model.do_trial() (Additional) –

Returns

DataFrame containing accumulator traces for each repitition.

If model.n_traces > 1, X uses a MultiIndex.

R: Responses for each repitition. T: Response times for each repitition.

Return type

X

evidently.utils.do_dataset_with_stimuli(model, n, pars=None, *args, **kwargs)[source]

Simulate a dataset for a model that takes trial-by-trial inputs.

Parameters
  • model – pycumulate.AccumulatorModel object model must have its stimuli attribute set. Stimuli should be of shape (n_trials, …), e.g. (n_trials,) for scaler inputs, (n_trials, j) for 1-D inputs, (n_trials, j, k) for 2-D inputs, etc.

  • n – number of repititions to simulate.

  • arguments get passed to model.do_trial() (Additional) –

Returns

DataFrame containing accumulator traces for each repitition of each trial.. R: Responses for each repitition (Shape: (n_trials, n)) T: Response times for each repitition (Shape: (n_trials, n)).

Return type

X

evidently.utils.epanechnikov_kde(x, h=None)[source]
evidently.utils.flip
evidently.utils.generate_randoms(means: list, sds: list, n=None, dist='normal')[source]

Lists of random numbers with specified means, SDs, and distributions.

Parameters
  • means – List of k mean values

  • sds – List of k SD values

  • n – How many values to sample (None or int)

  • dist – Distribution to use. String, or list of length k. Accepted values so far are ‘normal’ and ‘gamma’.

Returns

A list of randomly sampled values.

Return type

List of np.ndarray

evidently.utils.leaky_accumulation

Vectorised leaky accumulation.

Parameters
  • x0 – Starting values (Shape: n)

  • k – Decay parameter

  • V – Input (including noise) (Shape (nt, n))

evidently.utils.lock_to_movement(X, rts, duration=2, min_rt=None)[source]

Realign simulated data to the time it crosses a threshold. :param X: Simulated data (pd.DataFrame) :param rts: Simulated response times :param duration: Number of seconds prior to threshold to include (Default 2). :param min_rt: Shortest RT to include. Defaults to duration.

evidently.utils.random_gamma(mean: float, sd: float, n=None)[source]

Gamma distribution parameterised by mean and standard deviation.

evidently.utils.random_normal(mean: float, sd: float, n=None)[source]

np.random.normal(loc=mean, scale=sd, size=n)

evidently.utils.random_samples(mean: float, sd: float, dist: str, n=None)[source]

Random samples with a given mean, sd, from a given distribution. If sd = 0, returns np.repeat(mean, n). Like np.random, output is a float if n=None (default), array otherwise.

evidently.utils.silverman_bandwidth(x)[source]
evidently.utils.split_by_accumulator(trace: pandas.core.frame.DataFrame)[source]
evidently.utils.unit_bind(x)[source]