Colab Instructions¶
If you would like to run this tutorial on Google colab, please click this link.
Once you are in the colab, follow the installation instructions below and then restart your runtime.
Just uncomment the code in the next code cell and run it!
NOTE:
You may want to switch your runtime to have a GPU or TPU. To do so, go to Runtime > Change runtime type and select the desired hardware accelerator.
Note that if you switch your runtime you have to follow the installation instructions again.
# If running this on Colab, please uncomment the next line
# !pip install hssm
Using lapse probabilities and distributions in HSSM¶
Since v0.1.2, HSSM has added the ability to model outliers in the distribution with lapse probabilities and distributions. Let's see how it works.
import warnings
import arviz as az
import bambi as bmb
import matplotlib.pyplot as plt
import hssm
warnings.filterwarnings("ignore")
Lapse probabilities and distributions are enabled by default.¶
From v0.1.2 on, lapse probabilities and distributions are enabled by default. If left unspecified, the probability for outliers will be a fixed value of 0.05 and the distribution will be specified as Uniform(0, 10).
# Simulate some data
ddm_data = hssm.simulate_data(
model="ddm", theta=dict(v=0.5, a=1.5, z=0.5, t=0.1), size=1000
)
ddm_data.head()
| rt | response | |
|---|---|---|
| 0 | 1.391625 | 1.0 |
| 1 | 1.034041 | 1.0 |
| 2 | 1.303063 | 1.0 |
| 3 | 1.623968 | 1.0 |
| 4 | 0.732956 | 1.0 |
# Build the simplest model specifying only data
# Note the model output
ddm_model_default = hssm.HSSM(data=ddm_data)
ddm_model_default
Model initialized successfully.
Hierarchical Sequential Sampling Model
Model: ddm
Response variable: rt,response
Likelihood: analytical
Observations: 1000
Parameters:
v:
Prior: Normal(mu: 0.0, sigma: 2.0)
Explicit bounds: (-inf, inf)
a:
Prior: HalfNormal(sigma: 2.0)
Explicit bounds: (0.0, inf)
z:
Prior: Uniform(lower: 0.0, upper: 1.0)
Explicit bounds: (0.0, 1.0)
t:
Prior: HalfNormal(sigma: 2.0)
Explicit bounds: (0.0, inf)
Lapse probability: 0.05
Lapse distribution: Uniform(lower: 0.0, upper: 20.0)
Note
Note in the above output that lapse probability and lapse distributions are at default values.
Specifying lapse probability and distribution¶
It is easy to change the lapse probability and distribution. HSSM has added two arguments, p_outlier and lapse to allow the lapse probability and distribution to be specified.
The optional p_outlier accepts a float, a dict, or a bmb.Prior object. When p_outlier is specified as a single float value, it will be considered "fixed". You can also specify a prior distribution for p_outlier through a dict or a bmb.Prior object, the same way as you would when specifying priors for any other parameter. That way, the lapse probability will be considered another parameter and will be estimated during MCMC sampling.
Likewise, the lapse argument accepts a dict or a bmb.Prior object to specify a fixed lapse distribution. This distribution will be considered as the one that outliers are generated from.
ddm_model_lapse = hssm.HSSM(
data=ddm_data,
p_outlier={"name": "Uniform", "lower": 0.0001, "upper": 0.5},
lapse=bmb.Prior("Uniform", lower=0.0, upper=20.0),
)
ddm_model_lapse
Model initialized successfully.
Hierarchical Sequential Sampling Model
Model: ddm
Response variable: rt,response
Likelihood: analytical
Observations: 1000
Parameters:
v:
Prior: Normal(mu: 0.0, sigma: 2.0)
Explicit bounds: (-inf, inf)
a:
Prior: HalfNormal(sigma: 2.0)
Explicit bounds: (0.0, inf)
z:
Prior: Uniform(lower: 0.0, upper: 1.0)
Explicit bounds: (0.0, 1.0)
t:
Prior: HalfNormal(sigma: 2.0)
Explicit bounds: (0.0, inf)
Lapse probability: Uniform(lower: 0.0001, upper: 0.5)
Lapse distribution: Uniform(lower: 0.0, upper: 20.0)
lapse_trace = ddm_model_lapse.sample()
lapse_trace
Using default initvals.
Initializing NUTS using adapt_diag...
Multiprocess sampling (4 chains in 4 jobs)
NUTS: [p_outlier, z, a, t, v]
Sampling 4 chains for 1_000 tune and 1_000 draw iterations (4_000 + 4_000 draws total) took 11 seconds.
<xarray.DataTree>
Group: /
├── Group: /posterior
│ Dimensions: (chain: 4, draw: 1000)
│ Coordinates:
│ * chain (chain) int64 32B 0 1 2 3
│ * draw (draw) int64 8kB 0 1 2 3 4 5 6 7 ... 993 994 995 996 997 998 999
│ Data variables:
│ p_outlier (chain, draw) float64 32kB 0.004007 0.001762 ... 0.02591 0.008776
│ a (chain, draw) float64 32kB 1.473 1.476 1.493 ... 1.5 1.48 1.443
│ v (chain, draw) float64 32kB 0.4497 0.4572 0.4467 ... 0.5294 0.5615
│ t (chain, draw) float64 32kB 0.1235 0.1059 0.1261 ... 0.1201 0.1637
│ z (chain, draw) float64 32kB 0.4986 0.5276 0.5125 ... 0.4975 0.4995
│ Attributes:
│ created_at: 2026-06-29T18:30:58.927879+00:00
│ creation_library: ArviZ
│ creation_library_version: 1.1.0
│ creation_library_language: Python
│ inference_library: pymc
│ inference_library_version: 6.0.1
│ sample_dims: ['chain', 'draw']
│ sampling_time: 10.559141159057617
│ tuning_steps: 1000
│ modeling_interface: bambi
│ modeling_interface_version: 0.18.0
├── Group: /sample_stats
│ Dimensions: (chain: 4, draw: 1000)
│ Coordinates:
│ * chain (chain) int64 32B 0 1 2 3
│ * draw (draw) int64 8kB 0 1 2 3 4 5 ... 995 996 997 998 999
│ Data variables: (12/18)
│ acceptance_rate (chain, draw) float64 32kB 0.4617 0.5416 ... 0.375
│ energy (chain, draw) float64 32kB 1.983e+03 ... 1.983e+03
│ perf_counter_diff (chain, draw) float64 32kB 0.001559 ... 0.003039
│ n_steps (chain, draw) float64 32kB 3.0 7.0 3.0 ... 7.0 7.0
│ largest_eigval (chain, draw) float64 32kB nan nan nan ... nan nan
│ lp (chain, draw) float64 32kB -1.981e+03 ... -1.982e+03
│ ... ...
│ energy_error (chain, draw) float64 32kB 0.5972 0.5976 ... 0.9939
│ smallest_eigval (chain, draw) float64 32kB nan nan nan ... nan nan
│ process_time_diff (chain, draw) float64 32kB 0.001558 ... 0.003038
│ diverging (chain, draw) bool 4kB False False ... False False
│ step_size (chain, draw) float64 32kB 0.6138 0.6138 ... 0.4901
│ perf_counter_start (chain, draw) float64 32kB 1.125e+06 ... 1.125e+06
│ Attributes:
│ created_at: 2026-06-29T18:30:58.932863+00:00
│ creation_library: ArviZ
│ creation_library_version: 1.1.0
│ creation_library_language: Python
│ inference_library: pymc
│ inference_library_version: 6.0.1
│ sample_dims: ['chain', 'draw']
│ sampling_time: 10.559141159057617
│ tuning_steps: 1000
│ modeling_interface: bambi
│ modeling_interface_version: 0.18.0
├── Group: /observed_data
│ Dimensions: (__obs__: 1000, rt,response_extra_dim_0: 2)
│ Coordinates:
│ * __obs__ (__obs__) int64 8kB 0 1 2 3 4 ... 996 997 998 999
│ * rt,response_extra_dim_0 (rt,response_extra_dim_0) int64 16B 0 1
│ Data variables:
│ rt,response (__obs__, rt,response_extra_dim_0) float64 16kB ...
│ Attributes:
│ created_at: 2026-06-29T18:30:58.934741+00:00
│ creation_library: ArviZ
│ creation_library_version: 1.1.0
│ creation_library_language: Python
│ inference_library: pymc
│ inference_library_version: 6.0.1
│ sample_dims: []
│ modeling_interface: bambi
│ modeling_interface_version: 0.18.0
└── Group: /log_likelihood
Dimensions: (chain: 4, draw: 1000, __obs__: 1000)
Coordinates:
* chain (chain) int64 32B 0 1 2 3
* draw (draw) int64 8kB 0 1 2 3 4 5 6 ... 993 994 995 996 997 998 999
* __obs__ (__obs__) int64 8kB 0 1 2 3 4 5 6 ... 994 995 996 997 998 999
Data variables:
rt,response (chain, draw, __obs__) float64 32MB -1.216 -1.018 ... -3.701
Attributes:
modeling_interface: bambi
modeling_interface_version: 0.18.0az.summary(lapse_trace)
| mean | sd | eti89_lb | eti89_ub | ess_bulk | ess_tail | r_hat | mcse_mean | mcse_sd | |
|---|---|---|---|---|---|---|---|---|---|
| p_outlier | 0.0113 | 0.0086 | 0.00093 | 0.027 | 2031 | 1478 | 1.00 | 0.00017 | 0.00015 |
| a | 1.494 | 0.0279 | 1.4 | 1.5 | 2182 | 2227 | 1.00 | 0.0006 | 0.00044 |
| v | 0.51 | 0.0318 | 0.46 | 0.56 | 2532 | 2718 | 1.00 | 0.00063 | 0.00044 |
| t | 0.119 | 0.0217 | 0.085 | 0.15 | 2186 | 2529 | 1.00 | 0.00047 | 0.00034 |
| z | 0.5047 | 0.0127 | 0.48 | 0.52 | 2464 | 2510 | 1.00 | 0.00026 | 0.00018 |
az.plot_trace_dist(lapse_trace)
plt.tight_layout()
Disable lapse probabilities and distributions¶
When p_outliers is set to None or 0, lapse probability and distributions will be ignored. They will not be included in the model output.
Note
If `p_outlier` is set to `None` or 0 but `lapse` is not set to None, you will receive a warning. Please remember to also set `lapse` to `None`.
ddm_model_no_lapse = hssm.HSSM(data=ddm_data, p_outlier=None, lapse=None)
ddm_model_no_lapse
Model initialized successfully.
Hierarchical Sequential Sampling Model
Model: ddm
Response variable: rt,response
Likelihood: analytical
Observations: 1000
Parameters:
v:
Prior: Normal(mu: 0.0, sigma: 2.0)
Explicit bounds: (-inf, inf)
a:
Prior: HalfNormal(sigma: 2.0)
Explicit bounds: (0.0, inf)
z:
Prior: Uniform(lower: 0.0, upper: 1.0)
Explicit bounds: (0.0, 1.0)
t:
Prior: HalfNormal(sigma: 2.0)
Explicit bounds: (0.0, inf)
ddm_model_no_lapse_warn = hssm.HSSM(data=ddm_data, p_outlier=0)
ddm_model_no_lapse_warn
Model initialized successfully.
Hierarchical Sequential Sampling Model
Model: ddm
Response variable: rt,response
Likelihood: analytical
Observations: 1000
Parameters:
v:
Prior: Normal(mu: 0.0, sigma: 2.0)
Explicit bounds: (-inf, inf)
a:
Prior: HalfNormal(sigma: 2.0)
Explicit bounds: (0.0, inf)
z:
Prior: Uniform(lower: 0.0, upper: 1.0)
Explicit bounds: (0.0, 1.0)
t:
Prior: HalfNormal(sigma: 2.0)
Explicit bounds: (0.0, inf)