• Home
  • CV
  • Notes

On this page

  • The basic model
  • A simpler starting point: EZ-Diffusion
    • Some caveats
  • Advancing to the more complex 8-parameter model
  • Connections between Signal Detection Theory, Drift Diffusion Model, and Sequential Probability Ratio Tests

Notes on Drift Diffusion Models

statistics
decision-making
Some preliminary notes on the drift diffusion model.
Author

Sheng Long

Updated

November 5, 2025

NoteA very short background

The Drift Diffusion Model (DDM), also known as Ratcliff’s Diffusion Model (RDM), was first developed by Ratcliff in 1978 (Ratcliff 1978). It is a model based on accumulation of evidence, otherwise more generally called sampling models. These models represent decisions as the accumulation of evidence until a threshold is reached, leading to a corresponding action.

The basic model

We will use the accumulate function in purrr to accumulate evidence sampled from \(\mathcal{N}(0, 0.1)\)1. We also assumed that the starting point is 0.5, and that there is no drift.

1 If we don’t care about whether accumulated evidence stays the same after it reaches the decision thresholds, then we could also just use the cumsum function in base R.

Code
# define function of sampling till it reaches the "decision boundary" of 
# 0 or 1 
sample_till_boundry <- function(out, input) {
  if (out >= 1){
    return(1)
  } else if (out <= 0) {
    return(0)
  }
  out + rnorm(1, sd = 0.1)
}

# 1:100 %>% accumulate(sample_till_boundry, .init = 0.5) %>% plot(.)

n_lines <- 5
n_steps <- 100

map(1:n_lines, \(i) 1:(n_steps-1)) %>% 
  set_names(paste0("sim", 1:n_lines)) %>% 
  map(\(l) accumulate(l, sample_till_boundry, .init = 0.5)) %>% 
  map(\(x) tibble(value = x, step = 1:n_steps)) %>% 
  list_rbind(names_to = "simulation") %>% 
  ggplot(aes(x = step, y = value)) + 
  geom_line(aes(color = simulation)) + 
  geom_hline(yintercept = 1, color = "darkgray", linetype = 2) + 
  geom_hline(yintercept = 0, color = "darkgray", linetype = 2) + 
  scale_y_continuous(breaks = scales::pretty_breaks(n = 5))

The model assumes two boundaries, each triggering a certain response (e.g., “yes” and “no” response in a same-different experiment). The evidence accumulation is a process that fluctuates from a starting point towards one of two boundaries.

The RDM requires 8 parameters:

  • mean drift rate (\(v\))
  • across-trial variability in drift rate (\(\eta\))
  • within-trial variability in drift rate (\(s\))
  • boundary separation (\(a\))
  • mean starting point (\(z\))
  • across-trial range of variability in starting point (\(s_z\))
  • mean processing time of the non-decision components (\(T_{e r}\)) where \(e r\) stands for encoding and motor response time where \(T_{e r} \equiv T_e + T_r\).
  • across-trials variability in the non-decision component of processing (\(s_{T_{e r}}\))

A simpler starting point: EZ-Diffusion

We will first focus on a simplified version of the RDM model, aka, the EZ Diffusion Model2. It has fewer parameters than the original model, and thus requires less empirical data to fit.

2 For details, see (T. Groulx, Harding, and Cousineau 2020)

The EZ model focuses on three parameters:

  1. the drift rate \(v\)
  2. the boundary separation \(a\)3
  3. the non-decision time \(T_{e r}\)

3 Note that the starting point, \(z\), is fixed to be the halfway point in the boundary, i.e., \(z \equiv a / 2\)

It does not require raw data at all, only three descriptive statistics:

  1. the mean of the all the response time in a given condition,
  2. the variance of those response times, and
  3. the proportion of correct answers.

First we install the EZ2 package:

# install.packages("EZ2", repos = "http://R-Forge.R-project.org")
library(EZ2)

We will use the data set used in a tutorial by Henrik Singmann, i.e., the Speed-Accuracy data speed-acc from (Wagenmakers et al. 2008):

data(speed_acc, package = "rtdists")

speed_acc %>% head(.)
id block condition stim stim_cat frequency response rt censor
31 1 1 speed 5015 nonword nw_low nonword 0.700 FALSE
32 1 1 speed 3623 word very_low nonword 0.392 FALSE
33 1 1 speed 6481 nonword nw_very_low nonword 0.460 FALSE
34 1 1 speed 3305 word very_low word 0.455 FALSE
35 1 1 speed 2244 word low nonword 0.505 FALSE
36 1 1 speed 4468 nonword nw_high nonword 0.773 FALSE
glimpse(speed_acc)
Rows: 31,522
Columns: 9
$ id        <fct> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
$ block     <fct> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
$ condition <fct> speed, speed, speed, speed, speed, speed, speed, speed, spee…
$ stim      <fct> 5015, 3623, 6481, 3305, 2244, 4468, 1047, 5711, 5036, 1111, …
$ stim_cat  <fct> nonword, word, nonword, word, word, nonword, word, nonword, …
$ frequency <fct> nw_low, very_low, nw_very_low, very_low, low, nw_high, high,…
$ response  <fct> nonword, nonword, nonword, word, nonword, nonword, word, wor…
$ rt        <dbl> 0.700, 0.392, 0.460, 0.455, 0.505, 0.773, 0.390, 0.587, 0.60…
$ censor    <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALS…

