Fit Bayesian MPT Models with brms & Stan
mpt.RdFit a Bayesian multinomial processing tree (MPT) model using brms::brm()
(so ultimately Stan) to trial-level data, potentially including a
multilevel/hierarchical model structure. To fit an MPT, first create a model
object using make_mpt() and then pass the model object, the data, as well
as a formula providing a symbolic description of the regression (i.e.,
fixed-effect) and hierarchical (i.e., random-effect) structure. The returned
object can be used for model post-processing.
Usage
mpt(
formula,
data,
tree,
model,
default_prior_intercept = "normal(0, 1)",
default_prior_coef = "normal(0, 0.5)",
default_priors = TRUE,
data_format = "long",
log_p = FALSE,
link = "probit",
...
)Arguments
- formula
Either a
formulathat is applied to each MPT model parameter or ampt_formulaobject (created bympt_formula()) specifying separate formulas for each parameter. If aformula, the LHS needs to specify the response variable.- data
data.framecontaining the variables informula. Data needs to be on an observation-level (i.e., each row is one response/observation) and cannot be aggregated in any way. TODO: change this- tree
one-sided formula or character specifying the variable in
dataindicating the tree (or item type) of a given observation. The values of thetreevariable need to match the names of the trees inmodel. Can be omitted for models with only one tree.- model
mpt_modelobject as created bymake_mpt(), ignored ifformulais an object ofmpt_formula.- default_prior_intercept
character string describing the prior applied to the fixed-effect intercepts for each MPT model parameter on the unconstrained scale (if
default_priors = TRUE). The default,"normal(0, 1)"implies a flat prior on the MPT parameter scale.- default_prior_coef
character string describing the prior applied to the non-intercept fixed-effect parameters for each MPT model parameter on the unconstrained scale (if
default_priors = TRUE).- default_priors
logical value indicating whether (the default,
TRUE) or not (FALSE) the priors specified via thedefault_prior_interceptanddefault_prior_coefargument should be applied.- data_format
character string indicating whether the formula is to be generated for fitting data in long format / non-aggregated data (
long, the default), where a single variable contains trial-level responses, or for data in wide format / aggregated data (wide/aggregated), where a separate column for each response category contains the respective . frequency. Only used if a formula object (not an mpt_formula) is given as input and ignored otherwise.- log_p
logical value indicating whether the likelihood should be evaluated with probabilities (the default,
FALSE) or log probabilities (TRUE). Settinglog_ptoTRUEcan help in case of convergence issues but might be slower.- link
character specifying the link function for transforming from unconstrained space to MPT model parameter (i.e., 0 to 1) space. Default is
"probit".- ...
Further arguments passed to
brms::brm()such asprior,chains,iter,warmup, andcores.
Value
A fitted model object returned from brms::brm() of class brmsfit
with additional class mpt_fit and some extra slots (i.e., call,
mpt_formula, and orig_data). This object should seemlessly interact
with the brms ecosystem (e.g., can be used for obtaining posterior
predictive values and information criteria, see Examples).
Examples
if (FALSE) { # \dontrun{
### Step 1: Specify model using make_mpt()
## model in easy format (with model specified as text)
## unsure-extended 2-high threshold model for recognition memory
u2htm <- "
# Old Items
Do + (1 - Do) * (1 - g1) * g2
(1 - Do) * g1
(1 - Do) * (1 - g1) * (1 - g2)
# New Items
(1 - Dn) * (1 - g1) * g2
(1 - Dn) * g1
Dn + (1 - Dn) * (1 - g1) * (1 - g2)
"
# need to specify tree names and category names for easy format
u2htsm_model <- make_mpt(text = u2htm, trees = c("old", "new"),
categories = rep(c("old", "unsure", "new"), 2))
u2htsm_model
### Step 2: Fit model with same formula for all model parameters
## we fit to data from Singmann, Kellen, & Klauer (2013, CogSci-Proc):
# Investigating the Other-Race Effect of Germans towards Turks and Arabs using
# Multinomial Processing Tree Models
# http://singmann.org/download/publications/SKK-CogSci2013.pdf
str(skk13)
## here we use simplified syntax without any random effects for fitting speed.
fit_fast <- mpt(resp ~ race, data = skk13, model = u2htsm_model,
tree = "type",
cores = min(c(4, parallel::detectCores()))) ## uses multicore
## a more appropriate formula would be: resp ~ race + (race|s|id) + (1|p|stim)
## (i.e., crossed-random effects and full correlations among random terms)
### Step 3: Inspect results
fit_fast # in output, no parameter name refers to first MPT parameter (here: Dn)
## Check model fit
ppp_test(fit_fast)
## we can use mpt_emmeans() for marginal effects of all MPT model parameters
# requires package emmeans to be installed
mpt_emmeans(fit_fast, "race")
## Alternatively, we can invoke emmeans() individually for each MPT model parameter
# Default is first MPT model parameter (here: Dn)
emmeans::emmeans(fit_fast, "race", type = "response")
# using the dpar argument, we can get output for any other model parameter
emmeans::emmeans(fit_fast, "race", type = "response", dpar = "Do")
emmeans::emmeans(fit_fast, "race", type = "response", dpar = "g1x")
emmeans::emmeans(fit_fast, "race", type = "response", dpar = "g2x")
## We can also use all brms post-processing
# information criteria (e.g., loo)
(loo_model <- loo(fit_fast))
# posterior predictive checks
pp_check(fit_fast, type = "bars_grouped", group = "mpt_tree", ndraws = 100)
# get posterior mean predictions
pepred <- posterior_epred(fit_fast)
str(pepred) ## dimensions are: samples, observations, probability (in tree)
### Alternative Step 2: First specify formula, then fit model
## Step 2a: Specify formula for each parameter separately using mpt_formula()
## (formula could be different for each model parameter)
u2htm_formula <- mpt_formula(
Do ~ race + (race|s|id) + (1|p|stim),
Dn ~ race + (race|s|id) + (1|p|stim),
g1x ~ race + (race|s|id) + (1|p|stim),
g2x ~ race + (race|s|id) + (1|p|stim),
response = ~ resp,
model = u2htsm_model
)
u2htm_formula
## Step 2b: Fit model using formula (takes rather long)
fit_slow <- mpt(u2htm_formula, data = skk13,
tree = "type",
cores = min(c(4, parallel::detectCores()))) ## uses multicore
fit_slow
} # }