library(rstan)library(loo)library(RWiener)
# if running chains in parallelrstan_options(auto_write = TRUE)options(mc.cores = parallel::detectCores())
# wiener parametersa <- 3.25t <- 0.25b <- 0.4v <- 0.65n <- 150
# random RT values from RWiener using parameters abovert <- rwiener( n = n, alpha = a, tau = t, beta = b, delta = v)
# make stan data liststan_data <- list(rt = rt$q, acc = ifelse(rt[, "resp"] == "upper", 1, 0), n = nrow(rt))
# number of chains to runn_chains <- 5
# use inits from above dist. parametersstan_inits <- lapply(1:n_chains, function(i) { list( a_mu = max(c(0.0001, a)), t_mu = max(c(0.0001, t)), v_mu = max(c(0.0001, v)), a_raw = 0.01, t_raw = 0.01, v_raw = 0.01, a_sd = 1, t_sd = 1, v_sd = 1, b = b )})
# STAN codestan_model <-"data { int<lower=1> n; vector[n] rt; vector<lower=0,upper=1>[n] acc;}parameters { real<lower=0,upper=10> a_mu; real<lower=0,upper=3> a_sd; real a_raw; real<lower=0,upper=3> t_mu; real<lower=0,upper=2> t_sd; real t_raw; real<lower=0,upper=5> v_mu; real<lower=0,upper=2> v_sd; real v_raw; real<lower=0,upper=1> b; // <- beta}transformed parameters { real a; // <- alpha real t; // <- tau real v; // <- delta
a <- a_mu + a_sd * a_raw; // a ~ normal(a_mu, a_sd) t <- t_mu + t_sd * t_raw; // t ~ normal(t_mu, t_sd) v <- v_mu + v_sd * v_raw; // v ~ normal(v_mu, v_sd)}model { a_raw ~ normal(0,1); t_raw ~ normal(0,1); v_raw ~ normal(0,1); b ~ beta(2, 2);
// likelihood for (i in 1:n) { if (acc[n] == 1) { rt[i] ~ wiener(a, t, b, v); // upper bound } else { rt[i] ~ wiener(a, t, 1-b, -v); // lower bound } }}generated quantities { vector[n] log_lik;
for (i in 1:n) { if (acc[n] == 1) { // upper log_lik[i] <- wiener_log(rt[i], a, t, b, v); } else { // lower log_lik[i] <- wiener_log(rt[i], a, t, 1-b, -v); } }}"
# run modelstan_fit <- stan( model_name = "diffusion_test", model_code = stan_model, data = stan_data, init = stan_inits, chains = n_chains )
# print stan model parametersprint(stan_fit)
# print elpd_looprint(loo(extract_log_lik(stan_fit)), digits = 3)
# print RWiener likelihoodprint(wiener_likelihood(c(a,t,b,v), rt))
# Plots -------------------------------------------------------------------
# stan traceplottraceplot(stan_fit)
# plot distributions from RWienerplot_rwiener <- function(rt) { rt_u <- rt$q[rt$resp == "upper"] rt_l <- rt$q[rt$resp == "lower"]
xlim <- max(c(rt_u, rt_l)) rt_seq <- seq(0, xlim, .005)
d_rt_u <- dwiener(rt_seq, a, t, b, v, resp = rep("upper", length(rt_seq))) d_rt_l <- dwiener(rt_seq, a, t, b, v, resp = rep("lower", length(rt_seq)))
ylim <- max(c(d_rt_u, d_rt_l))
par(mfrow = c(3, 1))
plot( x = rt_seq, y = d_rt_u, type = "l", xlim = c(0, xlim), ylim = c(-ylim, ylim), main = "Density of upper/lower responses", ylab = "density", xlab = "quantile", col = "green" )
lines(x = rt_seq, y = -d_rt_l, col = "red")
xbrks <- seq(0, xlim, length.out = 30)
hist( rt_u, freq = FALSE, breaks = xbrks, xlim = c(0, xlim), ylim = c(0, ylim * 2), main = "upper", xlab = paste("N =", length(rt_u)) )
hist( rt_l, freq = FALSE, breaks = xbrks, xlim = c(0, xlim), ylim = c(0, ylim * 2), main = "lower", xlab = paste("N =", length(rt_l)) )}
plot_rwiener(rt)
a = a, t = t, v = v, b = b )})
# STAN codestan_model <-"data { int<lower=1> n; vector[n] rt; vector<lower=0,upper=1>[n] acc;}parameters { real<lower=0,upper=10> a; real<lower=0,upper=5> t; real<lower=0,upper=5> v; real<lower=0,upper=1> b;}model { //a ~ normal(0, 2); //t ~ normal(0, 2); //v ~ normal(0, 2); //b ~ beta(2, 2);library(rstan)library(loo)library(RWiener)
# if running chains in parallelrstan_options(auto_write = TRUE)options(mc.cores = parallel::detectCores())
# wiener parametersa <- 3.25t <- 0.25b <- 0.4v <- 0.65n <- 1000
# random RT values from RWiener using parameters abovert <- rwiener( n = n, alpha = a, tau = t, beta = b, delta = v)
# make stan data liststan_data <- list(rt = rt$q, acc = ifelse(rt[, "resp"] == "upper", 1, 0), n = nrow(rt), min_t = min(rt$q))
# number of chains to runn_chains <- 5
# use inits from above dist. parametersstan_inits <- lapply(1:n_chains, function(i) { list( a = a, t = t, v = v, b = b )})
# STAN codestan_model <-"data { int<lower=1> n; vector[n] rt; vector<lower=0,upper=1>[n] acc; real<lower=0> min_t;}parameters { real<lower=0,upper=6> a; real<lower=.1,upper=min_t> t; real<lower=-2,upper=2> v; real<lower=0,upper=1> b;}model { a ~ normal(0, 2); t ~ cauchy(0, 0.1); v ~ normal(0, 2); b ~ beta(1.25, 1.25);print(lapply(extract(stan_fit), mean))
# Plots -------------------------------------------------------------------
# stan traceplot#traceplot(stan_fit)#plot_rwiener(rt)
# install these packages if not already installed, run:# install.packages(c("rstan", "loo", "RWiener"))library(rstan) # need to load namespace due to Rcpp dependencies
# for running multiple chains in parallel, uncomment next two lines#rstan::rstan_options(auto_write = TRUE)#options(mc.cores = parallel::detectCores())
# wiener parameters to try and estimate in STANa <- 3t <- 0.25b <- 0.33v <- 1n <- 50
# random RT values from RWiener package using parameters from abovert <- RWiener::rwiener( n = n, alpha = a, tau = t, beta = b, delta = v)
# make stan data liststan_data <- list(rt = rt$q, acc = ifelse(rt[, "resp"] == "upper", 1, 0), n = nrow(rt), min_t = min(rt$q), max_t = max(rt$q))
# number of chains to runn_chains <- 3
# use initial values from above weiner parametersstan_inits <- lapply(1:n_chains, function(i) { list( a = a, t = t, v = v, b = b )})
# STAN model codestan_model <-"data { int<lower=1> n; vector[n] rt; vector<lower=0,upper=1>[n] acc; real<lower=0> min_t; real<lower=0> max_t;}parameters { real<lower=0,upper=100> a; // speed-acc tradeoff / boundary width real<lower=0.1,upper=min_t> t; // motor latency / non-decision time real<lower=-max_t,upper=max_t> v; // processing speed / drift rate real<lower=0,upper=1> b; // response bias / boundary bias}model { a ~ gamma(0.75, 0.25); v ~ normal(0, max_t/3); b ~ beta(1.25, 1.25); // implied: t ~ uniform(0.1, mininum RT)
// likelihood for (i in 1:n) { if (acc[i] == 1) { rt[i] ~ wiener(a, t, b, v); // upper bound } else { rt[i] ~ wiener(a, t, 1 - b, -1 * v); // lower bound } }}generated quantities { vector[n] log_lik;
for (i in 1:n) { if (acc[i] == 1) { // upper boundary log_lik[i] <- wiener_log(rt[i], a, t, b, v); } else { // lower boundary log_lik[i] <- wiener_log(rt[i], a, t, 1 - b, -1 * v); } }}"
# Fit STAN model ----------------------------------------------------------
stan_fit <- rstan::stan( model_name = "diffusion_test", model_code = stan_model, data = stan_data, init = stan_inits, chains = n_chains, iter = n_chains * 1000 )
# print stan model parametersprint(stan_fit)
# print elpd_loo, expected log-prob density of leave-one-out cross validation with importance samplingprint(loo::loo(loo::extract_log_lik(stan_fit)), digits = 3)
# print log likelihood from RWiener packageprint(RWiener::wiener_likelihood(c(a,t,b,v), rt))
# print means of posterior distributions for each parameterprint(unlist(lapply(rstan::extract(stan_fit), mean)))
# Plots -------------------------------------------------------------------
# rstan traceplot of parametersrstan::traceplot(stan_fit, pars = c("a", "t", "b", "v"))
# function to plot distributions from RWienerplot_rwiener <- function(rt) { rt_u <- rt$q[rt$resp == "upper"] rt_l <- rt$q[rt$resp == "lower"]
xlim <- max(c(rt_u, rt_l)) rt_seq <- seq(0, xlim, .005)
d_rt_u <- RWiener::dwiener(rt_seq, a, t, b, v, resp = rep("upper", length(rt_seq))) d_rt_l <- RWiener::dwiener(rt_seq, a, t, b, v, resp = rep("lower", length(rt_seq)))