{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "J_ccrCpFyQ0A" }, "source": [ "(mmm_budget_allocation_example)=\n", "# Budget Allocation with PyMC-Marketing\n", "\n", "The purpose of this notebook is to explore the recently included function in the PyMC-Marketing library that focuses on budget allocation. This function's underpinnings are based on the methodologies inspired by Bolt's work in the article, [\"Budgeting with Bayesian Models\"](https://bolt.eu/en/blog/budgeting-with-bayesian-models-pymc-marketing/).\n", "\n", "## Prerequisite Knowledge\n", "The notebook assumes the reader has knowledge of the essential functionalities of PyMC-Marketing. If one is unfamiliar, the [\"MMM Example Notebook\"](https://www.pymc-marketing.io/en/stable/notebooks/mmm/mmm_example.html) serves as an excellent starting point, offering a comprehensive introduction to media mix models in this context.\n", "\n", "## Introducing the budget allocator\n", "This notebook instigates an examination of the function within the PyMC-Marketing library, which addresses these challenges using Bayesian models. The function intends to provide:\n", "\n", "1. Quantitative measures of the effectiveness of different media channels.\n", "2. Probabilistic ROI estimates under a range of budget scenarios." ] }, { "cell_type": "markdown", "metadata": { "id": "vWMGdRlmyjcI" }, "source": [ "## Basic Setup\n", "Like previous notebooks revolving around PyMC-Marketing, this relies on a specific library set. Here are the requisite imports necessary for executing the provided code snippets subsequently." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "ExecuteTime": { "end_time": "2025-01-15T14:30:44.969426Z", "start_time": "2025-01-15T14:30:37.851150Z" }, "id": "28_D6j7jjQTy" }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "OMP: Info #276: omp_set_nested routine deprecated, please use omp_set_max_active_levels instead.\n", "/Users/carlostrujillo/Documents/GitHub/pymc-marketing/pymc_marketing/mmm/multidimensional.py:72: FutureWarning: This functionality is experimental and subject to change. If you encounter any issues or have suggestions, please raise them at: https://github.com/pymc-labs/pymc-marketing/issues/new\n", " warnings.warn(warning_msg, FutureWarning, stacklevel=1)\n", "/var/folders/f0/rbz8xs8s17n3k3f_ccp31bvh0000gn/T/ipykernel_38045/3141621575.py:9: UserWarning: The pymc_marketing.mmm.builders module is experimental and its API may change without warning.\n", " from pymc_marketing.mmm.builders.yaml import build_mmm_from_yaml\n" ] } ], "source": [ "import warnings\n", "\n", "import arviz as az\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import pandas as pd\n", "import xarray as xr\n", "\n", "from pymc_marketing.mmm.builders.yaml import build_mmm_from_yaml\n", "from pymc_marketing.mmm.multidimensional import (\n", " MultiDimensionalBudgetOptimizerWrapper,\n", ")\n", "from pymc_marketing.paths import data_dir\n", "\n", "warnings.filterwarnings(\"ignore\")\n", "\n", "az.style.use(\"arviz-darkgrid\")\n", "plt.rcParams[\"figure.figsize\"] = [12, 7]\n", "plt.rcParams[\"figure.dpi\"] = 100\n", "\n", "%load_ext autoreload\n", "%autoreload 2\n", "%config InlineBackend.figure_format = \"retina\"" ] }, { "cell_type": "markdown", "metadata": { "id": "9AlvbqZ6yqhs" }, "source": [ "These imports and configurations form the fundamental setup necessary for the entire span of this notebook.\n", "\n", "The expectation is that a model has already been trained using the functionalities provided in prior versions of the PyMC-Marketing library. Thus, the data generation and training processes will be replicated in a different notebook. Those unfamiliar with these procedures are advised to refer to the [\"MMM Example Notebook.\"](https://www.pymc-marketing.io/en/stable/notebooks/mmm/mmm_example.html)\n", "\n", "## Loading a Pre-Trained Model\n", "To utilize a saved model, load it into a new instance of the MMM class using the `build_mmm_from_yaml` method below." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "seed: int = sum(map(ord, \"mmm_allocation_example\"))\n", "rng: np.random.Generator = np.random.default_rng(seed=seed)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | date | \n", "y | \n", "x1 | \n", "x2 | \n", "event_1 | \n", "event_2 | \n", "dayofyear | \n", "t | \n", "geo | \n", "
---|---|---|---|---|---|---|---|---|---|
0 | \n", "2018-04-02 | \n", "3984.662237 | \n", "159.290009 | \n", "0.0 | \n", "0.0 | \n", "0.0 | \n", "92 | \n", "0 | \n", "geo_a | \n", "
1 | \n", "2018-04-09 | \n", "3762.871794 | \n", "56.194238 | \n", "0.0 | \n", "0.0 | \n", "0.0 | \n", "99 | \n", "1 | \n", "geo_a | \n", "
2 | \n", "2018-04-16 | \n", "4466.967388 | \n", "146.200133 | \n", "0.0 | \n", "0.0 | \n", "0.0 | \n", "106 | \n", "2 | \n", "geo_a | \n", "
3 | \n", "2018-04-23 | \n", "3864.219373 | \n", "35.699276 | \n", "0.0 | \n", "0.0 | \n", "0.0 | \n", "113 | \n", "3 | \n", "geo_a | \n", "
4 | \n", "2018-04-30 | \n", "4441.625278 | \n", "193.372577 | \n", "0.0 | \n", "0.0 | \n", "0.0 | \n", "120 | \n", "4 | \n", "geo_a | \n", "
\n", " | mean | \n", "sd | \n", "hdi_3% | \n", "hdi_97% | \n", "mcse_mean | \n", "mcse_sd | \n", "ess_bulk | \n", "ess_tail | \n", "r_hat | \n", "
---|---|---|---|---|---|---|---|---|---|
saturation_beta[x1] | \n", "0.370 | \n", "0.021 | \n", "0.332 | \n", "0.409 | \n", "0.001 | \n", "0.001 | \n", "565.0 | \n", "537.0 | \n", "1.01 | \n", "
saturation_beta[x2] | \n", "0.269 | \n", "0.061 | \n", "0.182 | \n", "0.384 | \n", "0.003 | \n", "0.003 | \n", "552.0 | \n", "499.0 | \n", "1.01 | \n", "
saturation_lam[x1] | \n", "4.025 | \n", "0.409 | \n", "3.242 | \n", "4.756 | \n", "0.016 | \n", "0.013 | \n", "625.0 | \n", "490.0 | \n", "1.00 | \n", "
saturation_lam[x2] | \n", "2.815 | \n", "1.091 | \n", "1.139 | \n", "4.744 | \n", "0.053 | \n", "0.060 | \n", "492.0 | \n", "430.0 | \n", "1.01 | \n", "
adstock_alpha[x1] | \n", "0.395 | \n", "0.032 | \n", "0.331 | \n", "0.453 | \n", "0.001 | \n", "0.001 | \n", "728.0 | \n", "555.0 | \n", "1.00 | \n", "
adstock_alpha[x2] | \n", "0.178 | \n", "0.043 | \n", "0.104 | \n", "0.266 | \n", "0.002 | \n", "0.001 | \n", "624.0 | \n", "325.0 | \n", "1.01 | \n", "
<xarray.DataArray (channel: 2)> Size: 16B\n", "array([2000., 2000.])\n", "Coordinates:\n", " * channel (channel) <U2 16B 'x1' 'x2'
<xarray.DataArray 'allocation' (channel: 2)> Size: 16B\n", "array([2000., 2000.])\n", "Coordinates:\n", " * channel (channel) <U2 16B 'x1' 'x2'" ], "text/plain": [ "
<xarray.DataArray 'x1' (date: 21)> Size: 168B\n", "array([2001.05516828, 1998.17680521, 2000.86259682, 2000.53354004,\n", " 2001.24720109, 2001.03767898, 2000.10398136, 2002.55438021,\n", " 2000.10373669, 1999.06157133, 2000.07774446, 2000.98811459,\n", " 2000.96803296, 0. , 0. , 0. ,\n", " 0. , 0. , 0. , 0. ,\n", " 0. ])\n", "Coordinates:\n", " * date (date) datetime64[ns] 168B 2021-09-06 2021-09-13 ... 2022-01-24" ], "text/plain": [ "
<xarray.Dataset> Size: 833kB\n", "Dimensions: (date: 21, geo: 2, sample: 800,\n", " channel: 2)\n", "Coordinates:\n", " * date (date) datetime64[ns] 168B 2021-...\n", " * geo (geo) <U5 40B 'geo_a' 'geo_b'\n", " * channel (channel) <U2 16B 'x1' 'x2'\n", " * sample (sample) object 6kB MultiIndex\n", " * chain (sample) int64 6kB 0 0 0 ... 1 1 1\n", " * draw (sample) int64 6kB 0 1 ... 398 399\n", "Data variables:\n", " y (date, geo, sample) float64 269kB ...\n", " channel_contribution (date, geo, channel, sample) float64 538kB ...\n", " total_media_contribution_original_scale (sample) float64 6kB 1.54e+05 .....\n", " allocation (geo, channel) float64 32B 1.527...\n", " x1 (date, geo) float64 336B 1.528e+...\n", " x2 (date, geo) float64 336B 1.281e+...\n", "Attributes:\n", " created_at: 2025-07-26T13:44:44.502389+00:00\n", " arviz_version: 0.22.0\n", " inference_library: pymc\n", " inference_library_version: 5.25.1" ], "text/plain": [ "
<xarray.DataArray (geo: 2, channel: 2)> Size: 32B\n", "array([[1., 1.],\n", " [1., 1.]])\n", "Coordinates:\n", " * geo (geo) <U5 40B 'geo_a' 'geo_b'\n", " * channel (channel) <U2 16B 'x1' 'x2'