Chapter 6 Using EMC2 for EAMs II - Race Models
In this example, we provide examples of race models – a class of EAMs where the model assumes a race between accumulators. Examples of race models include the linear ballistic accumulator (LBA; Brown and Heathcote (2008)) and the racing diffusion model (RDM; Tillman, Van Zandt, and Logan (2020)). Compared to the DDM example, we use the same model checks and data set, so these examples are slightly shorter than the previous chapter. By the end of this chapter, we should have three models (DDM, LBA, RDM) which all nicely fit the data, and in the following chapter, we’ll show you how you can compare these differing accounts.
6.1 LBA
The LBA is a “race” model of evidence accumulation, where evidence is assumed to accumulate balistically towards threshold for a number of accumulators (each representing a choice alternative). A graphical example of the model can be seen above. The LBA has similar parameters to the DDM, however, we use some slightly different names for these (consistent with the rtdists
package). The parameters of the LBA are as follows;
v
: Drift rate.The rate of evidence accumulation for each accumulator. For the models, we generally estimate intercept and difference terms, such that the difference is the difference in drift rate between competing accumulators. The intercept drift term is often seen as the urgency term.sv
: Drift rate variance. This is the between trial variance parameter for the drift rate distribution. Typically,sv
is set as a constant to 1 (Donkin et al. 2011) (however we show options below for this).B
: Response threshold or response caution. The arbitrary amount of evidence needed before the corresponding response is executed. Generally,b = B + A
to ensure that threshold is greater than start point.A
: Start point interval or evidence in accumulator before beginning of decision process. Start point varies from trial to trial in the interval [0, A] (uniform distribution). Average amount of evidence before evidence accumulation across trials is A/2.t0
: non-decision time or response time constant (in seconds). Lower bound for the duration of all non-decisional processes (encoding and response execution).
6.1.1 LBA models in EMC2 (and checks)
In this section, we show a variety of models that we try for the Forstmann (2008) data, where the main factor of interest is the emphasis manipulation. We show the design functions for each of these models, some custom contrasts and then some extra checks we propose. First, let’s load in the data as before.
rm(list=ls())
source("emc/emc.R")
source("models/RACE/LBA/lbaB.R")
print( load("Data/PNAS.RData"))
<- data[,c("s","E","S","R","RT")]
dat names(dat)[c(1,5)] <- c("subjects","rt")
levels(dat$R) <- levels(dat$S)
# NB: This data has been truncated at 0.25s and 1.5s
Now, we’re going to fit a series of models to the Forstmann (2008) data. The first model will only vary threshold with emphasis. The second varies threshold, drift and non-decision time with emphasis (saturated). The next three models include the estimation of a variability parameter sv
. In the first models we set sv=1
to establish a scale.
In the three later models, we fit a series of models where sv
differs between matching and mismatching accumulators, with its intercept fixed at 1 to establish scaling. Typically allowing this difference greatly improves LBA fit and results in sv_TRUE
(i.e., match) > sv_FALSE
. All of these designs are effect coded, so it’s worth checking out the sampled_p_vector
of each model to understand which parameters are being estimated and think about how these would be mapped.
# Average rate = intercept, and rate d = difference (match-mismatch) contrast
<- matrix(c(-1/2,1/2),ncol=1,dimnames=list(NULL,"d"))
ADmat
<- matrix(c(0,-1,0,0,0,-1),nrow=3)
Emat dimnames(Emat) <- list(NULL,c("a-n","a-s"))
# Only B affected by E
<- make_design(
design_B Ffactors=list(subjects=levels(dat$subjects),S=levels(dat$S),E=levels(dat$E)),
Rlevels=levels(dat$R),matchfun=function(d)d$S==d$lR,
Clist=list(lM=ADmat,lR=ADmat,S=ADmat,E=Emat),
Flist=list(v~lM,sv~1,B~E,A~1,t0~1),
constants=c(sv=log(1)),
model=lbaB)
# samplers <- make_samplers(dat,design_B,type="standard",rt_resolution=.02)
# save(samplers,file="sPNAS_B.RData")
# B, v and t0 affected by E
<- make_design(
design_Bvt0 Ffactors=list(subjects=unique(dat$subjects),S=levels(dat$S),E=levels(dat$E)),
Rlevels=levels(dat$R),matchfun=function(d)d$S==d$lR,
Clist=list(lM=ADmat,lR=ADmat,S=ADmat,E=Emat),
Flist=list(v~E*lM,sv~1,B~lR*E,A~1,t0~E),
constants=c(sv=log(1)),
model=lbaB)
# samplers <- make_samplers(dat,design_Bvt0,type="standard",rt_resolution=.02)
# save(samplers,file="sPNAS_Bvt0.RData")
# First, allowing E to affect B and t0
<- make_design(
design_Bt0_sv Ffactors=list(subjects=unique(dat$subjects),S=levels(dat$S),E=levels(dat$E)),
Rlevels=levels(dat$R),matchfun=function(d)d$S==d$lR,
Clist=list(lM=ADmat,lR=ADmat,S=ADmat,E=Emat),
Flist=list(v~lM,sv~lM,B~lR*E,A~1,t0~E),
constants=c(sv=log(1)),
model=lbaB)
# samplers <- make_samplers(dat,design_Bt0_sv,type="standard",rt_resolution=.02)
# save(samplers,file="sPNAS_Bt0_sv.RData")
# Now E affects B and v
<- make_design(
design_Bv_sv Ffactors=list(subjects=unique(dat$subjects),S=levels(dat$S),E=levels(dat$E)),
Rlevels=levels(dat$R),matchfun=function(d)d$S==d$lR,
Clist=list(lM=ADmat,lR=ADmat,S=ADmat,E=Emat),
Flist=list(v~E*lM,sv~lM,B~lR*E,A~1,t0~1),
constants=c(sv=log(1)),
model=lbaB)
# samplers <- make_samplers(dat,design_Bv_sv,type="standard",rt_resolution=.02)
# save(samplers,file="sPNAS_Bv_sv.RData")
# Now all three
<- make_design(
design_Bvt0_sv Ffactors=list(subjects=unique(dat$subjects),S=levels(dat$S),E=levels(dat$E)),
Rlevels=levels(dat$R),matchfun=function(d)d$S==d$lR,
Clist=list(lM=ADmat,lR=ADmat,S=ADmat,E=Emat),
Flist=list(v~E*lM,sv~lM,B~lR*E,A~1,t0~E),
constants=c(sv=log(1)),
model=lbaB)
# samplers <- make_samplers(dat,design_Bvt0_sv,type="standard",rt_resolution=.02)
# save(samplers,file="sPNAS_Bvt0_sv.RData")
We can run these five models and check the fit metrics as we did in the previous chapter. The last model fails to converge (or rather some parameter were so strongly autocorrelated it would have taken an impractically large run to produce anything useful). This might happen when doing complex modelling and can be the result of several issues, however, these issues generally relate to the amount of information available. For example, if we have a model with many parameters across varying conditions, it is likely that we have less information for each cell of the estimated design, and in these scenarios, the sampler may struggle to converge. Further, if we have a low number of subjects, this will also cause difficulty.
Here we talk about autocorrelation (using the integrated autocorrelation time stat) and effective sample sizes - these are good metrics to evaluate the quality of sampling. The basic idea behind autocorrelation is that the samples in chains are not independent, so we should estimate the effective number of independent samples. This is often because new samples are based on the previous sample in an MCMC chain. If we see high autocorrelation, this may be because we have not yet reached the posterior mode for sampling or the posterior distribution is multi-modal. We can run the sampler for a very long time, which would give us a huge number of samples, and then we could assess the effective sample size (i.e., the number of independent samples). Generally however, these problems can be solved by thinking about the model being estimated.
Looking at estimates, most issues were around the a_n
contrast, which might not be surprising given this had a weak manifest effect. Here we fit this model again but dropping the a_n
contrast for the emphasis effects on drift and non-decision time, instead estimating an intercept and the difference between the average of accuracy and neutral and speed, a 14 parameter model.
<- matrix(c(1/4,1/4,-1/2),nrow=3)
E_AVan_s_mat dimnames(E_AVan_s_mat) <- list(NULL,c("an-s"))
<- make_design(
design_Bvt0_sv_NOa_n Ffactors=list(subjects=unique(dat$subjects),S=levels(dat$S),E=levels(dat$E)),
Rlevels=levels(dat$R),matchfun=function(d)d$S==d$lR,
Clist=list(v=list(E=E_AVan_s_mat,lM=ADmat),sv=list(lM=ADmat),
B=list(E=Emat,lR=ADmat),t0=list(E=E_AVan_s_mat)),
Flist=list(v~E*lM,sv~lM,B~lR*E,A~1,t0~E),
constants=c(sv=log(1)),
model=lbaB)
# samplers <- make_samplers(dat,design_Bvt0_sv_NOa_n,type="standard",rt_resolution=.02)
# save(samplers,file="sPNAS_Bvt0_sv_NOa_n.RData")
For the sv=1
models we used a similar script as for the DDM. For the other LBA models we use a slightly “smarter” script that only fits the next stage if the previous one worked, e.g., for the Bvsv
model.
Given that we have already run these models, let’s look through some functions to check whether burn-in was completed, adaptation was completed and some other checks.
# Here we test if burn in had been done previously.
#
if (is.null(attr(samplers,"burnt")) || is.na(attr(samplers,"burnt"))) {
<- run_burn(samplers,cores_per_chain=4)
sPNAS_Bv_sv save(sPNAS_Bv_sv,file="sPNAS_Bv_sv.RData")
}
# Here we check if adaptation was already done
#
if (is.null(attr(sPNAS_Bv_sv,"adapted")) && !is.na(attr(sPNAS_Bv_sv,"burnt"))) {
<- run_adapt(sPNAS_Bv_sv,cores_per_chain=4)
sPNAS_Bv_sv save(sPNAS_Bv_sv,file="sPNAS_Bv_sv.RData")
}
# Here we only move on to sampling of adaptation was successful
#
if (!is.null(attr(sPNAS_Bv_sv,"adapted")) && attr(sPNAS_Bv_sv,"adapted")) {
<- run_sample(sPNAS_Bv_sv,iter=2000,cores_per_chain=4)
sPNAS_Bv_sv save(sPNAS_Bv_sv,file="sPNAS_Bv_sv.RData")
}
As a side note, this code below was run later after choosing this as the best model and knowing that the first 2000 iterations of the sample run had to be discarded, giving 5000*3 = 15000
good samples to work with.
<- run_sample(sPNAS_Bv_sv,iter=4000,cores_per_chain=10)
sPNAS_Bv_sv save(sPNAS_Bv_sv,file="sPNAS_Bv_sv.RData")
<- post_predict(sPNAS_Bv_sv,n_cores=19,subfilter=2000)
ppPNAS_Bv_sv save(ppPNAS_Bv_sv,sPNAS_Bv_sv,file="sPNAS_Bv_sv.RData")
6.1.2 Inference for the LBA
For inference, lets first load in all of the models we estimated.
#### Load model results ----
print(load("~/Desktop/emc2/models/RACE/LBA/examples/samples/sPNAS_B.RData"))
## [1] "sPNAS_B"
print(load("~/Desktop/emc2/models/RACE/LBA/examples/samples/sPNAS_Bvt0.RData"))
## [1] "sPNAS_Bvt0"
print(load("~/Desktop/emc2/models/RACE/LBA/examples/samples/sPNAS_Bt0_sv.RData"))
## [1] "sPNAS_Bt0_sv"
print(load("~/Desktop/emc2/models/RACE/LBA/examples/samples/sPNAS_Bv_sv.RData"))
## [1] "ppPNAS_Bv_sv" "sPNAS_Bv_sv"
print(load("~/Desktop/emc2/models/RACE/LBA/examples/samples/sPNAS_Bvt0_sv.RData")) # Failed model, forced to adapt and sample
## [1] "sPNAS_Bvt0_sv"
print(load("~/Desktop/emc2/models/RACE/LBA/examples/samples/sPNAS_Bvt0_sv_NOa_n.RData"))
## [1] "sPNAS_Bvt0_sv_NOa_n"
Note that this includes one of the failed models (Bvt0_sv
). It’s worth taking a look at the chains and diagnostics for this model to help identify problems in your own modelling. Comparing these estimates to a “good” run will be immediately obvious, with stuck chains, parameters not showing stationarity, low GD statistics and low effective sample sizes.
6.1.3 Model Checks
We’re now going to again go through some basic checks to see how our models fared. We’ve left notes in the code so that you are able to check these yourself and see what we saw. For the simple B
model, we can use this as a comparison for the other models.
It is important to note the difference between a good model and good estimation. For any model we estimate, we need to be able to estimate it well such that we can make clear inference on the posterior. It is this posterior that dictates whether this is an accurate model of the data, and it is on the posterior that we do model comparison. If the sampling has failed, this could indicate a poor model or just poor sampling, but regardless, it is problematic to make inference when we have not reached the posterior. On the other hand, if sampling has been completed, this does not indicate a good model, only that we have reached the posterior (which could be wrong).
Note Running the check_run
function will prompt you to press ‘Enter’ to see each statistic. It will also save these plots as pdf files.
#### Check convergence ----
# Aim to get 1000 good samples as a basis for model comparison (but note this
# is not enough for inference on some parameters)
check_run(sPNAS_B)
# Slow to converge, but there by 4500
check_run(sPNAS_Bvt0,subfilter = 4500,layout=c(3,3))
# Low efficiency for t0_Ea-n, t0, and B_lRd:Ea-n
check_run(sPNAS_Bt0_sv,subfilter=2000,layout=c(3,5))
# B_lRd:Ea-n, B_Ea-n, v_Ea-n, v_Ea-n:lMd all inefficient. Some slow-wave
# oscillations, definitely need longer series if using the parameter estimates
# (even though likely stationary after 2000)
check_run(sPNAS_Bv_sv,subfilter=2000,layout=c(3,5))
# After extensive burn (although not achieving Rhat < 1.2), adaptation was quick
# but chains were very poor. Decided not to pursue further.
check_run(sPNAS_Bvt0_sv,subfilter=1000)
# Burned in quickly and converged well after 1000, B_lRd:Ea-n and especially
# t0_Ean-s quite inefficient
check_run(sPNAS_Bvt0_sv_NOa_n,subfilter=1000,layout=c(3,5))
6.1.4 Model selection
We fit 5 different LBA models, and so in a standard modelling application, we would want to know which is the best model. More importantly, we would want to objectively know which model is best using some quantifiable measures. Here, we compare information criteria (IC) for 5 different models. The ICs we compare are deviance information criterion (DIC) and Bayesian predictive information criterion (BPIC). For both of these ICs, lower IC is indicative of better model fit.
IC methods are generally a “quick and dirty” method for model comparison, where model complexity is penalized “post-hoc” and the model fit is the key metric. For these metrics, we want the model to closely match the data, as this would indicate a good fit. However, ICs can potentially miss over fitting or issues related to model complexity (i.e., sometimes a simpler model does not fit quite as well, but is more flexible to potential future data, whereas a more complex model may only fit the observed data). We’ll discuss this further in the [Model Comparison with IS2] chapter.
Let’s first compare these using the compare_IC
function;
compare_IC(list(B=sPNAS_B,Bvt0=sPNAS_Bvt0,Bt0sv=sPNAS_Bt0_sv,Bvsv=sPNAS_Bv_sv,
Bvt0sv=sPNAS_Bvt0_sv_NOa_n),subfilter=list(0,4500,2000,2001:3000,1000))
## DIC wDIC BPIC wBPIC EffectiveN meanD Dmean minD
## B -15243 0 -15100 0.000 143 -15386 -15485 -15529
## Bvt0 -15946 0 -15711 0.000 236 -16182 -16336 -16418
## Bt0sv -16870 0 -16667 0.000 203 -17073 -17206 -17276
## Bvsv -17200 1 -16986 0.999 214 -17414 -17569 -17627
## Bvt0sv -17182 0 -16973 0.001 209 -17391 -17542 -17601
<- compare_ICs(list(B=sPNAS_B, Bvt0=sPNAS_Bvt0, Bt0sv=sPNAS_Bt0_sv,
ICs Bvsv=sPNAS_Bv_sv, Bvt0sv=sPNAS_Bvt0_sv_NOa_n),subfilter=list(0,4500,2000,2001:3000,1000))
## wDIC_B wDIC_Bvt0 wDIC_Bt0sv wDIC_Bvsv wDIC_Bvt0sv wBPIC_B wBPIC_Bvt0
## as1t 0 0.000 0.028 0.124 0.848 0 0.000
## bd6t 0 0.000 0.000 0.592 0.408 0 0.000
## bl1t 0 0.000 0.000 0.507 0.493 0 0.000
## hsft 0 0.000 0.000 0.548 0.452 0 0.000
## hsgt 0 0.000 0.001 0.636 0.363 0 0.000
## kd6t 0 0.000 0.254 0.454 0.292 0 0.000
## kd9t 0 0.000 0.003 0.511 0.485 0 0.000
## kh6t 0 0.000 0.150 0.496 0.354 0 0.000
## kmat 0 0.000 0.992 0.002 0.007 0 0.000
## ku4t 0 0.001 0.000 0.688 0.311 0 0.001
## na1t 0 0.000 0.044 0.595 0.360 0 0.000
## rmbt 0 0.000 0.000 0.926 0.073 0 0.000
## rt2t 0 0.000 0.000 0.918 0.082 0 0.000
## rt3t 0 0.000 0.005 0.119 0.877 0 0.000
## rt5t 0 0.001 0.228 0.319 0.452 0 0.001
## scat 0 0.000 0.330 0.255 0.416 0 0.000
## ta5t 0 0.000 0.000 0.945 0.055 0 0.000
## vf1t 0 0.000 0.000 0.867 0.133 0 0.000
## zk1t 0 0.000 0.020 0.869 0.111 0 0.000
## wBPIC_Bt0sv wBPIC_Bvsv wBPIC_Bvt0sv
## as1t 0.030 0.068 0.901
## bd6t 0.000 0.504 0.496
## bl1t 0.000 0.614 0.386
## hsft 0.000 0.587 0.413
## hsgt 0.002 0.673 0.324
## kd6t 0.368 0.394 0.237
## kd9t 0.008 0.366 0.626
## kh6t 0.118 0.498 0.384
## kmat 0.998 0.000 0.001
## ku4t 0.001 0.784 0.215
## na1t 0.119 0.523 0.358
## rmbt 0.001 0.740 0.259
## rt2t 0.000 0.961 0.039
## rt3t 0.001 0.070 0.929
## rt5t 0.311 0.326 0.362
## scat 0.332 0.217 0.452
## ta5t 0.000 0.959 0.041
## vf1t 0.000 0.858 0.142
## zk1t 0.003 0.790 0.207
Comparing all 5 models, clearly we need sv (NB: use only 1000 from Bvsv
after convergence, more added for parameter inference as this is the winning model). We noted this above, as the sv
parameter often helps to capture some noise in the distributions. Let’s now try this across subjects. The latter function returns a list of matrices for each participant, so we can use that to count winners as follows.
table(unlist(lapply(ICs,function(x){row.names(x)[which.min(x$DIC)]})))
##
## Bt0sv Bvsv Bvt0sv
## 1 14 4
table(unlist(lapply(ICs,function(x){row.names(x)[which.min(x$BPIC)]})))
##
## Bt0sv Bvsv Bvt0sv
## 1 13 5
Again here we see mostly Bvsv
winning, second Bvt0sv
with no Ea_n
, and one clear Bt0sv
. We could try the simpler E contrast with the Bvsv
model, but we are going to leave that as an extension exercise for you try. Now that we know the best LBA model, let’s compare this LBA model to the best fitting DDM. Let’s first load in the DDM
Comparing the best (by IC methods) DDM (16 parameters) to the best (15 parameter) LBA model, we see that the latter has a slight edge. This is born out in testing fit, as we see that both models fit well but the small overestimation of error RT in the speed condition evident in the DDM is no longer evident in the LBA.
source("models/DDM/DDM/ddmTZD.R")
load("~/Desktop/emc2/models/DDM/DDM/examples/samples/sPNAS_avt0_full.RData")
Now we can compare the ICs of the two “best” models;
# For the remaining analysis add 4000 iterations to Bvsv model
compare_IC(list(avt0=sPNAS_avt0_full,Bvsv=sPNAS_Bv_sv),subfilter=list(500,2000))
## DIC wDIC BPIC wBPIC EffectiveN meanD Dmean minD
## avt0 -17043 0 -16802 0 240 -17283 -17468 -17523
## Bvsv -17188 1 -16964 1 224 -17412 -17564 -17636
From the table of ICs, we can see that the LBA has slightly lower criteria for both metrics. Let’s now plot the fit of the winning LBA model.
#### Fit of winning (Bvsv) model ----
# post predict did not use first 2000, so inference based on 5000*3 samples
plot_fit(dat,ppPNAS_Bv_sv,layout=c(2,3),factors=c("E","S"),lpos="right",xlim=c(.25,1.5))
#plot_fits(dat,ppPNAS_Bv_sv,layout=c(2,3),lpos="right")
You’ll see by running the code below that there is no great evidence of misfit. Again, for these plots, it is useful to assess a variety of metrics (as we show here). These include the mean RTs and accuracy, as well as upper and lower quantiles to see the fit across the spread of the data, the standard deviation, and the fit to different types of responses (i.e., correct and error), as often error response times can be difficult to fit.
# No evidence of any misfit
<- function(d) 100*mean(d$S==d$R)
pc plot_fit(dat,ppPNAS_Bv_sv,layout=c(2,3),factors=c("E","S"),
stat=pc,stat_name="Accuracy (%)",xlim=c(70,95))
<- plot_fit(dat,ppPNAS_Bv_sv,layout=c(2,3),factors=c("E","S"),
tab stat=function(d){mean(d$rt)},stat_name="Mean RT (s)",xlim=c(0.375,.625))
<- plot_fit(dat,ppPNAS_Bv_sv,layout=c(2,3),factors=c("E","S"),xlim=c(0.275,.4),
tab stat=function(d){quantile(d$rt,.1)},stat_name="10th Percentile (s)")
<- plot_fit(dat,ppPNAS_Bv_sv,layout=c(2,3),factors=c("E","S"),xlim=c(0.525,.975),
tab stat=function(d){quantile(d$rt,.9)},stat_name="90th Percentile (s)")
<- plot_fit(dat,ppPNAS_Bv_sv,layout=c(2,3),factors=c("E","S"),
tab stat=function(d){sd(d$rt)},stat_name="SD (s)",xlim=c(0.1,.355))
<- plot_fit(dat,ppPNAS_Bv_sv,layout=c(2,3),factors=c("E","S"),xlim=c(0.375,.725),
tab stat=function(d){mean(d$rt[d$R!=d$S])},stat_name="Mean Error RT (s)")
6.1.5 Posterior parameter inference
Given we are now happy with the fit of the model (relative to other models and in an absolute sense), we can begin making inference on the parameter estimates. If there is some misfit present, it is important to always contextualize inference with the level of misfit of the model to the data.
6.1.5.1 Population level
For inference, let’s start at the population level, looking at mean parameters. First we see that the priors (red lines) are all well dominated except for some rate parameters.
### Population mean (mu) tests
<- plot_density(sPNAS_Bv_sv,layout=c(3,6),selection="mu",subfilter=2000) ciPNAS_Bv_sv
On the natural scale it is evident that this is because the mismatch (FALSE) rates are least well updated, due to the fairly low error rates (errors give the most information about FALSE rates). In many modelling exercises, we may be using data with low error rates. Literature has been somewhat varied on this, with ranges of 60% to 90% accuracy said to be in a “good” range for accuracy. However, with less information (in this case, less errors), parameters are less informed, which leads to estimation difficulties.
Let’s look at the density again where we use mapped=TRUE
to alternate the figures to show correct and error (rather than left and right) responses.
<- plot_density(sPNAS_Bv_sv,layout=c(3,6),
ciPNAS_Bv_sv_mapped selection="mu",mapped=TRUE)
We can now compare the parameters both with and without mapping. We find this is often useful when considering the effects that may be estimated by the model, as only looking at one variation may cause us to miss effects in the other variation.
round(ciPNAS_Bv_sv,2)
## v v_Ea-n v_Ea-s v_lMd v_Ea-n:lMd v_Ea-s:lMd sv_lMd B B_lRd B_Ea-n
## 2.5% 0.73 -0.36 -0.94 1.94 0.10 0.72 -0.81 -0.28 -0.01 -0.03
## 50% 1.21 -0.26 -0.66 2.70 0.22 1.12 -0.68 -0.16 0.04 -0.01
## 97.5% 1.74 -0.17 -0.35 3.38 0.32 1.49 -0.53 -0.04 0.09 0.02
## B_Ea-s B_lRd:Ea-n B_lRd:Ea-s A t0
## 2.5% 0.20 -0.03 -0.08 -1.52 -2.46
## 50% 0.27 -0.01 -0.05 -1.22 -2.30
## 97.5% 0.34 0.01 -0.01 -0.90 -2.15
round(ciPNAS_Bv_sv_mapped,2)
## v_accuracy_TRUE v_accuracy_FALSE v_neutral_TRUE v_neutral_FALSE v_speed_TRUE
## 2.5% 2.25 -0.92 2.42 -0.50 2.37
## 50% 2.55 -0.14 2.71 0.24 2.65
## 97.5% 2.86 0.73 3.01 1.06 2.94
## v_speed_FALSE sv_TRUE sv_FALSE B_left_accuracy B_right_accuracy B_left_neutral
## 2.5% 0.54 0.67 1.3 0.74 0.78 0.73
## 50% 1.08 0.71 1.4 0.83 0.87 0.84
## 97.5% 1.66 0.77 1.5 0.95 0.98 0.96
## B_right_neutral B_left_speed B_right_speed A t0
## 2.5% 0.78 0.54 0.59 0.20 0.09
## 50% 0.88 0.62 0.68 0.29 0.10
## 97.5% 1.00 0.72 0.78 0.41 0.12
For simpler estimates, we see that;
A
is usually found with the LBAsv_true
>sv_false
t0
is quite small (100ms)- In this case start point noise (.29) is small relative to
B
(which has interceptexp(-.16) = 0.85
, so about 1/4 ofb
).
6.1.5.2 Threshold effects
Let’s now look at the all important threshold effects. Remember for this task we were looking at an instructions manipulated speed-accuracy tradeoff effect (i.e., be fast or be accurate), where the hypothesis was that thresholds would vary with emphasis.
First we check the mapping to recall the parameterisation.
# Recall the map used with
get_map(sPNAS_Bv_sv)$B
## lR E B B_lRd B_Ea-n B_Ea-s B_lRd:Ea-n B_lRd:Ea-s
## 1 left accuracy 1 -0.5 0 0 0.0 0.0
## 7 right accuracy 1 0.5 0 0 0.0 0.0
## 2 left neutral 1 -0.5 -1 0 0.5 0.0
## 8 right neutral 1 0.5 -1 0 -0.5 0.0
## 3 left speed 1 -0.5 0 -1 0.0 0.5
## 9 right speed 1 0.5 0 -1 0.0 -0.5
Second we test right vs left response thresholds.
p_test(x=sPNAS_Bv_sv,x_name="B_lRd",subfilter=2000)
## B_lRd mu
## 2.5% -0.01 NA
## 50% 0.04 0
## 97.5% 0.09 NA
## attr(,"less")
## [1] 0.037
B_lRd
tests threshold_right - threshold_left
. Although not quite credible, it indicates slightly higher right thresholds (i.e., a bias to respond left).
Then we check the difference in thresholds between accuracy and neutral (B_Ea-n
) and accuracy and speed (B_Ea-s
).
p_test(x=sPNAS_Bv_sv,x_name="B_Ea-n",subfilter=2000)
## B_Ea-n mu
## 2.5% -0.03 NA
## 50% -0.01 0
## 97.5% 0.02 NA
## attr(,"less")
## [1] 0.69
p_test(x=sPNAS_Bv_sv,x_name="B_Ea-s",subfilter=2000)
## B_Ea-s mu
## 2.5% 0.20 NA
## 50% 0.27 0
## 97.5% 0.34 NA
## attr(,"less")
## [1] 0
B_Ea-n
and B_Ea-s
measure differences in response caution, accuracy - neutral
and accuracy - speed
respectively. These include thresholds averaged over left and right accumulators. Caution (threshold) for accuracy is clearly higher than speed, but not credibly greater than neutral (i.e., neutral ~= accuracy
).
Next we construct a test showing the threshold advantage is greater for speed than neutral;
p_test(x=sPNAS_Bv_sv,mapped=TRUE,x_name="average B: neutral-speed",
x_fun=function(x){mean(x[c("B_left_neutral","B_right_neutral")]) -
mean(x[c("B_left_speed","B_right_speed")])})
## average B: neutral-speed mu
## 2.5% 0.16 NA
## 50% 0.21 0
## 97.5% 0.26 NA
## attr(,"less")
## [1] 0
However, we see no evidence of a difference between accuracy and neutral thresholds;
p_test(x=sPNAS_Bv_sv,x_name="B_Ea-n",subfilter=2000)
## B_Ea-n mu
## 2.5% -0.03 NA
## 50% -0.01 0
## 97.5% 0.02 NA
## attr(,"less")
## [1] 0.69
Looking at the accuracy vs speed difference though;
p_test(x=sPNAS_Bv_sv,x_name="B_Ea-s",subfilter=2000)
## B_Ea-s mu
## 2.5% 0.20 NA
## 50% 0.27 0
## 97.5% 0.34 NA
## attr(,"less")
## [1] 0
We see thresholds are clearly higher for speed (by about 0.2 on the natural scale).
The remaining terms test interactions with bias (i.e., lR), with evidence of a small but just credibly stronger bias to respond left (i.e., a lower threshold for the left accumulator) for speed than accuracy.
p_test(x=sPNAS_Bv_sv,x_name="B_lRd:Ea-s",subfilter=1500,digits=2)
## B_lRd:Ea-s mu
## 2.5% -0.08 NA
## 50% -0.05 0
## 97.5% -0.01 NA
## attr(,"less")
## [1] 0.996
6.1.5.3 Drift rate effects
Next, lets look at drift rate effects. For these, we’ll again look at the mapping first, and then look at the difference parameters between accuracy and neutral or speed conditions.
# Again recall the map used with
get_map(sPNAS_Bv_sv)$v
## E lM v v_Ea-n v_Ea-s v_lMd v_Ea-n:lMd v_Ea-s:lMd
## 1 accuracy TRUE 1 0 0 0.5 0.0 0.0
## 7 accuracy FALSE 1 0 0 -0.5 0.0 0.0
## 2 neutral TRUE 1 -1 0 0.5 -0.5 0.0
## 8 neutral FALSE 1 -1 0 -0.5 0.5 0.0
## 3 speed TRUE 1 0 -1 0.5 0.0 -0.5
## 9 speed FALSE 1 0 -1 -0.5 0.0 0.5
Here, v_Ea-n
and v_Ea-s
indicate that processing rate (the average of matching and mismatching rates) is least in accuracy, slightly greater in neutral and the highest in speed.
p_test(x=sPNAS_Bv_sv,x_name="v_Ea-n",subfilter=2000)
## v_Ea-n mu
## 2.5% -0.36 NA
## 50% -0.26 0
## 97.5% -0.17 NA
## attr(,"less")
## [1] 1
p_test(x=sPNAS_Bv_sv,x_name="v_Ea-s",subfilter=2000)
## v_Ea-s mu
## 2.5% -0.94 NA
## 50% -0.66 0
## 97.5% -0.35 NA
## attr(,"less")
## [1] 1
Let’s now check whether processing is faster in the speed condition, i.e., the instruction leads to some form of faciliation.
p_test(x=sPNAS_Bv_sv,mapped=TRUE,x_name="average v: speed-neutral",
x_fun=function(x){mean(x[c("v_speed_TRUE","v_speed_FALSE")]) -
mean(x[c("v_neutral_TRUE","v_neutral_FALSE")])})
## average v: speed-neutral mu
## 2.5% 0.12 NA
## 50% 0.39 0
## 97.5% 0.64 NA
## attr(,"less")
## [1] 0.004
Looking at the parameter v_lMd
tests the quality of selective attention, i.e., rate for match minus rate for mismatch.
p_test(x=sPNAS_Bv_sv,x_name="v_lMd",subfilter=2000)
## v_lMd mu
## 2.5% 1.94 NA
## 50% 2.70 0
## 97.5% 3.38 NA
## attr(,"less")
## [1] 0
Next, v_Ea-n
tests if quality neutral is different to quality accuracy.
p_test(x=sPNAS_Bv_sv,x_name="v_Ea-n:lMd",subfilter=2000)
## v_Ea-n:lMd mu
## 2.5% 0.10 NA
## 50% 0.22 0
## 97.5% 0.32 NA
## attr(,"less")
## [1] 0
The difference is ~5 times larger for accuracy - speed
;
p_test(x=sPNAS_Bv_sv,x_name="v_Ea-s:lMd",subfilter=2000)
## v_Ea-s:lMd mu
## 2.5% 0.72 NA
## 50% 1.12 0
## 97.5% 1.49 NA
## attr(,"less")
## [1] 0
Finally, The neutral - speed
difference is also highly credible, and can be tested in the mapped form;
p_test(x=sPNAS_Bv_sv,mapped=TRUE,x_name="quality: accuracy-neutral",
x_fun=function(x){diff(x[c("v_neutral_FALSE","v_neutral_TRUE")]) -
diff(x[c("v_speed_FALSE","v_speed_TRUE")])})
## quality: accuracy-neutral mu
## 2.5% 0.52 NA
## 50% 0.90 0
## 97.5% 1.25 NA
## attr(,"less")
## [1] 0
Or from the sampled parameters;
p_test(x=sPNAS_Bv_sv,x_name="v_Ea-s:lMd",y=sPNAS_Bv_sv,y_name="v_Ea-n:lMd",
subfilter=2000,digits=3)
## v_Ea-s:lMd v_Ea-n:lMd v_Ea-s:lMd-v_Ea-n:lMd
## 2.5% 0.721 0.096 0.530
## 50% 1.123 0.216 0.908
## 97.5% 1.486 0.323 1.255
## attr(,"less")
## [1] 0
6.1.5.4 Visualising results
In this section, we’re going to show some extensions of visualizations, by first extracting the parameter estimates, and then plotting these using ggplot2
. Let’s start by extracting the parameters and checking the means of the posterior.
library(tidyverse)
# Get parameter data frame
<- parameters_data_frame(sPNAS_Bv_sv, mapped = TRUE)
ps head(ps)
## v_accuracy_TRUE v_accuracy_FALSE v_neutral_TRUE v_neutral_FALSE v_speed_TRUE
## 1 2.526213 -0.06444518 2.718539 0.42221219 2.624610
## 2 2.300613 -0.71180244 2.671168 -0.05991449 2.497907
## 3 2.323223 -0.65978316 2.604941 0.05056899 2.610084
## 4 2.518273 -1.12244957 2.694049 -0.43434192 2.630910
## 5 2.318271 -1.00748037 2.571730 -0.48496663 2.585076
## 6 2.469045 -0.91488990 2.640153 -0.41631866 2.575907
## v_speed_FALSE sv_TRUE sv_FALSE B_left_accuracy B_right_accuracy B_left_neutral
## 1 0.7279810 0.7438907 1.344284 0.8047483 0.8436372 0.8285359
## 2 0.8849442 0.6881459 1.453180 0.6733857 0.6792392 0.7070098
## 3 0.9512200 0.7026347 1.423215 0.7070980 0.7797117 0.7136950
## 4 0.2649155 0.6663098 1.500803 0.7374192 0.7577417 0.7872392
## 5 0.7612078 0.6742474 1.483135 0.7428754 0.7602723 0.7493119
## 6 0.4505837 0.6699235 1.492708 0.8672715 0.9165751 0.8490002
## B_right_neutral B_left_speed B_right_speed A t0
## 1 0.8568205 0.6007733 0.6544962 0.3326415 0.11728475
## 2 0.7152202 0.4372691 0.4839382 0.3086353 0.13019744
## 3 0.8233317 0.5219825 0.6400104 0.3057428 0.10378461
## 4 0.7791123 0.5582606 0.5846386 0.1722742 0.10862906
## 5 0.7820744 0.5250702 0.5770507 0.2128573 0.11958983
## 6 0.9113578 0.6808935 0.7485422 0.2276435 0.09364553
# Calculate means
<- data.frame(lapply(ps, mean))
pmeans pmeans
## v_accuracy_TRUE v_accuracy_FALSE v_neutral_TRUE v_neutral_FALSE v_speed_TRUE
## 1 2.553057 -0.1260086 2.712327 0.2487697 2.652366
## v_speed_FALSE sv_TRUE sv_FALSE B_left_accuracy B_right_accuracy B_left_neutral
## 1 1.087434 0.7131412 1.404017 0.836204 0.8730531 0.8374889
## B_right_neutral B_left_speed B_right_speed A t0
## 1 0.8846271 0.6237197 0.6834642 0.2959662 0.1008881
Next, we calculate the quality (match-mismatch difference) and quantity (match-mismatch average) of accumulation rates
<- data.frame(
vmeans a_quality = mean(ps$v_accuracy_TRUE - ps$v_accuracy_FALSE),
n_quality = mean(ps$v_neutral_TRUE - ps$v_neutral_FALSE),
s_quality = mean(ps$v_speed_TRUE - ps$v_speed_FALSE),
a_quantity = mean(c(ps$v_accuracy_TRUE, ps$v_accuracy_FALSE)),
n_quantity = mean(c(ps$v_neutral_TRUE, ps$v_neutral_FALSE)),
s_quantity = mean(c(ps$v_speed_TRUE, ps$v_speed_FALSE))
) vmeans
## a_quality n_quality s_quality a_quantity n_quantity s_quantity
## 1 2.679066 2.463557 1.564932 1.213524 1.480548 1.8699
Reshaping this to a long format;
<- vmeans %>% transmute(Accuracy_Quality = a_quality,
QQ Neutral_Quality = n_quality,
Speed_Quality = s_quality,
Accuracy_Quantity = a_quantity,
Neutral_Quantity = n_quantity,
Speed_Quantity = s_quantity) %>%
pivot_longer(cols = everything(),
names_to = c("Emphasis", "Measure"),
names_pattern = "(.*)_(.*)",
values_to = "v")
QQ
## # A tibble: 6 x 3
## Emphasis Measure v
## <chr> <chr> <dbl>
## 1 Accuracy Quality 2.68
## 2 Neutral Quality 2.46
## 3 Speed Quality 1.56
## 4 Accuracy Quantity 1.21
## 5 Neutral Quantity 1.48
## 6 Speed Quantity 1.87
Using the drift rate parameters, we can plot quality and quantity. As our parameter tests above showed, processing quality is poorer in the speed emphasis condition, but quantity is higher. This reflects additional effort or resources deployed in order to respond more quickly, without necessarily improving the quality of processing.
<- ggplot(data = QQ, aes(Emphasis, v, col = Measure)) +
QQ_plot geom_line(aes(group = Measure), lty = "dashed", lwd = 1) +
geom_point(size = 4, shape = 19) +
ylim(0.8, 3) +
theme_minimal() + theme(text = element_text(size = 15))
QQ_plot
Now, let’s look at thresholds;
<- pmeans %>% transmute(Accuracy_Left = B_left_accuracy,
B Accuracy_Right = B_right_accuracy,
Neutral_Left = B_left_neutral,
Neutral_Right = B_right_neutral,
Speed_Left = B_left_speed,
Speed_Right = B_right_speed) %>%
pivot_longer(cols = everything(),
names_to = c("Emphasis", "Accumulator"),
names_pattern = "(.*)_(.*)",
values_to = "B")
B
## # A tibble: 6 x 3
## Emphasis Accumulator B
## <chr> <chr> <dbl>
## 1 Accuracy Left 0.836
## 2 Accuracy Right 0.873
## 3 Neutral Left 0.837
## 4 Neutral Right 0.885
## 5 Speed Left 0.624
## 6 Speed Right 0.683
Plotting separately for left and right accumulators shows the overall bias towards responding ‘left’.
<- ggplot(data = B, aes(Emphasis, B, col = Accumulator)) +
B_plot geom_line(aes(group = Accumulator), lty = "dashed", lwd = 1) +
geom_point(size = 4, shape = 19) +
ylim(0.5, 1) +
theme_minimal() + theme(text = element_text(size = 15))
B_plot
6.2 RDM
The Racing Diffusion Model (RDM) is a model which utilises both the race structure and diffusion model framework. Here, we use a diffusion process towards a single threshold for each accumulator of the model. A grpahical example can be seen below.
6.2.1 RDM in EMC2
To use the RDM, we show the a similar structure as we did for the LBA and LNR. First, let’s prepare our environment.
rm(list=ls())
source("emc/emc.R")
source("models/RACE/RDM/rdmB.R")
print( load("Data/PNAS.RData"))
<- data[,c("s","E","S","R","RT")]
dat names(dat)[c(1,5)] <- c("subjects","rt")
levels(dat$R) <- levels(dat$S)
6.2.2 RDM Model Design
Now we can look at the design for our model. The parameters we specify for the RDM are very similar to the LBA, with v
the mean rate of evidence accumulation, B
the threshold, A
the start point and t0
the non-decision time. We can also include additional variability parameters as is shown below.
In this code, we again show several different types of model designs that vary different parameters. These include a thresholds only model; threshold, drift and t0 model; threshold and t0 model; and a threshold and drift model.
# Average and difference matrix
<- matrix(c(-1/2,1/2),ncol=1,dimnames=list(NULL,"d"))
ADmat
<- matrix(c(0,-1,0,0,0,-1),nrow=3)
Emat dimnames(Emat) <- list(NULL,c("a-n","a-s"))
<- make_design(
design_B Ffactors=list(subjects=levels(dat$subjects),S=levels(dat$S),E=levels(dat$E)),
Rlevels=levels(dat$R),matchfun=function(d)d$S==d$lR,
Clist=list(lM=ADmat,lR=ADmat,S=ADmat,E=Emat),
Flist=list(v~lM,B~lR*E,A~1,t0~1),
model=rdmB)
<- make_design(
design_Bvt0Ffactors=list(subjects=levels(dat$subjects),S=levels(dat$S),E=levels(dat$E)),
Rlevels=levels(dat$R),matchfun=function(d)d$S==d$lR,
Clist=list(lM=ADmat,lR=ADmat,S=ADmat,E=Emat),
Flist=list(v~lM*E,B~lR*E,A~1,t0~E),
model=rdmB)
<- make_design(
design_Bt0Ffactors=list(subjects=levels(dat$subjects),S=levels(dat$S),E=levels(dat$E)),
Rlevels=levels(dat$R),matchfun=function(d)d$S==d$lR,
Clist=list(lM=ADmat,lR=ADmat,S=ADmat,E=Emat),
Flist=list(v~lM,B~lR*E,A~1,t0~E),
model=rdmB)
<- make_design(
design_BvFfactors=list(subjects=levels(dat$subjects),S=levels(dat$S),E=levels(dat$E)),
Rlevels=levels(dat$R),matchfun=function(d)d$S==d$lR,
Clist=list(lM=ADmat,lR=ADmat,S=ADmat,E=Emat),
Flist=list(v~lM*E,B~lR*E,A~1,t0~1),
model=rdmB)
# rdm_B <- make_samplers(dat,design_B,type="standard",rt_resolution=.02)
# rdm_Bvt0<- make_samplers(dat,design_Bvt0,type="standard",rt_resolution=.02)
# rdm_Bt0 <- make_samplers(dat,design_Bt0,type="standard",rt_resolution=.02)
# rdm_Bv <- make_samplers(dat,design_Bv,type="standard",rt_resolution=.02)
#
All of these models are run in a single file, run_rdm.R using the run_emc function. This function is given the name of the file containing the samplers object and any arguments to its constituent functions (run_burn
, run_adapt
and run_sample
). For example the first model was fit with 8 cores per chain and so 24 cores in total given the default of 3 chains.
run_emc(“rdmPNAS_B.RData”,cores_per_chain=8)
If any stage fails run_check stops, saving the progress so far. The only argument unique to this function is nsample, which determines the number of iterations performed if the sample stage is reached (by default 1000).
After the convergence checking reported below extra samples were obtained for some models that converged slowly, so all had 1000 converged samples. This was done by adding another run_emc call with nsamples set appropriately (run_emc recognizes that burn and adapt stages are complete and so just adds on the extra samples at the end).
Finally for the selected model, extra samples were added to obtain 5000 iterations, so posterior inference was reliable, and posterior predictives were obtained. (NB: if the file is run several times some lines must be commented out or unwanted sample stage iteration will be added). First, let’s load the pre-sampled models from the osf.
print(load("~/Desktop/emc2/models/RACE/RDM/examples/samples/rdmPNAS_B.RData"))
## [1] "rdm_B"
print(load("~/Desktop/emc2/models/RACE/RDM/examples/samples/rdmPNAS_Bt0.RData"))
## [1] "rdm_Bt0"
print(load("~/Desktop/emc2/models/RACE/RDM/examples/samples/rdmPNAS_Bv.RData"))
## [1] "rdm_Bv"
print(load("~/Desktop/emc2/models/RACE/RDM/examples/samples/rdmPNAS_Bvt0.RData"))
## [1] "rdm_Bvt0" "pprdm_Bvt0"
Next, we can again do check_run
for each of these models. Remember, running the code below will ask you to press enter across a series of checks.
#### Check convergence ----
check_run(rdm_B)
check_run(rdm_Bt0,subfilter=500)
check_run(rdm_Bv,subfilter=1500)
check_run(rdm_Bvt0,subfilter=1500)
6.2.3 Model selection
Next, we’ll again look at model comparisons using some quick IC measures. First, we’ll start with group level measures.
compare_IC(list(B=rdm_B,Bt0=rdm_Bt0,Bv=rdm_Bv,Bvt0=rdm_Bvt0),
subfilter=list(0,500,1500,1500))
## DIC wDIC BPIC wBPIC EffectiveN meanD Dmean minD
## B -16514 0 -16333 0 180 -16694 -16844 -16874
## Bt0 -16511 0 -16309 0 202 -16714 -16863 -16916
## Bv -16628 0 -16420 1 208 -16836 -16999 -17044
## Bvt0 -16648 1 -16403 0 245 -16893 -17054 -17137
We see here that Bvt0
wins, with Bt0
second across the different RDM models. This is similar to our LBA and DDM examples. Let’s also check this out at the subject level.
<- compare_ICs(list(B=rdm_B,Bt0=rdm_Bt0,Bv=rdm_Bv,Bvt0=rdm_Bvt0),
ICs subfilter=list(0,500,1500,1500:2500))
## wDIC_B wDIC_Bt0 wDIC_Bv wDIC_Bvt0 wBPIC_B wBPIC_Bt0 wBPIC_Bv wBPIC_Bvt0
## as1t 0.123 0.249 0.394 0.234 0.259 0.344 0.297 0.099
## bd6t 0.000 0.000 0.007 0.993 0.000 0.000 0.013 0.987
## bl1t 0.000 0.000 0.000 1.000 0.000 0.000 0.000 1.000
## hsft 0.000 0.001 0.052 0.947 0.002 0.001 0.135 0.862
## hsgt 0.045 0.030 0.244 0.681 0.070 0.033 0.344 0.553
## kd6t 0.232 0.115 0.264 0.389 0.570 0.128 0.202 0.101
## kd9t 0.012 0.030 0.261 0.697 0.035 0.047 0.272 0.645
## kh6t 0.220 0.073 0.679 0.027 0.241 0.015 0.740 0.004
## kmat 0.553 0.396 0.019 0.032 0.647 0.334 0.008 0.011
## ku4t 0.088 0.094 0.445 0.373 0.113 0.110 0.507 0.270
## na1t 0.038 0.032 0.216 0.714 0.112 0.084 0.297 0.507
## rmbt 0.001 0.000 0.745 0.253 0.003 0.000 0.710 0.287
## rt2t 0.063 0.059 0.699 0.179 0.074 0.079 0.718 0.128
## rt3t 0.208 0.683 0.079 0.031 0.150 0.797 0.044 0.009
## rt5t 0.345 0.364 0.208 0.083 0.326 0.431 0.208 0.034
## scat 0.105 0.458 0.151 0.286 0.180 0.704 0.054 0.061
## ta5t 0.017 0.007 0.523 0.453 0.048 0.005 0.545 0.402
## vf1t 0.000 0.000 0.019 0.981 0.000 0.000 0.017 0.983
## zk1t 0.394 0.025 0.452 0.129 0.628 0.002 0.356 0.014
table(unlist(lapply(ICs,function(x){row.names(x)[which.min(x$DIC)]})))
##
## B Bt0 Bv Bvt0
## 1 3 7 8
table(unlist(lapply(ICs,function(x){row.names(x)[which.min(x$BPIC)]})))
##
## B Bt0 Bv Bvt0
## 3 4 5 7
We see similar results here, but at the subject level the Bv
model is second. Let’s now compare these with the best DDM and LBA models.
## DIC wDIC BPIC wBPIC EffectiveN meanD Dmean minD
## DDM_avt0 -17043 0 -16802 0 240 -17283 -17468 -17523
## LBA_Bvsv -17188 1 -16964 1 224 -17412 -17564 -17636
## RDM_Bvt0 -16648 0 -16403 0 245 -16893 -17054 -17137
source("models/DDM/DDM/ddmTZD.R")
load("~/Desktop/emc2/models/DDM/DDM/examples/samples/sPNAS_avt0_full.RData")
source("models/RACE/LBA/lbaB.R")
load("~/Desktop/emc2/models/RACE/LBA/examples/samples/sPNAS_Bv_sv.RData")
compare_IC(list(DDM_avt0=sPNAS_avt0_full,LBA_Bvsv=sPNAS_Bv_sv,RDM_Bvt0=rdm_Bvt0),
subfilter=list(500,2000,1500))
Comparing the “best” RDM with the “best” DDM (16 parameter) and LBA (15 parameter) models, we see that the RDM is the worst out of these three. Let’s look at the model fit and start analysing why this might be.
6.2.4 Model fit
Here we use the plot_fit
on posterior predictive data from the Bvt0
model.
# post predict did not use first 1500, so inference based on 5000*3 samples
plot_fit(dat,pprdm_Bvt0,layout=c(2,3),factors=c("E","S"),lpos="right",xlim=c(.25,1.5))
#plot_fits(dat,pprdm_Bvt0,layout=c(2,3),lpos="right")
The fits seem to be pretty decent. These plots below also show a pretty good fit, with a slight under-estimation of 10th percentile and over-estimation of error RT in speed. Here, we only show these plots where misfit is present.
<- function(d) 100*mean(d$S==d$R)
pc plot_fit(dat,pprdm_Bvt0,layout=c(2,3),factors=c("E","S"),
stat=pc,stat_name="Accuracy (%)",xlim=c(70,95))
<- plot_fit(dat,pprdm_Bvt0,layout=c(2,3),factors=c("E","S"),
tab stat=function(d){mean(d$rt)},stat_name="Mean RT (s)",xlim=c(0.375,.625))
<- plot_fit(dat,pprdm_Bvt0,layout=c(2,3),factors=c("E","S"),xlim=c(0.275,.4),
tab stat=function(d){quantile(d$rt,.1)},stat_name="10th Percentile (s)")
<- plot_fit(dat,pprdm_Bvt0,layout=c(2,3),factors=c("E","S"),xlim=c(0.525,.975),
tab stat=function(d){quantile(d$rt,.9)},stat_name="90th Percentile (s)")
<- plot_fit(dat,pprdm_Bvt0,layout=c(2,3),factors=c("E","S"),
tab stat=function(d){sd(d$rt)},stat_name="SD (s)",xlim=c(0.1,.355))
<- plot_fit(dat,pprdm_Bvt0,layout=c(2,3),factors=c("E","S"),xlim=c(0.375,.725),
tab stat=function(d){mean(d$rt[d$R!=d$S])},stat_name="Mean Error RT (s)")
<- function(d) 100*mean(d$S==d$R)
pc
<- plot_fit(dat,pprdm_Bvt0,layout=c(2,3),factors=c("E","S"),xlim=c(0.275,.4),
tab stat=function(d){quantile(d$rt,.1)},stat_name="10th Percentile (s)")
<- plot_fit(dat,pprdm_Bvt0,layout=c(2,3),factors=c("E","S"),xlim=c(0.375,.725),
tab stat=function(d){mean(d$rt[d$R!=d$S])},stat_name="Mean Error RT (s)")
6.2.5 Posterior parameter inference
Now that we’ve analysed the fit, we can also look at some posterior inference to try and understand whether this model shows any differences to the LBA or DDM. We start by looking at the group level tests. Here we show parameter estimates both with and without mapping.
# Priors all well dominated except some rate parameters
<- plot_density(rdm_Bvt0,layout=c(3,6),selection="mu",subfilter=1500)
cirdm_Bvt0
# On the natural scale it is evident this is because the mismatch (FALSE) rates
# are least well updated, due to the fairly low error rates (errors give the
# most information about FALSE rates).
<- plot_density(rdm_Bvt0,layout=c(3,6),
cirdm_Bvt0_mapped selection="mu",mapped=TRUE)
# Looking at parameters both with and without mapping
round(cirdm_Bvt0,2)
## v v_lMd v_Ea-n v_Ea-s v_lMd:Ea-n v_lMd:Ea-s B B_lRd B_Ea-n B_Ea-s
## 2.5% 0.23 1.20 -0.14 -0.55 -0.05 0.36 -0.17 0.00 -0.05 0.26
## 50% 0.48 1.70 -0.10 -0.37 0.03 0.63 -0.10 0.07 0.01 0.41
## 97.5% 0.74 2.17 -0.06 -0.18 0.11 0.90 -0.02 0.14 0.06 0.55
## B_lRd:Ea-n B_lRd:Ea-s A t0 t0_Ea-n t0_Ea-s
## 2.5% -0.05 -0.13 -1.00 -1.47 0.00 0.04
## 50% -0.02 -0.08 -0.79 -1.43 0.03 0.07
## 97.5% 0.01 -0.02 -0.58 -1.38 0.06 0.10
round(cirdm_Bvt0_mapped,2)
## v_TRUE_accuracy v_FALSE_accuracy v_TRUE_neutral v_FALSE_neutral v_TRUE_speed
## 2.5% 3.11 0.43 3.37 0.46 3.23
## 50% 3.77 0.69 4.09 0.76 3.97
## 97.5% 4.54 1.10 4.92 1.25 4.82
## v_FALSE_speed B_left_accuracy B_right_accuracy B_left_neutral B_right_neutral
## 2.5% 0.93 0.81 0.87 0.78 0.86
## 50% 1.36 0.88 0.94 0.87 0.94
## 97.5% 1.93 0.96 1.02 0.95 1.03
## B_left_speed B_right_speed A t0_accuracy t0_neutral t0_speed
## 2.5% 0.47 0.56 0.36 0.23 0.22 0.21
## 50% 0.56 0.65 0.45 0.24 0.23 0.22
## 97.5% 0.66 0.76 0.56 0.25 0.25 0.23
For simpler estimates: 1) t0 is longer than the LBA 2) Start point noise slightly larger relative to B than for the LBA.
6.2.5.1 B effects
Let’s now check our all important threshold effects. First, recall the mapping used for B
get_map(rdm_Bvt0)$B
## lR E B B_lRd B_Ea-n B_Ea-s B_lRd:Ea-n B_lRd:Ea-s
## 1 left accuracy 1 -0.5 0 0 0.0 0.0
## 7 right accuracy 1 0.5 0 0 0.0 0.0
## 2 left neutral 1 -0.5 -1 0 0.5 0.0
## 8 right neutral 1 0.5 -1 0 -0.5 0.0
## 3 left speed 1 -0.5 0 -1 0.0 0.5
## 9 right speed 1 0.5 0 -1 0.0 -0.5
Now let’s look at B_lRd
which tests threshold right - threshold left
, similar to in the LBA.
p_test(x=rdm_Bvt0,x_name="B_lRd",subfilter=1500,digits=3)
## B_lRd mu
## 2.5% -0.004 NA
## 50% 0.068 0
## 97.5% 0.142 NA
## attr(,"less")
## [1] 0.031
Although not quite credible, it indicates slightly higher right thresholds (i.e., a bias to respond left).
Similar to the LBA, B_Ea-n
and B_Ea-s
measure differences in response caution (i.e., thresholds averaged over left and right accumulators), accuracy - neutral
and accuracy - speed
respectively.
p_test(x=rdm_Bvt0,x_name="B_Ea-n",subfilter=1500)
## B_Ea-n mu
## 2.5% -0.05 NA
## 50% 0.01 0
## 97.5% 0.06 NA
## attr(,"less")
## [1] 0.419
p_test(x=rdm_Bvt0,x_name="B_Ea-s",subfilter=1500)
## B_Ea-s mu
## 2.5% 0.26 NA
## 50% 0.41 0
## 97.5% 0.55 NA
## attr(,"less")
## [1] 0
Caution for accuracy is clearly higher than speed, but not credibly greater than neutral.
Here we construct a test on the natural scale showing caution is greater for neutral than speed;
p_test(x=rdm_Bvt0,mapped=TRUE,x_name="average B: neutral-speed",
x_fun=function(x){mean(x[c("B_left_neutral","B_right_neutral")]) -
mean(x[c("B_left_speed","B_right_speed")])})
## average B: neutral-speed mu
## 2.5% 0.21 NA
## 50% 0.30 0
## 97.5% 0.39 NA
## attr(,"less")
## [1] 0
The remaining term (B_lRd:Ea-s
) tests interactions with bias (i.e., lR), with evidence of a small but credibly stronger bias to respond left (i.e., a lower threshold for the left accumulator) for speed than accuracy.
p_test(x=rdm_Bvt0,x_name="B_lRd:Ea-s",subfilter=1500,digits=2)
## B_lRd:Ea-s mu
## 2.5% -0.13 NA
## 50% -0.08 0
## 97.5% -0.02 NA
## attr(,"less")
## [1] 0.994
6.2.6 v effects
Let’s now check for any drift rate effects. First, let’s look at the mapping used.
get_map(rdm_Bvt0)$v
## lM E v v_lMd v_Ea-n v_Ea-s v_lMd:Ea-n v_lMd:Ea-s
## 1 TRUE accuracy 1 0.5 0 0 0.0 0.0
## 7 FALSE accuracy 1 -0.5 0 0 0.0 0.0
## 2 TRUE neutral 1 0.5 -1 0 -0.5 0.0
## 8 FALSE neutral 1 -0.5 -1 0 0.5 0.0
## 3 TRUE speed 1 0.5 0 -1 0.0 -0.5
## 9 FALSE speed 1 -0.5 0 -1 0.0 0.5
Here, v_Ea-n
and v_Ea-s
indicate that processing rate (the average of matching and mismatching rates) is less in the accuracy condition than in neutral or speed.
p_test(x=rdm_Bvt0,x_name="v_Ea-n",subfilter=1500)
## v_Ea-n mu
## 2.5% -0.14 NA
## 50% -0.10 0
## 97.5% -0.06 NA
## attr(,"less")
## [1] 1
p_test(x=rdm_Bvt0,x_name="v_Ea-s",subfilter=1500)
## v_Ea-s mu
## 2.5% -0.55 NA
## 50% -0.37 0
## 97.5% -0.18 NA
## attr(,"less")
## [1] 1
However, neutral and speed do not credibly differ;
p_test(x=rdm_Bvt0,mapped=TRUE,x_name="average v: speed-neutral",
x_fun=function(x){mean(x[c("v_TRUE_speed","v_FALSE_speed")]) -
mean(x[c("v_TRUE_neutral","v_FALSE_neutral")])})
## average v: speed-neutral mu
## 2.5% -0.06 NA
## 50% 0.23 0
## 97.5% 0.55 NA
## attr(,"less")
## [1] 0.059
v_lMd
tests the “quality” of selective attention, rate match - rate mismatch
.
p_test(x=rdm_Bvt0,x_name="v_lMd",subfilter=1500)
## v_lMd mu
## 2.5% 1.20 NA
## 50% 1.70 0
## 97.5% 2.17 NA
## attr(,"less")
## [1] 0
v_Ea-n
indicates quality does not differ credibly between accuracy and neutral.
p_test(x=rdm_Bvt0,x_name="v_lMd:Ea-n",subfilter=1500)
## v_lMd:Ea-n mu
## 2.5% -0.05 NA
## 50% 0.03 0
## 97.5% 0.11 NA
## attr(,"less")
## [1] 0.196
In contrast there is a strong difference for accuracy - speed;
p_test(x=rdm_Bvt0,x_name="v_lMd:Ea-s",subfilter=1500)
## v_lMd:Ea-s mu
## 2.5% 0.36 NA
## 50% 0.63 0
## 97.5% 0.90 NA
## attr(,"less")
## [1] 0
The neutral - speed difference is also highly credible, here is is tested in the mapped form.
p_test(x=rdm_Bvt0,mapped=TRUE,x_name="quality: accuracy-neutral",
x_fun=function(x){diff(x[c("v_FALSE_neutral","v_TRUE_neutral")]) -
diff(x[c("v_FALSE_speed","v_TRUE_speed")])})
## quality: accuracy-neutral mu
## 2.5% 0.35 NA
## 50% 0.71 0
## 97.5% 1.08 NA
## attr(,"less")
## [1] 0
6.2.6.1 Visualising results
In this section, as we do for the LBA, we’re again going to show some extensions of visualizations, by first extracting the parameter estimates, and then plotting these using ggplot2
. Let’s start by extracting the parameters and checking the means of the posterior.
# Here we visualize these threshold and rate effects
library(tidyverse)
# Get parameter data frame
<- parameters_data_frame(rdm_Bvt0, mapped = TRUE)
ps head(ps)
## v_TRUE_accuracy v_FALSE_accuracy v_TRUE_neutral v_FALSE_neutral v_TRUE_speed
## 1 3.431639 0.3446701 4.239264 0.5468789 3.870593
## 2 3.947793 0.6922556 4.394294 0.9208254 4.211111
## 3 4.058286 0.5966165 4.342919 0.6887796 4.521430
## 4 3.993086 0.4738672 4.664679 0.5177178 4.635995
## 5 3.547141 1.2149620 4.090971 1.4267556 3.506973
## 6 3.148097 0.5603768 3.594237 0.5885173 3.423264
## v_FALSE_speed B_left_accuracy B_right_accuracy B_left_neutral B_right_neutral
## 1 0.7505228 0.7918152 0.8460093 0.8862445 0.9515371
## 2 1.3238674 0.7591425 0.8086740 0.8692756 0.9276422
## 3 1.4160110 0.8000483 0.9496064 0.8030501 0.9474515
## 4 1.2893575 0.8030587 0.8549157 0.7966596 0.8564589
## 5 1.4739013 0.8388881 0.8914065 0.8796424 0.9465314
## 6 1.1172589 0.7788311 0.9010827 0.8365712 0.9730959
## B_left_speed B_right_speed A t0_accuracy t0_neutral t0_speed
## 1 0.4498708 0.5225185 0.5251879 0.2418921 0.2213071 0.2214772
## 2 0.6561390 0.7430251 0.5257231 0.2570650 0.2345159 0.2237344
## 3 0.4949914 0.6179072 0.5172401 0.2495441 0.2367346 0.2313448
## 4 0.5303871 0.5965826 0.5233095 0.2471920 0.2425336 0.2226937
## 5 0.5499901 0.5886816 0.5283719 0.2239879 0.2119343 0.2105091
## 6 0.5314943 0.6575876 0.4881616 0.2417799 0.2354508 0.2254859
# Get means
<- data.frame(lapply(ps, mean))
pmeans pmeans
## v_TRUE_accuracy v_FALSE_accuracy v_TRUE_neutral v_FALSE_neutral v_TRUE_speed
## 1 3.7817 0.705524 4.108446 0.7857492 3.987888
## v_FALSE_speed B_left_accuracy B_right_accuracy B_left_neutral B_right_neutral
## 1 1.377339 0.8803732 0.9419822 0.8660072 0.9425966
## B_left_speed B_right_speed A t0_accuracy t0_neutral t0_speed
## 1 0.5634169 0.6511609 0.4547375 0.239195 0.2331849 0.222763
Next, we look at thresholds by emphasis and accumulator;
<- pmeans %>% transmute(Accuracy_Left = B_left_accuracy,
B Accuracy_Right = B_right_accuracy,
Neutral_Left = B_left_neutral,
Neutral_Right = B_right_neutral,
Speed_Left = B_left_speed,
Speed_Right = B_right_speed) %>%
pivot_longer(cols = everything(),
names_to = c("Emphasis", "Accumulator"),
names_pattern = "(.*)_(.*)",
values_to = "B")
B
## # A tibble: 6 x 3
## Emphasis Accumulator B
## <chr> <chr> <dbl>
## 1 Accuracy Left 0.880
## 2 Accuracy Right 0.942
## 3 Neutral Left 0.866
## 4 Neutral Right 0.943
## 5 Speed Left 0.563
## 6 Speed Right 0.651
We can the plot thresholds
<- ggplot(data = B, aes(Emphasis, B, col = Accumulator)) +
B_plot geom_line(aes(group = Accumulator), lty = "dashed", lwd = 1) +
geom_point(size = 4, shape = 19) +
ylim(0.5, 1) +
theme_minimal() + theme(text = element_text(size = 15))
B_plot
Here, instead we will calculate the difference between thresholds for left and right responses to better illustrate the change in bias across emphasis conditions
<- data.frame(
Bmeans a_bias = mean(ps$B_right_accuracy - ps$B_left_accuracy),
n_bias = mean(ps$B_right_neutral - ps$B_left_neutral),
s_bias = mean(ps$B_right_speed - ps$B_left_speed)
) Bmeans
## a_bias n_bias s_bias
## 1 0.06160906 0.07658941 0.08774396
Now looking at the long format;
<- Bmeans %>% transmute(Accuracy = a_bias,
B_bias Neutral = n_bias,
Speed = s_bias) %>%
pivot_longer(cols = everything(),
names_to = c("Emphasis"),
names_pattern = "(.*)",
values_to = "Bias")
B_bias
## # A tibble: 3 x 2
## Emphasis Bias
## <chr> <dbl>
## 1 Accuracy 0.0616
## 2 Neutral 0.0766
## 3 Speed 0.0877
Plot threshold bias;
<- ggplot(data = B_bias, aes(Emphasis, Bias)) +
B_plot geom_line(aes(group = 1), lty = "dashed", lwd = 1) +
geom_point(size = 4, shape = 19) +
ylim(0, 0.12) +
theme_minimal() + theme(text = element_text(size = 15))
B_plot
Now we will calculate the quality (match-mismatch difference) and quantity (match-mismatch average) of accumulation rates;
<- data.frame(
vmeans a_quality = mean(ps$v_TRUE_accuracy - ps$v_FALSE_accuracy),
n_quality = mean(ps$v_TRUE_neutral - ps$v_FALSE_neutral),
s_quality = mean(ps$v_TRUE_speed - ps$v_FALSE_speed),
a_quantity = mean(c(ps$v_TRUE_accuracy, ps$v_FALSE_accuracy)),
n_quantity = mean(c(ps$v_TRUE_neutral, ps$v_FALSE_neutral)),
s_quantity = mean(c(ps$v_TRUE_speed, ps$v_FALSE_speed))
) vmeans
## a_quality n_quality s_quality a_quantity n_quantity s_quantity
## 1 3.076175 3.322696 2.610549 2.243612 2.447097 2.682614
Let’s now look at our quantile-quantile plots;
<- vmeans %>% transmute(Accuracy_Quality = a_quality,
QQ Neutral_Quality = n_quality,
Speed_Quality = s_quality,
Accuracy_Quantity = a_quantity,
Neutral_Quantity = n_quantity,
Speed_Quantity = s_quantity) %>%
pivot_longer(cols = everything(),
names_to = c("Emphasis", "Measure"),
names_pattern = "(.*)_(.*)",
values_to = "v")
QQ
## # A tibble: 6 x 3
## Emphasis Measure v
## <chr> <chr> <dbl>
## 1 Accuracy Quality 3.08
## 2 Neutral Quality 3.32
## 3 Speed Quality 2.61
## 4 Accuracy Quantity 2.24
## 5 Neutral Quantity 2.45
## 6 Speed Quantity 2.68
Again, we’ll do a QQ plot for quality and quantity. Similar to what we saw with the LBA, quality degrades under speed emphasis but participants deploy more overall resources (quantity) to meet the extra demands of faster responding.
<- ggplot(data = QQ, aes(Emphasis, v, col = Measure)) +
QQ_plot geom_line(aes(group = Measure), lty = "dashed", lwd = 1) +
geom_point(size = 4, shape = 19) +
ylim(1.8, 3.6) +
theme_minimal() + theme(text = element_text(size = 15))
QQ_plot
6.3 LNR
The Lognormal distribution: a distribution whose logarithm is normal.
The log-normal distribution has long history of being used to model RT distribution with the near universal positively skewed shape evident for RT. It is another type of central limit for the product of random variables, xi. The log-normal distribution is similar to a response time distribution, but the log-normal distribution starts at 0, whereas (as we discussed above), response time should begin a bit later than that (maybe around .2 seconds). To overcome this, we can add a shift the the log-normal. For this example we will use the shifted log-normal to model RT distribution:
\(RT ~ shift + Lognormal(meanlog,sdlog)\)
$meanlog/sdlog = mean and sd $ on the log scale
This paper (Heathcote and Love 2012) discusses this history and how the log-normal distribution can arise from different psychological processes such as a “cascade” process where the random variable are the rates of each stage in the cascade. The paper also develops a model of choice, which we will briefly return to in subsequent chapters. The log-normal race model is the most tractable of EMC2’s race models. For now, we will use the shifted log-normal to model RT distribution. For more on the log-normal race model that addresses choice processing see (Rouder et al. 2015).
6.3.1 Theory and Model
First, let’s graphically look at the log-normal distribution;
Again, this looks similar to the response time distributions we saw above. When thinking about how the “model” works, we can take the log of the distribution, which stretches out our distribution to give us something that resembles a normal distribution (which is easy to estimate);
6.3.2 EMC2 for Lognormal Race
Let’s now look at how to specify the LNR using EMC2. A lot of this is similar to the previous race models, but the parameters are noticeably different.
rm(list=ls())
source("emc/emc.R")
source("models/RACE/LNR/lnrMS.R")
print( load("Data/PNAS.RData"))
<- data[,c("s","E","S","R","RT")]
dat names(dat)[c(1,5)] <- c("subjects","rt")
levels(dat$R) <- levels(dat$S)
Let’s specify our contrasts;
# Average and difference matrix
<- matrix(c(-1/2,1/2),ncol=1,dimnames=list(NULL,"d"))
ADmat ADmat
## d
## [1,] -0.5
## [2,] 0.5
<- matrix(c(0,-1,0,0,0,-1),nrow=3)
Emat dimnames(Emat) <- list(NULL,c("a-n","a-s"))
Emat
## a-n a-s
## [1,] 0 0
## [2,] -1 0
## [3,] 0 -1
6.3.3 LNR Designs
Here, we show five different designs, that sequentially build up the parameters. In the first, Mu (i.e., the mean of the distribution) varies by stimulus, emphasis, and latent match. Secondly, we let sigma also vary by latent match. In the third model, let t0 vary by speed-accuracy emphasis. In the fourth model, sigma varies with emphasis and latent match. And finally, for the fifth model, again let t0 vary by emphasis.
It’s important to remember that we do not just start with these designs, these designs were generated by incorporating our hypotheses and then exploring many different models that add in parameters to improve the fit. Evidently, the full model space is quite large, so building up the models this way is a good test - as long as we include alternate models to test against and do not rely just on intuition.
<- make_design(
design_mu Ffactors=list(subjects=levels(dat$subjects),S=levels(dat$S),E=levels(dat$E)),
Rlevels=levels(dat$R),matchfun=function(d)d$S==d$lR,
Clist=list(lM=ADmat,lR=ADmat,E=Emat,S=ADmat),
Flist=list(m~S*E*lM,s~1,t0~1),
model=lnrMS)
## m m_Sd m_Ea-n m_Ea-s m_lMd m_Sd:Ea-n
## 0 0 0 0 0 0
## m_Sd:Ea-s m_Sd:lMd m_Ea-n:lMd m_Ea-s:lMd m_Sd:Ea-n:lMd m_Sd:Ea-s:lMd
## 0 0 0 0 0 0
## s t0
## 0 0
## attr(,"map")
## attr(,"map")$m
## m m_Sd m_Ea-n m_Ea-s m_lMd m_Sd:Ea-n m_Sd:Ea-s m_Sd:lMd m_Ea-n:lMd m_Ea-s:lMd
## 1 1 -0.5 0 0 0.5 0.0 0.0 -0.25 0.0 0.0
## 229 1 -0.5 0 0 -0.5 0.0 0.0 0.25 0.0 0.0
## 39 1 -0.5 -1 0 0.5 0.5 0.0 -0.25 -0.5 0.0
## 267 1 -0.5 -1 0 -0.5 0.5 0.0 0.25 0.5 0.0
## 77 1 -0.5 0 -1 0.5 0.0 0.5 -0.25 0.0 -0.5
## 305 1 -0.5 0 -1 -0.5 0.0 0.5 0.25 0.0 0.5
## 20 1 0.5 0 0 -0.5 0.0 0.0 -0.25 0.0 0.0
## 248 1 0.5 0 0 0.5 0.0 0.0 0.25 0.0 0.0
## 58 1 0.5 -1 0 -0.5 -0.5 0.0 -0.25 0.5 0.0
## 286 1 0.5 -1 0 0.5 -0.5 0.0 0.25 -0.5 0.0
## 96 1 0.5 0 -1 -0.5 0.0 -0.5 -0.25 0.0 0.5
## 324 1 0.5 0 -1 0.5 0.0 -0.5 0.25 0.0 -0.5
## m_Sd:Ea-n:lMd m_Sd:Ea-s:lMd
## 1 0.00 0.00
## 229 0.00 0.00
## 39 0.25 0.00
## 267 -0.25 0.00
## 77 0.00 0.25
## 305 0.00 -0.25
## 20 0.00 0.00
## 248 0.00 0.00
## 58 0.25 0.00
## 286 -0.25 0.00
## 96 0.00 0.25
## 324 0.00 -0.25
##
## attr(,"map")$s
## s
## 1 1
##
## attr(,"map")$t0
## t0
## 1 1
# lnr_mu <- make_samplers(dat,design_mu,type="standard",rt_resolution=.02)
# save(lnr_mu,file="lnrPNAS_mu.RData")
<- make_design(
design_mu_slM Ffactors=list(subjects=levels(dat$subjects),S=levels(dat$S),E=levels(dat$E)),
Rlevels=levels(dat$R),matchfun=function(d)d$S==d$lR,
Clist=list(lM=ADmat,lR=ADmat,E=Emat,S=ADmat),
Flist=list(m~S*E*lM,s~lM,t0~1),
model=lnrMS)
## m m_Sd m_Ea-n m_Ea-s m_lMd m_Sd:Ea-n
## 0 0 0 0 0 0
## m_Sd:Ea-s m_Sd:lMd m_Ea-n:lMd m_Ea-s:lMd m_Sd:Ea-n:lMd m_Sd:Ea-s:lMd
## 0 0 0 0 0 0
## s s_lMd t0
## 0 0 0
## attr(,"map")
## attr(,"map")$m
## m m_Sd m_Ea-n m_Ea-s m_lMd m_Sd:Ea-n m_Sd:Ea-s m_Sd:lMd m_Ea-n:lMd m_Ea-s:lMd
## 1 1 -0.5 0 0 0.5 0.0 0.0 -0.25 0.0 0.0
## 229 1 -0.5 0 0 -0.5 0.0 0.0 0.25 0.0 0.0
## 39 1 -0.5 -1 0 0.5 0.5 0.0 -0.25 -0.5 0.0
## 267 1 -0.5 -1 0 -0.5 0.5 0.0 0.25 0.5 0.0
## 77 1 -0.5 0 -1 0.5 0.0 0.5 -0.25 0.0 -0.5
## 305 1 -0.5 0 -1 -0.5 0.0 0.5 0.25 0.0 0.5
## 20 1 0.5 0 0 -0.5 0.0 0.0 -0.25 0.0 0.0
## 248 1 0.5 0 0 0.5 0.0 0.0 0.25 0.0 0.0
## 58 1 0.5 -1 0 -0.5 -0.5 0.0 -0.25 0.5 0.0
## 286 1 0.5 -1 0 0.5 -0.5 0.0 0.25 -0.5 0.0
## 96 1 0.5 0 -1 -0.5 0.0 -0.5 -0.25 0.0 0.5
## 324 1 0.5 0 -1 0.5 0.0 -0.5 0.25 0.0 -0.5
## m_Sd:Ea-n:lMd m_Sd:Ea-s:lMd
## 1 0.00 0.00
## 229 0.00 0.00
## 39 0.25 0.00
## 267 -0.25 0.00
## 77 0.00 0.25
## 305 0.00 -0.25
## 20 0.00 0.00
## 248 0.00 0.00
## 58 0.25 0.00
## 286 -0.25 0.00
## 96 0.00 0.25
## 324 0.00 -0.25
##
## attr(,"map")$s
## s s_lMd
## 1 1 0.5
## 229 1 -0.5
##
## attr(,"map")$t0
## t0
## 1 1
# lnr_mu_slM <- make_samplers(dat,design_mu_slM,type="standard",rt_resolution=.02)
# save(lnr_mu_slM,file="lnrPNAS_mu_slM.RData")
<- make_design(
design_mu_slM_t0 Ffactors=list(subjects=levels(dat$subjects),S=levels(dat$S),E=levels(dat$E)),
Rlevels=levels(dat$R),matchfun=function(d)d$S==d$lR,
Clist=list(lM=ADmat,lR=ADmat,E=Emat,S=ADmat),
Flist=list(m~S*E*lM,s~lM,t0~E),
model=lnrMS)
## m m_Sd m_Ea-n m_Ea-s m_lMd m_Sd:Ea-n
## 0 0 0 0 0 0
## m_Sd:Ea-s m_Sd:lMd m_Ea-n:lMd m_Ea-s:lMd m_Sd:Ea-n:lMd m_Sd:Ea-s:lMd
## 0 0 0 0 0 0
## s s_lMd t0 t0_Ea-n t0_Ea-s
## 0 0 0 0 0
## attr(,"map")
## attr(,"map")$m
## m m_Sd m_Ea-n m_Ea-s m_lMd m_Sd:Ea-n m_Sd:Ea-s m_Sd:lMd m_Ea-n:lMd m_Ea-s:lMd
## 1 1 -0.5 0 0 0.5 0.0 0.0 -0.25 0.0 0.0
## 229 1 -0.5 0 0 -0.5 0.0 0.0 0.25 0.0 0.0
## 39 1 -0.5 -1 0 0.5 0.5 0.0 -0.25 -0.5 0.0
## 267 1 -0.5 -1 0 -0.5 0.5 0.0 0.25 0.5 0.0
## 77 1 -0.5 0 -1 0.5 0.0 0.5 -0.25 0.0 -0.5
## 305 1 -0.5 0 -1 -0.5 0.0 0.5 0.25 0.0 0.5
## 20 1 0.5 0 0 -0.5 0.0 0.0 -0.25 0.0 0.0
## 248 1 0.5 0 0 0.5 0.0 0.0 0.25 0.0 0.0
## 58 1 0.5 -1 0 -0.5 -0.5 0.0 -0.25 0.5 0.0
## 286 1 0.5 -1 0 0.5 -0.5 0.0 0.25 -0.5 0.0
## 96 1 0.5 0 -1 -0.5 0.0 -0.5 -0.25 0.0 0.5
## 324 1 0.5 0 -1 0.5 0.0 -0.5 0.25 0.0 -0.5
## m_Sd:Ea-n:lMd m_Sd:Ea-s:lMd
## 1 0.00 0.00
## 229 0.00 0.00
## 39 0.25 0.00
## 267 -0.25 0.00
## 77 0.00 0.25
## 305 0.00 -0.25
## 20 0.00 0.00
## 248 0.00 0.00
## 58 0.25 0.00
## 286 -0.25 0.00
## 96 0.00 0.25
## 324 0.00 -0.25
##
## attr(,"map")$s
## s s_lMd
## 1 1 0.5
## 229 1 -0.5
##
## attr(,"map")$t0
## t0 t0_Ea-n t0_Ea-s
## 1 1 0 0
## 39 1 -1 0
## 77 1 0 -1
# lnr_mu_slM_t0 <- make_samplers(dat,design_mu_slM_t0,type="standard",rt_resolution=.02)
# save(lnr_mu_slM_t0,file="lnrPNAS_mu_slM_t0.RData")
<- make_design(
design_mu_sElM Ffactors=list(subjects=levels(dat$subjects),S=levels(dat$S),E=levels(dat$E)),
Rlevels=levels(dat$R),matchfun=function(d)d$S==d$lR,
Clist=list(lM=ADmat,lR=ADmat,E=Emat,S=ADmat),
Flist=list(m~S*E*lM,s~E*lM,t0~1),
model=lnrMS)
## m m_Sd m_Ea-n m_Ea-s m_lMd m_Sd:Ea-n
## 0 0 0 0 0 0
## m_Sd:Ea-s m_Sd:lMd m_Ea-n:lMd m_Ea-s:lMd m_Sd:Ea-n:lMd m_Sd:Ea-s:lMd
## 0 0 0 0 0 0
## s s_Ea-n s_Ea-s s_lMd s_Ea-n:lMd s_Ea-s:lMd
## 0 0 0 0 0 0
## t0
## 0
## attr(,"map")
## attr(,"map")$m
## m m_Sd m_Ea-n m_Ea-s m_lMd m_Sd:Ea-n m_Sd:Ea-s m_Sd:lMd m_Ea-n:lMd m_Ea-s:lMd
## 1 1 -0.5 0 0 0.5 0.0 0.0 -0.25 0.0 0.0
## 229 1 -0.5 0 0 -0.5 0.0 0.0 0.25 0.0 0.0
## 39 1 -0.5 -1 0 0.5 0.5 0.0 -0.25 -0.5 0.0
## 267 1 -0.5 -1 0 -0.5 0.5 0.0 0.25 0.5 0.0
## 77 1 -0.5 0 -1 0.5 0.0 0.5 -0.25 0.0 -0.5
## 305 1 -0.5 0 -1 -0.5 0.0 0.5 0.25 0.0 0.5
## 20 1 0.5 0 0 -0.5 0.0 0.0 -0.25 0.0 0.0
## 248 1 0.5 0 0 0.5 0.0 0.0 0.25 0.0 0.0
## 58 1 0.5 -1 0 -0.5 -0.5 0.0 -0.25 0.5 0.0
## 286 1 0.5 -1 0 0.5 -0.5 0.0 0.25 -0.5 0.0
## 96 1 0.5 0 -1 -0.5 0.0 -0.5 -0.25 0.0 0.5
## 324 1 0.5 0 -1 0.5 0.0 -0.5 0.25 0.0 -0.5
## m_Sd:Ea-n:lMd m_Sd:Ea-s:lMd
## 1 0.00 0.00
## 229 0.00 0.00
## 39 0.25 0.00
## 267 -0.25 0.00
## 77 0.00 0.25
## 305 0.00 -0.25
## 20 0.00 0.00
## 248 0.00 0.00
## 58 0.25 0.00
## 286 -0.25 0.00
## 96 0.00 0.25
## 324 0.00 -0.25
##
## attr(,"map")$s
## s s_Ea-n s_Ea-s s_lMd s_Ea-n:lMd s_Ea-s:lMd
## 1 1 0 0 0.5 0.0 0.0
## 229 1 0 0 -0.5 0.0 0.0
## 39 1 -1 0 0.5 -0.5 0.0
## 267 1 -1 0 -0.5 0.5 0.0
## 77 1 0 -1 0.5 0.0 -0.5
## 305 1 0 -1 -0.5 0.0 0.5
##
## attr(,"map")$t0
## t0
## 1 1
# lnr_mu_sElM <- make_samplers(dat,design_mu_sElM,type="standard",rt_resolution=.02)
# save(lnr_mu_sElM,file="lnrPNAS_mu_sElM.RData")
<- make_design(
design_mu_sElM_t0 Ffactors=list(subjects=levels(dat$subjects),S=levels(dat$S),E=levels(dat$E)),
Rlevels=levels(dat$R),matchfun=function(d)d$S==d$lR,
Clist=list(lM=ADmat,lR=ADmat,E=Emat,S=ADmat),
Flist=list(m~S*E*lM,s~E*lM,t0~E),
model=lnrMS)
## m m_Sd m_Ea-n m_Ea-s m_lMd m_Sd:Ea-n
## 0 0 0 0 0 0
## m_Sd:Ea-s m_Sd:lMd m_Ea-n:lMd m_Ea-s:lMd m_Sd:Ea-n:lMd m_Sd:Ea-s:lMd
## 0 0 0 0 0 0
## s s_Ea-n s_Ea-s s_lMd s_Ea-n:lMd s_Ea-s:lMd
## 0 0 0 0 0 0
## t0 t0_Ea-n t0_Ea-s
## 0 0 0
## attr(,"map")
## attr(,"map")$m
## m m_Sd m_Ea-n m_Ea-s m_lMd m_Sd:Ea-n m_Sd:Ea-s m_Sd:lMd m_Ea-n:lMd m_Ea-s:lMd
## 1 1 -0.5 0 0 0.5 0.0 0.0 -0.25 0.0 0.0
## 229 1 -0.5 0 0 -0.5 0.0 0.0 0.25 0.0 0.0
## 39 1 -0.5 -1 0 0.5 0.5 0.0 -0.25 -0.5 0.0
## 267 1 -0.5 -1 0 -0.5 0.5 0.0 0.25 0.5 0.0
## 77 1 -0.5 0 -1 0.5 0.0 0.5 -0.25 0.0 -0.5
## 305 1 -0.5 0 -1 -0.5 0.0 0.5 0.25 0.0 0.5
## 20 1 0.5 0 0 -0.5 0.0 0.0 -0.25 0.0 0.0
## 248 1 0.5 0 0 0.5 0.0 0.0 0.25 0.0 0.0
## 58 1 0.5 -1 0 -0.5 -0.5 0.0 -0.25 0.5 0.0
## 286 1 0.5 -1 0 0.5 -0.5 0.0 0.25 -0.5 0.0
## 96 1 0.5 0 -1 -0.5 0.0 -0.5 -0.25 0.0 0.5
## 324 1 0.5 0 -1 0.5 0.0 -0.5 0.25 0.0 -0.5
## m_Sd:Ea-n:lMd m_Sd:Ea-s:lMd
## 1 0.00 0.00
## 229 0.00 0.00
## 39 0.25 0.00
## 267 -0.25 0.00
## 77 0.00 0.25
## 305 0.00 -0.25
## 20 0.00 0.00
## 248 0.00 0.00
## 58 0.25 0.00
## 286 -0.25 0.00
## 96 0.00 0.25
## 324 0.00 -0.25
##
## attr(,"map")$s
## s s_Ea-n s_Ea-s s_lMd s_Ea-n:lMd s_Ea-s:lMd
## 1 1 0 0 0.5 0.0 0.0
## 229 1 0 0 -0.5 0.0 0.0
## 39 1 -1 0 0.5 -0.5 0.0
## 267 1 -1 0 -0.5 0.5 0.0
## 77 1 0 -1 0.5 0.0 -0.5
## 305 1 0 -1 -0.5 0.0 0.5
##
## attr(,"map")$t0
## t0 t0_Ea-n t0_Ea-s
## 1 1 0 0
## 39 1 -1 0
## 77 1 0 -1
# lnr_mu_sElM_t0 <- make_samplers(dat,design_mu_sElM_t0,type="standard",rt_resolution=.02)
# save(lnr_mu_sElM_t0,file="lnrPNAS_mu_sElM_t0.RData")
Let’s load in the presampled models.
# Load saved samples
print(load("~/Desktop/emc2/models/RACE/LNR/examples/samples/lnrPNAS_mu.RData"))
## [1] "lnr_mu"
print(load("~/Desktop/emc2/models/RACE/LNR/examples/samples/lnrPNAS_mu_slM.RData"))
## [1] "lnr_mu_slM"
print(load("~/Desktop/emc2/models/RACE/LNR/examples/samples/lnrPNAS_mu_slM_t0.RData"))
## [1] "lnr_mu_slM_t0"
print(load("~/Desktop/emc2/models/RACE/LNR/examples/samples/lnrPNAS_mu_sElM.RData"))
## [1] "lnr_mu_sElM"
print(load("~/Desktop/emc2/models/RACE/LNR/examples/samples/lnrPNAS_mu_sElM_t0.RData"))
## [1] "lnr_mu_sElM_t0" "pplnr_musElMt0"
Again we can conduct our sampling checks, pressing ‘Enter’ for each model check;
# Sampling checks
check_run(lnr_mu,layout=c(3,5),subfilter=500)
check_run(lnr_mu_slM,layout=c(3,5),subfilter=500)
check_run(lnr_mu_slM_t0,layout=c(3,5),subfilter=1000)
check_run(lnr_mu_sElM,layout=c(3,5),subfilter=1500)
check_run(lnr_mu_sElM_t0,layout=c(3,5),subfilter=2000:3000)
6.3.3.0.1 Model selection
For the LNR, we can now compare the models using IC methods. Here we see that muElMt0
wins by DIC but mulMt0
wins by BPIC;
compare_IC(list(mu=lnr_mu,mulM=lnr_mu_slM,mulMt0=lnr_mu_slM_t0,
muElM=lnr_mu_sElM,muElMt0=lnr_mu_sElM_t0), subfilter=list(500,500,1000,1500,2000))
## DIC wDIC BPIC wBPIC EffectiveN meanD Dmean minD
## mu -15080 0 -14869 0 211 -15290 -15451 -15501
## mulM -16840 0 -16633 0 207 -17047 -17217 -17254
## mulMt0 -17102 0 -16879 1 223 -17325 -17509 -17548
## muElM -17053 0 -16809 0 245 -17298 -17501 -17542
## muElMt0 -17129 1 -16846 0 283 -17411 -17609 -17694
# On an individual basis muElMt0 also wins
<- compare_ICs(list(mu=lnr_mu,mulM=lnr_mu_slM,mulMt0=lnr_mu_slM_t0,
ICs muElM=lnr_mu_sElM,muElMt0=lnr_mu_sElM_t0), subfilter=list(0,0,0,500,1000))
## wDIC_mu wDIC_mulM wDIC_mulMt0 wDIC_muElM wDIC_muElMt0 wBPIC_mu wBPIC_mulM
## as1t 0 0.003 0.657 0.102 0.239 0 0.003
## bd6t 0 0.020 0.165 0.002 0.814 0 0.121
## bl1t 0 0.000 0.210 0.000 0.789 0 0.000
## hsft 0 0.000 0.188 0.037 0.775 0 0.000
## hsgt 0 0.001 0.042 0.000 0.956 0 0.021
## kd6t 0 0.000 0.138 0.118 0.745 0 0.000
## kd9t 0 0.000 0.081 0.012 0.908 0 0.000
## kh6t 0 0.000 0.002 0.955 0.043 0 0.000
## kmat 0 0.001 0.005 0.807 0.187 0 0.002
## ku4t 0 0.027 0.299 0.662 0.012 0 0.061
## na1t 0 0.005 0.013 0.001 0.980 0 0.017
## rmbt 0 0.000 0.070 0.154 0.776 0 0.000
## rt2t 0 0.000 0.745 0.078 0.177 0 0.000
## rt3t 0 0.665 0.209 0.087 0.039 0 0.880
## rt5t 0 0.004 0.162 0.478 0.357 0 0.006
## scat 0 0.000 0.097 0.275 0.627 0 0.001
## ta5t 0 0.000 0.460 0.449 0.090 0 0.000
## vf1t 0 0.000 0.658 0.000 0.342 0 0.000
## zk1t 0 0.000 0.001 0.172 0.827 0 0.000
## wBPIC_mulMt0 wBPIC_muElM wBPIC_muElMt0
## as1t 0.766 0.066 0.165
## bd6t 0.544 0.001 0.333
## bl1t 0.687 0.000 0.312
## hsft 0.204 0.043 0.753
## hsgt 0.591 0.004 0.384
## kd6t 0.255 0.195 0.550
## kd9t 0.196 0.017 0.787
## kh6t 0.003 0.981 0.016
## kmat 0.002 0.908 0.088
## ku4t 0.410 0.528 0.001
## na1t 0.030 0.002 0.951
## rmbt 0.081 0.211 0.708
## rt2t 0.928 0.033 0.039
## rt3t 0.079 0.030 0.010
## rt5t 0.173 0.286 0.536
## scat 0.282 0.456 0.262
## ta5t 0.432 0.531 0.038
## vf1t 0.940 0.000 0.060
## zk1t 0.003 0.288 0.709
sort(table(unlist(lapply(ICs,function(x){row.names(x)[which.min(x$DIC)]}))))
##
## mulM muElM mulMt0 muElMt0
## 1 4 4 10
sort(table(unlist(lapply(ICs,function(x){row.names(x)[which.min(x$BPIC)]}))))
##
## mulM muElM mulMt0 muElMt0
## 1 5 6 7
Let’s now compare the RDM with the best DDM (16 parameter) model, the best (15 parameter) LBA model and the best (16 parameter) RDM. The best LNR model included 21 parameters - muElMt0
. For the comparison, we see that the LNR comes in second.
## [1] "ppPNAS_avt0_full" "sPNAS_avt0_full"
## [1] "ppPNAS_Bv_sv" "sPNAS_Bv_sv"
## [1] "rdm_Bvt0" "pprdm_Bvt0"
## DIC wDIC BPIC wBPIC EffectiveN meanD Dmean minD
## DDM_avt0 -17043 0 -16802 0 240 -17283 -17468 -17523
## LBA_Bvsv -17188 1 -16964 1 224 -17412 -17564 -17636
## RDM_Bvt0 -16648 0 -16403 0 245 -16893 -17054 -17137
## LNRmulMt0 -17129 0 -16846 0 283 -17411 -17609 -17694
source("models/DDM/DDM/ddmTZD.R")
source("models/RACE/LBA/lbaB.R")
source("models/RACE/RDM/rdmB.R")
print(load("~/Desktop/emc2/models/DDM/DDM/examples/samples/sPNAS_avt0_full.RData"))
print(load("~/Desktop/emc2/models/RACE/LBA/examples/samples/sPNAS_Bv_sv.RData"))
print(load("~/Desktop/emc2/models/RACE/RDM/examples/samples/rdmPNAS_Bvt0.RData"))
compare_IC(list(DDM_avt0=sPNAS_avt0_full,LBA_Bvsv=sPNAS_Bv_sv,RDM_Bvt0=rdm_Bvt0,
LNRmulMt0=lnr_mu_sElM_t0),subfilter=list(500,2000,1500,2000))
Here we add in the version of the winning DDM model that did not use cell coding. We see that there is very little effect on the ICs;
print(load("~/Desktop/emc2/models/DDM/DDM/examples/samples/sPNAS_avt0_full_nocell.RData"))
## [1] "sPNAS_avt0_full_nocell"
compare_IC(list(DDM_avt0=sPNAS_avt0_full_nocell,LBA_Bvsv=sPNAS_Bv_sv,RDM_Bvt0=rdm_Bvt0,
LNRmulMt0=lnr_mu_sElM_t0),subfilter=list(500,2000,1500,2000))
## DIC wDIC BPIC wBPIC EffectiveN meanD Dmean minD
## DDM_avt0 -17039 0 -16806 0 233 -17271 -17449 -17504
## LBA_Bvsv -17188 1 -16964 1 224 -17412 -17564 -17636
## RDM_Bvt0 -16648 0 -16403 0 245 -16893 -17054 -17137
## LNRmulMt0 -17129 0 -16846 0 283 -17411 -17609 -17694
Now let’s check the fit of the winning (E on mu, sigma and t0) LNR model.
# post predict did not use first 2000, so inference based on 5000*3 samples
plot_fit(dat,pplnr_musElMt0,layout=c(2,3),factors=c("E","S"),lpos="right",xlim=c(.25,1.5))
#plot_fits(dat,pplnr_musElMt0,layout=c(2,3),lpos="right")
We see this is a very accurate fit! You can look at some more fit plots by using the code below.
<- function(d) 100*mean(d$S==d$R)
pc plot_fit(dat,pplnr_musElMt0,layout=c(2,3),factors=c("E","S"),
stat=pc,stat_name="Accuracy (%)",xlim=c(70,95))
<- plot_fit(dat,pplnr_musElMt0,layout=c(2,3),factors=c("E","S"),
tab stat=function(d){mean(d$rt)},stat_name="Mean RT (s)",xlim=c(0.375,.625))
<- plot_fit(dat,pplnr_musElMt0,layout=c(2,3),factors=c("E","S"),xlim=c(0.275,.4),
tab stat=function(d){quantile(d$rt,.1)},stat_name="10th Percentile (s)")
<- plot_fit(dat,pplnr_musElMt0,layout=c(2,3),factors=c("E","S"),xlim=c(0.525,.975),
tab stat=function(d){quantile(d$rt,.9)},stat_name="90th Percentile (s)")
<- plot_fit(dat,pplnr_musElMt0,layout=c(2,3),factors=c("E","S"),
tab stat=function(d){sd(d$rt)},stat_name="SD (s)",xlim=c(0.1,.355))
<- plot_fit(dat,pplnr_musElMt0,layout=c(2,3),factors=c("E","S"),xlim=c(0.375,.725),
tab stat=function(d){mean(d$rt[d$R!=d$S])},stat_name="Mean Error RT (s)")
6.3.3.1 Posterior parameter inference
First, let’s look at the population mean (mu) tests, where we see that the priors all well dominated ;
<- plot_density(lnr_mu_sElM_t0,layout=c(2,3),selection="mu",subfilter=2000) cilnr_mu_sElM_t0
# On the natural scale it is evident this is because the mismatch (FALSE) rates
# are least well updated, due to the fairly low error rates (errors give the
# most information about FALSE rates).
<- plot_density(lnr_mu_sElM_t0,layout=c(2,3),subfilter=2000,
cilnr_mu_sElM_t0_mapped selection="mu",mapped=TRUE)
# Looking at parameters both with and without mapping
round(cilnr_mu_sElM_t0,2)
## m m_Sd m_Ea-n m_Ea-s m_lMd m_Sd:Ea-n m_Sd:Ea-s m_Sd:lMd m_Ea-n:lMd
## 2.5% -0.85 -0.08 0.04 0.36 -1.75 -0.09 -0.04 0.07 -0.21
## 50% -0.69 -0.05 0.09 0.54 -1.41 -0.05 0.00 0.23 -0.14
## 97.5% -0.53 -0.02 0.15 0.71 -1.06 -0.02 0.04 0.39 -0.08
## m_Ea-s:lMd m_Sd:Ea-n:lMd m_Sd:Ea-s:lMd s s_Ea-n s_Ea-s s_lMd s_Ea-n:lMd
## 2.5% -0.75 -0.03 -0.24 -0.46 0.07 -0.03 -0.73 -0.04
## 50% -0.56 0.05 -0.12 -0.37 0.10 0.05 -0.60 0.02
## 97.5% -0.37 0.14 0.01 -0.29 0.13 0.11 -0.46 0.08
## s_Ea-s:lMd t0 t0_Ea-n t0_Ea-s
## 2.5% -0.09 -1.41 0.06 0.14
## 50% -0.02 -1.36 0.08 0.17
## 97.5% 0.05 -1.30 0.10 0.21
round(cilnr_mu_sElM_t0_mapped,2)
## m_left_accuracy_TRUE m_left_accuracy_FALSE m_left_neutral_TRUE
## 2.5% -1.59 -0.21 -1.63
## 50% -1.43 0.10 -1.46
## 97.5% -1.26 0.40 -1.29
## m_left_neutral_FALSE m_left_speed_TRUE m_left_speed_FALSE
## 2.5% -0.38 -1.90 -0.94
## 50% -0.10 -1.72 -0.69
## 97.5% 0.17 -1.53 -0.44
## m_right_accuracy_FALSE m_right_accuracy_TRUE m_right_neutral_FALSE
## 2.5% -0.36 -1.53 -0.46
## 50% -0.07 -1.37 -0.19
## 97.5% 0.21 -1.20 0.07
## m_right_neutral_TRUE m_right_speed_FALSE m_right_speed_TRUE s_accuracy_TRUE
## 2.5% -1.53 -1.16 -1.78 0.46
## 50% -1.37 -0.92 -1.60 0.51
## 97.5% -1.21 -0.68 -1.40 0.56
## s_accuracy_FALSE s_neutral_TRUE s_neutral_FALSE s_speed_TRUE s_speed_FALSE
## 2.5% 0.82 0.41 0.74 0.44 0.77
## 50% 0.93 0.46 0.85 0.49 0.88
## 97.5% 1.04 0.50 0.97 0.55 1.00
## t0_accuracy t0_neutral t0_speed
## 2.5% 0.24 0.22 0.20
## 50% 0.26 0.24 0.22
## 97.5% 0.27 0.25 0.23
Let’s remember the mapping used;
get_map(lnr_mu_sElM_t0)$m
## S E lM m m_Sd m_Ea-n m_Ea-s m_lMd m_Sd:Ea-n m_Sd:Ea-s m_Sd:lMd
## 1 left accuracy TRUE 1 -0.5 0 0 0.5 0.0 0.0 -0.25
## 7 left accuracy FALSE 1 -0.5 0 0 -0.5 0.0 0.0 0.25
## 2 left neutral TRUE 1 -0.5 -1 0 0.5 0.5 0.0 -0.25
## 8 left neutral FALSE 1 -0.5 -1 0 -0.5 0.5 0.0 0.25
## 3 left speed TRUE 1 -0.5 0 -1 0.5 0.0 0.5 -0.25
## 9 left speed FALSE 1 -0.5 0 -1 -0.5 0.0 0.5 0.25
## 4 right accuracy FALSE 1 0.5 0 0 -0.5 0.0 0.0 -0.25
## 10 right accuracy TRUE 1 0.5 0 0 0.5 0.0 0.0 0.25
## 5 right neutral FALSE 1 0.5 -1 0 -0.5 -0.5 0.0 -0.25
## 11 right neutral TRUE 1 0.5 -1 0 0.5 -0.5 0.0 0.25
## 6 right speed FALSE 1 0.5 0 -1 -0.5 0.0 -0.5 -0.25
## 12 right speed TRUE 1 0.5 0 -1 0.5 0.0 -0.5 0.25
## m_Ea-n:lMd m_Ea-s:lMd m_Sd:Ea-n:lMd m_Sd:Ea-s:lMd
## 1 0.0 0.0 0.00 0.00
## 7 0.0 0.0 0.00 0.00
## 2 -0.5 0.0 0.25 0.00
## 8 0.5 0.0 -0.25 0.00
## 3 0.0 -0.5 0.00 0.25
## 9 0.0 0.5 0.00 -0.25
## 4 0.0 0.0 0.00 0.00
## 10 0.0 0.0 0.00 0.00
## 5 0.5 0.0 0.25 0.00
## 11 -0.5 0.0 -0.25 0.00
## 6 0.0 0.5 0.00 0.25
## 12 0.0 -0.5 0.00 -0.25
lMd
tests match minus mismatch, which is strongly negative, as the match racer is much faster than the mismatch racer.
p_test(x=lnr_mu_sElM_t0,x_name="m_lMd",subfilter=2000)
## m_lMd mu
## 2.5% -1.75 NA
## 50% -1.41 0
## 97.5% -1.06 NA
## attr(,"less")
## [1] 1
m_Sd
tests main effect of stimulus (the mean for (right - left), and indicates a smaller mean (faster processing) for right (-.92) than left (-0.88).
p_test(x=lnr_mu_sElM_t0,x_name="m_Sd",subfilter=2000)
## m_Sd mu
## 2.5% -0.08 NA
## 50% -0.05 0
## 97.5% -0.02 NA
## attr(,"less")
## [1] 0.999
m_Sd:lMd
tests right(match-mismatch) - left(match-mismatch) which is positive, indicating better discrimination for right than left. Rearranging this is also (right_match+left_mismatch) - (left_match+right_mismatch) = right accumulator - left accumulator
, so it is also a measure of response bias. The positive value indicates a bias to respond left (i.e., a lesser time for the left racer to finish). These two interpretations cannot be disambiguated from LNR parameter estimates.
p_test(x=lnr_mu_sElM_t0,x_name="m_Sd:lMd",subfilter=2000)
## m_Sd:lMd mu
## 2.5% 0.07 NA
## 50% 0.23 0
## 97.5% 0.39 NA
## attr(,"less")
## [1] 0.003
m_Ea-n
and m_Ea-s
measure differences the time overall race time between accuracy and neutral/speed. Both are positive indicating the race time is slowest for accuracy.
p_test(x=lnr_mu_sElM_t0,x_name="m_Ea-n",subfilter=2000)
## m_Ea-n mu
## 2.5% 0.04 NA
## 50% 0.09 0
## 97.5% 0.15 NA
## attr(,"less")
## [1] 0.001
p_test(x=lnr_mu_sElM_t0,x_name="m_Ea-s",subfilter=2000)
## m_Ea-s mu
## 2.5% 0.36 NA
## 50% 0.54 0
## 97.5% 0.71 NA
## attr(,"less")
## [1] 0
We can test neutral - speed
as follows, showing speed is quicker than neutral;
p_test(x=lnr_mu_sElM_t0,x_name="m_Ea-s",y=lnr_mu_sElM_t0,y_name="m_Ea-n",subfilter=2000)
## m_Ea-s m_Ea-n m_Ea-s-m_Ea-n
## 2.5% 0.36 0.04 0.30
## 50% 0.54 0.09 0.45
## 97.5% 0.71 0.15 0.59
## attr(,"less")
## [1] 0
We will not look at the remaining interactions here sigma effects. Again recall the map used with;
get_map(lnr_mu_sElM_t0)$s
## E lM s s_Ea-n s_Ea-s s_lMd s_Ea-n:lMd s_Ea-s:lMd
## 1 accuracy TRUE 1 0 0 0.5 0.0 0.0
## 7 accuracy FALSE 1 0 0 -0.5 0.0 0.0
## 2 neutral TRUE 1 -1 0 0.5 -0.5 0.0
## 8 neutral FALSE 1 -1 0 -0.5 0.5 0.0
## 3 speed TRUE 1 0 -1 0.5 0.0 -0.5
## 9 speed FALSE 1 0 -1 -0.5 0.0 0.5
This gives the overall mean on the natural scale.
p_test(x=lnr_mu_sElM_t0,x_name="sigma",subfilter=2000,x_fun=function(x){exp(x["s"])})
## sigma mu
## 2.5% 0.63 NA
## 50% 0.69 0
## 97.5% 0.75 NA
## attr(,"less")
## [1] 0
s_Ea-n
and s_Ea-s
show sigma is credibly greater for accuracy than neutral, but not for speed.
p_test(x=lnr_mu_sElM_t0,x_name="s_Ea-n",subfilter=2000)
## s_Ea-n mu
## 2.5% 0.07 NA
## 50% 0.10 0
## 97.5% 0.13 NA
## attr(,"less")
## [1] 0
p_test(x=lnr_mu_sElM_t0,x_name="s_Ea-s",subfilter=2000)
## s_Ea-s mu
## 2.5% -0.03 NA
## 50% 0.05 0
## 97.5% 0.11 NA
## attr(,"less")
## [1] 0.098
Sigma is substantially less for match than mismatch;
p_test(x=lnr_mu_sElM_t0,x_name="s_lMd",subfilter=2000)
## s_lMd mu
## 2.5% -0.73 NA
## 50% -0.60 0
## 97.5% -0.46 NA
## attr(,"less")
## [1] 1
s_Ea-n:lMd
and s_Ea-s:lMd
(interactions) show no credible differences in the match vs. mismatch difference between accuracy and neutral or speed, suggesting an additive model would be better (E+lM
).
p_test(x=lnr_mu_sElM_t0,x_name="s_Ea-n:lMd",subfilter=2000)
## s_Ea-n:lMd mu
## 2.5% -0.04 NA
## 50% 0.02 0
## 97.5% 0.08 NA
## attr(,"less")
## [1] 0.213
p_test(x=lnr_mu_sElM_t0,x_name="s_Ea-s:lMd",subfilter=2000)
## s_Ea-s:lMd mu
## 2.5% -0.09 NA
## 50% -0.02 0
## 97.5% 0.05 NA
## attr(,"less")
## [1] 0.72
Looking at t0
effects, first recall the map used with;
get_map(lnr_mu_sElM_t0)$t0
## t0 t0_Ea-n t0_Ea-s
## 1 1 1 0 0
## 39 2 1 -1 0
## 77 3 1 0 -1
From the tables we see that t0 for accuracy (0.26s) is credibly greater than for neutral and speed. The following test shows that neutral is credibly greater than speed.
p_test(mapped=TRUE,subfilter=2000,x=lnr_mu_sElM_t0,x_name="t0_neutral",
y=lnr_mu_sElM_t0,y_name="t0_speed")
## t0_neutral t0_speed t0_neutral-t0_speed
## 2.5% 0.22 0.20 0.01
## 50% 0.24 0.22 0.02
## 97.5% 0.25 0.23 0.03
## attr(,"less")
## [1] 0
p_test(mapped=TRUE,subfilter=2000,x=lnr_mu_sElM_t0,x_name="t0_accuracy",
y=lnr_mu_sElM_t0,y_name="t0_neutral")
## t0_accuracy t0_neutral t0_accuracy-t0_neutral
## 2.5% 0.24 0.22 0.01
## 50% 0.26 0.24 0.02
## 97.5% 0.27 0.25 0.02
## attr(,"less")
## [1] 0
6.3.3.2 Visualising results
As we do above, we’re again going to show some extensions of visualizations, by first extracting the parameter estimates, and then plotting these using ggplot2
. Let’s start by extracting the parameters and checking the means of the posterior.
# Make parameter plots
library(tidyverse)
# Get parameter data frame
<- parameters_data_frame(lnr_mu_sElM_t0, mapped = TRUE)
ps head(ps)
## m_left_accuracy_TRUE m_left_accuracy_FALSE m_left_neutral_TRUE
## 1 -1.428823 -0.05764236 -1.439785
## 2 -1.364566 -0.15423333 -1.384132
## 3 -1.461074 -0.08887203 -1.524404
## 4 -1.279325 -0.02028169 -1.349081
## 5 -1.466642 -0.07482722 -1.446334
## 6 -1.440625 0.14385488 -1.504156
## m_left_neutral_FALSE m_left_speed_TRUE m_left_speed_FALSE m_right_accuracy_FALSE
## 1 -0.21603425 -1.869920 -0.6965596 -0.12567363
## 2 -0.28652571 -1.757259 -0.6123884 -0.24570387
## 3 -0.22219493 -1.867271 -0.5252956 -0.24281879
## 4 -0.26268193 -1.607256 -0.3120321 -0.05174350
## 5 -0.16574172 -1.767169 -0.6096806 -0.20729331
## 6 -0.09894226 -1.706098 -0.3641162 0.07800542
## m_right_accuracy_TRUE m_right_neutral_FALSE m_right_neutral_TRUE
## 1 -1.410301 -0.22218216 -1.444755
## 2 -1.333929 -0.37537926 -1.346274
## 3 -1.369590 -0.33527778 -1.351359
## 4 -1.317917 -0.15515511 -1.344875
## 5 -1.419014 -0.31421202 -1.399972
## 6 -1.422158 0.01006113 -1.463113
## m_right_speed_FALSE m_right_speed_TRUE s_accuracy_TRUE s_accuracy_FALSE
## 1 -0.9149364 -1.785443 0.5109779 0.9015137
## 2 -0.8849329 -1.670659 0.5510193 0.8764208
## 3 -0.8586790 -1.748387 0.4991804 0.8748535
## 4 -0.6085621 -1.615860 0.4725567 0.9646245
## 5 -0.8988785 -1.709416 0.4927625 0.9169674
## 6 -0.5240941 -1.727374 0.5216469 1.0098260
## s_neutral_TRUE s_neutral_FALSE s_speed_TRUE s_speed_FALSE t0_accuracy t0_neutral
## 1 0.4560181 0.7906519 0.5411936 1.005409 0.2685825 0.2471035
## 2 0.5027792 0.7692438 0.5936935 1.007716 0.2553711 0.2344799
## 3 0.4547302 0.7755225 0.5536948 1.030833 0.2537479 0.2340374
## 4 0.4295109 0.8040917 0.4680630 1.047541 0.2615501 0.2431886
## 5 0.4400312 0.8071623 0.5448357 1.044816 0.2540929 0.2331306
## 6 0.4912248 0.8554349 0.5640184 1.156585 0.2596239 0.2369449
## t0_speed
## 1 0.2451876
## 2 0.2357603
## 3 0.2354981
## 4 0.2349378
## 5 0.2337057
## 6 0.2341568
# Calculate means
<- data.frame(lapply(ps, mean))
pmeans pmeans
## m_left_accuracy_TRUE m_left_accuracy_FALSE m_left_neutral_TRUE
## 1 -1.426817 0.1132749 -1.457047
## m_left_neutral_FALSE m_left_speed_TRUE m_left_speed_FALSE m_right_accuracy_FALSE
## 1 -0.1163084 -1.718697 -0.6876808 -0.06514239
## m_right_accuracy_TRUE m_right_neutral_FALSE m_right_neutral_TRUE
## 1 -1.363143 -0.2031698 -1.371207
## m_right_speed_FALSE m_right_speed_TRUE s_accuracy_TRUE s_accuracy_FALSE
## 1 -0.9186984 -1.599274 0.5105725 0.9325671
## s_neutral_TRUE s_neutral_FALSE s_speed_TRUE s_speed_FALSE t0_accuracy t0_neutral
## 1 0.4553644 0.8401986 0.4952231 0.884088 0.2573007 0.2373127
## t0_speed
## 1 0.2172329
Next, let’s plot the Mu’s
<- pmeans %>% transmute(Accuracy_left_TRUE = m_left_accuracy_TRUE,
m Accuracy_left_FALSE = m_left_accuracy_FALSE,
Accuracy_right_TRUE = m_right_accuracy_TRUE,
Accuracy_right_FALSE = m_right_accuracy_FALSE,
Neutral_left_TRUE = m_left_neutral_TRUE,
Neutral_left_FALSE = m_left_neutral_FALSE,
Neutral_right_TRUE = m_right_neutral_TRUE,
Neutral_right_FALSE = m_right_neutral_FALSE,
Speed_left_TRUE = m_left_speed_TRUE,
Speed_left_FALSE = m_left_speed_FALSE,
Speed_right_TRUE = m_right_speed_TRUE,
Speed_right_FALSE = m_right_speed_FALSE) %>%
pivot_longer(cols = everything(),
names_to = c("Emphasis", "Stimulus", "Match"),
names_pattern = "(.*)_(.*)_(.*)",
values_to = "m")
m
## # A tibble: 12 x 4
## Emphasis Stimulus Match m
## <chr> <chr> <chr> <dbl>
## 1 Accuracy left TRUE -1.43
## 2 Accuracy left FALSE 0.113
## 3 Accuracy right TRUE -1.36
## 4 Accuracy right FALSE -0.0651
## 5 Neutral left TRUE -1.46
## 6 Neutral left FALSE -0.116
## 7 Neutral right TRUE -1.37
## 8 Neutral right FALSE -0.203
## 9 Speed left TRUE -1.72
## 10 Speed left FALSE -0.688
## 11 Speed right TRUE -1.60
## 12 Speed right FALSE -0.919
<- ggplot(data = m, aes(Emphasis, m, col = Match)) +
m_plot geom_line(aes(group = Match), lty = "dashed", lwd = 1) +
geom_point(size = 4, shape = 19) +
facet_grid(Stimulus ~ .) +
ylim(-2, 1) +
theme_minimal() + theme(text = element_text(size = 15))
m_plot
Now, plotting sigma. We can really start to visualise the effects we found to be credible above.
<- pmeans %>% transmute(Accuracy_TRUE = s_accuracy_TRUE,
s Accuracy_FALSE = s_accuracy_FALSE,
Neutral_TRUE = s_neutral_TRUE,
Neutral_FALSE = s_neutral_FALSE,
Speed_TRUE = s_speed_TRUE,
Speed_FALSE = s_speed_FALSE) %>%
pivot_longer(cols = everything(),
names_to = c("Emphasis", "Match"),
names_pattern = "(.*)_(.*)",
values_to = "s")
s
## # A tibble: 6 x 3
## Emphasis Match s
## <chr> <chr> <dbl>
## 1 Accuracy TRUE 0.511
## 2 Accuracy FALSE 0.933
## 3 Neutral TRUE 0.455
## 4 Neutral FALSE 0.840
## 5 Speed TRUE 0.495
## 6 Speed FALSE 0.884
<- ggplot(data = s, aes(Emphasis, s, col = Match)) +
s_plot geom_line(aes(group = Match), lty = "dashed", lwd = 1) +
geom_point(size = 4, shape = 19) +
ylim(0.3, 1) +
theme_minimal() + theme(text = element_text(size = 15))
s_plot
Finally, plotting non-decision time;
<- pmeans %>% transmute(Accuracy = t0_accuracy,
t0 Neutral = t0_neutral,
Speed = t0_speed) %>%
pivot_longer(cols = everything(),
names_to = c("Emphasis"),
names_pattern = "(.*)",
values_to = "t0")
t0
## # A tibble: 3 x 2
## Emphasis t0
## <chr> <dbl>
## 1 Accuracy 0.257
## 2 Neutral 0.237
## 3 Speed 0.217
<- ggplot(data = t0, aes(Emphasis, t0)) +
t0_plot geom_line(aes(group = 1), lty = "dashed", lwd = 1) +
geom_point(size = 4, shape = 19) +
ylim(0.18, 0.3) +
theme_minimal() + theme(text = element_text(size = 15))
t0_plot
6.4 Conclusion (important)
Despite us running several different designs across a number of different models, we’re seeing clear patterns. In many applications, it may not be useful to try all these different model fits - instead we may focus on one model with many different competing designs.
In these examples, we want to make the point about inference. Making inference from models can be difficult, especially when different designs produce different explanations. For this, there are several methods for drawing stronger inference. First, we should do model selection to rule out other models – for example, if a v
model won in these examples, then we would seriously need to reconsider our inference. Secondly, we want to look at the effects across the designs and models.
In the PNAS data from Forstmann et al., (2008), we hypothesized a threshold effect from emphasis. We then fit a variety of models, where the B
only model was not the winner. Instead, we regularly found that B
, v
and t0
effects were preferenced to better explain the data. Across all of these winning models, we regularly found evidence for a difference in threshold parameters. Evidently, it appears that our hypothesis was supported, however, it is important to contextualise this finding within.
By contextualising this finding, we refer to discussions about different models and parameterisations, as well as thinking about the winning model (and parameter differences) in the context of any misfit. We may see very slight differences between parameterisations of models, so in these instances, we need to think about our research question. If the same effect is commonly observed across these very similar models, then we have more evidence on which to base our conclusion. However, if the parameterisations varied such that this was not the case, then we may be less confident in our inference.
Evidently, it is highly important to consider and test a variety of explanations, as well as discussing your inference within the context of the models and misfit.