Stop Guessing Your Ad Spend: The Bayesian Guide To Budget Optimization With Pymc-marketing

Writen by:
21 minutes estimated reading time

This technical guide demonstrates how to bridge the gap between Bayesian rigor and strategic action using PyMC-Marketing to automate high-stakes budget allocation.

Using MMM for marketing budget optimization, representing the transition from 10-day manual MMM to 5-minute Agentic budget optimization.

Introduction

Traditional marketing reports are post-mortems as they tell you what you spent, but rarely what you should do next. In our previous deep dive, we used PyMC-Marketing to build a Bayesian MMM that isolated organic baselines and mapped the diminishing returns of every channel.

But a model is only a tool. Budget Optimization is the steering wheel. In an era where “Agentic” workflows are replacing 10-day manual reporting cycles, the ability to instantly translate complex posterior distributions into a risk-aware spend strategy is the ultimate competitive advantage. This post transitions from model validation to strategic execution. We will show you how to use PyMC-Marketing’s native optimization suite to solve the two most critical questions in capital allocation:

  • The Growth Play: How to maximize total contribution without breaching your budget ceiling or channel-level limits.
  • The Efficiency Play: How to minimize total spend while hitting non-negotiable revenue or acquisition targets.

By the end of this guide, you will be able to move from uncertainty to precision, writing the code that turns Bayesian inference into a concrete, executive-ready roadmap.

All the code snippets and visualizations we’ll cover in this post are available in the demo_budget_optimization.ipynb notebook. For more information about PyMC-Marketing, visit here.

Setting up the environment

Before we can optimize the budget, we need a stable environment. We’ll use a dedicated virtual environment to handle the Bayesian dependencies (like PyMC and ArviZ) without version conflicts.

python

Initializing the Script

With the environment ready, we’ll start our notebook by importing the Bayesian ecosystem. We use arviz for posterior analysis and pymc_marketing for the domain-specific MMM components.

python

Data Import

We will continue working with the synthetic marketing data generated in the previous post. If you are following along in the companion notebook, you can load the data directly using the snippet below:

python

Building the model with the Multi-Dimensional API

We begin by building the model. While we already built an MMM in our previous post, we are going to reconstruct it here for a very important reason: this analysis leverages PyMC-Marketing’s latest native multi-dimensional API. Let us begin by defining train and test datasets:

python

Let us define the priors to be used in the modeling, we will use spend shares per channel for saturation coefficients.

python

And now we are all set to define the configuration of the model

python

Now, we are ready to instantiate our model using the MMM class from PyMC-Marketing’s multi-dimensional API

python

Next, we build the underlying PyMC model and configure our trace tracking:

python

In the code above mmm.build_model(…) compiles pyMC PyTesor graph behind the scenes, mapping our inputs(X) and outputs (y) to the model’s structure and mmm.add_original_scale_contribution_variable(...) is used to calculate original scale of contributions and inject them directly into the model trace. This makes downstream plotting and budget optimization incredibly straightforward.

Prior Predictive Checks: The “Marketing Physics” Filter

Before we allow our model to ingest historical data (the posterior sampling phase), we must perform a crucial Bayesian sanity check: Prior Predictive Checks.

Think of this as a “Physics Check” for your marketing strategy. Prior predictive checks generate simulated sales data based entirely on our initial assumptions (priors). This step answers a fundamental question: Are our starting assumptions plausible, or are they mathematically absurd?

If our priors allow for a scenario where $1 of TikTok spend generates $1 billion in sales, or conversely, suggest that marketing spend can regularly cause negative sales, our “Marketing Physics” is broken. Catching these errors now prevents us from wasting hours on heavy sampling runs and ensures our optimization logic is grounded in reality.

Visualizing the Sanity Check

We generate these prior samples and overlay them with actual historical sales. We aren’t looking for a perfect fit yet; we are looking for alignment in scale.

javascript
prior-predictive.png

In this visualization, we plot our true historical sales as a solid black line, surrounded by 50% and 94% highest density intervals (HDI) of our prior predictive simulations. We notice that the actual sales line (black) is well-enveloped by the shaded blue predictive intervals, confirming that our model’s priors are well-calibrated and we are safe to proceed to training.

Model Fitting: Running the “Heavy Machinery”

