Use Getting Started for setup, not for the whole methodology
The Getting Started pages are intentionally practical. Once you can run the package, use the workflow section to answer the two questions that matter most in Bayesian MMM:
how should I think about priors?
which diagnostics matter before I trust outputs?
Subsections of Getting Started
Install and Setup
Audience
Engineers and analysts setting up DSAMbayes for local development or modelling runs.
Prerequisites
R >= 4.1 — check with R --version.
A C++ toolchain for Stan compilation. This is the most common source of setup issues:
macOS: install Xcode Command Line Tools (xcode-select --install).
Windows: install Rtools matching your R version. Ensure make is on your PATH.
Linux (Ubuntu/Debian):sudo apt install build-essential.
# 1. Select an ABI-safe host library and create it with the cachesource scripts/r-library-path.sh
dsambayes_set_r_library host
mkdir -p "$R_LIBS_USER" .cache
# 2. Set the cache path (add both settings to .bashrc/.zshrc for persistence)exportXDG_CACHE_HOME="$PWD/.cache"# 3. Install DSAMbayes from the local checkoutR -q -e 'install.packages(".", repos = NULL, type = "source")'
This keeps all package libraries and Stan compilation caches inside the repo, avoiding permission issues with system library paths.
Do not share a compiled package library between R runtimes or containers.
dsambayes_set_r_library host selects
.Rlib-host-r<active-R-version>/; use dsambayes_set_r_library container
inside a container instead. The path is deliberately derived from the active
runtime, not hard-coded in the repository.
Verify the installation
1. Confirm DSAMbayes loads
R -q -e 'library(DSAMbayes); cat("Version:", as.character(utils::packageVersion("DSAMbayes")), "\n")'
Expected: prints Version: 1.3.3 (or current version).
Symptom:install.packages(".", repos = NULL, type = "source") errors.
Actions:
Confirm you are in the repository root directory.
Confirm the selected R_LIBS_USER directory exists and is writable.
Check for missing system dependencies in the error output.
Stale Stan cache
Symptom: unexpected model behaviour after updating the package.
Actions:
Clear the cache: rm -rf .cache/dsambayes.
Re-run with model.force_recompile: true in your config if you need to invalidate a stale compiled model.
Permission issues
Symptom: write failures for library, cache, or run outputs.
Actions:
Ensure R_LIBS_USER, .cache, and results/ are writable.
Keep R_LIBS_USER and XDG_CACHE_HOME set in your shell session.
Run all commands from the repository root.
Concepts
Purpose
Give new DSAMbayes users a compact conceptual orientation before they move into tutorials, runner usage, or the workflow section.
This page is intentionally introductory. It does not try to be the full methodology guide for Bayesian MMM. For that, use Principled Bayesian Workflow.
What is DSAMbayes?
DSAMbayes is an R package for Bayesian marketing mix modelling built on Stan. It provides:
an lm()-style modelling interface for interactive work
model classes for single-series, hierarchical, and pooled MMM
prior and boundary controls
post-fit extraction, diagnostics, decomposition, and optimisation tooling
a YAML/CLI runner for reproducible runs
The main practical difference from classical regression is that DSAMbayes works with a posterior distribution, not just a single fitted coefficient vector.
Why Bayesian MMM?
MMM datasets often have the exact features that make naive regression unstable:
short time series
overlapping media timing
strong baseline structure
uncertain functional form
real business need for uncertainty-aware decisions
Bayesian modelling helps because it makes several things explicit:
regularisation through priors
structural constraints through boundaries
uncertainty propagation into downstream outputs
diagnostic gates rather than fit-statistic-only thinking
The DSAMbayes mental model
DSAMbayes should be thought of as a workflow, not just a fitter.
At a high level:
specify the model and priors
fit the model
check whether the posterior computation is trustworthy
check whether the fitted model is adequate for the data
only then interpret decomposition, comparison, or optimisation outputs
That is the main philosophical shift from a simpler OLS-style workflow.
Model classes
DSAMbayes supports three main model classes.
BLM
Single-market Bayesian linear model.
Use when:
you have one KPI series
one market / brand / region is the modelling unit
you want the simplest Bayesian MMM starting point
Hierarchical
Multi-group model with partial pooling.
Use when:
you have panel data across markets, regions, or brands
you want to borrow strength across groups while preserving group structure
Pooled
Single-market model with structured pooling across labelled media dimensions.
Use when:
the outcome is one series
the media structure has nested or repeated dimensions that should share information
This walkthrough uses the synthetic dataset shipped at data/synthetic_dsam_example_wide_data.csv. It contains weekly observations for a single market with columns for:
First-time Stan compilation takes 1–3 minutes. Subsequent runs use a cached binary. With 2 chains on synthetic data, sampling typically completes in under 2 minutes.
Step 5: Sampler diagnostics
chain_diagnostics(fitted_model)
Metric
Good
Concern
Max Rhat
<= 1.01
> 1.01 means chains have not converged
Min ESS (bulk)
> 400
< 200 means too few effective samples
Divergences
0
Any non-zero count warrants investigation
These are the computational checks. They do not by themselves prove the model is adequate for interpretation.
Step 6: Extract the posterior
post<-get_posterior(fitted_model)
post is a tibble with one row per draw containing coef (named coefficient list), yhat (fitted values), noise_sd, r2, rmse, and smape.
For a well-specified MMM on weekly data, in-sample R² above 0.85 is typical.
Step 8: Response decomposition
decomp_tbl<-decomp(fitted_model)head(decomp_tbl)
Shows each term’s contribution (coefficient × design-matrix column) to the predicted KPI at each time point — the foundation for media contribution and ROI reporting.
Step 9: MAP for rapid iteration
During development, use MAP for fast point estimates:
Use MCMC for final reporting; MAP for formula iteration. A MAP result is one
point estimate, not posterior draws: it has no valid credible intervals or
MCMC diagnostics. Review the restart diagnostics if objectives differ
materially; use fit() when uncertainty, convergence, or decision risk
matters.
Common pitfalls
Pitfall
Symptom
Fix
Forgetting to set boundaries
Media coefficients go negative
Add set_boundary(m_x > 0)
Too few iterations
High Rhat, low ESS
Increase iter and warmup
Missing controls
High residual autocorrelation
Add trend, seasonality, or holiday terms
Scaling confusion
Coefficients look wrong
model.scale: true is default; get_posterior() back-transforms automatically
Build, fit, and interpret a multi-market hierarchical model with partial pooling and optional CRE (Mundlak) correction using the DSAMbayes R API.
This page is a hands-on tutorial. For the broader methodological questions behind prior-setting, diagnostics, and interpretation, use the workflow pages:
Understanding of random-effects / mixed-model concepts.
Dataset
This walkthrough uses data/synthetic_dsam_example_hierarchical_data.csv — a panel dataset with weekly observations across multiple markets. Key columns:
Response:kpi_value — weekly KPI per market.
Group:market — market identifier.
Media:m_tv, m_search, m_social — media exposure variables.
Controls:trend, seasonality, brand_metric.
Date:date — weekly date index.
library(DSAMbayes)panel_df<-read.csv("data/synthetic_dsam_example_hierarchical_data.csv")table(panel_df$market)# Check group counts
Step 1: Construct the hierarchical model
The (term | group) syntax tells DSAMbayes to fit random effects. Terms inside the parentheses get group-specific deviations from the population mean:
Boundaries apply to the population-level coefficients.
Step 3: (Optional) Add CRE / Mundlak correction
If you suspect that group-level spending patterns are correlated with unobserved market characteristics (e.g. high-spend markets also have higher baseline demand), CRE controls for this:
This adds cre_mean_m_tv, cre_mean_m_search, cre_mean_m_social as fixed effects — the group-level means of each media variable. The within-group coefficients then represent purely temporal variation, controlling for between-group confounding.
Hierarchical models are slower than BLM — expect 10–30 minutes depending on group count and data size. First-time Stan compilation of the hierarchical template adds 2–3 minutes.
Step 5: Check diagnostics
chain_diagnostics(fitted_model)
Pay special attention to Rhat and ESS for sd_* parameters (group-level standard deviations), which are often harder to estimate than population coefficients.
Step 6: Extract the posterior
post<-get_posterior(fitted_model)
For hierarchical models, coefficient draws from get_posterior() return vectors (one value per group) rather than scalars. The population-level (fixed-effect) estimates are averaged across groups.
Step 7: Group-level results
Fitted values and decomposition are returned per group:
# Fitted values — one row per observation, grouped by marketfit_tbl<-fitted(fitted_model)head(fit_tbl)# Decomposition — per-group predictor contributionsdecomp_tbl<-decomp(fitted_model)
Step 8: Budget optimisation (population level)
Budget optimisation uses population-level (fixed-effect) beta draws, not group-specific totals:
# See Budget Optimisation docs for full scenario specificationresult<-optimise_budget(fitted_model,scenario=my_scenario)
Key differences from BLM
Aspect
BLM
Hierarchical
Data structure
Single market
Panel (multiple groups)
Coefficient draws
Scalars
Vectors (one per group)
Fit time
2–5 min
10–30 min
Decomposition
Direct
May fail gracefully for `
Forest/prior-posterior plots
Direct
Group-averaged population estimates
Stan template
bayes_lm_updater_revised.stan
general_hierarchical.stan (templated per group count)
Common pitfalls
Pitfall
Symptom
Fix
Too few groups
Weak partial pooling; group SDs poorly estimated
Need 4+ groups for meaningful hierarchical structure
Run from YAML — reproducible hierarchical runs via the runner
Quickstart (YAML Runner)
Goal
Complete one reproducible DSAMbayes runner execution from validation to artefact inspection, then load the fitted model in R to explore the results interactively.
This page is operational by design. It teaches you how to run the package, not the full modelling methodology. After the quickstart succeeds, use Principled Bayesian Workflow before treating outputs as decision-ready.
Usually 1 to 3 minutes. Subsequent runs typically reuse the cached binary. If compilation appears stuck, check the C++ toolchain in Install and Setup.
Do I need to set R_LIBS_USER every time?
Yes, unless you add it to your shell profile. Use
dsambayes_set_r_library host to select a repo-local path that is isolated
from both your system library and any container library.
Can I use renv instead of .Rlib?
Yes. The repo includes renv.lock. Use renv::restore() if you want exact dependency restoration.
Modelling
How many weeks of data do I need?
There is no hard minimum, but a useful rule of thumb is:
BLM: about 100+ weeks for a model with roughly 10 to 15 predictors
Hierarchical: about 80+ weeks per group, ideally with at least 4 groups
Shorter series can still be modelled, but the posterior will usually be much more prior-driven and less decision-ready.
Should I use identity or log response?
Identity when the KPI is naturally additive and variance is fairly stable
Log when the KPI is strictly positive and effect interpretation is more naturally multiplicative
If unsure, fit both and compare the adequacy and diagnostic picture, not just a single fit metric. See Response Scale Semantics.
How strict is the stationarity requirement for MMM?
DSAMbayes does not require the raw KPI to satisfy a textbook stationarity condition before fitting.
The important question is whether the remaining unexplained structure, after adding sensible controls and baseline terms, is weak enough that media effects are not standing in for missing baseline dynamics.
When should I set boundaries on media coefficients?
Use m_channel > 0 when non-negativity is a structural belief you would defend in writing. Do not apply blanket sign constraints just to make the output look tidier. See Stage 2: Model and Priors and Minimal-Prior Policy.
When should I use CRE (Mundlak)?
Use CRE when you want to separate within-group temporal effects from between-group cross-sectional structure in a hierarchical model. See CRE / Mundlak.
How should I handle CRE mean terms in decomposition / attribution?
Treat cre_mean_* terms as baseline or between-group structure, not as media attribution terms. They are there to absorb confounding structure, not to claim channel contribution.
What priors should I use on CRE mean terms?
Usually the defaults. Avoid manually tightening or positivity-constraining them unless you have a very strong reason, because that can undermine the whole point of CRE adjustment.
Can I add random slopes for CRE mean terms?
No. Those terms are constant within group, so random slopes on them are not separately identifiable from the group intercept.
What does scale = TRUE do?
It standardises the response and predictors before Stan fitting to improve sampler efficiency. Post-fit coefficient extraction is back-transformed automatically.
Runner and outputs
How long does a typical run take?
Roughly:
BLM MCMC: a few minutes
BLM MAP: seconds
Hierarchical MCMC: tens of minutes depending on size
Pooled MCMC: usually between BLM and hierarchical
First-time Stan compilation adds extra startup time.
What is the difference between validate and run?
validate checks config and data contracts without compiling or fitting Stan
run validates, fits, writes staged artefacts, and runs diagnostics
Always validate first after config changes.
Where do outputs go?
Under results/<timestamp>_<model_name>/ by default. See Output Artefacts.
How do I compare two model runs?
Use compare_runs() or compare the model-selection artefacts directly. See Compare Runs.
That is more important than memorising one threshold in isolation.
What does “Pareto-k > 0.7” mean?
It means the LOO approximation is unreliable for that observation and the point is highly influential. Investigate the observation and be cautious about using LOO-based comparisons mechanically.
My diagnostics say warn. Should I worry?
Usually yes, but not always in the same way.
in exploratory work, a warning may be acceptable if understood
in shareable reporting, warnings should be disclosed and interpreted
repeated or severe warnings usually mean the model needs revision before decision use
It searches feasible spend allocations within channel constraints and scores them against the fitted model. It is a decision layer built on the model, not an independent source of truth.
Can I use budget optimisation with MAP-fitted models?
Yes, but then the result is point-estimate-driven rather than uncertainty-rich. That is fine for rough iteration, not ideal for final decision support.