The above speed_acc data comes from 17 participants performing a task in which they have to decide if a presented string is a word or a non-word. Participants made decisions either in under condition speed or condition accuracy, where the conditions differ in the instructions. We will restrict our analysis to participant 1, and the condition speed to calculate the descriptive statistics:

pid1 <- speed_acc %>% filter(id == 1, condition == "speed")
pid1 %>% head(5)
id block condition stim stim_cat frequency response rt censor
1 1 speed 5015 nonword nw_low nonword 0.700 FALSE
1 1 speed 3623 word very_low nonword 0.392 FALSE
1 1 speed 6481 nonword nw_very_low nonword 0.460 FALSE
1 1 speed 3305 word very_low word 0.455 FALSE
1 1 speed 2244 word low nonword 0.505 FALSE

Calculate descriptive statistics for participant with id == 1:

# mean response time 
mrt <- pid1 %>% pull(rt) %>% mean(.)
# variance response time 
vrt <- pid1 %>% pull(rt) %>% var(.)
# proportion of correct answers 
pid1 %>% mutate(response = as.character(response), 
                stim_cat = as.character(stim_cat)) %>% 
  count(stim_cat == response)
stim_cat == response n
FALSE 96
TRUE 864
p_c <-  864 / (96 + 864)

We can use the Data2EZ function to get the EZ diffusion model parameters:

Data2EZ(Pc = p_c, 
        VRT = vrt, 
        MRT = mrt)
$v
[1] 0.2046432

$a
[1] 0.1073686

$Ter
[1] 0.3302674

Some caveats

According to (T. Groulx, Harding, and Cousineau 2020), the EZ model provides a perfect fit at the level of descriptive statistics, but there is no guarantee that the fit is perfect at the raw data’s level.

Also, EZ, like any sampling model, should be fit on a per-participant basis as group characteristics are not necessarily the average of the individuals’ characteristics.

Advancing to the more complex 8-parameter model

The next step is to extend the current model to account for the parameters that won’t accounted for before. This time we will try to follow what was done in [this tutorial by Henrik Singmann]4 and also make things Bayesian.

4 http://singmann.org/wiener-model-analysis-with-brms-part-i/

#TODO

Connections between Signal Detection Theory, Drift Diffusion Model, and Sequential Probability Ratio Tests

In very simple terms:

  • The relationship between SDT and SPRT:
    • SDT uses one observation and one threshold that partitions the decision variable’s event space into two regions
    • SPRT uses an initially-undetermined number of observations and two decision thresholds that partition the decision variable’s event space into three regions5
  • The relationship between SPRT and DDM:
    • DDM can be viewed as a continuous-time, special case of the SPRT

5 In a limiting case, if we “squeeze” the two boundaries into one (i.e., \(a = 0\)), then it becomes the SDT model

For those who are more interested, there is an excellent tutorial by (Griffith, Baker, and Lepora 2021), as well as a more recent review article by (Duffy et al. 2025) that places more focus in the neural science domain.

References

Duffy, Jade S., Mark A. Bellgrove, Peter R. Murphy, and Redmond G. O’Connell. 2025. “Disentangling Sources of Variability in Decision-Making.” Nature Reviews Neuroscience 26 (5): 247–62. https://doi.org/10.1038/s41583-025-00916-3.
Griffith, Thom, Sophie-Anne Baker, and Nathan F. Lepora. 2021. “The Statistics of Optimal Decision Making: Exploring the Relationship Between Signal Detection Theory and Sequential Analysis.” Journal of Mathematical Psychology 103 (August): 102544. https://doi.org/10.1016/j.jmp.2021.102544.
Ratcliff, Roger. 1978. “A Theory of Memory Retrieval.” Psychological Review 85 (2): 59. https://doi.org/10.1037/0033-295X.85.2.59.
T. Groulx, Julien, Bradley Harding, and Denis Cousineau. 2020. “The EZ Diffusion Model: An Overview with Derivation, Software, and an Application to the Same-Different Task.” The Quantitative Methods for Psychology 16 (2): 154–74. https://doi.org/10.20982/tqmp.16.2.p154.
Wagenmakers, Eric-Jan, Roger Ratcliff, Pablo Gomez, and Gail McKoon. 2008. “A Diffusion Model Account of Criterion Shifts in the Lexical Decision Task.” Journal of Memory and Language 58 (1): 140–59.

© 2024 Sheng Long

 

This website is built with , , Quarto, fontawesome, iconify.design, and faviconer.