With our “Marketing Physics” (priors) validated, it’s time to move from theory to evidence. We now transition to Posterior Sampling—the process where the model “learns” from your historical data.
We use the No-U-Turn Sampler (NUTS), a state-of-the-art MCMC algorithm. Unlike simple regressions that search for a single “best-fit” line, NUTS explores thousands of possible scenarios to build a full probability distribution for every marketing channel. This ensures that your budget optimization isn’t based on a single point-in-time guess, but on a statistically robust foundation that accounts for real-world volatility.

javascript

Depending on your hardware, this step can take a few minutes as PyMC runs 4 parallel chains to thoroughly explore the parameter space.

To ensure our model is accurate enough to later make high-stakes budget allocation decisions, we must run a posterior predictive check. This generates simulated sales using our model’s trained parameters, which we can then overlay directly against our actual historical data.

python
posterior_predictive.png

We see that the predictions (shown by the dotted blue line) by the model closely follows the actual sales line (the black solid line), indicating a good fit.

Alternatively, if you want to use the built-in function for plotting posterior predictive with an interactive plot, then you can get that by the following Python code.

python

5. Model Evaluation: Calibrating Our Confidence

A visually appealing plot is a start, but before we hand our model over to the budget optimizer, we need to stress-test its “internal brain.” We aren’t just looking for a high score; we are looking for Convergence—proof that the model has reached a stable, reliable conclusion.

We evaluate the model through three critical lenses:

  1. Goodness-of-Fit ($R^2$ & MAPE): We quantify the “Error Bar.” $R^2$ tells us how much market volatility we’ve captured, while MAPE (Mean Absolute Percentage Error) gives the CFO a plain-English accuracy score (e.g., “The model is 92% accurate on average”).
  2. Prior vs. Posterior Convergence: This is the “Learning Delta.” We check how much the model actually learned from your data versus what we initially assumed. If the “Posterior” looks exactly like the “Prior,” the data wasn’t strong enough to move the needle.
  3. Sampling Health ($\hat{R}$ and ESS): The technical “Truth Test.” We use the $\hat{R}$ (R-hat) metric to ensure our four MCMC chains reached the same destination. An $\hat{R} < 1.01$ is our “Green Light” for optimization.

Performance Summary
Here is how to calculate your core accuracy metrics and print a clean, executive-ready summary:

python
python
Screenshot_2026-05-11_at_14.49.47.png

Overall performance is good; now let’s inspect individual parameters (e.g., saturation_beta). For this, we compare the prior beliefs against the posterior beliefs:

python
prior-posterior-dist.png

We notice the distributions moving from the initial belief, which means the model has learned from the data. In particular, channel1 is only half as effective as we originally assumed, channel2 is stronger than we gave it credit for, and channel3 has a very tight posterior distribution, which implies that the model is highly confident about this channel’s estimate. Similar plots can be generated for saturation_lam and adstock_alpha.

A robust Media Mix Model (MMM) should yield consistent parameter estimates even when trained on slightly different time slices. If a model’s parameters fluctuate wildly when you add a few weeks of data, your budget allocations will change erratically from month to month.

To safeguard against this, PyMC-Marketing provides a TimeSliceCrossValidator. This class slices our time series data chronologically, fits the model repeatedly across these sliding windows, and tracks how the parameter estimates change.

Let’s set up a cross-validation routine, run the multiple training folds, and plot the stability of our adstock_alpha (our channel memory decay) parameters:

python
python

Once our time-slice cross-validation is complete, we use cv.plot.param_stability to visualize our adstock_alpha estimates.

python
cv-adstock-alpha.png

The above forest plots show heavily overlapping intervals and steady median estimates across all channels, we can confidently confirm parameter stability.

Below are the forest plots for saturation_beta and saturation_lam , showing stable estimates for all channels.

cv-saturation-beta.png
cv-saturation-lambda.png

Evaluating parameter stability is only half of the cross-validation story. We also need to see how those stable parameters translate into actual forecasting power.

By calling cv.plot.cv_predictions, PyMC-Marketing generates a multi-panel visual timeline of our cross-validation folds (Fold 0 through Fold 4):

python
cv-folds.png

In analyzing the time-slice cross-validation folds above, the model’s forecasting engine demonstrates exceptional out-of-sample reliability. Across all five iterations, the transition from the training period (purple) to the 13-week forecasting horizon (orange) is incredibly smooth, proving that our seasonality and adstock carryover calculations translate perfectly to unseen time horizons.

