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 Update the R Package
Use the standalone installer for colleagues who call dsambayesplus from R or
RStudio. Downloading the whole repository is unnecessary for this workflow.
Updates are explicit: run the installer before loading the package, when you
intend to change versions. Do not put it in .Rprofile or a model-fitting script.
The installer needs internet access and personal read access to the private
tandpds/dsambayesplus repository. It installs source packages. R >= 4.1 and a
working C++ toolchain for Stan are still required; see the
Windows guide or
Linux/macOS guide for toolchain setup.
One-time setup
Each colleague completes this setup with their own GitHub account and token.
The repository administrator grants that account read access; the colleague
creates and stores their own credential. Share the installer and these
instructions. Do not create a shared team token or distribute the maintainer’s
personal token. Individual credentials allow access to be revoked separately.
In RStudio, install the helper dependencies into your writable personal or
project library:
install.packages(c("gh","remotes"))
Create your own GitHub personal access token. Where supported by your
organisation, use a fine-grained token restricted to this repository with
Contents: read-only permission. Complete any required organisation
approval or single sign-on authorisation. Follow your organisation’s access
policy if your membership does not support fine-grained tokens.
With Git installed and its credential manager configured, store the token
through the interactive prompt:
gitcreds::gitcreds_set()
gitcreds is installed as a dependency of gh. Use the operating system’s
credential manager where available. Without Git, GITHUB_PAT in your private
user-level.Renviron is an alternative; restart R after editing it.
An existing GITHUB_PAT or GITHUB_TOKEN can override stored credentials, so
remove or replace an expired environment token if authentication still fails.
Never distribute a shared token or put a token in the installer, project
files, console history or Git. A token does not grant access your account
lacks. See GitHub’s token guidance.
Open the installer source on GitHub
while signed in and save its raw contents as install_dsambayesplus.R in your
working directory. Download this one file, not the repository ZIP. Review the
file before sourcing it. Sourcing defines the helper; it does not install
anything until you call the function.
Install or refresh
Start a fresh R session (Session > Restart R in RStudio), then run:
The helper selects the numerically highest published vX.Y.Z software release.
It excludes draft releases, prereleases and handbook releases. A Git tag alone
is insufficient: it must have a published GitHub release. This policy does not
use GitHub’s “latest” label or install development main. Publishing a release
is the maintainer’s approval step; the helper does not validate the release’s
statistical methods or software quality.
The helper resolves the tag to a commit and installs that exact commit with
remotes. It skips installation if the selected version, commit and repository
already match the package in the target library. A previous ZIP/local install
without that provenance is reinstalled once. An explicit call can replace a
development version with the selected release, including an older version.
Required dependencies are installed as needed; upgrade = "never" avoids
upgrading other dependencies merely because newer versions exist. This does
not provide a complete dependency lock.
The output records the selected tag, commit, library and installed version.
The default target is .libPaths()[1L]. To use another existing writable
library, prepend it to .libPaths() before installing and loading the package.
Check what R loads with find.package("dsambayesplus").
To check without installing, or deliberately select a published version:
install_dsambayesplus(check_only=TRUE)install_dsambayesplus(ref="v1.0.1")# Only if this software release is published.
Check-only mode may run with the package loaded. Installation requires a fresh
session. Missing credentials, unavailable GitHub access or no eligible release
stop the helper before installation; there is no fallback to main. An install
failure stops execution rather than proceeding to load the package. Resolve
the error before starting an analysis.
Keep the saved helper for future release checks. Download it again when the
installer itself changes. The helper refreshes the installed package; it does
not refresh its own saved source file.
Keep existing analyses reproducible
Use a project library and renv.lock for an ongoing analysis. Install a chosen
release in that project, check the analysis, then record the environment with
renv::snapshot(). Colleagues use renv::restore() to recover the recorded
package versions. Review and snapshot an update deliberately; do not call the
latest-release installer every time an existing model runs. See the
renv workflow.
The lockfile records package versions and remote provenance. It does not
preserve your R executable, compiler, data, credentials or model results.
When a repository checkout is needed
The installed package includes the R API, including run_from_yaml() for your
own configuration files. Repository files such as runme.R, scripts/, bundled
configs and example data require a separate checkout. Package updates do not
update those files.
For that workflow, use Git to clone the private repository. To select a release
in an existing checkout, first preserve local work and inspect git status:
Replace v1.0.1 with the published software release you intend to use. If there
are local changes, resolve them before switching; do not discard them to make
the command succeed. In a fresh R session using the checkout’s package library,
install the selected checkout with
remotes::install_local(".", dependencies = NA, upgrade = "never"). This keeps
the package and repository runner on the same source version. Follow the
platform setup guide for library selection. Git commands also work in an
RStudio Terminal with Git installed. A downloaded ZIP is a fixed snapshot and
cannot be refreshed with Git.
Install and Setup
Audience
Engineers and analysts setting up dsambayesplus for local development or modelling runs. This page is written for a Unix shell (Linux or macOS). If you are on Windows using RStudio, especially on a work-issued machine without full administrator rights, use Install and Setup (Windows / RStudio) instead.
For package API use, follow Install and update the R package.
The checkout instructions below apply when you need repository runners, bundled
examples or development tools. Installing the package does not require a checkout.
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.
A local Git checkout of this repository for the instructions below. See
checkout updates
to keep its runner and installed package on the same release.
Quick setup (recommended)
Open a terminal in the repository root and run:
# 1. Select an ABI-safe host library and create it with the cachesource scripts/r-library-path.sh
dsambayesplus_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 dsambayesplus from the local checkoutR -q -e 'if (!requireNamespace("remotes", quietly = TRUE)) install.packages("remotes")'R -q -e 'remotes::install_local(".", dependencies = NA, upgrade = "never")'
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.
dsambayesplus_set_r_library host selects
.Rlib-host-r<active-R-version>/; use dsambayesplus_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 dsambayesplus loads
R -q -e 'library(dsambayesplus); cat("Version:", as.character(utils::packageVersion("dsambayesplus")), "\n")'
Use the standalone release installer.
It reads stored personal credentials and checks published software releases.
Run it explicitly in a fresh R session before loading the package. It does not
update a separate repository checkout or install development main.
Using renv (optional)
The repository includes a renv.lock file recording dependency versions. To use it:
R -q -e 'install.packages("renv"); renv::restore()'
This restores the recorded package versions, subject to source availability and
platform requirements. It does not preserve R, the compiler or input data. For
your own analysis, maintain a project lockfile and update it deliberately after
checking an upgrade; see project version management.
Rscript scripts/dsambayesplus.R run --config config/blm_timeseries.yaml
Expected: a timestamped run directory is created under results/ with model outputs and diagnostics.
Repository helper: runme.R
In a cloned checkout, runme.R is a command-line convenience wrapper around
the YAML runner. Run it from a terminal; do not source it in an interactive R
session.
Windows users running dsambayesplus through RStudio (or VS Code) on a work-issued machine without full administrator rights. If you use Linux or macOS, or you are comfortable with a Unix shell, use Install and Setup instead; this page only covers the parts that differ on Windows.
This page assumes no prior bash experience. Every command below runs from the RStudio Console or an RStudio Terminal tab.
For R API use, confirm the toolchain in step 1, then follow
Install and update the R package.
That route uses a short standalone helper and your personal credentials; it
does not need the full repository. Steps 2 onward below are for repository
runners, bundled examples and development.
Before you start
R >= 4.1 and RStudio Desktop. Both installers offer a per-user “Just Me” install mode that does not require administrator rights. If the installer still requests admin rights on your machine, or blocks silently, ask your IT team to install R and RStudio; both are standard enterprise packages.
For repository runners only: install Git for Windows and clone the private
repository using an authenticated Git client, or RStudio’s **File > New Project
Version Control > Git** with https://github.com/tandpds/dsambayesplus.git.
Open the checkout as your RStudio project. A ZIP is a fixed snapshot; it cannot
fetch later changes. See checkout updates.
1. Confirm R and the C++ toolchain
In the RStudio Console:
R.version.string
Confirm the version is 4.1 or later.
Stan compilation needs a C++ toolchain. On Windows, select Rtools for your installed R version using the compatibility table on its download page.
Download and run the Rtools installer for your R version.
Expected: TRUE. If this returns FALSE and you cannot complete the Rtools install yourself (some configurations need admin rights to register the toolchain on PATH), ask your IT team to install Rtools for your R version.
2. Set up the environment (no bash required)
The Linux/macOS setup uses a bash helper (scripts/r-library-path.sh) to select a repo-local package library and Stan cache directory. RStudio on Windows does not need bash for this: the same result is achieved with R code, run automatically at the start of every session.
Add a file named .Rprofile in the repository root (if one does not already exist) containing:
# Repo-local, R-version-specific package library and Stan cache.# Mirrors scripts/r-library-path.sh for Windows/RStudio sessions.repo_root<-normalizePath(getwd(),winslash="/",mustWork=TRUE)r_version<-as.character(getRversion())Sys.setenv(R_LIBS_USER=file.path(repo_root,paste0(".Rlib-host-r",r_version)))Sys.setenv(XDG_CACHE_HOME=file.path(repo_root,".cache"))dir.create(Sys.getenv("R_LIBS_USER"),recursive=TRUE,showWarnings=FALSE).libPaths(c(Sys.getenv("R_LIBS_USER"),.libPaths()))dir.create(Sys.getenv("XDG_CACHE_HOME"),recursive=TRUE,showWarnings=FALSE)
Then restart R so RStudio picks it up: Session > Restart R.
The .libPaths() call makes the new library active in the current session;
setting R_LIBS_USER inside .Rprofile alone is insufficient. If the project
uses renv, use its library activation instead of this snippet. Do not add
installation or update calls to .Rprofile.
This keeps the package library and Stan cache inside the repository folder, avoiding permission issues on a locked-down system library, exactly like the Linux/macOS setup. Do not commit .Rprofile if it contains anything machine-specific beyond the snippet above; the repository’s .gitignore already excludes .Rlib-* and .cache.
Where to place the repository: put it under a local, writable folder such as C:\Users\<you>\Documents\dsambayesplus, not a network drive or a folder your IT policy marks read-only. A network drive with a deep path is a common source of “permission denied” and Windows path-length errors.
3. Install dsambayesplus from the local checkout
With the project open in RStudio (so the working directory is the repository root) and R restarted after step 2:
Follow Install and update the R package
for the package-only helper, credential setup and project version management.
For this checkout workflow, follow that page’s Git update instructions, then
restart R and reinstall the selected local checkout using step 3. Refreshing
the installed package alone does not refresh runme.R or bundled configs.
Open Tools > Terminal > New Terminal. This opens a terminal already positioned at the repository root, whether RStudio is configured to use Git Bash, PowerShell, or Command Prompt on your machine (Tools > Global Options > Terminal shows and changes which one). The Rscript command below is identical in all three:
Rtools is missing, is the wrong version for your installed R, or was not registered on PATH. Reinstall Rtools matching R.version.string, restart RStudio, and check again. If that still fails, ask your IT team; some machine configurations restrict PATH changes to admin accounts.
Package or GitHub install fails with a network error
Check credentials and repository access first. A proxy or firewall may also
block the CRAN mirror, GitHub API or archive downloads. Ask IT to check the
failing URL in the error. A local checkout avoids downloading package source
from GitHub, but missing dependencies still require network access.
“Permission denied” writing to the library or cache folder
The repository is on a network drive or a folder your IT policy marks read-only. Move (or re-clone) it to a local folder such as C:\Users\<you>\Documents\dsambayesplus and repeat step 2.
.Rprofile changes do not seem to take effect
.Rprofile only runs when R starts. Use Session > Restart R, not just re-running the file’s contents, and confirm you are working in the project whose root contains the .Rprofile file.
Errors mentioning very long file paths
Windows has a default path-length limit. Keep the repository close to a drive root (for example C:\dev\dsambayesplus) rather than several folders deep under Documents or a synced cloud-storage folder.
Give new dsambayesplus 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 dsambayesplus?
dsambayesplus 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 dsambayesplus 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 dsambayesplus mental model
dsambayesplus 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
dsambayesplus 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 tracked synthetic dataset at
data/timeseries/demo_data_synthetic.csv. It contains weekly observations for
a single series with columns for:
First-time Stan compilation takes 1–3 minutes. Subsequent runs use a cached binary. With the default 4 chains split across 2 cores, sampling on synthetic data 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.
$DecompedData shows each term’s contribution (coefficient × design-matrix
column) to the predicted KPI at each time point. The result is a native
dsambayesplus_decomposition S3 object.
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 dsambayesplus R API.
This page is a hands-on tutorial. For the broader methodological questions behind prior-setting, diagnostics, and interpretation, use the workflow pages:
library(dsambayesplus)panel_df<-read.csv("data/geo_panel/demo_data_geo_panel.csv")table(panel_df$geo)# Check group counts
Step 1: Construct the hierarchical model
The (term | group) syntax tells dsambayesplus 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 can model this correlation when the conditional mean of
the group effect is adequately represented by the included group means:
This adds one cre_mean_<channel> term for each media variable as a fixed
effect. Conditional on the CRE specification and other included controls, the
original media coefficient represents the within-group temporal association.
CRE does not solve omitted time-varying confounding or establish a causal
effect.
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 geofit_tbl<-fitted(fitted_model)head(fit_tbl)# Decomposition, per-group predictor contributionstbl_map<-data.frame(actual.vars=c("intercept","t_scaled","sin52_1","cos52_1","events","newsletters","cre_mean_channel0_signal","cre_mean_channel1_signal","cre_mean_channel2_signal","cre_mean_channel3_signal","channel0_signal","channel1_signal","channel2_signal","channel3_signal"),group=c(rep("BASE",10),rep("media",4)),ref_points=c("none",rep("mean",13)))decomp_result<-decomp(fitted_model,tbl_map=tbl_map)# One native decomposition result per retained group:head(decomp_result$decomp[[1]]$DecompedData)
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
Native result per retained geo; probabilistic media transforms are rejected
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 dsambayesplus 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.
Complete the environment setup in Install and Setup (selecting the host library, creating the cache directory, and exporting XDG_CACHE_HOME) before continuing.
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
dsambayesplus_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.
add sparse sign constraints only for structural assumptions
add sparse prior overrides only when you can defend them in business or modelling terms
do not use priors as a substitute for weak model design
Where do prior numbers come from, and why aren’t they standardised like some other MMM tools?
Short answer: in dsambayesplus, you write priors in the original units of your
data, for example revenue, not in a standardised or z-score space. This is a
deliberate design choice, not a mistake, and it differs from some other MMM
tools, including Abacus, which ask you to specify priors directly in their
internal standardised space.
What “standardised space” means
Before Stan samples, most Bayesian MMM tools, dsambayesplus included, centre and
scale the response and predictors so the sampler works with unit-scale
quantities. This is a computational convenience: it improves sampler
efficiency and keeps step sizes well behaved across parameters with very
different natural magnitudes (e.g. revenue in the hundreds of thousands versus
a spend variable in the low thousands).
Where tools differ is which layer of that process they ask the user to think
in.
Abacus-style: you write the prior directly on the standardised space.
A config entry such as intercept: Normal(mu = 0, sigma = 2) is only
interpretable because Abacus has already decided how the target is scaled;
the 2 is “2 standard deviations of the standardised target”, not
“2 units of revenue”.
dsambayesplus: you write the prior on the original, reporting-scale units
of your data. intercept: Normal(mu = 120000, sigma = 15000) means
“baseline revenue is around 120,000, plus or minus roughly 15,000”, in
whatever currency or unit your target column uses. When model.scale: true
(the default), dsambayesplus converts this raw-scale prior into the correct
standardised parameterisation internally, fits, and then back-transforms
the posterior draws to your original units automatically. You never see or
touch the standardised numbers unless you set model.scale: false.
Both approaches produce equivalent underlying sampler behaviour. Neither is
“unscaled” in the sense of skipping standardisation; dsambayesplus just does not
require you to author priors in the post-scaling space.
Why dsambayesplus uses the reporting scale for the prior contract
The numbers stay checkable by a non-modeller. A stakeholder, or a
colleague reviewing your config, can look at
mu = 120000, sigma = 15000 and immediately judge whether that is a
sane assumption about baseline revenue. Nobody outside the modelling team
can sanity-check Normal(0, 2) on a standardised scale without first
recomputing what that implies in revenue terms.
The prior’s meaning does not silently drift between runs. A
standardised-space prior such as Normal(0, 2) means something different
each time you refit, because the underlying standard deviation used to
derive that scale changes with the data (different date range, different
market, a new data pull). A reporting-scale prior such as
Normal(120000, 15000) means the same thing, “baseline revenue is about
120k”, regardless of what the data’s standard deviation happens to be on
any given run. This avoids a common failure mode where a prior that looked
reasonable on one dataset becomes accidentally very informative, or
accidentally very diffuse, on the next.
It matches how priors are usually elicited in practice. Domain
knowledge about a KPI baseline, a channel’s plausible ROI, or a
competitor effect is almost always expressed in business units. Asking
the analyst to translate that into a standardised space by hand is an
extra, error-prone step that this design avoids.
This is consistent with standard Bayesian workflow guidance (see
What Principled Means and
Stage 2: Model and Priors): elicit
priors where you have real, defensible intuition, and let the software
handle re-parameterisation for computation.
What actually happens under the hood
dsambayesplus’s internal scaling of priors and boundaries, including the exact
transformation ratios for slopes, the intercept, and hierarchical group-level
standard deviations, is fully documented in
Priors and Boundaries under “Scale
semantics”. That page is the technical reference; this FAQ entry is only the
“why”.
How to sanity-check a prior you have written
Reason about it directly in your data’s natural units; that is what the
YAML priors: block and set_prior() both expect.
Use peek_prior(model) to see the full prior table on the reporting scale
before fitting.
If you want to see the internal standardised-space numbers dsambayesplus
actually passes to Stan, set model.scale: false on an otherwise identical
model and compare, or inspect the scaling terms directly; this is rarely
necessary for day-to-day modelling.
Do not manually convert your prior into a standardised space and enter that
instead. That would be double-scaling and will produce the wrong prior.
See also Minimal-Prior Policy for the
recommended default-first, sparse-override operating rule that this scaling
behaviour is designed to support.
How many MCMC iterations do I need?
The defaults are a reasonable starting point. Then inspect the Stage 4 diagnostics:
Rhat <= 1.01 and healthy ESS usually mean the draw count is adequate
Rhat > 1.01 or weak ESS usually means you need to increase iterations and warmup
any divergences should be addressed before treating the fit as decision-ready
How strict is the stationarity requirement for MMM?
dsambayesplus 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.