Model Classes
Purpose
DSAMbayes provides three model classes for Bayesian marketing mix modelling. Each class targets a different data structure and pooling strategy. This page describes the constructor pathways, fit support, and practical limitations of each class so that an operator can select the appropriate model for a given dataset.
Use this page to choose the right modelling surface for your data structure and decision problem. Do not use it as a substitute for the broader workflow: class selection does not settle prior design, computational trustworthiness, model adequacy, or causal interpretation. For that framing, start with What Principled Means, Stage 2: Model and Priors, and Stage 5: Model Adequacy.
Selection discipline
- Choose the simplest class that matches the real data structure.
- Do not move to hierarchical or pooled models only because they look more advanced.
- Treat model class as a structural choice, not proof that the resulting model is decision-ready.
- After choosing a class, return to the workflow pages for prior-setting, diagnostics, and interpretation discipline.
Class summary
| Class | S3 class chain | Constructor | Data structure | Grouping | Typical use case |
|---|---|---|---|---|---|
| BLM | blm |
blm(formula, data) |
Single market/brand | None | One-market regression with full prior and boundary control |
| Hierarchical | hierarchical, blm |
blm(formula, data) with (term | group) syntax |
Panel (long format) | Random effects by group | Multi-market models sharing strength across groups |
| Pooled | pooled, blm |
pool(blm_obj, grouping_vars, map) |
Single market | Structured coefficient pooling via dimension map | Single-market models with media coefficients pooled across labelled dimensions |
BLM (blm)
Construction
blm() dispatches on the first argument. When passed a formula, it creates a blm object with default priors and boundaries. When passed an lm object, it creates a bayes_lm_updater whose priors are initialised from the OLS coefficient estimates and standard errors.
Fit support
| Method | Function | Backend |
|---|---|---|
| MCMC | fit(model, ...) |
rstan::sampling() |
| MAP | fit_map(model, n_runs, ...) |
rstan::optimizing() (repeated starts) |
Post-fit accessors
get_posterior()— coefficient draws, fitted values, metricsfitted()— predicted response on the original scaledecomp()— predictor-level decomposition via DSAMdecompoptimise_budget()— decision-layer budget allocation
Limitations
- No group structure. For multi-market data, use the hierarchical class.
optimise_budget()aborts ifscale=TRUEand an offset is present (unsupported combination for thebayes_lm_updaterStan template).
Hierarchical (hierarchical)
Construction
The hierarchical class is created automatically when blm() detects random-effects syntax (|) in the formula:
Terms to the left of | become random slopes; the variable to the right defines the grouping factor. Multiple grouping terms are supported.
CRE / Mundlak extension
For correlated random effects, call set_cre() after construction:
This augments the population formula with group-mean terms (cre_mean_*) and updates priors and boundaries accordingly. See CRE / Mundlak for details.
Fit support
| Method | Function | Backend |
|---|---|---|
| MCMC | fit(model, ...) |
rstan::sampling() |
| MAP | fit_map(model, n_runs, ...) |
rstan::optimizing() (repeated starts) |
Post-fit accessors
Same as BLM. Coefficient draws from get_posterior() return vectors (one value per group) rather than scalars. Budget optimisation uses the population-level (fixed-effect) coefficient draws from the beta parameter.
Limitations
- Stan template compilation uses a templated source (
general_hierarchical.stan) rendered per number of groups and parameterisation mode. First compilation is slow; subsequent runs use a cached binary. - Response decomposition via
model.matrix()may fail for formulas containing|syntax. The runner wraps this intryCatchand skips gracefully. - Posterior forest and prior-vs-posterior plots average group-specific draws to produce a single population-level estimate.
- Offset support in the hierarchical Stan template is handled via
stats::model.offset()withinbuild_hierarchical_frame_data().
Pooled (pooled)
Construction
The pooled class is created by converting an existing BLM object with pool():
The map is a data frame with a variable column mapping formula terms to pooling dimension labels. Exact formula-term labels are preferred; raw variable names are accepted only when they resolve unambiguously to a single non-offset formula term. Priors and boundaries are reset to defaults when pool() is called.
Fit support
| Method | Function | Backend |
|---|---|---|
| MCMC | fit(model, ...) |
rstan::sampling() |
MAP fitting (fit_map) is not currently implemented for pooled models.
Post-fit accessors
Same as BLM. The design matrix is split into base terms (intercept + non-pooled) and media terms (pooled). The Stan template uses a per-dimension coefficient structure.
Limitations
- MAP fitting is not available.
extract_stan_design_matrix()may return a zero-row matrix, which causes VIF computation to be skipped.- The pooled Stan cache key includes sorted grouping variable names to avoid collisions between different pooling configurations.
- Time-series cross-validation is available for pooled MCMC models, subject to the same media-transform restrictions as other classes.
Class selection guide
| Scenario | Recommended class | Rationale |
|---|---|---|
| Single market, sufficient data | BLM | Simplest pathway; full accessor and optimisation support |
| Single market, OLS baseline available | BLM via blm(lm_obj, data) |
Priors initialised from OLS; Bayesian updating |
| Multi-market panel | Hierarchical | Partial pooling shares strength across markets |
| Multi-market panel with confounding concerns | Hierarchical + CRE | Mundlak terms control for between-group confounding |
| Single market with structured media dimensions | Pooled | Coefficient pooling across labelled media categories |
In practice, the class decision should usually be driven by three questions:
- Is the dataset a single time series or a grouped panel?
- Do you need partial pooling across real groups, or pooling across labelled coefficient dimensions?
- Is the added structure necessary for the business question, or are you adding complexity without a clear identifiability benefit?
Fit method selection
| Criterion | MCMC (fit) |
MAP (fit_map) |
|---|---|---|
| Full posterior | Yes | No (point estimate only) |
| Credible intervals | Yes | No; restart diagnostics only |
| Diagnostics (Rhat, ESS, divergences) | Yes | Not applicable |
| LOO-CV / model selection | Yes | Not supported |
| Speed | Minutes to hours | Seconds to minutes |
| Budget optimisation | Full posterior-based | Point-estimate-based |
For production runs where diagnostics and uncertainty quantification matter, MCMC is the recommended fit method. MAP is useful for rapid iteration during model development.
MAP returns one selected optimum, not posterior draws. Do not derive credible
intervals or MCMC diagnostics from it; its point estimate can understate
uncertainty, especially for hierarchical variance components. fit_map()
retains the restart results for inspection (and runner outputs include
optimisation_runs.csv), so materially different restart objectives should be
treated as optimisation instability or competing local optima, not as a
substitute for posterior uncertainty.
Cross-references
- Model Object Lifecycle — state transitions from construction to post-fit
- Priors and Boundaries — prior and constraint specifications
- CRE / Mundlak — correlated random effects for hierarchical models
- Diagnostics Gates — post-fit quality checks
- Stage 2: Model and Priors — workflow framing for structural choices and prior design
- Stage 5: Model Adequacy — what must still be checked after selecting a class