The orange test bands consistently and accurately encompass the observed sales (black line), while naturally expanding to reflect realistic forecasting uncertainty farther out in time. Because the model successfully navigates these chronological stress tests without drifting or showing erratic prediction errors, we can confidently confirm that its predictive power is highly stable, giving us the ultimate green light to trust its recommendations for future budget planning.

Media Insights: Beyond Static Charts

While our previous deep dive covered the fundamentals of attribution, we’re no longer just looking at the past. Before we trigger the budget optimizer, we need to inspect the Model Dynamics—the “DNA” of how your marketing spend actually converts into revenue.

In the past, generating these diagnostic plots required dozens of lines of complex boilerplate code. Today, thanks to the plot_interactive module, we can spin up a Plotly-driven dashboard—including Return on Ad Spend (ROAS), Saturation Curves, and Adstock Decay—with a single line of code. These aren’t just pictures; they are interactive tools that allow you to hover, zoom, and facet across custom dimensions (like specific Geos or Markets) to find hidden efficiency leaks.

Launching the Interactive Dashboard

Use the following script to generate a comprehensive view of your model’s internal logic:

python

Budget Optimization: From Insights to Capital Allocation

We have verified the model’s stability and calibrated our confidence. Now, we move from validation to Strategic Action. Our first scenario tackles the most critical question in marketing: “We have a fixed budget of $X for the next quarter. How do we allocate it across our channels to maximize total sales?” Using PyMC-Marketing’s BudgetOptimizer, we perform thousands of simulations to find the “Global Optimum”—the specific point on your multi-channel saturation curves where every additional dollar spent yields the highest possible marginal return. This isn’t just a “best guess”; it is a risk-aware optimization that respects your real-world constraints.

Preparing the Optimization Parameters

Before triggering the optimizer, we need to define our “Search Space”—the time horizon we are planning for and the total capital we are willing to deploy.

python

To keep our optimization realistic, we set a 50% operational boundary (percentage_change = 0.5). This tells the optimizer that it cannot slash any channel’s budget by more than 50%, nor can it increase it by more than 50% of its historical average. As a rule of thumb, larger boundaries can yield higher expected return, albeit with higher uncertainty (more risky).

Because PyMC-Marketing’s multi-dimensional engine relies on xarray, we convert these boundaries into an xr.DataArray to align perfectly with our model’s channel coordinates:

python

We are now ready to pass our trained model to PyMC-Marketing’s MultiDimensionalBudgetOptimizerWrapper.

python

Finally, we trigger the optimization using optimize_budget. Under the hood, this function defaults to maximizing our target response variable within the constraints we’ve defined:

python

We specify method="SLSQP" (Sequential Least Squares Quadratic Programming). This is a highly robust numerical solver designed specifically for handling smooth, non-linear objective functions with both bound constraints (our +/- 50% limits) and equality constraints ensuring our total allocated spend matches our fixed weekly budget.

Let us now look at what suggestion comes out of the optimizer:

python
Screenshot_2026-05-10_at_21.21.37.png

As expected we notice that optimizer suggests to cut from less efficient channel1 as it has hit saturation at the current spend and shift the budget to more efficient channels channel2 and channel3.

Next, let us use this allocation strategy to find out multiplier for each channel.

python
Screenshot_2026-05-10_at_21.23.16.png

We now use these multipliers to get weighted test data, which will contain optimized allocation for each channel.

python

Let us now look at how optimized allocation compares visually with the original allocation for each channel over the test period:

python
original-optimized-budget.png

We are now ready to sample form posterior distribution for our baseline spend X_test and optimized spend X_test_weighted to do the forecasting.

python

Understanding how much each Channel contributes to sales?

Let us look at how channel contributions from original allocation and optimized allocation evolve over the test period:

python
channel-contri-comparison.png

We see a clear uplift in channel contributions by adapting the allocation strategy suggested by the model. Next, let us quantify this increment and calculate how confident is the model about this uplift.

python
channel-contri-lift.png

By executing the optimized allocation strategy, we have 98% probability of outperforming our baseline plan, capturing an expected 5.3% lift in sales without increasing the budget.

Total sales comparison

In this subsection, we compare the forecast of sales with the baseline spend and optimized spend.

python
sales-contri.png

Again, we see an uplift in sales coming from optimized spend, let us quantify this uplift as follows:

python
sales-uplift.png

For the uplift in sales, we get 3% lift in sales with 79% probability of outperforming baseline allocation strategy.

By running this optimization routine, we successfully answered the absolute core question of campaign planning: how to maximize return without increasing risk. Statistically, this is a massive win!

Minimizing budget to hit a target

Often, the goal of budget planning isn’t to spend every dollar available, but to hit a specific business milestone as efficiently as possible. In this section, we’ll configure PyMC-Marketing to find the cheapest channel allocation that safely reaches our target.

Before running the optimizer, we need to prepare our input data and build a baseline simulation. Because PyMC-Marketing’s multi-dimensional engine relies on xarray, we start by converting our initial budget dictionary into a formatted DataArray:

python

With our budget formatted, we can simulate our sales predictions. We use sample_response_distribution to project our sales under both our current budget allocation and our future optimized allocation:

python

To run a minimization scenario, we have to translate our business goal into formal mathematical constraints that the optimization engine (which uses scipy.optimize under the hood) can solve.

Here is the setup to define our target, construct our constraint, and initialize the BudgetOptimizer:

python

In the code above we first define a constraint function to inform the optimizer about what boundaries it must play within. We then define the objective utility, by default budget optimizers are built to maximize utility (e.g., maximizing revenue), but, because we want to minimize the spend, we return negative sum of budgets.

Finally, we initialize the optimizer, notice that we set default_constraints=False. This is crucial because, by default, PyMC-Marketing assumes you have a fixed total budget ceiling. Since we are doing budget minimization, we turn off the default budget cap and replace it with our custom target_response_constraint.

With our constraints and utility functions defined, we are ready to run the optimization algorithm. We call optimizer.allocate_budget to calculate the final numbers:

python
Screenshot_2026-05-10_at_22.53.56.png

So we see that the optimized weekly minimum budget is 18,679. This means we save 1,848 every single week, a 9% reduction in marketing costs, while achieving the exact same revenue target of $1.84M!

To fully understand the value of these optimization routines, we should look at the full distributions of our simulated future sales. In the code below, we generate posterior response simulations for our new minimized-budget strategy (sample_response_given_allocation_target_response).

python

we now use ArviZ’s plot_dist to overlay all three of our scenarios:

  1. Initial planned allocation (Blue)
  2. Optimized allocation to maximize response (Red)
  3. Optimized allocation to minimize budget (Green)
python
budget-sizing.png

This final visual plot tells a compelling story about strategic marketing decision-making:

  • The Blue Curve (Initial): This represents our status-quo starting point. With a weekly budget of $20,528, the model expected an average response of ~1.84M (represented by the dashed blue line).
  • The Green Curve (Minimized Budget): Notice how the green curve and dashed line land almost perfectly on top of the blue curve. This is mathematical proof that the solver successfully hit the target! The distribution of expected sales is virtually identical to our initial baseline, but as we proved in the previous step, we achieved this while spending 9% less money.
  • The Red Curve (Maximized Response): This shows what happens when we keep our original $20,528 budget but let the optimizer shift funds to maximize output. The red curve is shifted far to the right, showing that simply reallocating the same budget could boost our expected response to a much higher level.

8. Conclusion: From Code to Capital Efficiency

We’ve moved beyond the traditional “Post-Mortem” reporting cycle. By leveraging PyMC-Marketing and Bayesian inference, we’ve successfully transitioned from analyzing what happened to engineering what’s next.

To recap our journey from model validation to real-world deployment, here are the core milestones we achieved:

  • Validated Predictive Power: Through rigorous posterior predictive checks and time-slice cross-validation, we proved our model doesn’t just fit historical data—it accurately forecasts future out-of-sample sales.
  • Unlocked Maximum Growth: By allowing the optimizer to locate the exact “Sweet Spot” on our non-linear saturation curves, we identified a 5.3% expected lift in marketing contribution under a fixed budget scenario.
  • Engineered Capital Efficiency: In our minimization scenario, the model successfully shaved 9% off our weekly marketing spend while landing precisely on our $1.84M sales target.
  • Replaced Guesswork with Risk Management: Because our framework is fully Bayesian, we can present final strategies to leadership with reliable probabilities of success (e.g., a 98% chance of outperforming the baseline plan).

Budget optimization is no longer a quarterly “guessing game.” It is a continuous, data-driven process of capital allocation that ensures every marketing dollar is working at its highest marginal utility.

Get the Code: You can find the complete codebase, including the optimization loops and visualization scripts, in our GitHub Repository.

Scale Your Marketing with Agentic MMM Solutions

While PyMC-Marketing provides the scientific foundation, the modern marketing landscape moves too fast for manual notebook execution. In the 10 days it takes a data science team to manually tune and validate these models, the market has already moved.

At ELIYA, we bridge the gap between Bayesian Precision and Agentic Speed. We help brands move from 10-day reporting cycles to 5-minute strategic decisions.

  • Custom Bayesian Frameworks: Tailored MMM solutions designed for E-commerce, Retail, and Fintech.
  • Agentic Orchestration: Chat-driven budget optimization that handles the “Heavy Machinery” for you.
  • Incrementality-First: Every dollar spent is linked to verifiable growth.

Ready to unlock the true potential of your marketing spend?

Book a Demo with ELIYA Today

FAQs

Why use Bayesian MMM over traditional Linear Regression?

Traditional OLS (Ordinary Least Squares) regression often treats every marketing channel as a vacuum and struggles with “multicollinearity” (when two channels, like Search and Social, move together). Bayesian MMM allows us to incorporate “priors”—industry benchmarks or previous experiment results—to guide the model. It doesn’t just give you a single “lucky” number; it provides a probability distribution, allowing you to plan for risk, not just averages.

How does the Optimizer handle “Saturated” channels?

The optimizer uses the Logistic Saturation curves we defined during model fitting. It calculates the Marginal Return of every dollar. If a channel like Meta is currently in a state of diminishing returns, the optimizer will automatically shift that capital to a channel with a steeper “growth slope,” even if the total ROI of that second channel is lower. It solves for the next dollar, not the last dollar.

What is the “10-day vs. 5-minute” difference with Eliya AI?

In a standard data science workflow (as shown in the code above), a human must manually clean the data, define the priors, run the MCMC chains, check for convergence, and then manually iterate on the optimization constraints. This cycle typically takes several days and on average 10 working days or even longer. Eliya’s Agentic MMM automates this—allowing an executive to run the same high-fidelity MMM model via a chat interface, or conversational analytics in under 5 minutes.

Can the model handle “external” factors like seasonality or price changes?

Yes. One of the strengths of the PyMC-Marketing framework is its ability to include Control Variables. You can add holidays, inflation indices, or competitor price changes as non-marketing regressors. This ensures the model doesn’t “mistakenly” credit your Meta ads for a sales spike that was actually caused by a Black Friday promotion or a seasonal trend.

Do I need a Data Science team to use this?

While the Python code above is designed for data scientists, Eliya is built to empower the “Citizen Data Scientist” (Marketing Ops, Growth Leads, and CMOs). Our agentic interface translates the complex Machine Learning and Bayesian outputs into plain-English strategy, so you get the rigor of Eliya’s MMM without needing to write a single line of Python.

How often should we run this Budget Optimization?

In 2026, the “Quarterly Plan” is becoming obsolete. We recommend a Monthly Optimization for high-level capital allocation and a Weekly “Pulse Check” via the Agentic Chat. Because the cost of re-running the model is now minutes instead of days, you can respond to platform shifts (like a sudden spike in TikTok CPMs) in real-time rather than waiting for the next quarterly review.

How can the model help us hit a fixed sales target while actually spending less money?

A: Every marketing channel eventually suffers from “ad fatigue” or diminishing returns, spending twice as much money rarely results in twice as many sales. The optimization tool automatically identifies when a channel is starting to plateau. It “shaves off” those wasteful, lower-performing dollars and calculates the most efficient, leaner budget mix required to cross your sales goal.

When you say we have a “98% probability of success,” what does that mean in plain English?

A: Traditional marketing plans rely on a single, static forecast (e.g., “We expect exactly $1.5M in revenue”), which is rarely 100% accurate. Because our approach is built on risk-aware simulations, we test our new budget against thousands of volatile future market scenarios. Saying we have a 98% probability of success means that in 98 out of 100 simulated futures, the new optimized budget plan outperforms our old one.

Why is a 3% lift in total sales considered a major win if channel contributions went up by over 5%?

A: Your company’s total sales are driven by a massive mix of factors which are your brand reputation, economic conditions, baseline organic demand, and seasonality. Marketing spend only directly controls a portion of that pie. While the optimizer boosted the efficiency of our ad spend by 5.3%, that translates to a highly realistic, rock-solid 3% increase to the company’s absolute bottom line.


Similar Posts in Marketing Mix Modeling