From fe21c517883ad0a5bccb8f76df6815734654b962 Mon Sep 17 00:00:00 2001 From: Michal Raczycki Date: Thu, 3 Aug 2023 16:30:25 +0200 Subject: [PATCH 1/5] including ModelBuilder intro notebook --- ...delBuilder in PyMC-Marketing context.ipynb | 17374 ++++++++++++++++ 1 file changed, 17374 insertions(+) create mode 100644 examples/model_builder/ModelBuilder in PyMC-Marketing context.ipynb diff --git a/examples/model_builder/ModelBuilder in PyMC-Marketing context.ipynb b/examples/model_builder/ModelBuilder in PyMC-Marketing context.ipynb new file mode 100644 index 000000000..11b7e71f8 --- /dev/null +++ b/examples/model_builder/ModelBuilder in PyMC-Marketing context.ipynb @@ -0,0 +1,17374 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "1d74584c", + "metadata": {}, + "source": [ + "# Deploying MMMs and CLVs in Production: Saving and Loading Models" + ] + }, + { + "cell_type": "markdown", + "id": "3222ef04", + "metadata": {}, + "source": [ + "In this article, we'll tackle the historically challenging process of deploying Bayesian models built with PyMC. Introducing a revolutionary deployment module, we bring unprecedented simplicity and efficiency to the deployment of PyMC models. As we prioritize user-friendly solutions, let's delve into how this innovation can significantly elevate your data science projects." + ] + }, + { + "cell_type": "markdown", + "id": "ddb28436", + "metadata": {}, + "source": [ + "\n", + "Recent release of PyMC-Marketing by [Labs](https://www.pymc-labs.io) proves to be a big hit [(PyMC-Marketing)](https://www.pymc-labs.io/blog-posts/pymc-marketing-a-bayesian-approach-to-marketing-data-science/). In the feedback one could see an ongoing theme, many of you have been requesting easy and robust way of deploying models to production. It’s been a long-standing problem with PyMC ( and most other PPLs). The reason for that is that there’s no obvious way, and doesn’t matter which approach you try it proves to be tricky. That is why we’re happy to announce the release of `ModelBuilder`, brand new PyMC-experimental module that addresses this need, and improves on the deployment process significantly.\n", + "\n", + "The ModelBuilder module is a new feature of PyMC based models. It provides 2 easy-to-use methods: save() and load() that can be used after the model has been fit.save() allow easy preservation of the model to .netcdf format, and load() gives one-line replication of the original model. Users can control the prior settings with model_config, and customize the sampling process using sampler_config. Default values of those are working just fine, so first time give it a try without changing, and provide your own model_config and model_sampler if afterwards you want to try to customize it more for your use case!\n" + ] + }, + { + "cell_type": "markdown", + "id": "a808e36a", + "metadata": {}, + "source": [ + "For this notebook I'll use the example model used in [MMM Example Notebook](https://www.pymc-marketing.io/en/stable/notebooks/mmm/mmm_example.html), but ommit the details of data generation and plotting functionalities, since they're out of scope for this introduction, I highly recommend to see that part as well, but for now let's focus on today's topic: Groundbreaking deployment improvements in PyMC-Marketing!" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "1050a937", + "metadata": {}, + "outputs": [], + "source": [ + "import arviz as az\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "from pymc_marketing.mmm import DelayedSaturatedMMM" + ] + }, + { + "cell_type": "markdown", + "id": "f37d808e", + "metadata": {}, + "source": [ + "Let's load the dataset:" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "b7b1193f", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
date_weekyx1x2event_1event_2dayofyeartsin_order_1cos_order_1sin_order_2cos_order_2
02018-04-023984.6622370.3185800.0000000.00.09200.999930-0.011826-0.023651-0.999720
12018-04-093762.8717940.1123880.0000000.00.09910.991269-0.131859-0.261414-0.965227
22018-04-164466.9673880.2924000.0000000.00.010620.968251-0.249981-0.484089-0.875019
32018-04-233864.2193730.0713990.0000000.00.011330.931210-0.364483-0.678820-0.734304
42018-04-304441.6252780.3867450.0000000.00.012040.880683-0.473706-0.834370-0.551205
.......................................
1742021-08-023553.5461480.0330240.0000000.00.0214174-0.513901-0.8578490.8816990.471812
1752021-08-095565.5096820.1656150.8633490.00.0221175-0.613230-0.7899050.9687860.247898
1762021-08-164137.6514850.1718820.0000000.00.0228176-0.703677-0.7105200.9999530.009676
1772021-08-234479.0413510.2802570.0000000.00.0235177-0.783934-0.6208440.973402-0.229104
1782021-08-304675.9734390.4388570.0000000.00.0242178-0.852837-0.5221780.890665-0.454661
\n", + "

179 rows × 12 columns

\n", + "
" + ], + "text/plain": [ + " date_week y x1 x2 event_1 event_2 dayofyear \\\n", + "0 2018-04-02 3984.662237 0.318580 0.000000 0.0 0.0 92 \n", + "1 2018-04-09 3762.871794 0.112388 0.000000 0.0 0.0 99 \n", + "2 2018-04-16 4466.967388 0.292400 0.000000 0.0 0.0 106 \n", + "3 2018-04-23 3864.219373 0.071399 0.000000 0.0 0.0 113 \n", + "4 2018-04-30 4441.625278 0.386745 0.000000 0.0 0.0 120 \n", + ".. ... ... ... ... ... ... ... \n", + "174 2021-08-02 3553.546148 0.033024 0.000000 0.0 0.0 214 \n", + "175 2021-08-09 5565.509682 0.165615 0.863349 0.0 0.0 221 \n", + "176 2021-08-16 4137.651485 0.171882 0.000000 0.0 0.0 228 \n", + "177 2021-08-23 4479.041351 0.280257 0.000000 0.0 0.0 235 \n", + "178 2021-08-30 4675.973439 0.438857 0.000000 0.0 0.0 242 \n", + "\n", + " t sin_order_1 cos_order_1 sin_order_2 cos_order_2 \n", + "0 0 0.999930 -0.011826 -0.023651 -0.999720 \n", + "1 1 0.991269 -0.131859 -0.261414 -0.965227 \n", + "2 2 0.968251 -0.249981 -0.484089 -0.875019 \n", + "3 3 0.931210 -0.364483 -0.678820 -0.734304 \n", + "4 4 0.880683 -0.473706 -0.834370 -0.551205 \n", + ".. ... ... ... ... ... \n", + "174 174 -0.513901 -0.857849 0.881699 0.471812 \n", + "175 175 -0.613230 -0.789905 0.968786 0.247898 \n", + "176 176 -0.703677 -0.710520 0.999953 0.009676 \n", + "177 177 -0.783934 -0.620844 0.973402 -0.229104 \n", + "178 178 -0.852837 -0.522178 0.890665 -0.454661 \n", + "\n", + "[179 rows x 12 columns]" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "url = \"https://raw.githubusercontent.com/pymc-labs/pymc-marketing/main/datasets/mmm_example.csv\"\n", + "df = pd.read_csv(url)\n", + "df" + ] + }, + { + "cell_type": "markdown", + "id": "87deb70d", + "metadata": {}, + "source": [ + "But for our model we need much smaller dataset, many of the previous features were contributing to generation of others, now as our target variable is computed we can filter out not needed columns:" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "52b6d127", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
date_weekyx1x2event_1event_2dayofyeart
02018-04-023984.6622370.3185800.00.00.0920
12018-04-093762.8717940.1123880.00.00.0991
22018-04-164466.9673880.2924000.00.00.01062
32018-04-233864.2193730.0713990.00.00.01133
42018-04-304441.6252780.3867450.00.00.01204
\n", + "
" + ], + "text/plain": [ + " date_week y x1 x2 event_1 event_2 dayofyear t\n", + "0 2018-04-02 3984.662237 0.318580 0.0 0.0 0.0 92 0\n", + "1 2018-04-09 3762.871794 0.112388 0.0 0.0 0.0 99 1\n", + "2 2018-04-16 4466.967388 0.292400 0.0 0.0 0.0 106 2\n", + "3 2018-04-23 3864.219373 0.071399 0.0 0.0 0.0 113 3\n", + "4 2018-04-30 4441.625278 0.386745 0.0 0.0 0.0 120 4" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "columns_to_keep = [\n", + " \"date_week\",\n", + " \"y\",\n", + " \"x1\",\n", + " \"x2\",\n", + " \"event_1\",\n", + " \"event_2\",\n", + " \"dayofyear\",\n", + "]\n", + "seed: int = sum(map(ord, \"mmm\"))\n", + "rng =np.random.default_rng(seed=seed)\n", + "\n", + "data = df[columns_to_keep].copy()\n", + "\n", + "data[\"t\"] = range(df.shape[0])\n", + "data.head()" + ] + }, + { + "cell_type": "markdown", + "id": "9518a885", + "metadata": {}, + "source": [ + "## _Model Creation_\n", + "After we have our dataset ready, we could proceed straight to our model definition, but first to show the full potential of one of the new features: `model_config` we need to use some of our data to define our prior for sigma parameter for each of the channels. `model_config` is a customizable dictionary with keys corresponding to priors within the model, and values containing a dictionaries with parameters necessary to initialize them. Later on we'll learn that through the `save()` method we can preserve our priors contained inside the `model_config`, to allow complete replication of our model." + ] + }, + { + "cell_type": "markdown", + "id": "4b52b2c1", + "metadata": {}, + "source": [ + "### model_config" + ] + }, + { + "cell_type": "markdown", + "id": "41021a72", + "metadata": {}, + "source": [ + "`default_model_config` attribute of every model inheriting from `ModelBuilder` will allow you to see which priors are available for customization. To see it simply initialize a dummy model:" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "284bd558", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'intercept': {'mu': 0, 'sigma': 2},\n", + " 'beta_channel': {'sigma': 2, 'dims': ('channel',)},\n", + " 'alpha': {'alpha': 1, 'beta': 3, 'dims': ('channel',)},\n", + " 'lam': {'alpha': 3, 'beta': 1, 'dims': ('channel',)},\n", + " 'sigma': {'sigma': 2},\n", + " 'gamma_control': {'mu': 0, 'sigma': 2, 'dims': ('control',)},\n", + " 'mu': {'dims': ('date',)},\n", + " 'likelihood': {'dims': ('date',)},\n", + " 'gamma_fourier': {'mu': 0, 'b': 1, 'dims': 'fourier_mode'}}" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dummy_model = DelayedSaturatedMMM(date_column = '', channel_columns= '', adstock_max_lag = 4)\n", + "dummy_model.default_model_config" + ] + }, + { + "cell_type": "markdown", + "id": "f0fd248f", + "metadata": {}, + "source": [ + "You can change only the prior parameters that you wish, no need to alter all of them, unless you'd like to!\n", + "In this case we'll just simply replace our sigma for beta_channel with our computed one:" + ] + }, + { + "cell_type": "markdown", + "id": "19f075f0-4d3d-4509-a9c6-f15efdb9293d", + "metadata": {}, + "source": [ + "First, let's compute the share of spend per channel:" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "4785596a-e333-4cd0-af15-1332e97b66d5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "x1 0.65632\n", + "x2 0.34368\n", + "dtype: float64" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "total_spend_per_channel = data[[\"x1\", \"x2\"]].sum(axis=0)\n", + "\n", + "spend_share = total_spend_per_channel / total_spend_per_channel.sum()\n", + "\n", + "spend_share" + ] + }, + { + "cell_type": "markdown", + "id": "40d17642-1e21-4adc-97f4-633eede87915", + "metadata": {}, + "source": [ + "Next, we specify the `sigma`parameter per channel:" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "672b36bd-3d08-46df-85b8-d67d3ade75d7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[2.1775326025486734, 1.140260877391939]" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# The scale necessary to make a HalfNormal distribution have unit variance\n", + "HALFNORMAL_SCALE = 1 / np.sqrt(1 - 2 / np.pi)\n", + "\n", + "n_channels = 2\n", + "\n", + "prior_sigma = HALFNORMAL_SCALE * n_channels * spend_share.to_numpy()\n", + "\n", + "prior_sigma.tolist()" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "bac9f587", + "metadata": {}, + "outputs": [], + "source": [ + "custom_beta_channel_prior = {'beta_channel': {'sigma': prior_sigma, 'dims': ('channel',)}}\n", + "my_model_config = dummy_model.default_model_config| custom_beta_channel_prior" + ] + }, + { + "cell_type": "markdown", + "id": "1aa435bf", + "metadata": {}, + "source": [ + "As mentioned in the original notebook: \"_For the prior specification there is no right or wrong answer. It all depends on the data, the context and the assumptions you are willing to make. It is always recommended to do some prior predictive sampling and sensitivity analysis to check the impact of the priors on the posterior. We skip this here for the sake of simplicity. If you are not sure about specific priors, the `DelayedSaturatedMMM` class has some default priors that you can use as a starting point._\"" + ] + }, + { + "cell_type": "markdown", + "id": "f195a79e", + "metadata": {}, + "source": [ + "The second feature that we can use for model definition is `sampler_config`. Similar to `model_config`, it's a dictionary that gets saved and contains things you'd usually pass to the `fit()` kwargs. It's not mandatory to create your own `sampler_config`; if not provided, both `model_config` and `sampler_config` will default to the forms specified by PyMC Labs experts, which allows for the usage of all model functionalities. The default `sampler_config` is left empty because the default sampling parameters usually prove sufficient for a start." + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "0ab8140c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{}" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dummy_model.default_sampler_config" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "bf5a50f4", + "metadata": {}, + "outputs": [], + "source": [ + "my_sampler_config = {\n", + " 'tune':1000,\n", + " 'draws':1000,\n", + " 'chains':4,\n", + " 'target_accept':0.95,\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "f3bfe090", + "metadata": {}, + "source": [ + "Let's finally assemble our model!" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "c7bd6909", + "metadata": {}, + "outputs": [], + "source": [ + "mmm = DelayedSaturatedMMM(\n", + " model_config = my_model_config,\n", + " sampler_config = my_sampler_config,\n", + " date_column=\"date_week\",\n", + " channel_columns=[\"x1\", \"x2\"],\n", + " control_columns=[\n", + " \"event_1\",\n", + " \"event_2\",\n", + " \"t\",\n", + " ],\n", + " adstock_max_lag=8,\n", + " yearly_seasonality=2,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "54095b1a", + "metadata": {}, + "source": [ + "An important thing to note here is that in the new version of `DelayedSaturatedMMM`, we don't pass our dataset to the class constructor itself. This is due to a reason I've mentioned before - it supports `sklearn` transformers and validations that require a usual X, y split and typically expect the data to be passed to the `fit()` method." + ] + }, + { + "cell_type": "markdown", + "id": "dec9b1b0", + "metadata": {}, + "source": [ + "## _Model Fitting_" + ] + }, + { + "cell_type": "markdown", + "id": "d5e64562-ba78-4497-a0f8-123b4bc88b79", + "metadata": {}, + "source": [ + "Let's split the dataset:" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "ff23006b-a55b-4a22-9f34-4eeaddf47486", + "metadata": {}, + "outputs": [], + "source": [ + "X = data.drop('y',axis=1)\n", + "y = data['y']" + ] + }, + { + "cell_type": "markdown", + "id": "403e3ed2", + "metadata": {}, + "source": [ + "All that's left now is to finally fit the model:\n", + "\n", + "As you can see below, you can still pass the sampler kwargs directly to `fit()` method. However, only those kwargs passed using `sampler_config` will be saved. Therefore, only these will be available after loading the model." + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "0f6ab0a8", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Auto-assigning NUTS sampler...\n", + "Initializing NUTS using jitter+adapt_diag...\n", + "Multiprocess sampling (4 chains in 4 jobs)\n", + "NUTS: [intercept, beta_channel, alpha, lam, sigma, gamma_control, gamma_fourier]\n" + ] + }, + { + "data": { + "text/html": [ + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "
\n", + " \n", + " 100.00% [8000/8000 00:29<00:00 Sampling 4 chains, 0 divergences]\n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Sampling 4 chains for 1_000 tune and 1_000 draw iterations (4_000 + 4_000 draws total) took 30 seconds.\n", + "Sampling: [alpha, beta_channel, gamma_control, gamma_fourier, intercept, lam, likelihood, sigma]\n", + "Sampling: [likelihood]\n" + ] + }, + { + "data": { + "text/html": [ + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "
\n", + " \n", + " 100.00% [4000/4000 00:00<00:00]\n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + "
arviz.InferenceData
\n", + "
\n", + "
    \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:                    (chain: 4, draw: 1000, control: 3,\n",
      +       "                                fourier_mode: 4, channel: 2, date: 179)\n",
      +       "Coordinates:\n",
      +       "  * chain                      (chain) int64 0 1 2 3\n",
      +       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 995 996 997 998 999\n",
      +       "  * control                    (control) <U7 'event_1' 'event_2' 't'\n",
      +       "  * fourier_mode               (fourier_mode) <U11 'sin_order_1' ... 'cos_ord...\n",
      +       "  * channel                    (channel) <U2 'x1' 'x2'\n",
      +       "  * date                       (date) <U10 '2018-04-02' ... '2021-08-30'\n",
      +       "Data variables: (12/13)\n",
      +       "    intercept                  (chain, draw) float64 0.3381 0.3361 ... 0.3479\n",
      +       "    gamma_control              (chain, draw, control) float64 0.2968 ... 0.00...\n",
      +       "    gamma_fourier              (chain, draw, fourier_mode) float64 -0.002612 ...\n",
      +       "    beta_channel               (chain, draw, channel) float64 0.3718 ... 0.2628\n",
      +       "    alpha                      (chain, draw, channel) float64 0.4162 ... 0.2007\n",
      +       "    lam                        (chain, draw, channel) float64 4.26 ... 2.758\n",
      +       "    ...                         ...\n",
      +       "    channel_adstock            (chain, draw, date, channel) float64 0.1868 .....\n",
      +       "    channel_adstock_saturated  (chain, draw, date, channel) float64 0.3781 .....\n",
      +       "    channel_contributions      (chain, draw, date, channel) float64 0.1406 .....\n",
      +       "    control_contributions      (chain, draw, date, control) float64 0.0 ... 0...\n",
      +       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 -0.0...\n",
      +       "    mu                         (chain, draw, date) float64 0.4769 ... 0.5924\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:14.027598\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1\n",
      +       "    sampling_time:              29.821417093276978\n",
      +       "    tuning_steps:               1000

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:     (chain: 4, draw: 1000, date: 179)\n",
      +       "Coordinates:\n",
      +       "  * chain       (chain) int64 0 1 2 3\n",
      +       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999\n",
      +       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "Data variables:\n",
      +       "    likelihood  (chain, draw, date) float64 0.5039 0.439 ... 0.5873 0.6072\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:15.416164\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:                (chain: 4, draw: 1000)\n",
      +       "Coordinates:\n",
      +       "  * chain                  (chain) int64 0 1 2 3\n",
      +       "  * draw                   (draw) int64 0 1 2 3 4 5 ... 994 995 996 997 998 999\n",
      +       "Data variables: (12/17)\n",
      +       "    process_time_diff      (chain, draw) float64 0.008982 0.009454 ... 0.009203\n",
      +       "    step_size_bar          (chain, draw) float64 0.05522 0.05522 ... 0.06921\n",
      +       "    step_size              (chain, draw) float64 0.05862 0.05862 ... 0.07543\n",
      +       "    acceptance_rate        (chain, draw) float64 0.9987 0.9934 ... 0.8931 0.9167\n",
      +       "    index_in_trajectory    (chain, draw) int64 -12 20 43 -17 ... 42 20 -43 -29\n",
      +       "    tree_depth             (chain, draw) int64 6 6 6 6 7 6 6 7 ... 6 5 5 6 7 6 6\n",
      +       "    ...                     ...\n",
      +       "    energy_error           (chain, draw) float64 -0.01181 -0.02828 ... -0.01478\n",
      +       "    perf_counter_diff      (chain, draw) float64 0.009316 0.01008 ... 0.009355\n",
      +       "    n_steps                (chain, draw) float64 63.0 63.0 63.0 ... 63.0 63.0\n",
      +       "    diverging              (chain, draw) bool False False False ... False False\n",
      +       "    perf_counter_start     (chain, draw) float64 3.949e+06 ... 3.949e+06\n",
      +       "    lp                     (chain, draw) float64 355.1 355.2 ... 355.6 351.6\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:14.040220\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1\n",
      +       "    sampling_time:              29.821417093276978\n",
      +       "    tuning_steps:               1000

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:                    (chain: 1, draw: 500, fourier_mode: 4,\n",
      +       "                                date: 179, channel: 2, control: 3)\n",
      +       "Coordinates:\n",
      +       "  * chain                      (chain) int64 0\n",
      +       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 495 496 497 498 499\n",
      +       "  * fourier_mode               (fourier_mode) <U11 'sin_order_1' ... 'cos_ord...\n",
      +       "  * date                       (date) <U10 '2018-04-02' ... '2021-08-30'\n",
      +       "  * channel                    (channel) <U2 'x1' 'x2'\n",
      +       "  * control                    (control) <U7 'event_1' 'event_2' 't'\n",
      +       "Data variables: (12/13)\n",
      +       "    gamma_fourier              (chain, draw, fourier_mode) float64 1.28 ... 1...\n",
      +       "    intercept                  (chain, draw) float64 1.178 -2.005 ... 2.533\n",
      +       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 1.28...\n",
      +       "    mu                         (chain, draw, date) float64 0.8703 ... -44.96\n",
      +       "    channel_contributions      (chain, draw, date, channel) float64 0.4222 .....\n",
      +       "    control_contributions      (chain, draw, date, control) float64 0.0 ... -...\n",
      +       "    ...                         ...\n",
      +       "    gamma_control              (chain, draw, control) float64 1.547 ... -0.2666\n",
      +       "    channel_adstock            (chain, draw, date, channel) float64 0.3087 .....\n",
      +       "    alpha                      (chain, draw, channel) float64 0.03434 ... 0.1455\n",
      +       "    lam                        (chain, draw, channel) float64 2.558 ... 4.149\n",
      +       "    channel_adstock_saturated  (chain, draw, date, channel) float64 0.3755 .....\n",
      +       "    sigma                      (chain, draw) float64 0.05319 1.662 ... 1.212\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:15.159471\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:     (chain: 1, draw: 500, date: 179)\n",
      +       "Coordinates:\n",
      +       "  * chain       (chain) int64 0\n",
      +       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 492 493 494 495 496 497 498 499\n",
      +       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "Data variables:\n",
      +       "    likelihood  (chain, draw, date) float64 0.8725 3.274 6.447 ... -45.43 -45.69\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:15.164125\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:     (date: 179)\n",
      +       "Coordinates:\n",
      +       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "Data variables:\n",
      +       "    likelihood  (date) float64 0.4794 0.4527 0.5374 ... 0.4978 0.5388 0.5625\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:14.043853\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:       (date: 179, channel: 2, control: 3, fourier_mode: 4)\n",
      +       "Coordinates:\n",
      +       "  * date          (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "  * channel       (channel) <U2 'x1' 'x2'\n",
      +       "  * control       (control) <U7 'event_1' 'event_2' 't'\n",
      +       "  * fourier_mode  (fourier_mode) <U11 'sin_order_1' ... 'cos_order_2'\n",
      +       "Data variables:\n",
      +       "    channel_data  (date, channel) float64 0.3196 0.0 0.1128 ... 0.0 0.4403 0.0\n",
      +       "    target        (date) float64 0.4794 0.4527 0.5374 ... 0.4978 0.5388 0.5625\n",
      +       "    control_data  (date, control) float64 0.0 0.0 0.0 0.0 ... 0.0 0.0 178.0\n",
      +       "    fourier_data  (date, fourier_mode) float64 0.9999 -0.01183 ... -0.4547\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:14.045029\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:    (index: 179)\n",
      +       "Coordinates:\n",
      +       "  * index      (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      +       "Data variables:\n",
      +       "    date_week  (index) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "    x1         (index) float64 0.3186 0.1124 0.2924 ... 0.1719 0.2803 0.4389\n",
      +       "    x2         (index) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.8633 0.0 0.0 0.0\n",
      +       "    event_1    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      +       "    event_2    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      +       "    dayofyear  (index) int64 92 99 106 113 120 127 ... 207 214 221 228 235 242\n",
      +       "    t          (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      +       "    y          (index) float64 3.985e+03 3.763e+03 ... 4.479e+03 4.676e+03

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
\n", + "
\n", + " " + ], + "text/plain": [ + "Inference data with groups:\n", + "\t> posterior\n", + "\t> posterior_predictive\n", + "\t> sample_stats\n", + "\t> prior\n", + "\t> prior_predictive\n", + "\t> observed_data\n", + "\t> constant_data\n", + "\t> fit_data" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mmm.fit(X=X, y=y, random_seed=rng)" + ] + }, + { + "cell_type": "markdown", + "id": "c29a6461", + "metadata": {}, + "source": [ + "The `fit()` method automatically builds the model using the priors from `model_config`, and assigns the created model to our instance. You can access it as a normal attribute." + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "c6b8e2af", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "pymc.model.Model" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(mmm.model)" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "f046ee2c", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "clusterdate (179) x channel (2)\n", + "\n", + "date (179) x channel (2)\n", + "\n", + "\n", + "clusterdate (179)\n", + "\n", + "date (179)\n", + "\n", + "\n", + "clusterchannel (2)\n", + "\n", + "channel (2)\n", + "\n", + "\n", + "clusterdate (179) x control (3)\n", + "\n", + "date (179) x control (3)\n", + "\n", + "\n", + "clustercontrol (3)\n", + "\n", + "control (3)\n", + "\n", + "\n", + "clusterdate (179) x fourier_mode (4)\n", + "\n", + "date (179) x fourier_mode (4)\n", + "\n", + "\n", + "clusterfourier_mode (4)\n", + "\n", + "fourier_mode (4)\n", + "\n", + "\n", + "\n", + "channel_contributions\n", + "\n", + "channel_contributions\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "mu\n", + "\n", + "mu\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "channel_contributions->mu\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "channel_data\n", + "\n", + "channel_data\n", + "~\n", + "MutableData\n", + "\n", + "\n", + "\n", + "channel_adstock\n", + "\n", + "channel_adstock\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "channel_data->channel_adstock\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "channel_adstock_saturated\n", + "\n", + "channel_adstock_saturated\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "channel_adstock->channel_adstock_saturated\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "channel_adstock_saturated->channel_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "target\n", + "\n", + "target\n", + "~\n", + "MutableData\n", + "\n", + "\n", + "\n", + "likelihood\n", + "\n", + "likelihood\n", + "~\n", + "Normal\n", + "\n", + "\n", + "\n", + "mu->likelihood\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "likelihood->target\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "intercept\n", + "\n", + "intercept\n", + "~\n", + "Normal\n", + "\n", + "\n", + "\n", + "intercept->mu\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sigma\n", + "\n", + "sigma\n", + "~\n", + "HalfNormal\n", + "\n", + "\n", + "\n", + "sigma->likelihood\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "lam\n", + "\n", + "lam\n", + "~\n", + "Gamma\n", + "\n", + "\n", + "\n", + "lam->channel_adstock_saturated\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "alpha\n", + "\n", + "alpha\n", + "~\n", + "Beta\n", + "\n", + "\n", + "\n", + "alpha->channel_adstock\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "beta_channel\n", + "\n", + "beta_channel\n", + "~\n", + "HalfNormal\n", + "\n", + "\n", + "\n", + "beta_channel->channel_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "control_data\n", + "\n", + "control_data\n", + "~\n", + "MutableData\n", + "\n", + "\n", + "\n", + "control_contributions\n", + "\n", + "control_contributions\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "control_data->control_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "control_contributions->mu\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "gamma_control\n", + "\n", + "gamma_control\n", + "~\n", + "Normal\n", + "\n", + "\n", + "\n", + "gamma_control->control_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fourier_contributions\n", + "\n", + "fourier_contributions\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "fourier_contributions->mu\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fourier_data\n", + "\n", + "fourier_data\n", + "~\n", + "MutableData\n", + "\n", + "\n", + "\n", + "fourier_data->fourier_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "gamma_fourier\n", + "\n", + "gamma_fourier\n", + "~\n", + "Laplace\n", + "\n", + "\n", + "\n", + "gamma_fourier->fourier_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mmm.graphviz()" + ] + }, + { + "cell_type": "markdown", + "id": "c804b600", + "metadata": {}, + "source": [ + "posterior trace can be accessed by `fit_result` attribute" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "66903965", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.Dataset>\n",
+       "Dimensions:                    (chain: 4, draw: 1000, control: 3,\n",
+       "                                fourier_mode: 4, channel: 2, date: 179)\n",
+       "Coordinates:\n",
+       "  * chain                      (chain) int64 0 1 2 3\n",
+       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 995 996 997 998 999\n",
+       "  * control                    (control) <U7 'event_1' 'event_2' 't'\n",
+       "  * fourier_mode               (fourier_mode) <U11 'sin_order_1' ... 'cos_ord...\n",
+       "  * channel                    (channel) <U2 'x1' 'x2'\n",
+       "  * date                       (date) <U10 '2018-04-02' ... '2021-08-30'\n",
+       "Data variables: (12/13)\n",
+       "    intercept                  (chain, draw) float64 0.3381 0.3361 ... 0.3479\n",
+       "    gamma_control              (chain, draw, control) float64 0.2968 ... 0.00...\n",
+       "    gamma_fourier              (chain, draw, fourier_mode) float64 -0.002612 ...\n",
+       "    beta_channel               (chain, draw, channel) float64 0.3718 ... 0.2628\n",
+       "    alpha                      (chain, draw, channel) float64 0.4162 ... 0.2007\n",
+       "    lam                        (chain, draw, channel) float64 4.26 ... 2.758\n",
+       "    ...                         ...\n",
+       "    channel_adstock            (chain, draw, date, channel) float64 0.1868 .....\n",
+       "    channel_adstock_saturated  (chain, draw, date, channel) float64 0.3781 .....\n",
+       "    channel_contributions      (chain, draw, date, channel) float64 0.1406 .....\n",
+       "    control_contributions      (chain, draw, date, control) float64 0.0 ... 0...\n",
+       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 -0.0...\n",
+       "    mu                         (chain, draw, date) float64 0.4769 ... 0.5924\n",
+       "Attributes:\n",
+       "    created_at:                 2023-08-03T11:09:14.027598\n",
+       "    arviz_version:              0.16.1\n",
+       "    inference_library:          pymc\n",
+       "    inference_library_version:  5.6.1\n",
+       "    sampling_time:              29.821417093276978\n",
+       "    tuning_steps:               1000
" + ], + "text/plain": [ + "\n", + "Dimensions: (chain: 4, draw: 1000, control: 3,\n", + " fourier_mode: 4, channel: 2, date: 179)\n", + "Coordinates:\n", + " * chain (chain) int64 0 1 2 3\n", + " * draw (draw) int64 0 1 2 3 4 5 ... 995 996 997 998 999\n", + " * control (control) \n", + "
\n", + "
arviz.InferenceData
\n", + "
\n", + "
    \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:                    (chain: 4, draw: 1000, control: 3,\n",
      +       "                                fourier_mode: 4, channel: 2, date: 179)\n",
      +       "Coordinates:\n",
      +       "  * chain                      (chain) int64 0 1 2 3\n",
      +       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 995 996 997 998 999\n",
      +       "  * control                    (control) <U7 'event_1' 'event_2' 't'\n",
      +       "  * fourier_mode               (fourier_mode) <U11 'sin_order_1' ... 'cos_ord...\n",
      +       "  * channel                    (channel) <U2 'x1' 'x2'\n",
      +       "  * date                       (date) <U10 '2018-04-02' ... '2021-08-30'\n",
      +       "Data variables: (12/13)\n",
      +       "    intercept                  (chain, draw) float64 0.3381 0.3361 ... 0.3479\n",
      +       "    gamma_control              (chain, draw, control) float64 0.2968 ... 0.00...\n",
      +       "    gamma_fourier              (chain, draw, fourier_mode) float64 -0.002612 ...\n",
      +       "    beta_channel               (chain, draw, channel) float64 0.3718 ... 0.2628\n",
      +       "    alpha                      (chain, draw, channel) float64 0.4162 ... 0.2007\n",
      +       "    lam                        (chain, draw, channel) float64 4.26 ... 2.758\n",
      +       "    ...                         ...\n",
      +       "    channel_adstock            (chain, draw, date, channel) float64 0.1868 .....\n",
      +       "    channel_adstock_saturated  (chain, draw, date, channel) float64 0.3781 .....\n",
      +       "    channel_contributions      (chain, draw, date, channel) float64 0.1406 .....\n",
      +       "    control_contributions      (chain, draw, date, control) float64 0.0 ... 0...\n",
      +       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 -0.0...\n",
      +       "    mu                         (chain, draw, date) float64 0.4769 ... 0.5924\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:14.027598\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1\n",
      +       "    sampling_time:              29.821417093276978\n",
      +       "    tuning_steps:               1000

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:     (chain: 4, draw: 1000, date: 179)\n",
      +       "Coordinates:\n",
      +       "  * chain       (chain) int64 0 1 2 3\n",
      +       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999\n",
      +       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "Data variables:\n",
      +       "    likelihood  (chain, draw, date) float64 0.5039 0.439 ... 0.5873 0.6072\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:15.416164\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:                (chain: 4, draw: 1000)\n",
      +       "Coordinates:\n",
      +       "  * chain                  (chain) int64 0 1 2 3\n",
      +       "  * draw                   (draw) int64 0 1 2 3 4 5 ... 994 995 996 997 998 999\n",
      +       "Data variables: (12/17)\n",
      +       "    process_time_diff      (chain, draw) float64 0.008982 0.009454 ... 0.009203\n",
      +       "    step_size_bar          (chain, draw) float64 0.05522 0.05522 ... 0.06921\n",
      +       "    step_size              (chain, draw) float64 0.05862 0.05862 ... 0.07543\n",
      +       "    acceptance_rate        (chain, draw) float64 0.9987 0.9934 ... 0.8931 0.9167\n",
      +       "    index_in_trajectory    (chain, draw) int64 -12 20 43 -17 ... 42 20 -43 -29\n",
      +       "    tree_depth             (chain, draw) int64 6 6 6 6 7 6 6 7 ... 6 5 5 6 7 6 6\n",
      +       "    ...                     ...\n",
      +       "    energy_error           (chain, draw) float64 -0.01181 -0.02828 ... -0.01478\n",
      +       "    perf_counter_diff      (chain, draw) float64 0.009316 0.01008 ... 0.009355\n",
      +       "    n_steps                (chain, draw) float64 63.0 63.0 63.0 ... 63.0 63.0\n",
      +       "    diverging              (chain, draw) bool False False False ... False False\n",
      +       "    perf_counter_start     (chain, draw) float64 3.949e+06 ... 3.949e+06\n",
      +       "    lp                     (chain, draw) float64 355.1 355.2 ... 355.6 351.6\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:14.040220\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1\n",
      +       "    sampling_time:              29.821417093276978\n",
      +       "    tuning_steps:               1000

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:                    (chain: 1, draw: 500, fourier_mode: 4,\n",
      +       "                                date: 179, channel: 2, control: 3)\n",
      +       "Coordinates:\n",
      +       "  * chain                      (chain) int64 0\n",
      +       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 495 496 497 498 499\n",
      +       "  * fourier_mode               (fourier_mode) <U11 'sin_order_1' ... 'cos_ord...\n",
      +       "  * date                       (date) <U10 '2018-04-02' ... '2021-08-30'\n",
      +       "  * channel                    (channel) <U2 'x1' 'x2'\n",
      +       "  * control                    (control) <U7 'event_1' 'event_2' 't'\n",
      +       "Data variables: (12/13)\n",
      +       "    gamma_fourier              (chain, draw, fourier_mode) float64 1.28 ... 1...\n",
      +       "    intercept                  (chain, draw) float64 1.178 -2.005 ... 2.533\n",
      +       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 1.28...\n",
      +       "    mu                         (chain, draw, date) float64 0.8703 ... -44.96\n",
      +       "    channel_contributions      (chain, draw, date, channel) float64 0.4222 .....\n",
      +       "    control_contributions      (chain, draw, date, control) float64 0.0 ... -...\n",
      +       "    ...                         ...\n",
      +       "    gamma_control              (chain, draw, control) float64 1.547 ... -0.2666\n",
      +       "    channel_adstock            (chain, draw, date, channel) float64 0.3087 .....\n",
      +       "    alpha                      (chain, draw, channel) float64 0.03434 ... 0.1455\n",
      +       "    lam                        (chain, draw, channel) float64 2.558 ... 4.149\n",
      +       "    channel_adstock_saturated  (chain, draw, date, channel) float64 0.3755 .....\n",
      +       "    sigma                      (chain, draw) float64 0.05319 1.662 ... 1.212\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:15.159471\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:     (chain: 1, draw: 500, date: 179)\n",
      +       "Coordinates:\n",
      +       "  * chain       (chain) int64 0\n",
      +       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 492 493 494 495 496 497 498 499\n",
      +       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "Data variables:\n",
      +       "    likelihood  (chain, draw, date) float64 0.8725 3.274 6.447 ... -45.43 -45.69\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:15.164125\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:     (date: 179)\n",
      +       "Coordinates:\n",
      +       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "Data variables:\n",
      +       "    likelihood  (date) float64 0.4794 0.4527 0.5374 ... 0.4978 0.5388 0.5625\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:14.043853\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:       (date: 179, channel: 2, control: 3, fourier_mode: 4)\n",
      +       "Coordinates:\n",
      +       "  * date          (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "  * channel       (channel) <U2 'x1' 'x2'\n",
      +       "  * control       (control) <U7 'event_1' 'event_2' 't'\n",
      +       "  * fourier_mode  (fourier_mode) <U11 'sin_order_1' ... 'cos_order_2'\n",
      +       "Data variables:\n",
      +       "    channel_data  (date, channel) float64 0.3196 0.0 0.1128 ... 0.0 0.4403 0.0\n",
      +       "    target        (date) float64 0.4794 0.4527 0.5374 ... 0.4978 0.5388 0.5625\n",
      +       "    control_data  (date, control) float64 0.0 0.0 0.0 0.0 ... 0.0 0.0 178.0\n",
      +       "    fourier_data  (date, fourier_mode) float64 0.9999 -0.01183 ... -0.4547\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:14.045029\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:    (index: 179)\n",
      +       "Coordinates:\n",
      +       "  * index      (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      +       "Data variables:\n",
      +       "    date_week  (index) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "    x1         (index) float64 0.3186 0.1124 0.2924 ... 0.1719 0.2803 0.4389\n",
      +       "    x2         (index) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.8633 0.0 0.0 0.0\n",
      +       "    event_1    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      +       "    event_2    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      +       "    dayofyear  (index) int64 92 99 106 113 120 127 ... 207 214 221 228 235 242\n",
      +       "    t          (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      +       "    y          (index) float64 3.985e+03 3.763e+03 ... 4.479e+03 4.676e+03

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
\n", + " \n", + " " + ], + "text/plain": [ + "Inference data with groups:\n", + "\t> posterior\n", + "\t> posterior_predictive\n", + "\t> sample_stats\n", + "\t> prior\n", + "\t> prior_predictive\n", + "\t> observed_data\n", + "\t> constant_data\n", + "\t> fit_data" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mmm.idata" + ] + }, + { + "cell_type": "markdown", + "id": "8b433c7f-0f0d-40b2-bcfb-a19555b528bd", + "metadata": {}, + "source": [ + "## `Save` and `load`" + ] + }, + { + "cell_type": "markdown", + "id": "7b0a35f4", + "metadata": {}, + "source": [ + "All the data passed to the model on initialisation is stored in `idata.attrs`. This will be used later in the `save()` method to convert both this data and all the fit data into the netCDF format." + ] + }, + { + "cell_type": "markdown", + "id": "45948f46", + "metadata": {}, + "source": [ + "Simply specify the path to which you'd like to save your model:" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "b3abe93a", + "metadata": {}, + "outputs": [], + "source": [ + "mmm.save('my_saved_model.nc')" + ] + }, + { + "cell_type": "markdown", + "id": "8a5eba79", + "metadata": {}, + "source": [ + "And pass it to the `load()` method when it's needed again on the target system:" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "0421bae8", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/michalraczycki/Documents/pymc-marketing/.conda/envs/pymc-marketing/lib/python3.10/site-packages/arviz/data/inference_data.py:153: UserWarning: fit_data group is not defined in the InferenceData scheme\n", + " warnings.warn(\n" + ] + } + ], + "source": [ + "loaded_model = DelayedSaturatedMMM.load('my_saved_model.nc')" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "a8b666d3", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "clusterdate (179) x channel (2)\n", + "\n", + "date (179) x channel (2)\n", + "\n", + "\n", + "clusterdate (179)\n", + "\n", + "date (179)\n", + "\n", + "\n", + "clusterchannel (2)\n", + "\n", + "channel (2)\n", + "\n", + "\n", + "clusterdate (179) x control (3)\n", + "\n", + "date (179) x control (3)\n", + "\n", + "\n", + "clustercontrol (3)\n", + "\n", + "control (3)\n", + "\n", + "\n", + "clusterdate (179) x fourier_mode (4)\n", + "\n", + "date (179) x fourier_mode (4)\n", + "\n", + "\n", + "clusterfourier_mode (4)\n", + "\n", + "fourier_mode (4)\n", + "\n", + "\n", + "\n", + "channel_contributions\n", + "\n", + "channel_contributions\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "mu\n", + "\n", + "mu\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "channel_contributions->mu\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "channel_data\n", + "\n", + "channel_data\n", + "~\n", + "MutableData\n", + "\n", + "\n", + "\n", + "channel_adstock\n", + "\n", + "channel_adstock\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "channel_data->channel_adstock\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "channel_adstock_saturated\n", + "\n", + "channel_adstock_saturated\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "channel_adstock->channel_adstock_saturated\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "channel_adstock_saturated->channel_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "target\n", + "\n", + "target\n", + "~\n", + "MutableData\n", + "\n", + "\n", + "\n", + "likelihood\n", + "\n", + "likelihood\n", + "~\n", + "Normal\n", + "\n", + "\n", + "\n", + "mu->likelihood\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "likelihood->target\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "intercept\n", + "\n", + "intercept\n", + "~\n", + "Normal\n", + "\n", + "\n", + "\n", + "intercept->mu\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sigma\n", + "\n", + "sigma\n", + "~\n", + "HalfNormal\n", + "\n", + "\n", + "\n", + "sigma->likelihood\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "lam\n", + "\n", + "lam\n", + "~\n", + "Gamma\n", + "\n", + "\n", + "\n", + "lam->channel_adstock_saturated\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "alpha\n", + "\n", + "alpha\n", + "~\n", + "Beta\n", + "\n", + "\n", + "\n", + "alpha->channel_adstock\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "beta_channel\n", + "\n", + "beta_channel\n", + "~\n", + "HalfNormal\n", + "\n", + "\n", + "\n", + "beta_channel->channel_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "control_data\n", + "\n", + "control_data\n", + "~\n", + "MutableData\n", + "\n", + "\n", + "\n", + "control_contributions\n", + "\n", + "control_contributions\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "control_data->control_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "control_contributions->mu\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "gamma_control\n", + "\n", + "gamma_control\n", + "~\n", + "Normal\n", + "\n", + "\n", + "\n", + "gamma_control->control_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fourier_contributions\n", + "\n", + "fourier_contributions\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "fourier_contributions->mu\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fourier_data\n", + "\n", + "fourier_data\n", + "~\n", + "MutableData\n", + "\n", + "\n", + "\n", + "fourier_data->fourier_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "gamma_fourier\n", + "\n", + "gamma_fourier\n", + "~\n", + "Laplace\n", + "\n", + "\n", + "\n", + "gamma_fourier->fourier_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "loaded_model.graphviz()" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "cfb64a2c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + "
arviz.InferenceData
\n", + "
\n", + "
    \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:                    (chain: 4, draw: 1000, control: 3,\n",
      +       "                                fourier_mode: 4, channel: 2, date: 179)\n",
      +       "Coordinates:\n",
      +       "  * chain                      (chain) int64 0 1 2 3\n",
      +       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 995 996 997 998 999\n",
      +       "  * control                    (control) object 'event_1' 'event_2' 't'\n",
      +       "  * fourier_mode               (fourier_mode) object 'sin_order_1' ... 'cos_o...\n",
      +       "  * channel                    (channel) object 'x1' 'x2'\n",
      +       "  * date                       (date) object '2018-04-02' ... '2021-08-30'\n",
      +       "Data variables: (12/13)\n",
      +       "    intercept                  (chain, draw) float64 ...\n",
      +       "    gamma_control              (chain, draw, control) float64 ...\n",
      +       "    gamma_fourier              (chain, draw, fourier_mode) float64 ...\n",
      +       "    beta_channel               (chain, draw, channel) float64 ...\n",
      +       "    alpha                      (chain, draw, channel) float64 ...\n",
      +       "    lam                        (chain, draw, channel) float64 ...\n",
      +       "    ...                         ...\n",
      +       "    channel_adstock            (chain, draw, date, channel) float64 ...\n",
      +       "    channel_adstock_saturated  (chain, draw, date, channel) float64 ...\n",
      +       "    channel_contributions      (chain, draw, date, channel) float64 ...\n",
      +       "    control_contributions      (chain, draw, date, control) float64 ...\n",
      +       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 ...\n",
      +       "    mu                         (chain, draw, date) float64 ...\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:14.027598\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1\n",
      +       "    sampling_time:              29.821417093276978\n",
      +       "    tuning_steps:               1000

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:     (chain: 4, draw: 1000, date: 179)\n",
      +       "Coordinates:\n",
      +       "  * chain       (chain) int64 0 1 2 3\n",
      +       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999\n",
      +       "  * date        (date) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "Data variables:\n",
      +       "    likelihood  (chain, draw, date) float64 ...\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:15.416164\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:                (chain: 4, draw: 1000)\n",
      +       "Coordinates:\n",
      +       "  * chain                  (chain) int64 0 1 2 3\n",
      +       "  * draw                   (draw) int64 0 1 2 3 4 5 ... 994 995 996 997 998 999\n",
      +       "Data variables: (12/17)\n",
      +       "    process_time_diff      (chain, draw) float64 ...\n",
      +       "    step_size_bar          (chain, draw) float64 ...\n",
      +       "    step_size              (chain, draw) float64 ...\n",
      +       "    acceptance_rate        (chain, draw) float64 ...\n",
      +       "    index_in_trajectory    (chain, draw) int64 ...\n",
      +       "    tree_depth             (chain, draw) int64 ...\n",
      +       "    ...                     ...\n",
      +       "    energy_error           (chain, draw) float64 ...\n",
      +       "    perf_counter_diff      (chain, draw) float64 ...\n",
      +       "    n_steps                (chain, draw) float64 ...\n",
      +       "    diverging              (chain, draw) bool ...\n",
      +       "    perf_counter_start     (chain, draw) float64 ...\n",
      +       "    lp                     (chain, draw) float64 ...\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:14.040220\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1\n",
      +       "    sampling_time:              29.821417093276978\n",
      +       "    tuning_steps:               1000

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:                    (chain: 1, draw: 500, fourier_mode: 4,\n",
      +       "                                date: 179, channel: 2, control: 3)\n",
      +       "Coordinates:\n",
      +       "  * chain                      (chain) int64 0\n",
      +       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 495 496 497 498 499\n",
      +       "  * fourier_mode               (fourier_mode) object 'sin_order_1' ... 'cos_o...\n",
      +       "  * date                       (date) object '2018-04-02' ... '2021-08-30'\n",
      +       "  * channel                    (channel) object 'x1' 'x2'\n",
      +       "  * control                    (control) object 'event_1' 'event_2' 't'\n",
      +       "Data variables: (12/13)\n",
      +       "    gamma_fourier              (chain, draw, fourier_mode) float64 ...\n",
      +       "    intercept                  (chain, draw) float64 ...\n",
      +       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 ...\n",
      +       "    mu                         (chain, draw, date) float64 ...\n",
      +       "    channel_contributions      (chain, draw, date, channel) float64 ...\n",
      +       "    control_contributions      (chain, draw, date, control) float64 ...\n",
      +       "    ...                         ...\n",
      +       "    gamma_control              (chain, draw, control) float64 ...\n",
      +       "    channel_adstock            (chain, draw, date, channel) float64 ...\n",
      +       "    alpha                      (chain, draw, channel) float64 ...\n",
      +       "    lam                        (chain, draw, channel) float64 ...\n",
      +       "    channel_adstock_saturated  (chain, draw, date, channel) float64 ...\n",
      +       "    sigma                      (chain, draw) float64 ...\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:15.159471\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:     (chain: 1, draw: 500, date: 179)\n",
      +       "Coordinates:\n",
      +       "  * chain       (chain) int64 0\n",
      +       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 492 493 494 495 496 497 498 499\n",
      +       "  * date        (date) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "Data variables:\n",
      +       "    likelihood  (chain, draw, date) float64 ...\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:15.164125\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:     (date: 179)\n",
      +       "Coordinates:\n",
      +       "  * date        (date) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "Data variables:\n",
      +       "    likelihood  (date) float64 ...\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:14.043853\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:       (date: 179, channel: 2, control: 3, fourier_mode: 4)\n",
      +       "Coordinates:\n",
      +       "  * date          (date) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "  * channel       (channel) object 'x1' 'x2'\n",
      +       "  * control       (control) object 'event_1' 'event_2' 't'\n",
      +       "  * fourier_mode  (fourier_mode) object 'sin_order_1' ... 'cos_order_2'\n",
      +       "Data variables:\n",
      +       "    channel_data  (date, channel) float64 ...\n",
      +       "    target        (date) float64 ...\n",
      +       "    control_data  (date, control) float64 ...\n",
      +       "    fourier_data  (date, fourier_mode) float64 ...\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-03T11:09:14.045029\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:    (index: 179)\n",
      +       "Coordinates:\n",
      +       "  * index      (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      +       "Data variables:\n",
      +       "    date_week  (index) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "    x1         (index) float64 0.3186 0.1124 0.2924 ... 0.1719 0.2803 0.4389\n",
      +       "    x2         (index) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.8633 0.0 0.0 0.0\n",
      +       "    event_1    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      +       "    event_2    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      +       "    dayofyear  (index) int64 92 99 106 113 120 127 ... 207 214 221 228 235 242\n",
      +       "    t          (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      +       "    y          (index) float64 3.985e+03 3.763e+03 ... 4.479e+03 4.676e+03

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
\n", + "
\n", + " " + ], + "text/plain": [ + "Inference data with groups:\n", + "\t> posterior\n", + "\t> posterior_predictive\n", + "\t> sample_stats\n", + "\t> prior\n", + "\t> prior_predictive\n", + "\t> observed_data\n", + "\t> constant_data\n", + "\t> fit_data" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "loaded_model.idata" + ] + }, + { + "cell_type": "markdown", + "id": "ab64be46-7fe5-4f39-b72b-36da1419f809", + "metadata": {}, + "source": [ + "A model loaded in this way is ready to be used for sampling and prediction, and has access to all previous samples and data." + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "dd59d056-6ac7-431c-85ee-99e7a8eefd8a", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Sampling: [likelihood]\n" + ] + }, + { + "data": { + "text/html": [ + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "
\n", + " \n", + " 100.00% [4000/4000 00:00<00:00]\n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.Dataset>\n",
+       "Dimensions:     (chain: 4, draw: 1000, date: 179)\n",
+       "Coordinates:\n",
+       "  * chain       (chain) int64 0 1 2 3\n",
+       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999\n",
+       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
+       "Data variables:\n",
+       "    likelihood  (chain, draw, date) float64 0.4907 0.4282 ... 0.5548 0.5396\n",
+       "Attributes:\n",
+       "    created_at:                 2023-08-03T11:09:22.139450\n",
+       "    arviz_version:              0.16.1\n",
+       "    inference_library:          pymc\n",
+       "    inference_library_version:  5.6.1
" + ], + "text/plain": [ + "\n", + "Dimensions: (chain: 4, draw: 1000, date: 179)\n", + "Coordinates:\n", + " * chain (chain) int64 0 1 2 3\n", + " * draw (draw) int64 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999\n", + " * date (date) " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "az.plot_ppc(loaded_model.idata);" + ] + }, + { + "cell_type": "markdown", + "id": "e8e807f9", + "metadata": {}, + "source": [ + "## Summary:" + ] + }, + { + "cell_type": "markdown", + "id": "61f232c1", + "metadata": {}, + "source": [ + "In summary, this article introduces the revolutionary ModelBuilder, a new PyMC-experimental module that simplifies the deployment of PyMC Bayesian models. It addresses a historic challenge faced by users of PyMC and most PPLs by offering a user-friendly and efficient approach to model deployment. The ModelBuilder provides two straightforward methods, save() and load(), which streamline the model preservation and replication process post fitting. Users are offered flexibility in controlling the prior settings with model_config and customizing the sampling process via sampler_config.\n", + "\n", + "The use of an example model from the MMM Example Notebook demonstrates the practical implementation of ModelBuilder, emphasizing its ability to enhance model sharing among teams without the necessity for extensive domain knowledge about the model. The deployment improvements in PyMC-Marketing brought about by ModelBuilder are not only user-friendly but also significantly enhance efficiency, making PyMC models more accessible for a wider audience." + ] + }, + { + "cell_type": "markdown", + "id": "b8ad333d", + "metadata": {}, + "source": [ + "Even though this introduction is using `DelayedSaturatedMMM`, functionalities from `ModelBuilder` are available in the CLV models as well." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "pymc-marketing", + "language": "python", + "name": "pymc-marketing" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 414da20cb7ce5c8cdb07adc4f00ff1be6d72ada7 Mon Sep 17 00:00:00 2001 From: Michal Raczycki Date: Thu, 17 Aug 2023 16:11:13 +0200 Subject: [PATCH 2/5] notebook formatting --- .../howto/ModelBuilder_usage_example.ipynb | 17466 ++++++++++++++++ .../howto/ModelBuilder_usage_example.myst.md | 279 + 2 files changed, 17745 insertions(+) create mode 100644 examples/howto/ModelBuilder_usage_example.ipynb create mode 100644 examples/howto/ModelBuilder_usage_example.myst.md diff --git a/examples/howto/ModelBuilder_usage_example.ipynb b/examples/howto/ModelBuilder_usage_example.ipynb new file mode 100644 index 000000000..d9a409205 --- /dev/null +++ b/examples/howto/ModelBuilder_usage_example.ipynb @@ -0,0 +1,17466 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ad9920da-e687-408d-b99f-060a99c0b561", + "metadata": {}, + "source": [ + "(ModelBuilder usage example)=\n", + "# ModelBuilder usage example\n", + "\n", + ":::{post} Aug 18, 2023\n", + ":tags: ModelBuilder, model deployment,\n", + ":category: intermediate, tutorial\n", + ":author: Michał Raczycki\n", + ":::" + ] + }, + { + "cell_type": "markdown", + "id": "1d74584c", + "metadata": {}, + "source": [ + "# Deploying MMMs and CLVs in Production: Saving and Loading Models" + ] + }, + { + "cell_type": "markdown", + "id": "3222ef04", + "metadata": {}, + "source": [ + "In this article, we'll tackle the historically challenging process of deploying Bayesian models built with PyMC. Introducing a revolutionary deployment module, we bring unprecedented simplicity and efficiency to the deployment of PyMC models. As we prioritize user-friendly solutions, let's delve into how this innovation can significantly elevate your data science projects." + ] + }, + { + "cell_type": "markdown", + "id": "ddb28436", + "metadata": {}, + "source": [ + "\n", + "Recent release of PyMC-Marketing by [Labs](https://www.pymc-labs.io) proves to be a big hit [(PyMC-Marketing)](https://www.pymc-labs.io/blog-posts/pymc-marketing-a-bayesian-approach-to-marketing-data-science/). In the feedback one could see an ongoing theme, many of you have been requesting easy and robust way of deploying models to production. It’s been a long-standing problem with PyMC ( and most other Probabilistic Programming Languages). The reason for that is that there’s no obvious way, and doesn’t matter which approach you try it proves to be tricky. That is why we’re happy to announce the release of `ModelBuilder`, brand new PyMC-experimental module that addresses this need, and improves on the deployment process significantly.\n", + "\n", + "The ModelBuilder module is a new feature of PyMC based models. It provides 2 easy-to-use methods: save() and load() that can be used after the model has been fit.save() allow easy preservation of the model to .netcdf format, and load() gives one-line replication of the original model. Users can control the prior settings with model_config, and customize the sampling process using sampler_config. Default values of those are working just fine, so first time give it a try without changing, and provide your own model_config and model_sampler if afterwards you want to try to customize it more for your use case!\n" + ] + }, + { + "cell_type": "markdown", + "id": "a808e36a", + "metadata": {}, + "source": [ + "For this notebook I'll use the example model used in [MMM Example Notebook](https://www.pymc-marketing.io/en/stable/notebooks/mmm/mmm_example.html), but ommit the details of data generation and plotting functionalities, since they're out of scope for this introduction, I highly recommend to see that part as well, but for now let's focus on today's topic: Groundbreaking deployment improvements in PyMC-Marketing!" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "1050a937", + "metadata": {}, + "outputs": [], + "source": [ + "import arviz as az\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "from pymc_marketing.mmm import DelayedSaturatedMMM" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "e2c3f4c4-1d74-4ae2-9ff2-c13cbcf7fe54", + "metadata": {}, + "outputs": [], + "source": [ + "az.style.use(\"arviz-darkgrid\")" + ] + }, + { + "cell_type": "markdown", + "id": "f37d808e", + "metadata": {}, + "source": [ + "Let's load the dataset:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "b7b1193f", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
date_weekyx1x2event_1event_2dayofyeartsin_order_1cos_order_1sin_order_2cos_order_2
02018-04-023984.6622370.3185800.0000000.00.09200.999930-0.011826-0.023651-0.999720
12018-04-093762.8717940.1123880.0000000.00.09910.991269-0.131859-0.261414-0.965227
22018-04-164466.9673880.2924000.0000000.00.010620.968251-0.249981-0.484089-0.875019
32018-04-233864.2193730.0713990.0000000.00.011330.931210-0.364483-0.678820-0.734304
42018-04-304441.6252780.3867450.0000000.00.012040.880683-0.473706-0.834370-0.551205
.......................................
1742021-08-023553.5461480.0330240.0000000.00.0214174-0.513901-0.8578490.8816990.471812
1752021-08-095565.5096820.1656150.8633490.00.0221175-0.613230-0.7899050.9687860.247898
1762021-08-164137.6514850.1718820.0000000.00.0228176-0.703677-0.7105200.9999530.009676
1772021-08-234479.0413510.2802570.0000000.00.0235177-0.783934-0.6208440.973402-0.229104
1782021-08-304675.9734390.4388570.0000000.00.0242178-0.852837-0.5221780.890665-0.454661
\n", + "

179 rows × 12 columns

\n", + "
" + ], + "text/plain": [ + " date_week y x1 x2 event_1 event_2 dayofyear \\\n", + "0 2018-04-02 3984.662237 0.318580 0.000000 0.0 0.0 92 \n", + "1 2018-04-09 3762.871794 0.112388 0.000000 0.0 0.0 99 \n", + "2 2018-04-16 4466.967388 0.292400 0.000000 0.0 0.0 106 \n", + "3 2018-04-23 3864.219373 0.071399 0.000000 0.0 0.0 113 \n", + "4 2018-04-30 4441.625278 0.386745 0.000000 0.0 0.0 120 \n", + ".. ... ... ... ... ... ... ... \n", + "174 2021-08-02 3553.546148 0.033024 0.000000 0.0 0.0 214 \n", + "175 2021-08-09 5565.509682 0.165615 0.863349 0.0 0.0 221 \n", + "176 2021-08-16 4137.651485 0.171882 0.000000 0.0 0.0 228 \n", + "177 2021-08-23 4479.041351 0.280257 0.000000 0.0 0.0 235 \n", + "178 2021-08-30 4675.973439 0.438857 0.000000 0.0 0.0 242 \n", + "\n", + " t sin_order_1 cos_order_1 sin_order_2 cos_order_2 \n", + "0 0 0.999930 -0.011826 -0.023651 -0.999720 \n", + "1 1 0.991269 -0.131859 -0.261414 -0.965227 \n", + "2 2 0.968251 -0.249981 -0.484089 -0.875019 \n", + "3 3 0.931210 -0.364483 -0.678820 -0.734304 \n", + "4 4 0.880683 -0.473706 -0.834370 -0.551205 \n", + ".. ... ... ... ... ... \n", + "174 174 -0.513901 -0.857849 0.881699 0.471812 \n", + "175 175 -0.613230 -0.789905 0.968786 0.247898 \n", + "176 176 -0.703677 -0.710520 0.999953 0.009676 \n", + "177 177 -0.783934 -0.620844 0.973402 -0.229104 \n", + "178 178 -0.852837 -0.522178 0.890665 -0.454661 \n", + "\n", + "[179 rows x 12 columns]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "url = \"https://raw.githubusercontent.com/pymc-labs/pymc-marketing/main/datasets/mmm_example.csv\"\n", + "df = pd.read_csv(url)\n", + "df" + ] + }, + { + "cell_type": "markdown", + "id": "87deb70d", + "metadata": {}, + "source": [ + "But for our model we need much smaller dataset, many of the previous features were contributing to generation of others, now as our target variable is computed we can filter out not needed columns:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "52b6d127", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
date_weekyx1x2event_1event_2dayofyeart
02018-04-023984.6622370.3185800.00.00.0920
12018-04-093762.8717940.1123880.00.00.0991
22018-04-164466.9673880.2924000.00.00.01062
32018-04-233864.2193730.0713990.00.00.01133
42018-04-304441.6252780.3867450.00.00.01204
\n", + "
" + ], + "text/plain": [ + " date_week y x1 x2 event_1 event_2 dayofyear t\n", + "0 2018-04-02 3984.662237 0.318580 0.0 0.0 0.0 92 0\n", + "1 2018-04-09 3762.871794 0.112388 0.0 0.0 0.0 99 1\n", + "2 2018-04-16 4466.967388 0.292400 0.0 0.0 0.0 106 2\n", + "3 2018-04-23 3864.219373 0.071399 0.0 0.0 0.0 113 3\n", + "4 2018-04-30 4441.625278 0.386745 0.0 0.0 0.0 120 4" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "columns_to_keep = [\n", + " \"date_week\",\n", + " \"y\",\n", + " \"x1\",\n", + " \"x2\",\n", + " \"event_1\",\n", + " \"event_2\",\n", + " \"dayofyear\",\n", + "]\n", + "seed: int = sum(map(ord, \"mmm\"))\n", + "rng = np.random.default_rng(seed=seed)\n", + "\n", + "data = df[columns_to_keep].copy()\n", + "\n", + "data[\"t\"] = range(df.shape[0])\n", + "data.head()" + ] + }, + { + "cell_type": "markdown", + "id": "9518a885", + "metadata": {}, + "source": [ + "## _Model Creation_\n", + "After we have our dataset ready, we could proceed straight to our model definition, but first to show the full potential of one of the new features: `model_config` we need to use some of our data to define our prior for sigma parameter for each of the channels. `model_config` is a customizable dictionary with keys corresponding to priors within the model, and values containing a dictionaries with parameters necessary to initialize them. Later on we'll learn that through the `save()` method we can preserve our priors contained inside the `model_config`, to allow complete replication of our model." + ] + }, + { + "cell_type": "markdown", + "id": "4b52b2c1", + "metadata": {}, + "source": [ + "### model_config" + ] + }, + { + "cell_type": "markdown", + "id": "41021a72", + "metadata": {}, + "source": [ + "`default_model_config` attribute of every model inheriting from `ModelBuilder` will allow you to see which priors are available for customization. To see it simply initialize a dummy model:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "284bd558", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'intercept': {'mu': 0, 'sigma': 2},\n", + " 'beta_channel': {'sigma': 2, 'dims': ('channel',)},\n", + " 'alpha': {'alpha': 1, 'beta': 3, 'dims': ('channel',)},\n", + " 'lam': {'alpha': 3, 'beta': 1, 'dims': ('channel',)},\n", + " 'sigma': {'sigma': 2},\n", + " 'gamma_control': {'mu': 0, 'sigma': 2, 'dims': ('control',)},\n", + " 'mu': {'dims': ('date',)},\n", + " 'likelihood': {'dims': ('date',)},\n", + " 'gamma_fourier': {'mu': 0, 'b': 1, 'dims': 'fourier_mode'}}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dummy_model = DelayedSaturatedMMM(date_column=\"\", channel_columns=\"\", adstock_max_lag=4)\n", + "dummy_model.default_model_config" + ] + }, + { + "cell_type": "markdown", + "id": "f0fd248f", + "metadata": {}, + "source": [ + "You can change only the prior parameters that you wish, no need to alter all of them, unless you'd like to!\n", + "In this case we'll just simply replace our sigma for beta_channel with our computed one:" + ] + }, + { + "cell_type": "markdown", + "id": "19f075f0-4d3d-4509-a9c6-f15efdb9293d", + "metadata": {}, + "source": [ + "First, let's compute the share of spend per channel:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "4785596a-e333-4cd0-af15-1332e97b66d5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "x1 0.65632\n", + "x2 0.34368\n", + "dtype: float64" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "total_spend_per_channel = data[[\"x1\", \"x2\"]].sum(axis=0)\n", + "\n", + "spend_share = total_spend_per_channel / total_spend_per_channel.sum()\n", + "\n", + "spend_share" + ] + }, + { + "cell_type": "markdown", + "id": "40d17642-1e21-4adc-97f4-633eede87915", + "metadata": {}, + "source": [ + "Next, we specify the `sigma`parameter per channel:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "672b36bd-3d08-46df-85b8-d67d3ade75d7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[2.1775326025486734, 1.140260877391939]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# The scale necessary to make a HalfNormal distribution have unit variance\n", + "HALFNORMAL_SCALE = 1 / np.sqrt(1 - 2 / np.pi)\n", + "\n", + "n_channels = 2\n", + "\n", + "prior_sigma = HALFNORMAL_SCALE * n_channels * spend_share.to_numpy()\n", + "\n", + "prior_sigma.tolist()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "bac9f587", + "metadata": {}, + "outputs": [], + "source": [ + "custom_beta_channel_prior = {\"beta_channel\": {\"sigma\": prior_sigma, \"dims\": (\"channel\",)}}\n", + "my_model_config = dummy_model.default_model_config | custom_beta_channel_prior" + ] + }, + { + "cell_type": "markdown", + "id": "1aa435bf", + "metadata": {}, + "source": [ + "As mentioned in the original notebook: \"_For the prior specification there is no right or wrong answer. It all depends on the data, the context and the assumptions you are willing to make. It is always recommended to do some prior predictive sampling and sensitivity analysis to check the impact of the priors on the posterior. We skip this here for the sake of simplicity. If you are not sure about specific priors, the `DelayedSaturatedMMM` class has some default priors that you can use as a starting point._\"" + ] + }, + { + "cell_type": "markdown", + "id": "f195a79e", + "metadata": {}, + "source": [ + "The second feature that we can use for model definition is `sampler_config`. Similar to `model_config`, it's a dictionary that gets saved and contains things you'd usually pass to the `fit()` kwargs. It's not mandatory to create your own `sampler_config`; if not provided, both `model_config` and `sampler_config` will default to the forms specified by PyMC Labs experts, which allows for the usage of all model functionalities. The default `sampler_config` is left empty because the default sampling parameters usually prove sufficient for a start." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "0ab8140c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{}" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dummy_model.default_sampler_config" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "bf5a50f4", + "metadata": {}, + "outputs": [], + "source": [ + "my_sampler_config = {\n", + " \"tune\": 1000,\n", + " \"draws\": 1000,\n", + " \"chains\": 4,\n", + " \"target_accept\": 0.95,\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "f3bfe090", + "metadata": {}, + "source": [ + "Let's finally assemble our model!" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "c7bd6909", + "metadata": {}, + "outputs": [], + "source": [ + "mmm = DelayedSaturatedMMM(\n", + " model_config=my_model_config,\n", + " sampler_config=my_sampler_config,\n", + " date_column=\"date_week\",\n", + " channel_columns=[\"x1\", \"x2\"],\n", + " control_columns=[\n", + " \"event_1\",\n", + " \"event_2\",\n", + " \"t\",\n", + " ],\n", + " adstock_max_lag=8,\n", + " yearly_seasonality=2,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "54095b1a", + "metadata": {}, + "source": [ + "An important thing to note here is that in the new version of `DelayedSaturatedMMM`, we don't pass our dataset to the class constructor itself. This is due to a reason I've mentioned before - it supports `sklearn` transformers and validations that require a usual X, y split and typically expect the data to be passed to the `fit()` method." + ] + }, + { + "cell_type": "markdown", + "id": "dec9b1b0", + "metadata": {}, + "source": [ + "## _Model Fitting_" + ] + }, + { + "cell_type": "markdown", + "id": "d5e64562-ba78-4497-a0f8-123b4bc88b79", + "metadata": {}, + "source": [ + "Let's split the dataset:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "ff23006b-a55b-4a22-9f34-4eeaddf47486", + "metadata": {}, + "outputs": [], + "source": [ + "X = data.drop(\"y\", axis=1)\n", + "y = data[\"y\"]" + ] + }, + { + "cell_type": "markdown", + "id": "403e3ed2", + "metadata": {}, + "source": [ + "All that's left now is to finally fit the model:\n", + "\n", + "As you can see below, you can still pass the sampler kwargs directly to `fit()` method. However, only those kwargs passed using `sampler_config` will be saved. Therefore, only these will be available after loading the model." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "0f6ab0a8", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Auto-assigning NUTS sampler...\n", + "Initializing NUTS using jitter+adapt_diag...\n", + "Multiprocess sampling (4 chains in 4 jobs)\n", + "NUTS: [intercept, beta_channel, alpha, lam, sigma, gamma_control, gamma_fourier]\n" + ] + }, + { + "data": { + "text/html": [ + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "
\n", + " \n", + " 100.00% [8000/8000 00:27<00:00 Sampling 4 chains, 0 divergences]\n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Sampling 4 chains for 1_000 tune and 1_000 draw iterations (4_000 + 4_000 draws total) took 28 seconds.\n", + "Sampling: [alpha, beta_channel, gamma_control, gamma_fourier, intercept, lam, likelihood, sigma]\n", + "Sampling: [likelihood]\n" + ] + }, + { + "data": { + "text/html": [ + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "
\n", + " \n", + " 100.00% [4000/4000 00:00<00:00]\n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + "
arviz.InferenceData
\n", + "
\n", + "
    \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:                    (chain: 4, draw: 1000, control: 3,\n",
      +       "                                fourier_mode: 4, channel: 2, date: 179)\n",
      +       "Coordinates:\n",
      +       "  * chain                      (chain) int64 0 1 2 3\n",
      +       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 995 996 997 998 999\n",
      +       "  * control                    (control) <U7 'event_1' 'event_2' 't'\n",
      +       "  * fourier_mode               (fourier_mode) <U11 'sin_order_1' ... 'cos_ord...\n",
      +       "  * channel                    (channel) <U2 'x1' 'x2'\n",
      +       "  * date                       (date) <U10 '2018-04-02' ... '2021-08-30'\n",
      +       "Data variables: (12/13)\n",
      +       "    intercept                  (chain, draw) float64 0.3381 0.3361 ... 0.3479\n",
      +       "    gamma_control              (chain, draw, control) float64 0.2968 ... 0.00...\n",
      +       "    gamma_fourier              (chain, draw, fourier_mode) float64 -0.002612 ...\n",
      +       "    beta_channel               (chain, draw, channel) float64 0.3718 ... 0.2628\n",
      +       "    alpha                      (chain, draw, channel) float64 0.4162 ... 0.2007\n",
      +       "    lam                        (chain, draw, channel) float64 4.26 ... 2.758\n",
      +       "    ...                         ...\n",
      +       "    channel_adstock            (chain, draw, date, channel) float64 0.1868 .....\n",
      +       "    channel_adstock_saturated  (chain, draw, date, channel) float64 0.3781 .....\n",
      +       "    channel_contributions      (chain, draw, date, channel) float64 0.1406 .....\n",
      +       "    control_contributions      (chain, draw, date, control) float64 0.0 ... 0...\n",
      +       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 -0.0...\n",
      +       "    mu                         (chain, draw, date) float64 0.4769 ... 0.5924\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:12.916984\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1\n",
      +       "    sampling_time:              27.989259004592896\n",
      +       "    tuning_steps:               1000

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:     (chain: 4, draw: 1000, date: 179)\n",
      +       "Coordinates:\n",
      +       "  * chain       (chain) int64 0 1 2 3\n",
      +       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999\n",
      +       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "Data variables:\n",
      +       "    likelihood  (chain, draw, date) float64 0.5148 0.4369 ... 0.4858 0.6176\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:14.741457\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:                (chain: 4, draw: 1000)\n",
      +       "Coordinates:\n",
      +       "  * chain                  (chain) int64 0 1 2 3\n",
      +       "  * draw                   (draw) int64 0 1 2 3 4 5 ... 994 995 996 997 998 999\n",
      +       "Data variables: (12/17)\n",
      +       "    step_size              (chain, draw) float64 0.05862 0.05862 ... 0.07543\n",
      +       "    lp                     (chain, draw) float64 355.1 355.2 ... 355.6 351.6\n",
      +       "    n_steps                (chain, draw) float64 63.0 63.0 63.0 ... 63.0 63.0\n",
      +       "    largest_eigval         (chain, draw) float64 nan nan nan nan ... nan nan nan\n",
      +       "    energy                 (chain, draw) float64 -344.2 -349.9 ... -350.2 -347.5\n",
      +       "    acceptance_rate        (chain, draw) float64 0.9987 0.9934 ... 0.8931 0.9167\n",
      +       "    ...                     ...\n",
      +       "    diverging              (chain, draw) bool False False False ... False False\n",
      +       "    smallest_eigval        (chain, draw) float64 nan nan nan nan ... nan nan nan\n",
      +       "    max_energy_error       (chain, draw) float64 -0.06059 -0.06074 ... 0.284\n",
      +       "    index_in_trajectory    (chain, draw) int64 -12 20 43 -17 ... 42 20 -43 -29\n",
      +       "    energy_error           (chain, draw) float64 -0.01181 -0.02828 ... -0.01478\n",
      +       "    tree_depth             (chain, draw) int64 6 6 6 6 7 6 6 7 ... 6 5 5 6 7 6 6\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:12.932375\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1\n",
      +       "    sampling_time:              27.989259004592896\n",
      +       "    tuning_steps:               1000

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:                    (chain: 1, draw: 500, channel: 2, control: 3,\n",
      +       "                                date: 179, fourier_mode: 4)\n",
      +       "Coordinates:\n",
      +       "  * chain                      (chain) int64 0\n",
      +       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 495 496 497 498 499\n",
      +       "  * channel                    (channel) <U2 'x1' 'x2'\n",
      +       "  * control                    (control) <U7 'event_1' 'event_2' 't'\n",
      +       "  * date                       (date) <U10 '2018-04-02' ... '2021-08-30'\n",
      +       "  * fourier_mode               (fourier_mode) <U11 'sin_order_1' ... 'cos_ord...\n",
      +       "Data variables: (12/13)\n",
      +       "    beta_channel               (chain, draw, channel) float64 0.6143 ... 0.9639\n",
      +       "    sigma                      (chain, draw) float64 2.034 5.255 ... 0.07125\n",
      +       "    gamma_control              (chain, draw, control) float64 -0.9767 ... 0.0...\n",
      +       "    control_contributions      (chain, draw, date, control) float64 -0.0 ... ...\n",
      +       "    mu                         (chain, draw, date) float64 5.528 7.076 ... 8.396\n",
      +       "    channel_adstock_saturated  (chain, draw, date, channel) float64 0.3626 .....\n",
      +       "    ...                         ...\n",
      +       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 1.64...\n",
      +       "    lam                        (chain, draw, channel) float64 2.667 ... 1.438\n",
      +       "    intercept                  (chain, draw) float64 2.51 -3.898 ... -2.654\n",
      +       "    gamma_fourier              (chain, draw, fourier_mode) float64 1.647 ... ...\n",
      +       "    channel_adstock            (chain, draw, date, channel) float64 0.2848 .....\n",
      +       "    alpha                      (chain, draw, channel) float64 0.1089 ... 0.2786\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:14.422347\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:     (chain: 1, draw: 500, date: 179)\n",
      +       "Coordinates:\n",
      +       "  * chain       (chain) int64 0\n",
      +       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 492 493 494 495 496 497 498 499\n",
      +       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "Data variables:\n",
      +       "    likelihood  (chain, draw, date) float64 5.221 8.352 5.313 ... 7.793 8.528\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:14.428434\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:     (date: 179)\n",
      +       "Coordinates:\n",
      +       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "Data variables:\n",
      +       "    likelihood  (date) float64 0.4794 0.4527 0.5374 ... 0.4978 0.5388 0.5625\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:12.937052\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:       (date: 179, channel: 2, control: 3, fourier_mode: 4)\n",
      +       "Coordinates:\n",
      +       "  * date          (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "  * channel       (channel) <U2 'x1' 'x2'\n",
      +       "  * control       (control) <U7 'event_1' 'event_2' 't'\n",
      +       "  * fourier_mode  (fourier_mode) <U11 'sin_order_1' ... 'cos_order_2'\n",
      +       "Data variables:\n",
      +       "    channel_data  (date, channel) float64 0.3196 0.0 0.1128 ... 0.0 0.4403 0.0\n",
      +       "    target        (date) float64 0.4794 0.4527 0.5374 ... 0.4978 0.5388 0.5625\n",
      +       "    control_data  (date, control) float64 0.0 0.0 0.0 0.0 ... 0.0 0.0 178.0\n",
      +       "    fourier_data  (date, fourier_mode) float64 0.9999 -0.01183 ... -0.4547\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:12.938885\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:    (index: 179)\n",
      +       "Coordinates:\n",
      +       "  * index      (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      +       "Data variables:\n",
      +       "    date_week  (index) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "    x1         (index) float64 0.3186 0.1124 0.2924 ... 0.1719 0.2803 0.4389\n",
      +       "    x2         (index) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.8633 0.0 0.0 0.0\n",
      +       "    event_1    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      +       "    event_2    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      +       "    dayofyear  (index) int64 92 99 106 113 120 127 ... 207 214 221 228 235 242\n",
      +       "    t          (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      +       "    y          (index) float64 3.985e+03 3.763e+03 ... 4.479e+03 4.676e+03

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
\n", + "
\n", + " " + ], + "text/plain": [ + "Inference data with groups:\n", + "\t> posterior\n", + "\t> posterior_predictive\n", + "\t> sample_stats\n", + "\t> prior\n", + "\t> prior_predictive\n", + "\t> observed_data\n", + "\t> constant_data\n", + "\t> fit_data" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mmm.fit(X=X, y=y, random_seed=rng)" + ] + }, + { + "cell_type": "markdown", + "id": "c29a6461", + "metadata": {}, + "source": [ + "The `fit()` method automatically builds the model using the priors from `model_config`, and assigns the created model to our instance. You can access it as a normal attribute." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "c6b8e2af", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "pymc.model.Model" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(mmm.model)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "f046ee2c", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "clusterdate (179) x channel (2)\n", + "\n", + "date (179) x channel (2)\n", + "\n", + "\n", + "clusterdate (179)\n", + "\n", + "date (179)\n", + "\n", + "\n", + "clusterchannel (2)\n", + "\n", + "channel (2)\n", + "\n", + "\n", + "clusterdate (179) x control (3)\n", + "\n", + "date (179) x control (3)\n", + "\n", + "\n", + "clustercontrol (3)\n", + "\n", + "control (3)\n", + "\n", + "\n", + "clusterdate (179) x fourier_mode (4)\n", + "\n", + "date (179) x fourier_mode (4)\n", + "\n", + "\n", + "clusterfourier_mode (4)\n", + "\n", + "fourier_mode (4)\n", + "\n", + "\n", + "\n", + "channel_adstock_saturated\n", + "\n", + "channel_adstock_saturated\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "channel_contributions\n", + "\n", + "channel_contributions\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "channel_adstock_saturated->channel_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "mu\n", + "\n", + "mu\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "channel_contributions->mu\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "channel_data\n", + "\n", + "channel_data\n", + "~\n", + "MutableData\n", + "\n", + "\n", + "\n", + "channel_adstock\n", + "\n", + "channel_adstock\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "channel_data->channel_adstock\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "channel_adstock->channel_adstock_saturated\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "likelihood\n", + "\n", + "likelihood\n", + "~\n", + "Normal\n", + "\n", + "\n", + "\n", + "target\n", + "\n", + "target\n", + "~\n", + "MutableData\n", + "\n", + "\n", + "\n", + "likelihood->target\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "mu->likelihood\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sigma\n", + "\n", + "sigma\n", + "~\n", + "HalfNormal\n", + "\n", + "\n", + "\n", + "sigma->likelihood\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "intercept\n", + "\n", + "intercept\n", + "~\n", + "Normal\n", + "\n", + "\n", + "\n", + "intercept->mu\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "beta_channel\n", + "\n", + "beta_channel\n", + "~\n", + "HalfNormal\n", + "\n", + "\n", + "\n", + "beta_channel->channel_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "alpha\n", + "\n", + "alpha\n", + "~\n", + "Beta\n", + "\n", + "\n", + "\n", + "alpha->channel_adstock\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "lam\n", + "\n", + "lam\n", + "~\n", + "Gamma\n", + "\n", + "\n", + "\n", + "lam->channel_adstock_saturated\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "control_data\n", + "\n", + "control_data\n", + "~\n", + "MutableData\n", + "\n", + "\n", + "\n", + "control_contributions\n", + "\n", + "control_contributions\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "control_data->control_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "control_contributions->mu\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "gamma_control\n", + "\n", + "gamma_control\n", + "~\n", + "Normal\n", + "\n", + "\n", + "\n", + "gamma_control->control_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fourier_data\n", + "\n", + "fourier_data\n", + "~\n", + "MutableData\n", + "\n", + "\n", + "\n", + "fourier_contributions\n", + "\n", + "fourier_contributions\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "fourier_data->fourier_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fourier_contributions->mu\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "gamma_fourier\n", + "\n", + "gamma_fourier\n", + "~\n", + "Laplace\n", + "\n", + "\n", + "\n", + "gamma_fourier->fourier_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mmm.graphviz()" + ] + }, + { + "cell_type": "markdown", + "id": "c804b600", + "metadata": {}, + "source": [ + "posterior trace can be accessed by `fit_result` attribute:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "66903965", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.Dataset>\n",
+       "Dimensions:                    (chain: 4, draw: 1000, control: 3,\n",
+       "                                fourier_mode: 4, channel: 2, date: 179)\n",
+       "Coordinates:\n",
+       "  * chain                      (chain) int64 0 1 2 3\n",
+       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 995 996 997 998 999\n",
+       "  * control                    (control) <U7 'event_1' 'event_2' 't'\n",
+       "  * fourier_mode               (fourier_mode) <U11 'sin_order_1' ... 'cos_ord...\n",
+       "  * channel                    (channel) <U2 'x1' 'x2'\n",
+       "  * date                       (date) <U10 '2018-04-02' ... '2021-08-30'\n",
+       "Data variables: (12/13)\n",
+       "    intercept                  (chain, draw) float64 0.3381 0.3361 ... 0.3479\n",
+       "    gamma_control              (chain, draw, control) float64 0.2968 ... 0.00...\n",
+       "    gamma_fourier              (chain, draw, fourier_mode) float64 -0.002612 ...\n",
+       "    beta_channel               (chain, draw, channel) float64 0.3718 ... 0.2628\n",
+       "    alpha                      (chain, draw, channel) float64 0.4162 ... 0.2007\n",
+       "    lam                        (chain, draw, channel) float64 4.26 ... 2.758\n",
+       "    ...                         ...\n",
+       "    channel_adstock            (chain, draw, date, channel) float64 0.1868 .....\n",
+       "    channel_adstock_saturated  (chain, draw, date, channel) float64 0.3781 .....\n",
+       "    channel_contributions      (chain, draw, date, channel) float64 0.1406 .....\n",
+       "    control_contributions      (chain, draw, date, control) float64 0.0 ... 0...\n",
+       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 -0.0...\n",
+       "    mu                         (chain, draw, date) float64 0.4769 ... 0.5924\n",
+       "Attributes:\n",
+       "    created_at:                 2023-08-17T13:57:12.916984\n",
+       "    arviz_version:              0.16.1\n",
+       "    inference_library:          pymc\n",
+       "    inference_library_version:  5.6.1\n",
+       "    sampling_time:              27.989259004592896\n",
+       "    tuning_steps:               1000
" + ], + "text/plain": [ + "\n", + "Dimensions: (chain: 4, draw: 1000, control: 3,\n", + " fourier_mode: 4, channel: 2, date: 179)\n", + "Coordinates:\n", + " * chain (chain) int64 0 1 2 3\n", + " * draw (draw) int64 0 1 2 3 4 5 ... 995 996 997 998 999\n", + " * control (control) \n", + "
\n", + "
arviz.InferenceData
\n", + "
\n", + "
    \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:                    (chain: 4, draw: 1000, control: 3,\n",
      +       "                                fourier_mode: 4, channel: 2, date: 179)\n",
      +       "Coordinates:\n",
      +       "  * chain                      (chain) int64 0 1 2 3\n",
      +       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 995 996 997 998 999\n",
      +       "  * control                    (control) <U7 'event_1' 'event_2' 't'\n",
      +       "  * fourier_mode               (fourier_mode) <U11 'sin_order_1' ... 'cos_ord...\n",
      +       "  * channel                    (channel) <U2 'x1' 'x2'\n",
      +       "  * date                       (date) <U10 '2018-04-02' ... '2021-08-30'\n",
      +       "Data variables: (12/13)\n",
      +       "    intercept                  (chain, draw) float64 0.3381 0.3361 ... 0.3479\n",
      +       "    gamma_control              (chain, draw, control) float64 0.2968 ... 0.00...\n",
      +       "    gamma_fourier              (chain, draw, fourier_mode) float64 -0.002612 ...\n",
      +       "    beta_channel               (chain, draw, channel) float64 0.3718 ... 0.2628\n",
      +       "    alpha                      (chain, draw, channel) float64 0.4162 ... 0.2007\n",
      +       "    lam                        (chain, draw, channel) float64 4.26 ... 2.758\n",
      +       "    ...                         ...\n",
      +       "    channel_adstock            (chain, draw, date, channel) float64 0.1868 .....\n",
      +       "    channel_adstock_saturated  (chain, draw, date, channel) float64 0.3781 .....\n",
      +       "    channel_contributions      (chain, draw, date, channel) float64 0.1406 .....\n",
      +       "    control_contributions      (chain, draw, date, control) float64 0.0 ... 0...\n",
      +       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 -0.0...\n",
      +       "    mu                         (chain, draw, date) float64 0.4769 ... 0.5924\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:12.916984\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1\n",
      +       "    sampling_time:              27.989259004592896\n",
      +       "    tuning_steps:               1000

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:     (chain: 4, draw: 1000, date: 179)\n",
      +       "Coordinates:\n",
      +       "  * chain       (chain) int64 0 1 2 3\n",
      +       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999\n",
      +       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "Data variables:\n",
      +       "    likelihood  (chain, draw, date) float64 0.5148 0.4369 ... 0.4858 0.6176\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:14.741457\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:                (chain: 4, draw: 1000)\n",
      +       "Coordinates:\n",
      +       "  * chain                  (chain) int64 0 1 2 3\n",
      +       "  * draw                   (draw) int64 0 1 2 3 4 5 ... 994 995 996 997 998 999\n",
      +       "Data variables: (12/17)\n",
      +       "    step_size              (chain, draw) float64 0.05862 0.05862 ... 0.07543\n",
      +       "    lp                     (chain, draw) float64 355.1 355.2 ... 355.6 351.6\n",
      +       "    n_steps                (chain, draw) float64 63.0 63.0 63.0 ... 63.0 63.0\n",
      +       "    largest_eigval         (chain, draw) float64 nan nan nan nan ... nan nan nan\n",
      +       "    energy                 (chain, draw) float64 -344.2 -349.9 ... -350.2 -347.5\n",
      +       "    acceptance_rate        (chain, draw) float64 0.9987 0.9934 ... 0.8931 0.9167\n",
      +       "    ...                     ...\n",
      +       "    diverging              (chain, draw) bool False False False ... False False\n",
      +       "    smallest_eigval        (chain, draw) float64 nan nan nan nan ... nan nan nan\n",
      +       "    max_energy_error       (chain, draw) float64 -0.06059 -0.06074 ... 0.284\n",
      +       "    index_in_trajectory    (chain, draw) int64 -12 20 43 -17 ... 42 20 -43 -29\n",
      +       "    energy_error           (chain, draw) float64 -0.01181 -0.02828 ... -0.01478\n",
      +       "    tree_depth             (chain, draw) int64 6 6 6 6 7 6 6 7 ... 6 5 5 6 7 6 6\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:12.932375\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1\n",
      +       "    sampling_time:              27.989259004592896\n",
      +       "    tuning_steps:               1000

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:                    (chain: 1, draw: 500, channel: 2, control: 3,\n",
      +       "                                date: 179, fourier_mode: 4)\n",
      +       "Coordinates:\n",
      +       "  * chain                      (chain) int64 0\n",
      +       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 495 496 497 498 499\n",
      +       "  * channel                    (channel) <U2 'x1' 'x2'\n",
      +       "  * control                    (control) <U7 'event_1' 'event_2' 't'\n",
      +       "  * date                       (date) <U10 '2018-04-02' ... '2021-08-30'\n",
      +       "  * fourier_mode               (fourier_mode) <U11 'sin_order_1' ... 'cos_ord...\n",
      +       "Data variables: (12/13)\n",
      +       "    beta_channel               (chain, draw, channel) float64 0.6143 ... 0.9639\n",
      +       "    sigma                      (chain, draw) float64 2.034 5.255 ... 0.07125\n",
      +       "    gamma_control              (chain, draw, control) float64 -0.9767 ... 0.0...\n",
      +       "    control_contributions      (chain, draw, date, control) float64 -0.0 ... ...\n",
      +       "    mu                         (chain, draw, date) float64 5.528 7.076 ... 8.396\n",
      +       "    channel_adstock_saturated  (chain, draw, date, channel) float64 0.3626 .....\n",
      +       "    ...                         ...\n",
      +       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 1.64...\n",
      +       "    lam                        (chain, draw, channel) float64 2.667 ... 1.438\n",
      +       "    intercept                  (chain, draw) float64 2.51 -3.898 ... -2.654\n",
      +       "    gamma_fourier              (chain, draw, fourier_mode) float64 1.647 ... ...\n",
      +       "    channel_adstock            (chain, draw, date, channel) float64 0.2848 .....\n",
      +       "    alpha                      (chain, draw, channel) float64 0.1089 ... 0.2786\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:14.422347\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:     (chain: 1, draw: 500, date: 179)\n",
      +       "Coordinates:\n",
      +       "  * chain       (chain) int64 0\n",
      +       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 492 493 494 495 496 497 498 499\n",
      +       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "Data variables:\n",
      +       "    likelihood  (chain, draw, date) float64 5.221 8.352 5.313 ... 7.793 8.528\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:14.428434\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:     (date: 179)\n",
      +       "Coordinates:\n",
      +       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "Data variables:\n",
      +       "    likelihood  (date) float64 0.4794 0.4527 0.5374 ... 0.4978 0.5388 0.5625\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:12.937052\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:       (date: 179, channel: 2, control: 3, fourier_mode: 4)\n",
      +       "Coordinates:\n",
      +       "  * date          (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "  * channel       (channel) <U2 'x1' 'x2'\n",
      +       "  * control       (control) <U7 'event_1' 'event_2' 't'\n",
      +       "  * fourier_mode  (fourier_mode) <U11 'sin_order_1' ... 'cos_order_2'\n",
      +       "Data variables:\n",
      +       "    channel_data  (date, channel) float64 0.3196 0.0 0.1128 ... 0.0 0.4403 0.0\n",
      +       "    target        (date) float64 0.4794 0.4527 0.5374 ... 0.4978 0.5388 0.5625\n",
      +       "    control_data  (date, control) float64 0.0 0.0 0.0 0.0 ... 0.0 0.0 178.0\n",
      +       "    fourier_data  (date, fourier_mode) float64 0.9999 -0.01183 ... -0.4547\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:12.938885\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:    (index: 179)\n",
      +       "Coordinates:\n",
      +       "  * index      (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      +       "Data variables:\n",
      +       "    date_week  (index) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "    x1         (index) float64 0.3186 0.1124 0.2924 ... 0.1719 0.2803 0.4389\n",
      +       "    x2         (index) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.8633 0.0 0.0 0.0\n",
      +       "    event_1    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      +       "    event_2    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      +       "    dayofyear  (index) int64 92 99 106 113 120 127 ... 207 214 221 228 235 242\n",
      +       "    t          (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      +       "    y          (index) float64 3.985e+03 3.763e+03 ... 4.479e+03 4.676e+03

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
\n", + " \n", + " " + ], + "text/plain": [ + "Inference data with groups:\n", + "\t> posterior\n", + "\t> posterior_predictive\n", + "\t> sample_stats\n", + "\t> prior\n", + "\t> prior_predictive\n", + "\t> observed_data\n", + "\t> constant_data\n", + "\t> fit_data" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mmm.idata" + ] + }, + { + "cell_type": "markdown", + "id": "8b433c7f-0f0d-40b2-bcfb-a19555b528bd", + "metadata": {}, + "source": [ + "## `Save` and `load`" + ] + }, + { + "cell_type": "markdown", + "id": "7b0a35f4", + "metadata": {}, + "source": [ + "All the data passed to the model on initialisation is stored in `idata.attrs`. This will be used later in the `save()` method to convert both this data and all the fit data into the netCDF format." + ] + }, + { + "cell_type": "markdown", + "id": "45948f46", + "metadata": {}, + "source": [ + "Simply specify the path to which you'd like to save your model:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "b3abe93a", + "metadata": {}, + "outputs": [], + "source": [ + "mmm.save(\"my_saved_model.nc\")" + ] + }, + { + "cell_type": "markdown", + "id": "8a5eba79", + "metadata": {}, + "source": [ + "And pass it to the `load()` method when it's needed again on the target system:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "0421bae8", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/michalraczycki/Documents/pymc-marketing/.conda/envs/pymc-marketing/lib/python3.10/site-packages/arviz/data/inference_data.py:153: UserWarning: fit_data group is not defined in the InferenceData scheme\n", + " warnings.warn(\n" + ] + } + ], + "source": [ + "loaded_model = DelayedSaturatedMMM.load(\"my_saved_model.nc\")" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "a8b666d3", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "clusterdate (179) x channel (2)\n", + "\n", + "date (179) x channel (2)\n", + "\n", + "\n", + "clusterdate (179)\n", + "\n", + "date (179)\n", + "\n", + "\n", + "clusterchannel (2)\n", + "\n", + "channel (2)\n", + "\n", + "\n", + "clusterdate (179) x control (3)\n", + "\n", + "date (179) x control (3)\n", + "\n", + "\n", + "clustercontrol (3)\n", + "\n", + "control (3)\n", + "\n", + "\n", + "clusterdate (179) x fourier_mode (4)\n", + "\n", + "date (179) x fourier_mode (4)\n", + "\n", + "\n", + "clusterfourier_mode (4)\n", + "\n", + "fourier_mode (4)\n", + "\n", + "\n", + "\n", + "channel_adstock_saturated\n", + "\n", + "channel_adstock_saturated\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "channel_contributions\n", + "\n", + "channel_contributions\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "channel_adstock_saturated->channel_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "mu\n", + "\n", + "mu\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "channel_contributions->mu\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "channel_data\n", + "\n", + "channel_data\n", + "~\n", + "MutableData\n", + "\n", + "\n", + "\n", + "channel_adstock\n", + "\n", + "channel_adstock\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "channel_data->channel_adstock\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "channel_adstock->channel_adstock_saturated\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "likelihood\n", + "\n", + "likelihood\n", + "~\n", + "Normal\n", + "\n", + "\n", + "\n", + "target\n", + "\n", + "target\n", + "~\n", + "MutableData\n", + "\n", + "\n", + "\n", + "likelihood->target\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "mu->likelihood\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sigma\n", + "\n", + "sigma\n", + "~\n", + "HalfNormal\n", + "\n", + "\n", + "\n", + "sigma->likelihood\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "intercept\n", + "\n", + "intercept\n", + "~\n", + "Normal\n", + "\n", + "\n", + "\n", + "intercept->mu\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "beta_channel\n", + "\n", + "beta_channel\n", + "~\n", + "HalfNormal\n", + "\n", + "\n", + "\n", + "beta_channel->channel_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "alpha\n", + "\n", + "alpha\n", + "~\n", + "Beta\n", + "\n", + "\n", + "\n", + "alpha->channel_adstock\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "lam\n", + "\n", + "lam\n", + "~\n", + "Gamma\n", + "\n", + "\n", + "\n", + "lam->channel_adstock_saturated\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "control_data\n", + "\n", + "control_data\n", + "~\n", + "MutableData\n", + "\n", + "\n", + "\n", + "control_contributions\n", + "\n", + "control_contributions\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "control_data->control_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "control_contributions->mu\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "gamma_control\n", + "\n", + "gamma_control\n", + "~\n", + "Normal\n", + "\n", + "\n", + "\n", + "gamma_control->control_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fourier_data\n", + "\n", + "fourier_data\n", + "~\n", + "MutableData\n", + "\n", + "\n", + "\n", + "fourier_contributions\n", + "\n", + "fourier_contributions\n", + "~\n", + "Deterministic\n", + "\n", + "\n", + "\n", + "fourier_data->fourier_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fourier_contributions->mu\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "gamma_fourier\n", + "\n", + "gamma_fourier\n", + "~\n", + "Laplace\n", + "\n", + "\n", + "\n", + "gamma_fourier->fourier_contributions\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "loaded_model.graphviz()" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "cfb64a2c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + "
arviz.InferenceData
\n", + "
\n", + "
    \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:                    (chain: 4, draw: 1000, control: 3,\n",
      +       "                                fourier_mode: 4, channel: 2, date: 179)\n",
      +       "Coordinates:\n",
      +       "  * chain                      (chain) int64 0 1 2 3\n",
      +       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 995 996 997 998 999\n",
      +       "  * control                    (control) object 'event_1' 'event_2' 't'\n",
      +       "  * fourier_mode               (fourier_mode) object 'sin_order_1' ... 'cos_o...\n",
      +       "  * channel                    (channel) object 'x1' 'x2'\n",
      +       "  * date                       (date) object '2018-04-02' ... '2021-08-30'\n",
      +       "Data variables: (12/13)\n",
      +       "    intercept                  (chain, draw) float64 ...\n",
      +       "    gamma_control              (chain, draw, control) float64 ...\n",
      +       "    gamma_fourier              (chain, draw, fourier_mode) float64 ...\n",
      +       "    beta_channel               (chain, draw, channel) float64 ...\n",
      +       "    alpha                      (chain, draw, channel) float64 ...\n",
      +       "    lam                        (chain, draw, channel) float64 ...\n",
      +       "    ...                         ...\n",
      +       "    channel_adstock            (chain, draw, date, channel) float64 ...\n",
      +       "    channel_adstock_saturated  (chain, draw, date, channel) float64 ...\n",
      +       "    channel_contributions      (chain, draw, date, channel) float64 ...\n",
      +       "    control_contributions      (chain, draw, date, control) float64 ...\n",
      +       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 ...\n",
      +       "    mu                         (chain, draw, date) float64 ...\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:12.916984\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1\n",
      +       "    sampling_time:              27.989259004592896\n",
      +       "    tuning_steps:               1000

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:     (chain: 4, draw: 1000, date: 179)\n",
      +       "Coordinates:\n",
      +       "  * chain       (chain) int64 0 1 2 3\n",
      +       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999\n",
      +       "  * date        (date) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "Data variables:\n",
      +       "    likelihood  (chain, draw, date) float64 ...\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:14.741457\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:                (chain: 4, draw: 1000)\n",
      +       "Coordinates:\n",
      +       "  * chain                  (chain) int64 0 1 2 3\n",
      +       "  * draw                   (draw) int64 0 1 2 3 4 5 ... 994 995 996 997 998 999\n",
      +       "Data variables: (12/17)\n",
      +       "    step_size              (chain, draw) float64 ...\n",
      +       "    lp                     (chain, draw) float64 ...\n",
      +       "    n_steps                (chain, draw) float64 ...\n",
      +       "    largest_eigval         (chain, draw) float64 ...\n",
      +       "    energy                 (chain, draw) float64 ...\n",
      +       "    acceptance_rate        (chain, draw) float64 ...\n",
      +       "    ...                     ...\n",
      +       "    diverging              (chain, draw) bool ...\n",
      +       "    smallest_eigval        (chain, draw) float64 ...\n",
      +       "    max_energy_error       (chain, draw) float64 ...\n",
      +       "    index_in_trajectory    (chain, draw) int64 ...\n",
      +       "    energy_error           (chain, draw) float64 ...\n",
      +       "    tree_depth             (chain, draw) int64 ...\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:12.932375\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1\n",
      +       "    sampling_time:              27.989259004592896\n",
      +       "    tuning_steps:               1000

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:                    (chain: 1, draw: 500, channel: 2, control: 3,\n",
      +       "                                date: 179, fourier_mode: 4)\n",
      +       "Coordinates:\n",
      +       "  * chain                      (chain) int64 0\n",
      +       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 495 496 497 498 499\n",
      +       "  * channel                    (channel) object 'x1' 'x2'\n",
      +       "  * control                    (control) object 'event_1' 'event_2' 't'\n",
      +       "  * date                       (date) object '2018-04-02' ... '2021-08-30'\n",
      +       "  * fourier_mode               (fourier_mode) object 'sin_order_1' ... 'cos_o...\n",
      +       "Data variables: (12/13)\n",
      +       "    beta_channel               (chain, draw, channel) float64 ...\n",
      +       "    sigma                      (chain, draw) float64 ...\n",
      +       "    gamma_control              (chain, draw, control) float64 ...\n",
      +       "    control_contributions      (chain, draw, date, control) float64 ...\n",
      +       "    mu                         (chain, draw, date) float64 ...\n",
      +       "    channel_adstock_saturated  (chain, draw, date, channel) float64 ...\n",
      +       "    ...                         ...\n",
      +       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 ...\n",
      +       "    lam                        (chain, draw, channel) float64 ...\n",
      +       "    intercept                  (chain, draw) float64 ...\n",
      +       "    gamma_fourier              (chain, draw, fourier_mode) float64 ...\n",
      +       "    channel_adstock            (chain, draw, date, channel) float64 ...\n",
      +       "    alpha                      (chain, draw, channel) float64 ...\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:14.422347\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:     (chain: 1, draw: 500, date: 179)\n",
      +       "Coordinates:\n",
      +       "  * chain       (chain) int64 0\n",
      +       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 492 493 494 495 496 497 498 499\n",
      +       "  * date        (date) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "Data variables:\n",
      +       "    likelihood  (chain, draw, date) float64 ...\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:14.428434\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:     (date: 179)\n",
      +       "Coordinates:\n",
      +       "  * date        (date) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "Data variables:\n",
      +       "    likelihood  (date) float64 ...\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:12.937052\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:       (date: 179, channel: 2, control: 3, fourier_mode: 4)\n",
      +       "Coordinates:\n",
      +       "  * date          (date) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "  * channel       (channel) object 'x1' 'x2'\n",
      +       "  * control       (control) object 'event_1' 'event_2' 't'\n",
      +       "  * fourier_mode  (fourier_mode) object 'sin_order_1' ... 'cos_order_2'\n",
      +       "Data variables:\n",
      +       "    channel_data  (date, channel) float64 ...\n",
      +       "    target        (date) float64 ...\n",
      +       "    control_data  (date, control) float64 ...\n",
      +       "    fourier_data  (date, fourier_mode) float64 ...\n",
      +       "Attributes:\n",
      +       "    created_at:                 2023-08-17T13:57:12.938885\n",
      +       "    arviz_version:              0.16.1\n",
      +       "    inference_library:          pymc\n",
      +       "    inference_library_version:  5.6.1

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
  • \n", + " \n", + " \n", + "
    \n", + "
    \n", + "
      \n", + "
      \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
      <xarray.Dataset>\n",
      +       "Dimensions:    (index: 179)\n",
      +       "Coordinates:\n",
      +       "  * index      (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      +       "Data variables:\n",
      +       "    date_week  (index) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      +       "    x1         (index) float64 0.3186 0.1124 0.2924 ... 0.1719 0.2803 0.4389\n",
      +       "    x2         (index) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.8633 0.0 0.0 0.0\n",
      +       "    event_1    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      +       "    event_2    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      +       "    dayofyear  (index) int64 92 99 106 113 120 127 ... 207 214 221 228 235 242\n",
      +       "    t          (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      +       "    y          (index) float64 3.985e+03 3.763e+03 ... 4.479e+03 4.676e+03

      \n", + "
    \n", + "
    \n", + "
  • \n", + " \n", + "
\n", + "
\n", + " " + ], + "text/plain": [ + "Inference data with groups:\n", + "\t> posterior\n", + "\t> posterior_predictive\n", + "\t> sample_stats\n", + "\t> prior\n", + "\t> prior_predictive\n", + "\t> observed_data\n", + "\t> constant_data\n", + "\t> fit_data" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "loaded_model.idata" + ] + }, + { + "cell_type": "markdown", + "id": "ab64be46-7fe5-4f39-b72b-36da1419f809", + "metadata": {}, + "source": [ + "A model loaded in this way is ready to be used for sampling and prediction, and has access to all previous samples and data." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "dd59d056-6ac7-431c-85ee-99e7a8eefd8a", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Sampling: [likelihood]\n" + ] + }, + { + "data": { + "text/html": [ + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "
\n", + " \n", + " 100.00% [4000/4000 00:00<00:00]\n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.Dataset>\n",
+       "Dimensions:     (chain: 4, draw: 1000, date: 179)\n",
+       "Coordinates:\n",
+       "  * chain       (chain) int64 0 1 2 3\n",
+       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999\n",
+       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
+       "Data variables:\n",
+       "    likelihood  (chain, draw, date) float64 0.4907 0.4282 ... 0.5548 0.5396\n",
+       "Attributes:\n",
+       "    created_at:                 2023-08-17T13:57:22.302381\n",
+       "    arviz_version:              0.16.1\n",
+       "    inference_library:          pymc\n",
+       "    inference_library_version:  5.6.1
" + ], + "text/plain": [ + "\n", + "Dimensions: (chain: 4, draw: 1000, date: 179)\n", + "Coordinates:\n", + " * chain (chain) int64 0 1 2 3\n", + " * draw (draw) int64 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999\n", + " * date (date) " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "az.plot_ppc(loaded_model.idata);" + ] + }, + { + "cell_type": "markdown", + "id": "e8e807f9", + "metadata": {}, + "source": [ + "## Summary:" + ] + }, + { + "cell_type": "markdown", + "id": "61f232c1", + "metadata": {}, + "source": [ + "In summary, this article introduces the revolutionary ModelBuilder, a new [PyMC-experimental](https://github.com/pymc-devs/pymc-experimental) module that simplifies the deployment of PyMC Bayesian models. It addresses a historic challenge faced by users of PyMC and most PPLs by offering a user-friendly and efficient approach to model deployment. The ModelBuilder provides two straightforward methods, save() and load(), which streamline the model preservation and replication process post fitting. Users are offered flexibility in controlling the prior settings with `model_config` and customizing the sampling process via `sampler_config`.\n", + "\n", + "The use of an example model from the [MMM Example Notebook](https://www.pymc-marketing.io/en/stable/notebooks/index.html) demonstrates the practical implementation of `ModelBuilder`, emphasizing its ability to enhance model sharing among teams without the necessity for extensive domain knowledge about the model. The deployment improvements in [PyMC-Marketing](https://github.com/pymc-labs/pymc-marketing) brought about by ModelBuilder are not only user-friendly but also significantly enhance efficiency, making PyMC models more accessible for a wider audience." + ] + }, + { + "cell_type": "markdown", + "id": "b8ad333d", + "metadata": {}, + "source": [ + "Even though this introduction is using `DelayedSaturatedMMM`, functionalities from `ModelBuilder` are available in the CLV models as well." + ] + }, + { + "cell_type": "markdown", + "id": "de822885-2fb4-4ad1-aaf9-7659771f7363", + "metadata": {}, + "source": [ + "## Authors\n", + "- Authored by [Michał Raczycki](https://github.com/michaelraczycki) in August 2023" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "07ec32d2-2f38-47ec-a200-b9d7258c3ac5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Last updated: Thu Aug 17 2023\n", + "\n", + "Python implementation: CPython\n", + "Python version : 3.10.12\n", + "IPython version : 8.14.0\n", + "\n", + "pytensor: 2.12.3\n", + "aeppl : not installed\n", + "xarray : 2023.7.0\n", + "\n", + "numpy : 1.25.1\n", + "pandas: 2.0.3\n", + "arviz : 0.16.1\n", + "\n", + "Watermark: 2.4.3\n", + "\n" + ] + } + ], + "source": [ + "%load_ext watermark\n", + "%watermark -n -u -v -iv -w -p pytensor,aeppl,xarray" + ] + }, + { + "cell_type": "markdown", + "id": "7e453d63-39f3-456c-a099-2c780d3ba4a9", + "metadata": {}, + "source": [ + ":::\n", + "{include} ../page_footer.md\n", + ":::" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "pymc-marketing", + "language": "python", + "name": "pymc-marketing" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/howto/ModelBuilder_usage_example.myst.md b/examples/howto/ModelBuilder_usage_example.myst.md new file mode 100644 index 000000000..3ea5bbe16 --- /dev/null +++ b/examples/howto/ModelBuilder_usage_example.myst.md @@ -0,0 +1,279 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: pymc-marketing + language: python + name: pymc-marketing +--- + +(ModelBuilder usage example)= +# ModelBuilder usage example + +:::{post} Aug 18, 2023 +:tags: ModelBuilder, model deployment, +:category: intermediate, tutorial +:author: Michał Raczycki +::: + ++++ + +# Deploying MMMs and CLVs in Production: Saving and Loading Models + ++++ + +In this article, we'll tackle the historically challenging process of deploying Bayesian models built with PyMC. Introducing a revolutionary deployment module, we bring unprecedented simplicity and efficiency to the deployment of PyMC models. As we prioritize user-friendly solutions, let's delve into how this innovation can significantly elevate your data science projects. + ++++ + + +Recent release of PyMC-Marketing by [Labs](https://www.pymc-labs.io) proves to be a big hit [(PyMC-Marketing)](https://www.pymc-labs.io/blog-posts/pymc-marketing-a-bayesian-approach-to-marketing-data-science/). In the feedback one could see an ongoing theme, many of you have been requesting easy and robust way of deploying models to production. It’s been a long-standing problem with PyMC ( and most other Probabilistic Programming Languages). The reason for that is that there’s no obvious way, and doesn’t matter which approach you try it proves to be tricky. That is why we’re happy to announce the release of `ModelBuilder`, brand new PyMC-experimental module that addresses this need, and improves on the deployment process significantly. + +The ModelBuilder module is a new feature of PyMC based models. It provides 2 easy-to-use methods: save() and load() that can be used after the model has been fit.save() allow easy preservation of the model to .netcdf format, and load() gives one-line replication of the original model. Users can control the prior settings with model_config, and customize the sampling process using sampler_config. Default values of those are working just fine, so first time give it a try without changing, and provide your own model_config and model_sampler if afterwards you want to try to customize it more for your use case! + ++++ + +For this notebook I'll use the example model used in [MMM Example Notebook](https://www.pymc-marketing.io/en/stable/notebooks/mmm/mmm_example.html), but ommit the details of data generation and plotting functionalities, since they're out of scope for this introduction, I highly recommend to see that part as well, but for now let's focus on today's topic: Groundbreaking deployment improvements in PyMC-Marketing! + +```{code-cell} ipython3 +import arviz as az +import numpy as np +import pandas as pd + +from pymc_marketing.mmm import DelayedSaturatedMMM +``` + +```{code-cell} ipython3 +az.style.use("arviz-darkgrid") +``` + +Let's load the dataset: + +```{code-cell} ipython3 +url = "https://raw.githubusercontent.com/pymc-labs/pymc-marketing/main/datasets/mmm_example.csv" +df = pd.read_csv(url) +df +``` + +But for our model we need much smaller dataset, many of the previous features were contributing to generation of others, now as our target variable is computed we can filter out not needed columns: + +```{code-cell} ipython3 +columns_to_keep = [ + "date_week", + "y", + "x1", + "x2", + "event_1", + "event_2", + "dayofyear", +] +seed: int = sum(map(ord, "mmm")) +rng = np.random.default_rng(seed=seed) + +data = df[columns_to_keep].copy() + +data["t"] = range(df.shape[0]) +data.head() +``` + +## _Model Creation_ +After we have our dataset ready, we could proceed straight to our model definition, but first to show the full potential of one of the new features: `model_config` we need to use some of our data to define our prior for sigma parameter for each of the channels. `model_config` is a customizable dictionary with keys corresponding to priors within the model, and values containing a dictionaries with parameters necessary to initialize them. Later on we'll learn that through the `save()` method we can preserve our priors contained inside the `model_config`, to allow complete replication of our model. + ++++ + +### model_config + ++++ + +`default_model_config` attribute of every model inheriting from `ModelBuilder` will allow you to see which priors are available for customization. To see it simply initialize a dummy model: + +```{code-cell} ipython3 +dummy_model = DelayedSaturatedMMM(date_column="", channel_columns="", adstock_max_lag=4) +dummy_model.default_model_config +``` + +You can change only the prior parameters that you wish, no need to alter all of them, unless you'd like to! +In this case we'll just simply replace our sigma for beta_channel with our computed one: + ++++ + +First, let's compute the share of spend per channel: + +```{code-cell} ipython3 +total_spend_per_channel = data[["x1", "x2"]].sum(axis=0) + +spend_share = total_spend_per_channel / total_spend_per_channel.sum() + +spend_share +``` + +Next, we specify the `sigma`parameter per channel: + +```{code-cell} ipython3 +# The scale necessary to make a HalfNormal distribution have unit variance +HALFNORMAL_SCALE = 1 / np.sqrt(1 - 2 / np.pi) + +n_channels = 2 + +prior_sigma = HALFNORMAL_SCALE * n_channels * spend_share.to_numpy() + +prior_sigma.tolist() +``` + +```{code-cell} ipython3 +custom_beta_channel_prior = {"beta_channel": {"sigma": prior_sigma, "dims": ("channel",)}} +my_model_config = dummy_model.default_model_config | custom_beta_channel_prior +``` + +As mentioned in the original notebook: "_For the prior specification there is no right or wrong answer. It all depends on the data, the context and the assumptions you are willing to make. It is always recommended to do some prior predictive sampling and sensitivity analysis to check the impact of the priors on the posterior. We skip this here for the sake of simplicity. If you are not sure about specific priors, the `DelayedSaturatedMMM` class has some default priors that you can use as a starting point._" + ++++ + +The second feature that we can use for model definition is `sampler_config`. Similar to `model_config`, it's a dictionary that gets saved and contains things you'd usually pass to the `fit()` kwargs. It's not mandatory to create your own `sampler_config`; if not provided, both `model_config` and `sampler_config` will default to the forms specified by PyMC Labs experts, which allows for the usage of all model functionalities. The default `sampler_config` is left empty because the default sampling parameters usually prove sufficient for a start. + +```{code-cell} ipython3 +dummy_model.default_sampler_config +``` + +```{code-cell} ipython3 +my_sampler_config = { + "tune": 1000, + "draws": 1000, + "chains": 4, + "target_accept": 0.95, +} +``` + +Let's finally assemble our model! + +```{code-cell} ipython3 +mmm = DelayedSaturatedMMM( + model_config=my_model_config, + sampler_config=my_sampler_config, + date_column="date_week", + channel_columns=["x1", "x2"], + control_columns=[ + "event_1", + "event_2", + "t", + ], + adstock_max_lag=8, + yearly_seasonality=2, +) +``` + +An important thing to note here is that in the new version of `DelayedSaturatedMMM`, we don't pass our dataset to the class constructor itself. This is due to a reason I've mentioned before - it supports `sklearn` transformers and validations that require a usual X, y split and typically expect the data to be passed to the `fit()` method. + ++++ + +## _Model Fitting_ + ++++ + +Let's split the dataset: + +```{code-cell} ipython3 +X = data.drop("y", axis=1) +y = data["y"] +``` + +All that's left now is to finally fit the model: + +As you can see below, you can still pass the sampler kwargs directly to `fit()` method. However, only those kwargs passed using `sampler_config` will be saved. Therefore, only these will be available after loading the model. + +```{code-cell} ipython3 +mmm.fit(X=X, y=y, random_seed=rng) +``` + +The `fit()` method automatically builds the model using the priors from `model_config`, and assigns the created model to our instance. You can access it as a normal attribute. + +```{code-cell} ipython3 +type(mmm.model) +``` + +```{code-cell} ipython3 +mmm.graphviz() +``` + +posterior trace can be accessed by `fit_result` attribute: + +```{code-cell} ipython3 +mmm.fit_result +``` + +If you wish to inspect the entire inference data, use the `idata` attribute. Within `idata`, you can find the entire dataset passed to the model under `fit_data`. + +```{code-cell} ipython3 +mmm.idata +``` + +## `Save` and `load` + ++++ + +All the data passed to the model on initialisation is stored in `idata.attrs`. This will be used later in the `save()` method to convert both this data and all the fit data into the netCDF format. + ++++ + +Simply specify the path to which you'd like to save your model: + +```{code-cell} ipython3 +mmm.save("my_saved_model.nc") +``` + +And pass it to the `load()` method when it's needed again on the target system: + +```{code-cell} ipython3 +loaded_model = DelayedSaturatedMMM.load("my_saved_model.nc") +``` + +```{code-cell} ipython3 +loaded_model.graphviz() +``` + +```{code-cell} ipython3 +loaded_model.idata +``` + +A model loaded in this way is ready to be used for sampling and prediction, and has access to all previous samples and data. + +```{code-cell} ipython3 +with loaded_model.model: + new_predictions = loaded_model.sample_posterior_predictive( + X, extend_idata=True, combined=False, random_seed=rng + ) +new_predictions +``` + +```{code-cell} ipython3 +az.plot_ppc(loaded_model.idata); +``` + +## Summary: + ++++ + +In summary, this article introduces the revolutionary ModelBuilder, a new [PyMC-experimental](https://github.com/pymc-devs/pymc-experimental) module that simplifies the deployment of PyMC Bayesian models. It addresses a historic challenge faced by users of PyMC and most PPLs by offering a user-friendly and efficient approach to model deployment. The ModelBuilder provides two straightforward methods, save() and load(), which streamline the model preservation and replication process post fitting. Users are offered flexibility in controlling the prior settings with `model_config` and customizing the sampling process via `sampler_config`. + +The use of an example model from the [MMM Example Notebook](https://www.pymc-marketing.io/en/stable/notebooks/index.html) demonstrates the practical implementation of `ModelBuilder`, emphasizing its ability to enhance model sharing among teams without the necessity for extensive domain knowledge about the model. The deployment improvements in [PyMC-Marketing](https://github.com/pymc-labs/pymc-marketing) brought about by ModelBuilder are not only user-friendly but also significantly enhance efficiency, making PyMC models more accessible for a wider audience. + ++++ + +Even though this introduction is using `DelayedSaturatedMMM`, functionalities from `ModelBuilder` are available in the CLV models as well. + ++++ + +## Authors +- Authored by [Michał Raczycki](https://github.com/michaelraczycki) in August 2023 + +```{code-cell} ipython3 +%load_ext watermark +%watermark -n -u -v -iv -w -p pytensor,aeppl,xarray +``` + +::: +{include} ../page_footer.md +::: From 431dcd4402cddd3cd561285382e45aec05520f3a Mon Sep 17 00:00:00 2001 From: Michal Raczycki Date: Wed, 23 Aug 2023 10:45:37 +0200 Subject: [PATCH 3/5] removing initial notebook, updating model_builder.ipynb --- .../howto/ModelBuilder_usage_example.ipynb | 17466 ---------------- .../howto/ModelBuilder_usage_example.myst.md | 279 - examples/howto/model_builder.ipynb | 692 + examples/howto/model_builder.myst.md | 350 + 4 files changed, 1042 insertions(+), 17745 deletions(-) delete mode 100644 examples/howto/ModelBuilder_usage_example.ipynb delete mode 100644 examples/howto/ModelBuilder_usage_example.myst.md create mode 100644 examples/howto/model_builder.ipynb create mode 100644 examples/howto/model_builder.myst.md diff --git a/examples/howto/ModelBuilder_usage_example.ipynb b/examples/howto/ModelBuilder_usage_example.ipynb deleted file mode 100644 index d9a409205..000000000 --- a/examples/howto/ModelBuilder_usage_example.ipynb +++ /dev/null @@ -1,17466 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "ad9920da-e687-408d-b99f-060a99c0b561", - "metadata": {}, - "source": [ - "(ModelBuilder usage example)=\n", - "# ModelBuilder usage example\n", - "\n", - ":::{post} Aug 18, 2023\n", - ":tags: ModelBuilder, model deployment,\n", - ":category: intermediate, tutorial\n", - ":author: Michał Raczycki\n", - ":::" - ] - }, - { - "cell_type": "markdown", - "id": "1d74584c", - "metadata": {}, - "source": [ - "# Deploying MMMs and CLVs in Production: Saving and Loading Models" - ] - }, - { - "cell_type": "markdown", - "id": "3222ef04", - "metadata": {}, - "source": [ - "In this article, we'll tackle the historically challenging process of deploying Bayesian models built with PyMC. Introducing a revolutionary deployment module, we bring unprecedented simplicity and efficiency to the deployment of PyMC models. As we prioritize user-friendly solutions, let's delve into how this innovation can significantly elevate your data science projects." - ] - }, - { - "cell_type": "markdown", - "id": "ddb28436", - "metadata": {}, - "source": [ - "\n", - "Recent release of PyMC-Marketing by [Labs](https://www.pymc-labs.io) proves to be a big hit [(PyMC-Marketing)](https://www.pymc-labs.io/blog-posts/pymc-marketing-a-bayesian-approach-to-marketing-data-science/). In the feedback one could see an ongoing theme, many of you have been requesting easy and robust way of deploying models to production. It’s been a long-standing problem with PyMC ( and most other Probabilistic Programming Languages). The reason for that is that there’s no obvious way, and doesn’t matter which approach you try it proves to be tricky. That is why we’re happy to announce the release of `ModelBuilder`, brand new PyMC-experimental module that addresses this need, and improves on the deployment process significantly.\n", - "\n", - "The ModelBuilder module is a new feature of PyMC based models. It provides 2 easy-to-use methods: save() and load() that can be used after the model has been fit.save() allow easy preservation of the model to .netcdf format, and load() gives one-line replication of the original model. Users can control the prior settings with model_config, and customize the sampling process using sampler_config. Default values of those are working just fine, so first time give it a try without changing, and provide your own model_config and model_sampler if afterwards you want to try to customize it more for your use case!\n" - ] - }, - { - "cell_type": "markdown", - "id": "a808e36a", - "metadata": {}, - "source": [ - "For this notebook I'll use the example model used in [MMM Example Notebook](https://www.pymc-marketing.io/en/stable/notebooks/mmm/mmm_example.html), but ommit the details of data generation and plotting functionalities, since they're out of scope for this introduction, I highly recommend to see that part as well, but for now let's focus on today's topic: Groundbreaking deployment improvements in PyMC-Marketing!" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "1050a937", - "metadata": {}, - "outputs": [], - "source": [ - "import arviz as az\n", - "import numpy as np\n", - "import pandas as pd\n", - "\n", - "from pymc_marketing.mmm import DelayedSaturatedMMM" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "e2c3f4c4-1d74-4ae2-9ff2-c13cbcf7fe54", - "metadata": {}, - "outputs": [], - "source": [ - "az.style.use(\"arviz-darkgrid\")" - ] - }, - { - "cell_type": "markdown", - "id": "f37d808e", - "metadata": {}, - "source": [ - "Let's load the dataset:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "b7b1193f", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
date_weekyx1x2event_1event_2dayofyeartsin_order_1cos_order_1sin_order_2cos_order_2
02018-04-023984.6622370.3185800.0000000.00.09200.999930-0.011826-0.023651-0.999720
12018-04-093762.8717940.1123880.0000000.00.09910.991269-0.131859-0.261414-0.965227
22018-04-164466.9673880.2924000.0000000.00.010620.968251-0.249981-0.484089-0.875019
32018-04-233864.2193730.0713990.0000000.00.011330.931210-0.364483-0.678820-0.734304
42018-04-304441.6252780.3867450.0000000.00.012040.880683-0.473706-0.834370-0.551205
.......................................
1742021-08-023553.5461480.0330240.0000000.00.0214174-0.513901-0.8578490.8816990.471812
1752021-08-095565.5096820.1656150.8633490.00.0221175-0.613230-0.7899050.9687860.247898
1762021-08-164137.6514850.1718820.0000000.00.0228176-0.703677-0.7105200.9999530.009676
1772021-08-234479.0413510.2802570.0000000.00.0235177-0.783934-0.6208440.973402-0.229104
1782021-08-304675.9734390.4388570.0000000.00.0242178-0.852837-0.5221780.890665-0.454661
\n", - "

179 rows × 12 columns

\n", - "
" - ], - "text/plain": [ - " date_week y x1 x2 event_1 event_2 dayofyear \\\n", - "0 2018-04-02 3984.662237 0.318580 0.000000 0.0 0.0 92 \n", - "1 2018-04-09 3762.871794 0.112388 0.000000 0.0 0.0 99 \n", - "2 2018-04-16 4466.967388 0.292400 0.000000 0.0 0.0 106 \n", - "3 2018-04-23 3864.219373 0.071399 0.000000 0.0 0.0 113 \n", - "4 2018-04-30 4441.625278 0.386745 0.000000 0.0 0.0 120 \n", - ".. ... ... ... ... ... ... ... \n", - "174 2021-08-02 3553.546148 0.033024 0.000000 0.0 0.0 214 \n", - "175 2021-08-09 5565.509682 0.165615 0.863349 0.0 0.0 221 \n", - "176 2021-08-16 4137.651485 0.171882 0.000000 0.0 0.0 228 \n", - "177 2021-08-23 4479.041351 0.280257 0.000000 0.0 0.0 235 \n", - "178 2021-08-30 4675.973439 0.438857 0.000000 0.0 0.0 242 \n", - "\n", - " t sin_order_1 cos_order_1 sin_order_2 cos_order_2 \n", - "0 0 0.999930 -0.011826 -0.023651 -0.999720 \n", - "1 1 0.991269 -0.131859 -0.261414 -0.965227 \n", - "2 2 0.968251 -0.249981 -0.484089 -0.875019 \n", - "3 3 0.931210 -0.364483 -0.678820 -0.734304 \n", - "4 4 0.880683 -0.473706 -0.834370 -0.551205 \n", - ".. ... ... ... ... ... \n", - "174 174 -0.513901 -0.857849 0.881699 0.471812 \n", - "175 175 -0.613230 -0.789905 0.968786 0.247898 \n", - "176 176 -0.703677 -0.710520 0.999953 0.009676 \n", - "177 177 -0.783934 -0.620844 0.973402 -0.229104 \n", - "178 178 -0.852837 -0.522178 0.890665 -0.454661 \n", - "\n", - "[179 rows x 12 columns]" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "url = \"https://raw.githubusercontent.com/pymc-labs/pymc-marketing/main/datasets/mmm_example.csv\"\n", - "df = pd.read_csv(url)\n", - "df" - ] - }, - { - "cell_type": "markdown", - "id": "87deb70d", - "metadata": {}, - "source": [ - "But for our model we need much smaller dataset, many of the previous features were contributing to generation of others, now as our target variable is computed we can filter out not needed columns:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "52b6d127", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
date_weekyx1x2event_1event_2dayofyeart
02018-04-023984.6622370.3185800.00.00.0920
12018-04-093762.8717940.1123880.00.00.0991
22018-04-164466.9673880.2924000.00.00.01062
32018-04-233864.2193730.0713990.00.00.01133
42018-04-304441.6252780.3867450.00.00.01204
\n", - "
" - ], - "text/plain": [ - " date_week y x1 x2 event_1 event_2 dayofyear t\n", - "0 2018-04-02 3984.662237 0.318580 0.0 0.0 0.0 92 0\n", - "1 2018-04-09 3762.871794 0.112388 0.0 0.0 0.0 99 1\n", - "2 2018-04-16 4466.967388 0.292400 0.0 0.0 0.0 106 2\n", - "3 2018-04-23 3864.219373 0.071399 0.0 0.0 0.0 113 3\n", - "4 2018-04-30 4441.625278 0.386745 0.0 0.0 0.0 120 4" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "columns_to_keep = [\n", - " \"date_week\",\n", - " \"y\",\n", - " \"x1\",\n", - " \"x2\",\n", - " \"event_1\",\n", - " \"event_2\",\n", - " \"dayofyear\",\n", - "]\n", - "seed: int = sum(map(ord, \"mmm\"))\n", - "rng = np.random.default_rng(seed=seed)\n", - "\n", - "data = df[columns_to_keep].copy()\n", - "\n", - "data[\"t\"] = range(df.shape[0])\n", - "data.head()" - ] - }, - { - "cell_type": "markdown", - "id": "9518a885", - "metadata": {}, - "source": [ - "## _Model Creation_\n", - "After we have our dataset ready, we could proceed straight to our model definition, but first to show the full potential of one of the new features: `model_config` we need to use some of our data to define our prior for sigma parameter for each of the channels. `model_config` is a customizable dictionary with keys corresponding to priors within the model, and values containing a dictionaries with parameters necessary to initialize them. Later on we'll learn that through the `save()` method we can preserve our priors contained inside the `model_config`, to allow complete replication of our model." - ] - }, - { - "cell_type": "markdown", - "id": "4b52b2c1", - "metadata": {}, - "source": [ - "### model_config" - ] - }, - { - "cell_type": "markdown", - "id": "41021a72", - "metadata": {}, - "source": [ - "`default_model_config` attribute of every model inheriting from `ModelBuilder` will allow you to see which priors are available for customization. To see it simply initialize a dummy model:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "284bd558", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'intercept': {'mu': 0, 'sigma': 2},\n", - " 'beta_channel': {'sigma': 2, 'dims': ('channel',)},\n", - " 'alpha': {'alpha': 1, 'beta': 3, 'dims': ('channel',)},\n", - " 'lam': {'alpha': 3, 'beta': 1, 'dims': ('channel',)},\n", - " 'sigma': {'sigma': 2},\n", - " 'gamma_control': {'mu': 0, 'sigma': 2, 'dims': ('control',)},\n", - " 'mu': {'dims': ('date',)},\n", - " 'likelihood': {'dims': ('date',)},\n", - " 'gamma_fourier': {'mu': 0, 'b': 1, 'dims': 'fourier_mode'}}" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dummy_model = DelayedSaturatedMMM(date_column=\"\", channel_columns=\"\", adstock_max_lag=4)\n", - "dummy_model.default_model_config" - ] - }, - { - "cell_type": "markdown", - "id": "f0fd248f", - "metadata": {}, - "source": [ - "You can change only the prior parameters that you wish, no need to alter all of them, unless you'd like to!\n", - "In this case we'll just simply replace our sigma for beta_channel with our computed one:" - ] - }, - { - "cell_type": "markdown", - "id": "19f075f0-4d3d-4509-a9c6-f15efdb9293d", - "metadata": {}, - "source": [ - "First, let's compute the share of spend per channel:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "4785596a-e333-4cd0-af15-1332e97b66d5", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "x1 0.65632\n", - "x2 0.34368\n", - "dtype: float64" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "total_spend_per_channel = data[[\"x1\", \"x2\"]].sum(axis=0)\n", - "\n", - "spend_share = total_spend_per_channel / total_spend_per_channel.sum()\n", - "\n", - "spend_share" - ] - }, - { - "cell_type": "markdown", - "id": "40d17642-1e21-4adc-97f4-633eede87915", - "metadata": {}, - "source": [ - "Next, we specify the `sigma`parameter per channel:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "672b36bd-3d08-46df-85b8-d67d3ade75d7", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[2.1775326025486734, 1.140260877391939]" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# The scale necessary to make a HalfNormal distribution have unit variance\n", - "HALFNORMAL_SCALE = 1 / np.sqrt(1 - 2 / np.pi)\n", - "\n", - "n_channels = 2\n", - "\n", - "prior_sigma = HALFNORMAL_SCALE * n_channels * spend_share.to_numpy()\n", - "\n", - "prior_sigma.tolist()" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "bac9f587", - "metadata": {}, - "outputs": [], - "source": [ - "custom_beta_channel_prior = {\"beta_channel\": {\"sigma\": prior_sigma, \"dims\": (\"channel\",)}}\n", - "my_model_config = dummy_model.default_model_config | custom_beta_channel_prior" - ] - }, - { - "cell_type": "markdown", - "id": "1aa435bf", - "metadata": {}, - "source": [ - "As mentioned in the original notebook: \"_For the prior specification there is no right or wrong answer. It all depends on the data, the context and the assumptions you are willing to make. It is always recommended to do some prior predictive sampling and sensitivity analysis to check the impact of the priors on the posterior. We skip this here for the sake of simplicity. If you are not sure about specific priors, the `DelayedSaturatedMMM` class has some default priors that you can use as a starting point._\"" - ] - }, - { - "cell_type": "markdown", - "id": "f195a79e", - "metadata": {}, - "source": [ - "The second feature that we can use for model definition is `sampler_config`. Similar to `model_config`, it's a dictionary that gets saved and contains things you'd usually pass to the `fit()` kwargs. It's not mandatory to create your own `sampler_config`; if not provided, both `model_config` and `sampler_config` will default to the forms specified by PyMC Labs experts, which allows for the usage of all model functionalities. The default `sampler_config` is left empty because the default sampling parameters usually prove sufficient for a start." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "0ab8140c", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{}" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dummy_model.default_sampler_config" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "bf5a50f4", - "metadata": {}, - "outputs": [], - "source": [ - "my_sampler_config = {\n", - " \"tune\": 1000,\n", - " \"draws\": 1000,\n", - " \"chains\": 4,\n", - " \"target_accept\": 0.95,\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "f3bfe090", - "metadata": {}, - "source": [ - "Let's finally assemble our model!" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "c7bd6909", - "metadata": {}, - "outputs": [], - "source": [ - "mmm = DelayedSaturatedMMM(\n", - " model_config=my_model_config,\n", - " sampler_config=my_sampler_config,\n", - " date_column=\"date_week\",\n", - " channel_columns=[\"x1\", \"x2\"],\n", - " control_columns=[\n", - " \"event_1\",\n", - " \"event_2\",\n", - " \"t\",\n", - " ],\n", - " adstock_max_lag=8,\n", - " yearly_seasonality=2,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "54095b1a", - "metadata": {}, - "source": [ - "An important thing to note here is that in the new version of `DelayedSaturatedMMM`, we don't pass our dataset to the class constructor itself. This is due to a reason I've mentioned before - it supports `sklearn` transformers and validations that require a usual X, y split and typically expect the data to be passed to the `fit()` method." - ] - }, - { - "cell_type": "markdown", - "id": "dec9b1b0", - "metadata": {}, - "source": [ - "## _Model Fitting_" - ] - }, - { - "cell_type": "markdown", - "id": "d5e64562-ba78-4497-a0f8-123b4bc88b79", - "metadata": {}, - "source": [ - "Let's split the dataset:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "ff23006b-a55b-4a22-9f34-4eeaddf47486", - "metadata": {}, - "outputs": [], - "source": [ - "X = data.drop(\"y\", axis=1)\n", - "y = data[\"y\"]" - ] - }, - { - "cell_type": "markdown", - "id": "403e3ed2", - "metadata": {}, - "source": [ - "All that's left now is to finally fit the model:\n", - "\n", - "As you can see below, you can still pass the sampler kwargs directly to `fit()` method. However, only those kwargs passed using `sampler_config` will be saved. Therefore, only these will be available after loading the model." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "0f6ab0a8", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Auto-assigning NUTS sampler...\n", - "Initializing NUTS using jitter+adapt_diag...\n", - "Multiprocess sampling (4 chains in 4 jobs)\n", - "NUTS: [intercept, beta_channel, alpha, lam, sigma, gamma_control, gamma_fourier]\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - " \n", - " 100.00% [8000/8000 00:27<00:00 Sampling 4 chains, 0 divergences]\n", - "
\n", - " " - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Sampling 4 chains for 1_000 tune and 1_000 draw iterations (4_000 + 4_000 draws total) took 28 seconds.\n", - "Sampling: [alpha, beta_channel, gamma_control, gamma_fourier, intercept, lam, likelihood, sigma]\n", - "Sampling: [likelihood]\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - " \n", - " 100.00% [4000/4000 00:00<00:00]\n", - "
\n", - " " - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "
arviz.InferenceData
\n", - "
\n", - "
    \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:                    (chain: 4, draw: 1000, control: 3,\n",
      -       "                                fourier_mode: 4, channel: 2, date: 179)\n",
      -       "Coordinates:\n",
      -       "  * chain                      (chain) int64 0 1 2 3\n",
      -       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 995 996 997 998 999\n",
      -       "  * control                    (control) <U7 'event_1' 'event_2' 't'\n",
      -       "  * fourier_mode               (fourier_mode) <U11 'sin_order_1' ... 'cos_ord...\n",
      -       "  * channel                    (channel) <U2 'x1' 'x2'\n",
      -       "  * date                       (date) <U10 '2018-04-02' ... '2021-08-30'\n",
      -       "Data variables: (12/13)\n",
      -       "    intercept                  (chain, draw) float64 0.3381 0.3361 ... 0.3479\n",
      -       "    gamma_control              (chain, draw, control) float64 0.2968 ... 0.00...\n",
      -       "    gamma_fourier              (chain, draw, fourier_mode) float64 -0.002612 ...\n",
      -       "    beta_channel               (chain, draw, channel) float64 0.3718 ... 0.2628\n",
      -       "    alpha                      (chain, draw, channel) float64 0.4162 ... 0.2007\n",
      -       "    lam                        (chain, draw, channel) float64 4.26 ... 2.758\n",
      -       "    ...                         ...\n",
      -       "    channel_adstock            (chain, draw, date, channel) float64 0.1868 .....\n",
      -       "    channel_adstock_saturated  (chain, draw, date, channel) float64 0.3781 .....\n",
      -       "    channel_contributions      (chain, draw, date, channel) float64 0.1406 .....\n",
      -       "    control_contributions      (chain, draw, date, control) float64 0.0 ... 0...\n",
      -       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 -0.0...\n",
      -       "    mu                         (chain, draw, date) float64 0.4769 ... 0.5924\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:12.916984\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1\n",
      -       "    sampling_time:              27.989259004592896\n",
      -       "    tuning_steps:               1000

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:     (chain: 4, draw: 1000, date: 179)\n",
      -       "Coordinates:\n",
      -       "  * chain       (chain) int64 0 1 2 3\n",
      -       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999\n",
      -       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "Data variables:\n",
      -       "    likelihood  (chain, draw, date) float64 0.5148 0.4369 ... 0.4858 0.6176\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:14.741457\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:                (chain: 4, draw: 1000)\n",
      -       "Coordinates:\n",
      -       "  * chain                  (chain) int64 0 1 2 3\n",
      -       "  * draw                   (draw) int64 0 1 2 3 4 5 ... 994 995 996 997 998 999\n",
      -       "Data variables: (12/17)\n",
      -       "    step_size              (chain, draw) float64 0.05862 0.05862 ... 0.07543\n",
      -       "    lp                     (chain, draw) float64 355.1 355.2 ... 355.6 351.6\n",
      -       "    n_steps                (chain, draw) float64 63.0 63.0 63.0 ... 63.0 63.0\n",
      -       "    largest_eigval         (chain, draw) float64 nan nan nan nan ... nan nan nan\n",
      -       "    energy                 (chain, draw) float64 -344.2 -349.9 ... -350.2 -347.5\n",
      -       "    acceptance_rate        (chain, draw) float64 0.9987 0.9934 ... 0.8931 0.9167\n",
      -       "    ...                     ...\n",
      -       "    diverging              (chain, draw) bool False False False ... False False\n",
      -       "    smallest_eigval        (chain, draw) float64 nan nan nan nan ... nan nan nan\n",
      -       "    max_energy_error       (chain, draw) float64 -0.06059 -0.06074 ... 0.284\n",
      -       "    index_in_trajectory    (chain, draw) int64 -12 20 43 -17 ... 42 20 -43 -29\n",
      -       "    energy_error           (chain, draw) float64 -0.01181 -0.02828 ... -0.01478\n",
      -       "    tree_depth             (chain, draw) int64 6 6 6 6 7 6 6 7 ... 6 5 5 6 7 6 6\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:12.932375\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1\n",
      -       "    sampling_time:              27.989259004592896\n",
      -       "    tuning_steps:               1000

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:                    (chain: 1, draw: 500, channel: 2, control: 3,\n",
      -       "                                date: 179, fourier_mode: 4)\n",
      -       "Coordinates:\n",
      -       "  * chain                      (chain) int64 0\n",
      -       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 495 496 497 498 499\n",
      -       "  * channel                    (channel) <U2 'x1' 'x2'\n",
      -       "  * control                    (control) <U7 'event_1' 'event_2' 't'\n",
      -       "  * date                       (date) <U10 '2018-04-02' ... '2021-08-30'\n",
      -       "  * fourier_mode               (fourier_mode) <U11 'sin_order_1' ... 'cos_ord...\n",
      -       "Data variables: (12/13)\n",
      -       "    beta_channel               (chain, draw, channel) float64 0.6143 ... 0.9639\n",
      -       "    sigma                      (chain, draw) float64 2.034 5.255 ... 0.07125\n",
      -       "    gamma_control              (chain, draw, control) float64 -0.9767 ... 0.0...\n",
      -       "    control_contributions      (chain, draw, date, control) float64 -0.0 ... ...\n",
      -       "    mu                         (chain, draw, date) float64 5.528 7.076 ... 8.396\n",
      -       "    channel_adstock_saturated  (chain, draw, date, channel) float64 0.3626 .....\n",
      -       "    ...                         ...\n",
      -       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 1.64...\n",
      -       "    lam                        (chain, draw, channel) float64 2.667 ... 1.438\n",
      -       "    intercept                  (chain, draw) float64 2.51 -3.898 ... -2.654\n",
      -       "    gamma_fourier              (chain, draw, fourier_mode) float64 1.647 ... ...\n",
      -       "    channel_adstock            (chain, draw, date, channel) float64 0.2848 .....\n",
      -       "    alpha                      (chain, draw, channel) float64 0.1089 ... 0.2786\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:14.422347\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:     (chain: 1, draw: 500, date: 179)\n",
      -       "Coordinates:\n",
      -       "  * chain       (chain) int64 0\n",
      -       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 492 493 494 495 496 497 498 499\n",
      -       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "Data variables:\n",
      -       "    likelihood  (chain, draw, date) float64 5.221 8.352 5.313 ... 7.793 8.528\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:14.428434\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:     (date: 179)\n",
      -       "Coordinates:\n",
      -       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "Data variables:\n",
      -       "    likelihood  (date) float64 0.4794 0.4527 0.5374 ... 0.4978 0.5388 0.5625\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:12.937052\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:       (date: 179, channel: 2, control: 3, fourier_mode: 4)\n",
      -       "Coordinates:\n",
      -       "  * date          (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "  * channel       (channel) <U2 'x1' 'x2'\n",
      -       "  * control       (control) <U7 'event_1' 'event_2' 't'\n",
      -       "  * fourier_mode  (fourier_mode) <U11 'sin_order_1' ... 'cos_order_2'\n",
      -       "Data variables:\n",
      -       "    channel_data  (date, channel) float64 0.3196 0.0 0.1128 ... 0.0 0.4403 0.0\n",
      -       "    target        (date) float64 0.4794 0.4527 0.5374 ... 0.4978 0.5388 0.5625\n",
      -       "    control_data  (date, control) float64 0.0 0.0 0.0 0.0 ... 0.0 0.0 178.0\n",
      -       "    fourier_data  (date, fourier_mode) float64 0.9999 -0.01183 ... -0.4547\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:12.938885\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:    (index: 179)\n",
      -       "Coordinates:\n",
      -       "  * index      (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      -       "Data variables:\n",
      -       "    date_week  (index) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "    x1         (index) float64 0.3186 0.1124 0.2924 ... 0.1719 0.2803 0.4389\n",
      -       "    x2         (index) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.8633 0.0 0.0 0.0\n",
      -       "    event_1    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      -       "    event_2    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      -       "    dayofyear  (index) int64 92 99 106 113 120 127 ... 207 214 221 228 235 242\n",
      -       "    t          (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      -       "    y          (index) float64 3.985e+03 3.763e+03 ... 4.479e+03 4.676e+03

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
\n", - "
\n", - " " - ], - "text/plain": [ - "Inference data with groups:\n", - "\t> posterior\n", - "\t> posterior_predictive\n", - "\t> sample_stats\n", - "\t> prior\n", - "\t> prior_predictive\n", - "\t> observed_data\n", - "\t> constant_data\n", - "\t> fit_data" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mmm.fit(X=X, y=y, random_seed=rng)" - ] - }, - { - "cell_type": "markdown", - "id": "c29a6461", - "metadata": {}, - "source": [ - "The `fit()` method automatically builds the model using the priors from `model_config`, and assigns the created model to our instance. You can access it as a normal attribute." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "c6b8e2af", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "pymc.model.Model" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "type(mmm.model)" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "f046ee2c", - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "clusterdate (179) x channel (2)\n", - "\n", - "date (179) x channel (2)\n", - "\n", - "\n", - "clusterdate (179)\n", - "\n", - "date (179)\n", - "\n", - "\n", - "clusterchannel (2)\n", - "\n", - "channel (2)\n", - "\n", - "\n", - "clusterdate (179) x control (3)\n", - "\n", - "date (179) x control (3)\n", - "\n", - "\n", - "clustercontrol (3)\n", - "\n", - "control (3)\n", - "\n", - "\n", - "clusterdate (179) x fourier_mode (4)\n", - "\n", - "date (179) x fourier_mode (4)\n", - "\n", - "\n", - "clusterfourier_mode (4)\n", - "\n", - "fourier_mode (4)\n", - "\n", - "\n", - "\n", - "channel_adstock_saturated\n", - "\n", - "channel_adstock_saturated\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "channel_contributions\n", - "\n", - "channel_contributions\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "channel_adstock_saturated->channel_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "mu\n", - "\n", - "mu\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "channel_contributions->mu\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "channel_data\n", - "\n", - "channel_data\n", - "~\n", - "MutableData\n", - "\n", - "\n", - "\n", - "channel_adstock\n", - "\n", - "channel_adstock\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "channel_data->channel_adstock\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "channel_adstock->channel_adstock_saturated\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "likelihood\n", - "\n", - "likelihood\n", - "~\n", - "Normal\n", - "\n", - "\n", - "\n", - "target\n", - "\n", - "target\n", - "~\n", - "MutableData\n", - "\n", - "\n", - "\n", - "likelihood->target\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "mu->likelihood\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "sigma\n", - "\n", - "sigma\n", - "~\n", - "HalfNormal\n", - "\n", - "\n", - "\n", - "sigma->likelihood\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "intercept\n", - "\n", - "intercept\n", - "~\n", - "Normal\n", - "\n", - "\n", - "\n", - "intercept->mu\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "beta_channel\n", - "\n", - "beta_channel\n", - "~\n", - "HalfNormal\n", - "\n", - "\n", - "\n", - "beta_channel->channel_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "alpha\n", - "\n", - "alpha\n", - "~\n", - "Beta\n", - "\n", - "\n", - "\n", - "alpha->channel_adstock\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "lam\n", - "\n", - "lam\n", - "~\n", - "Gamma\n", - "\n", - "\n", - "\n", - "lam->channel_adstock_saturated\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "control_data\n", - "\n", - "control_data\n", - "~\n", - "MutableData\n", - "\n", - "\n", - "\n", - "control_contributions\n", - "\n", - "control_contributions\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "control_data->control_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "control_contributions->mu\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "gamma_control\n", - "\n", - "gamma_control\n", - "~\n", - "Normal\n", - "\n", - "\n", - "\n", - "gamma_control->control_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fourier_data\n", - "\n", - "fourier_data\n", - "~\n", - "MutableData\n", - "\n", - "\n", - "\n", - "fourier_contributions\n", - "\n", - "fourier_contributions\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "fourier_data->fourier_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fourier_contributions->mu\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "gamma_fourier\n", - "\n", - "gamma_fourier\n", - "~\n", - "Laplace\n", - "\n", - "\n", - "\n", - "gamma_fourier->fourier_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mmm.graphviz()" - ] - }, - { - "cell_type": "markdown", - "id": "c804b600", - "metadata": {}, - "source": [ - "posterior trace can be accessed by `fit_result` attribute:" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "66903965", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
<xarray.Dataset>\n",
-       "Dimensions:                    (chain: 4, draw: 1000, control: 3,\n",
-       "                                fourier_mode: 4, channel: 2, date: 179)\n",
-       "Coordinates:\n",
-       "  * chain                      (chain) int64 0 1 2 3\n",
-       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 995 996 997 998 999\n",
-       "  * control                    (control) <U7 'event_1' 'event_2' 't'\n",
-       "  * fourier_mode               (fourier_mode) <U11 'sin_order_1' ... 'cos_ord...\n",
-       "  * channel                    (channel) <U2 'x1' 'x2'\n",
-       "  * date                       (date) <U10 '2018-04-02' ... '2021-08-30'\n",
-       "Data variables: (12/13)\n",
-       "    intercept                  (chain, draw) float64 0.3381 0.3361 ... 0.3479\n",
-       "    gamma_control              (chain, draw, control) float64 0.2968 ... 0.00...\n",
-       "    gamma_fourier              (chain, draw, fourier_mode) float64 -0.002612 ...\n",
-       "    beta_channel               (chain, draw, channel) float64 0.3718 ... 0.2628\n",
-       "    alpha                      (chain, draw, channel) float64 0.4162 ... 0.2007\n",
-       "    lam                        (chain, draw, channel) float64 4.26 ... 2.758\n",
-       "    ...                         ...\n",
-       "    channel_adstock            (chain, draw, date, channel) float64 0.1868 .....\n",
-       "    channel_adstock_saturated  (chain, draw, date, channel) float64 0.3781 .....\n",
-       "    channel_contributions      (chain, draw, date, channel) float64 0.1406 .....\n",
-       "    control_contributions      (chain, draw, date, control) float64 0.0 ... 0...\n",
-       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 -0.0...\n",
-       "    mu                         (chain, draw, date) float64 0.4769 ... 0.5924\n",
-       "Attributes:\n",
-       "    created_at:                 2023-08-17T13:57:12.916984\n",
-       "    arviz_version:              0.16.1\n",
-       "    inference_library:          pymc\n",
-       "    inference_library_version:  5.6.1\n",
-       "    sampling_time:              27.989259004592896\n",
-       "    tuning_steps:               1000
" - ], - "text/plain": [ - "\n", - "Dimensions: (chain: 4, draw: 1000, control: 3,\n", - " fourier_mode: 4, channel: 2, date: 179)\n", - "Coordinates:\n", - " * chain (chain) int64 0 1 2 3\n", - " * draw (draw) int64 0 1 2 3 4 5 ... 995 996 997 998 999\n", - " * control (control) \n", - "
\n", - "
arviz.InferenceData
\n", - "
\n", - "
    \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:                    (chain: 4, draw: 1000, control: 3,\n",
      -       "                                fourier_mode: 4, channel: 2, date: 179)\n",
      -       "Coordinates:\n",
      -       "  * chain                      (chain) int64 0 1 2 3\n",
      -       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 995 996 997 998 999\n",
      -       "  * control                    (control) <U7 'event_1' 'event_2' 't'\n",
      -       "  * fourier_mode               (fourier_mode) <U11 'sin_order_1' ... 'cos_ord...\n",
      -       "  * channel                    (channel) <U2 'x1' 'x2'\n",
      -       "  * date                       (date) <U10 '2018-04-02' ... '2021-08-30'\n",
      -       "Data variables: (12/13)\n",
      -       "    intercept                  (chain, draw) float64 0.3381 0.3361 ... 0.3479\n",
      -       "    gamma_control              (chain, draw, control) float64 0.2968 ... 0.00...\n",
      -       "    gamma_fourier              (chain, draw, fourier_mode) float64 -0.002612 ...\n",
      -       "    beta_channel               (chain, draw, channel) float64 0.3718 ... 0.2628\n",
      -       "    alpha                      (chain, draw, channel) float64 0.4162 ... 0.2007\n",
      -       "    lam                        (chain, draw, channel) float64 4.26 ... 2.758\n",
      -       "    ...                         ...\n",
      -       "    channel_adstock            (chain, draw, date, channel) float64 0.1868 .....\n",
      -       "    channel_adstock_saturated  (chain, draw, date, channel) float64 0.3781 .....\n",
      -       "    channel_contributions      (chain, draw, date, channel) float64 0.1406 .....\n",
      -       "    control_contributions      (chain, draw, date, control) float64 0.0 ... 0...\n",
      -       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 -0.0...\n",
      -       "    mu                         (chain, draw, date) float64 0.4769 ... 0.5924\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:12.916984\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1\n",
      -       "    sampling_time:              27.989259004592896\n",
      -       "    tuning_steps:               1000

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:     (chain: 4, draw: 1000, date: 179)\n",
      -       "Coordinates:\n",
      -       "  * chain       (chain) int64 0 1 2 3\n",
      -       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999\n",
      -       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "Data variables:\n",
      -       "    likelihood  (chain, draw, date) float64 0.5148 0.4369 ... 0.4858 0.6176\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:14.741457\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:                (chain: 4, draw: 1000)\n",
      -       "Coordinates:\n",
      -       "  * chain                  (chain) int64 0 1 2 3\n",
      -       "  * draw                   (draw) int64 0 1 2 3 4 5 ... 994 995 996 997 998 999\n",
      -       "Data variables: (12/17)\n",
      -       "    step_size              (chain, draw) float64 0.05862 0.05862 ... 0.07543\n",
      -       "    lp                     (chain, draw) float64 355.1 355.2 ... 355.6 351.6\n",
      -       "    n_steps                (chain, draw) float64 63.0 63.0 63.0 ... 63.0 63.0\n",
      -       "    largest_eigval         (chain, draw) float64 nan nan nan nan ... nan nan nan\n",
      -       "    energy                 (chain, draw) float64 -344.2 -349.9 ... -350.2 -347.5\n",
      -       "    acceptance_rate        (chain, draw) float64 0.9987 0.9934 ... 0.8931 0.9167\n",
      -       "    ...                     ...\n",
      -       "    diverging              (chain, draw) bool False False False ... False False\n",
      -       "    smallest_eigval        (chain, draw) float64 nan nan nan nan ... nan nan nan\n",
      -       "    max_energy_error       (chain, draw) float64 -0.06059 -0.06074 ... 0.284\n",
      -       "    index_in_trajectory    (chain, draw) int64 -12 20 43 -17 ... 42 20 -43 -29\n",
      -       "    energy_error           (chain, draw) float64 -0.01181 -0.02828 ... -0.01478\n",
      -       "    tree_depth             (chain, draw) int64 6 6 6 6 7 6 6 7 ... 6 5 5 6 7 6 6\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:12.932375\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1\n",
      -       "    sampling_time:              27.989259004592896\n",
      -       "    tuning_steps:               1000

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:                    (chain: 1, draw: 500, channel: 2, control: 3,\n",
      -       "                                date: 179, fourier_mode: 4)\n",
      -       "Coordinates:\n",
      -       "  * chain                      (chain) int64 0\n",
      -       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 495 496 497 498 499\n",
      -       "  * channel                    (channel) <U2 'x1' 'x2'\n",
      -       "  * control                    (control) <U7 'event_1' 'event_2' 't'\n",
      -       "  * date                       (date) <U10 '2018-04-02' ... '2021-08-30'\n",
      -       "  * fourier_mode               (fourier_mode) <U11 'sin_order_1' ... 'cos_ord...\n",
      -       "Data variables: (12/13)\n",
      -       "    beta_channel               (chain, draw, channel) float64 0.6143 ... 0.9639\n",
      -       "    sigma                      (chain, draw) float64 2.034 5.255 ... 0.07125\n",
      -       "    gamma_control              (chain, draw, control) float64 -0.9767 ... 0.0...\n",
      -       "    control_contributions      (chain, draw, date, control) float64 -0.0 ... ...\n",
      -       "    mu                         (chain, draw, date) float64 5.528 7.076 ... 8.396\n",
      -       "    channel_adstock_saturated  (chain, draw, date, channel) float64 0.3626 .....\n",
      -       "    ...                         ...\n",
      -       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 1.64...\n",
      -       "    lam                        (chain, draw, channel) float64 2.667 ... 1.438\n",
      -       "    intercept                  (chain, draw) float64 2.51 -3.898 ... -2.654\n",
      -       "    gamma_fourier              (chain, draw, fourier_mode) float64 1.647 ... ...\n",
      -       "    channel_adstock            (chain, draw, date, channel) float64 0.2848 .....\n",
      -       "    alpha                      (chain, draw, channel) float64 0.1089 ... 0.2786\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:14.422347\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:     (chain: 1, draw: 500, date: 179)\n",
      -       "Coordinates:\n",
      -       "  * chain       (chain) int64 0\n",
      -       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 492 493 494 495 496 497 498 499\n",
      -       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "Data variables:\n",
      -       "    likelihood  (chain, draw, date) float64 5.221 8.352 5.313 ... 7.793 8.528\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:14.428434\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:     (date: 179)\n",
      -       "Coordinates:\n",
      -       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "Data variables:\n",
      -       "    likelihood  (date) float64 0.4794 0.4527 0.5374 ... 0.4978 0.5388 0.5625\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:12.937052\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:       (date: 179, channel: 2, control: 3, fourier_mode: 4)\n",
      -       "Coordinates:\n",
      -       "  * date          (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "  * channel       (channel) <U2 'x1' 'x2'\n",
      -       "  * control       (control) <U7 'event_1' 'event_2' 't'\n",
      -       "  * fourier_mode  (fourier_mode) <U11 'sin_order_1' ... 'cos_order_2'\n",
      -       "Data variables:\n",
      -       "    channel_data  (date, channel) float64 0.3196 0.0 0.1128 ... 0.0 0.4403 0.0\n",
      -       "    target        (date) float64 0.4794 0.4527 0.5374 ... 0.4978 0.5388 0.5625\n",
      -       "    control_data  (date, control) float64 0.0 0.0 0.0 0.0 ... 0.0 0.0 178.0\n",
      -       "    fourier_data  (date, fourier_mode) float64 0.9999 -0.01183 ... -0.4547\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:12.938885\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:    (index: 179)\n",
      -       "Coordinates:\n",
      -       "  * index      (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      -       "Data variables:\n",
      -       "    date_week  (index) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "    x1         (index) float64 0.3186 0.1124 0.2924 ... 0.1719 0.2803 0.4389\n",
      -       "    x2         (index) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.8633 0.0 0.0 0.0\n",
      -       "    event_1    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      -       "    event_2    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      -       "    dayofyear  (index) int64 92 99 106 113 120 127 ... 207 214 221 228 235 242\n",
      -       "    t          (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      -       "    y          (index) float64 3.985e+03 3.763e+03 ... 4.479e+03 4.676e+03

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
\n", - " \n", - " " - ], - "text/plain": [ - "Inference data with groups:\n", - "\t> posterior\n", - "\t> posterior_predictive\n", - "\t> sample_stats\n", - "\t> prior\n", - "\t> prior_predictive\n", - "\t> observed_data\n", - "\t> constant_data\n", - "\t> fit_data" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mmm.idata" - ] - }, - { - "cell_type": "markdown", - "id": "8b433c7f-0f0d-40b2-bcfb-a19555b528bd", - "metadata": {}, - "source": [ - "## `Save` and `load`" - ] - }, - { - "cell_type": "markdown", - "id": "7b0a35f4", - "metadata": {}, - "source": [ - "All the data passed to the model on initialisation is stored in `idata.attrs`. This will be used later in the `save()` method to convert both this data and all the fit data into the netCDF format." - ] - }, - { - "cell_type": "markdown", - "id": "45948f46", - "metadata": {}, - "source": [ - "Simply specify the path to which you'd like to save your model:" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "b3abe93a", - "metadata": {}, - "outputs": [], - "source": [ - "mmm.save(\"my_saved_model.nc\")" - ] - }, - { - "cell_type": "markdown", - "id": "8a5eba79", - "metadata": {}, - "source": [ - "And pass it to the `load()` method when it's needed again on the target system:" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "0421bae8", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/michalraczycki/Documents/pymc-marketing/.conda/envs/pymc-marketing/lib/python3.10/site-packages/arviz/data/inference_data.py:153: UserWarning: fit_data group is not defined in the InferenceData scheme\n", - " warnings.warn(\n" - ] - } - ], - "source": [ - "loaded_model = DelayedSaturatedMMM.load(\"my_saved_model.nc\")" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "a8b666d3", - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "clusterdate (179) x channel (2)\n", - "\n", - "date (179) x channel (2)\n", - "\n", - "\n", - "clusterdate (179)\n", - "\n", - "date (179)\n", - "\n", - "\n", - "clusterchannel (2)\n", - "\n", - "channel (2)\n", - "\n", - "\n", - "clusterdate (179) x control (3)\n", - "\n", - "date (179) x control (3)\n", - "\n", - "\n", - "clustercontrol (3)\n", - "\n", - "control (3)\n", - "\n", - "\n", - "clusterdate (179) x fourier_mode (4)\n", - "\n", - "date (179) x fourier_mode (4)\n", - "\n", - "\n", - "clusterfourier_mode (4)\n", - "\n", - "fourier_mode (4)\n", - "\n", - "\n", - "\n", - "channel_adstock_saturated\n", - "\n", - "channel_adstock_saturated\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "channel_contributions\n", - "\n", - "channel_contributions\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "channel_adstock_saturated->channel_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "mu\n", - "\n", - "mu\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "channel_contributions->mu\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "channel_data\n", - "\n", - "channel_data\n", - "~\n", - "MutableData\n", - "\n", - "\n", - "\n", - "channel_adstock\n", - "\n", - "channel_adstock\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "channel_data->channel_adstock\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "channel_adstock->channel_adstock_saturated\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "likelihood\n", - "\n", - "likelihood\n", - "~\n", - "Normal\n", - "\n", - "\n", - "\n", - "target\n", - "\n", - "target\n", - "~\n", - "MutableData\n", - "\n", - "\n", - "\n", - "likelihood->target\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "mu->likelihood\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "sigma\n", - "\n", - "sigma\n", - "~\n", - "HalfNormal\n", - "\n", - "\n", - "\n", - "sigma->likelihood\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "intercept\n", - "\n", - "intercept\n", - "~\n", - "Normal\n", - "\n", - "\n", - "\n", - "intercept->mu\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "beta_channel\n", - "\n", - "beta_channel\n", - "~\n", - "HalfNormal\n", - "\n", - "\n", - "\n", - "beta_channel->channel_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "alpha\n", - "\n", - "alpha\n", - "~\n", - "Beta\n", - "\n", - "\n", - "\n", - "alpha->channel_adstock\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "lam\n", - "\n", - "lam\n", - "~\n", - "Gamma\n", - "\n", - "\n", - "\n", - "lam->channel_adstock_saturated\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "control_data\n", - "\n", - "control_data\n", - "~\n", - "MutableData\n", - "\n", - "\n", - "\n", - "control_contributions\n", - "\n", - "control_contributions\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "control_data->control_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "control_contributions->mu\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "gamma_control\n", - "\n", - "gamma_control\n", - "~\n", - "Normal\n", - "\n", - "\n", - "\n", - "gamma_control->control_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fourier_data\n", - "\n", - "fourier_data\n", - "~\n", - "MutableData\n", - "\n", - "\n", - "\n", - "fourier_contributions\n", - "\n", - "fourier_contributions\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "fourier_data->fourier_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fourier_contributions->mu\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "gamma_fourier\n", - "\n", - "gamma_fourier\n", - "~\n", - "Laplace\n", - "\n", - "\n", - "\n", - "gamma_fourier->fourier_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "loaded_model.graphviz()" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "cfb64a2c", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "
arviz.InferenceData
\n", - "
\n", - "
    \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:                    (chain: 4, draw: 1000, control: 3,\n",
      -       "                                fourier_mode: 4, channel: 2, date: 179)\n",
      -       "Coordinates:\n",
      -       "  * chain                      (chain) int64 0 1 2 3\n",
      -       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 995 996 997 998 999\n",
      -       "  * control                    (control) object 'event_1' 'event_2' 't'\n",
      -       "  * fourier_mode               (fourier_mode) object 'sin_order_1' ... 'cos_o...\n",
      -       "  * channel                    (channel) object 'x1' 'x2'\n",
      -       "  * date                       (date) object '2018-04-02' ... '2021-08-30'\n",
      -       "Data variables: (12/13)\n",
      -       "    intercept                  (chain, draw) float64 ...\n",
      -       "    gamma_control              (chain, draw, control) float64 ...\n",
      -       "    gamma_fourier              (chain, draw, fourier_mode) float64 ...\n",
      -       "    beta_channel               (chain, draw, channel) float64 ...\n",
      -       "    alpha                      (chain, draw, channel) float64 ...\n",
      -       "    lam                        (chain, draw, channel) float64 ...\n",
      -       "    ...                         ...\n",
      -       "    channel_adstock            (chain, draw, date, channel) float64 ...\n",
      -       "    channel_adstock_saturated  (chain, draw, date, channel) float64 ...\n",
      -       "    channel_contributions      (chain, draw, date, channel) float64 ...\n",
      -       "    control_contributions      (chain, draw, date, control) float64 ...\n",
      -       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 ...\n",
      -       "    mu                         (chain, draw, date) float64 ...\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:12.916984\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1\n",
      -       "    sampling_time:              27.989259004592896\n",
      -       "    tuning_steps:               1000

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:     (chain: 4, draw: 1000, date: 179)\n",
      -       "Coordinates:\n",
      -       "  * chain       (chain) int64 0 1 2 3\n",
      -       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999\n",
      -       "  * date        (date) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "Data variables:\n",
      -       "    likelihood  (chain, draw, date) float64 ...\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:14.741457\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:                (chain: 4, draw: 1000)\n",
      -       "Coordinates:\n",
      -       "  * chain                  (chain) int64 0 1 2 3\n",
      -       "  * draw                   (draw) int64 0 1 2 3 4 5 ... 994 995 996 997 998 999\n",
      -       "Data variables: (12/17)\n",
      -       "    step_size              (chain, draw) float64 ...\n",
      -       "    lp                     (chain, draw) float64 ...\n",
      -       "    n_steps                (chain, draw) float64 ...\n",
      -       "    largest_eigval         (chain, draw) float64 ...\n",
      -       "    energy                 (chain, draw) float64 ...\n",
      -       "    acceptance_rate        (chain, draw) float64 ...\n",
      -       "    ...                     ...\n",
      -       "    diverging              (chain, draw) bool ...\n",
      -       "    smallest_eigval        (chain, draw) float64 ...\n",
      -       "    max_energy_error       (chain, draw) float64 ...\n",
      -       "    index_in_trajectory    (chain, draw) int64 ...\n",
      -       "    energy_error           (chain, draw) float64 ...\n",
      -       "    tree_depth             (chain, draw) int64 ...\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:12.932375\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1\n",
      -       "    sampling_time:              27.989259004592896\n",
      -       "    tuning_steps:               1000

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:                    (chain: 1, draw: 500, channel: 2, control: 3,\n",
      -       "                                date: 179, fourier_mode: 4)\n",
      -       "Coordinates:\n",
      -       "  * chain                      (chain) int64 0\n",
      -       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 495 496 497 498 499\n",
      -       "  * channel                    (channel) object 'x1' 'x2'\n",
      -       "  * control                    (control) object 'event_1' 'event_2' 't'\n",
      -       "  * date                       (date) object '2018-04-02' ... '2021-08-30'\n",
      -       "  * fourier_mode               (fourier_mode) object 'sin_order_1' ... 'cos_o...\n",
      -       "Data variables: (12/13)\n",
      -       "    beta_channel               (chain, draw, channel) float64 ...\n",
      -       "    sigma                      (chain, draw) float64 ...\n",
      -       "    gamma_control              (chain, draw, control) float64 ...\n",
      -       "    control_contributions      (chain, draw, date, control) float64 ...\n",
      -       "    mu                         (chain, draw, date) float64 ...\n",
      -       "    channel_adstock_saturated  (chain, draw, date, channel) float64 ...\n",
      -       "    ...                         ...\n",
      -       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 ...\n",
      -       "    lam                        (chain, draw, channel) float64 ...\n",
      -       "    intercept                  (chain, draw) float64 ...\n",
      -       "    gamma_fourier              (chain, draw, fourier_mode) float64 ...\n",
      -       "    channel_adstock            (chain, draw, date, channel) float64 ...\n",
      -       "    alpha                      (chain, draw, channel) float64 ...\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:14.422347\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:     (chain: 1, draw: 500, date: 179)\n",
      -       "Coordinates:\n",
      -       "  * chain       (chain) int64 0\n",
      -       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 492 493 494 495 496 497 498 499\n",
      -       "  * date        (date) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "Data variables:\n",
      -       "    likelihood  (chain, draw, date) float64 ...\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:14.428434\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:     (date: 179)\n",
      -       "Coordinates:\n",
      -       "  * date        (date) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "Data variables:\n",
      -       "    likelihood  (date) float64 ...\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:12.937052\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:       (date: 179, channel: 2, control: 3, fourier_mode: 4)\n",
      -       "Coordinates:\n",
      -       "  * date          (date) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "  * channel       (channel) object 'x1' 'x2'\n",
      -       "  * control       (control) object 'event_1' 'event_2' 't'\n",
      -       "  * fourier_mode  (fourier_mode) object 'sin_order_1' ... 'cos_order_2'\n",
      -       "Data variables:\n",
      -       "    channel_data  (date, channel) float64 ...\n",
      -       "    target        (date) float64 ...\n",
      -       "    control_data  (date, control) float64 ...\n",
      -       "    fourier_data  (date, fourier_mode) float64 ...\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-17T13:57:12.938885\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:    (index: 179)\n",
      -       "Coordinates:\n",
      -       "  * index      (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      -       "Data variables:\n",
      -       "    date_week  (index) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "    x1         (index) float64 0.3186 0.1124 0.2924 ... 0.1719 0.2803 0.4389\n",
      -       "    x2         (index) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.8633 0.0 0.0 0.0\n",
      -       "    event_1    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      -       "    event_2    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      -       "    dayofyear  (index) int64 92 99 106 113 120 127 ... 207 214 221 228 235 242\n",
      -       "    t          (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      -       "    y          (index) float64 3.985e+03 3.763e+03 ... 4.479e+03 4.676e+03

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
\n", - "
\n", - " " - ], - "text/plain": [ - "Inference data with groups:\n", - "\t> posterior\n", - "\t> posterior_predictive\n", - "\t> sample_stats\n", - "\t> prior\n", - "\t> prior_predictive\n", - "\t> observed_data\n", - "\t> constant_data\n", - "\t> fit_data" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "loaded_model.idata" - ] - }, - { - "cell_type": "markdown", - "id": "ab64be46-7fe5-4f39-b72b-36da1419f809", - "metadata": {}, - "source": [ - "A model loaded in this way is ready to be used for sampling and prediction, and has access to all previous samples and data." - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "dd59d056-6ac7-431c-85ee-99e7a8eefd8a", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Sampling: [likelihood]\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - " \n", - " 100.00% [4000/4000 00:00<00:00]\n", - "
\n", - " " - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
<xarray.Dataset>\n",
-       "Dimensions:     (chain: 4, draw: 1000, date: 179)\n",
-       "Coordinates:\n",
-       "  * chain       (chain) int64 0 1 2 3\n",
-       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999\n",
-       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
-       "Data variables:\n",
-       "    likelihood  (chain, draw, date) float64 0.4907 0.4282 ... 0.5548 0.5396\n",
-       "Attributes:\n",
-       "    created_at:                 2023-08-17T13:57:22.302381\n",
-       "    arviz_version:              0.16.1\n",
-       "    inference_library:          pymc\n",
-       "    inference_library_version:  5.6.1
" - ], - "text/plain": [ - "\n", - "Dimensions: (chain: 4, draw: 1000, date: 179)\n", - "Coordinates:\n", - " * chain (chain) int64 0 1 2 3\n", - " * draw (draw) int64 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999\n", - " * date (date) " - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "az.plot_ppc(loaded_model.idata);" - ] - }, - { - "cell_type": "markdown", - "id": "e8e807f9", - "metadata": {}, - "source": [ - "## Summary:" - ] - }, - { - "cell_type": "markdown", - "id": "61f232c1", - "metadata": {}, - "source": [ - "In summary, this article introduces the revolutionary ModelBuilder, a new [PyMC-experimental](https://github.com/pymc-devs/pymc-experimental) module that simplifies the deployment of PyMC Bayesian models. It addresses a historic challenge faced by users of PyMC and most PPLs by offering a user-friendly and efficient approach to model deployment. The ModelBuilder provides two straightforward methods, save() and load(), which streamline the model preservation and replication process post fitting. Users are offered flexibility in controlling the prior settings with `model_config` and customizing the sampling process via `sampler_config`.\n", - "\n", - "The use of an example model from the [MMM Example Notebook](https://www.pymc-marketing.io/en/stable/notebooks/index.html) demonstrates the practical implementation of `ModelBuilder`, emphasizing its ability to enhance model sharing among teams without the necessity for extensive domain knowledge about the model. The deployment improvements in [PyMC-Marketing](https://github.com/pymc-labs/pymc-marketing) brought about by ModelBuilder are not only user-friendly but also significantly enhance efficiency, making PyMC models more accessible for a wider audience." - ] - }, - { - "cell_type": "markdown", - "id": "b8ad333d", - "metadata": {}, - "source": [ - "Even though this introduction is using `DelayedSaturatedMMM`, functionalities from `ModelBuilder` are available in the CLV models as well." - ] - }, - { - "cell_type": "markdown", - "id": "de822885-2fb4-4ad1-aaf9-7659771f7363", - "metadata": {}, - "source": [ - "## Authors\n", - "- Authored by [Michał Raczycki](https://github.com/michaelraczycki) in August 2023" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "07ec32d2-2f38-47ec-a200-b9d7258c3ac5", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Last updated: Thu Aug 17 2023\n", - "\n", - "Python implementation: CPython\n", - "Python version : 3.10.12\n", - "IPython version : 8.14.0\n", - "\n", - "pytensor: 2.12.3\n", - "aeppl : not installed\n", - "xarray : 2023.7.0\n", - "\n", - "numpy : 1.25.1\n", - "pandas: 2.0.3\n", - "arviz : 0.16.1\n", - "\n", - "Watermark: 2.4.3\n", - "\n" - ] - } - ], - "source": [ - "%load_ext watermark\n", - "%watermark -n -u -v -iv -w -p pytensor,aeppl,xarray" - ] - }, - { - "cell_type": "markdown", - "id": "7e453d63-39f3-456c-a099-2c780d3ba4a9", - "metadata": {}, - "source": [ - ":::\n", - "{include} ../page_footer.md\n", - ":::" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "pymc-marketing", - "language": "python", - "name": "pymc-marketing" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.12" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/examples/howto/ModelBuilder_usage_example.myst.md b/examples/howto/ModelBuilder_usage_example.myst.md deleted file mode 100644 index 3ea5bbe16..000000000 --- a/examples/howto/ModelBuilder_usage_example.myst.md +++ /dev/null @@ -1,279 +0,0 @@ ---- -jupytext: - text_representation: - extension: .md - format_name: myst - format_version: 0.13 -kernelspec: - display_name: pymc-marketing - language: python - name: pymc-marketing ---- - -(ModelBuilder usage example)= -# ModelBuilder usage example - -:::{post} Aug 18, 2023 -:tags: ModelBuilder, model deployment, -:category: intermediate, tutorial -:author: Michał Raczycki -::: - -+++ - -# Deploying MMMs and CLVs in Production: Saving and Loading Models - -+++ - -In this article, we'll tackle the historically challenging process of deploying Bayesian models built with PyMC. Introducing a revolutionary deployment module, we bring unprecedented simplicity and efficiency to the deployment of PyMC models. As we prioritize user-friendly solutions, let's delve into how this innovation can significantly elevate your data science projects. - -+++ - - -Recent release of PyMC-Marketing by [Labs](https://www.pymc-labs.io) proves to be a big hit [(PyMC-Marketing)](https://www.pymc-labs.io/blog-posts/pymc-marketing-a-bayesian-approach-to-marketing-data-science/). In the feedback one could see an ongoing theme, many of you have been requesting easy and robust way of deploying models to production. It’s been a long-standing problem with PyMC ( and most other Probabilistic Programming Languages). The reason for that is that there’s no obvious way, and doesn’t matter which approach you try it proves to be tricky. That is why we’re happy to announce the release of `ModelBuilder`, brand new PyMC-experimental module that addresses this need, and improves on the deployment process significantly. - -The ModelBuilder module is a new feature of PyMC based models. It provides 2 easy-to-use methods: save() and load() that can be used after the model has been fit.save() allow easy preservation of the model to .netcdf format, and load() gives one-line replication of the original model. Users can control the prior settings with model_config, and customize the sampling process using sampler_config. Default values of those are working just fine, so first time give it a try without changing, and provide your own model_config and model_sampler if afterwards you want to try to customize it more for your use case! - -+++ - -For this notebook I'll use the example model used in [MMM Example Notebook](https://www.pymc-marketing.io/en/stable/notebooks/mmm/mmm_example.html), but ommit the details of data generation and plotting functionalities, since they're out of scope for this introduction, I highly recommend to see that part as well, but for now let's focus on today's topic: Groundbreaking deployment improvements in PyMC-Marketing! - -```{code-cell} ipython3 -import arviz as az -import numpy as np -import pandas as pd - -from pymc_marketing.mmm import DelayedSaturatedMMM -``` - -```{code-cell} ipython3 -az.style.use("arviz-darkgrid") -``` - -Let's load the dataset: - -```{code-cell} ipython3 -url = "https://raw.githubusercontent.com/pymc-labs/pymc-marketing/main/datasets/mmm_example.csv" -df = pd.read_csv(url) -df -``` - -But for our model we need much smaller dataset, many of the previous features were contributing to generation of others, now as our target variable is computed we can filter out not needed columns: - -```{code-cell} ipython3 -columns_to_keep = [ - "date_week", - "y", - "x1", - "x2", - "event_1", - "event_2", - "dayofyear", -] -seed: int = sum(map(ord, "mmm")) -rng = np.random.default_rng(seed=seed) - -data = df[columns_to_keep].copy() - -data["t"] = range(df.shape[0]) -data.head() -``` - -## _Model Creation_ -After we have our dataset ready, we could proceed straight to our model definition, but first to show the full potential of one of the new features: `model_config` we need to use some of our data to define our prior for sigma parameter for each of the channels. `model_config` is a customizable dictionary with keys corresponding to priors within the model, and values containing a dictionaries with parameters necessary to initialize them. Later on we'll learn that through the `save()` method we can preserve our priors contained inside the `model_config`, to allow complete replication of our model. - -+++ - -### model_config - -+++ - -`default_model_config` attribute of every model inheriting from `ModelBuilder` will allow you to see which priors are available for customization. To see it simply initialize a dummy model: - -```{code-cell} ipython3 -dummy_model = DelayedSaturatedMMM(date_column="", channel_columns="", adstock_max_lag=4) -dummy_model.default_model_config -``` - -You can change only the prior parameters that you wish, no need to alter all of them, unless you'd like to! -In this case we'll just simply replace our sigma for beta_channel with our computed one: - -+++ - -First, let's compute the share of spend per channel: - -```{code-cell} ipython3 -total_spend_per_channel = data[["x1", "x2"]].sum(axis=0) - -spend_share = total_spend_per_channel / total_spend_per_channel.sum() - -spend_share -``` - -Next, we specify the `sigma`parameter per channel: - -```{code-cell} ipython3 -# The scale necessary to make a HalfNormal distribution have unit variance -HALFNORMAL_SCALE = 1 / np.sqrt(1 - 2 / np.pi) - -n_channels = 2 - -prior_sigma = HALFNORMAL_SCALE * n_channels * spend_share.to_numpy() - -prior_sigma.tolist() -``` - -```{code-cell} ipython3 -custom_beta_channel_prior = {"beta_channel": {"sigma": prior_sigma, "dims": ("channel",)}} -my_model_config = dummy_model.default_model_config | custom_beta_channel_prior -``` - -As mentioned in the original notebook: "_For the prior specification there is no right or wrong answer. It all depends on the data, the context and the assumptions you are willing to make. It is always recommended to do some prior predictive sampling and sensitivity analysis to check the impact of the priors on the posterior. We skip this here for the sake of simplicity. If you are not sure about specific priors, the `DelayedSaturatedMMM` class has some default priors that you can use as a starting point._" - -+++ - -The second feature that we can use for model definition is `sampler_config`. Similar to `model_config`, it's a dictionary that gets saved and contains things you'd usually pass to the `fit()` kwargs. It's not mandatory to create your own `sampler_config`; if not provided, both `model_config` and `sampler_config` will default to the forms specified by PyMC Labs experts, which allows for the usage of all model functionalities. The default `sampler_config` is left empty because the default sampling parameters usually prove sufficient for a start. - -```{code-cell} ipython3 -dummy_model.default_sampler_config -``` - -```{code-cell} ipython3 -my_sampler_config = { - "tune": 1000, - "draws": 1000, - "chains": 4, - "target_accept": 0.95, -} -``` - -Let's finally assemble our model! - -```{code-cell} ipython3 -mmm = DelayedSaturatedMMM( - model_config=my_model_config, - sampler_config=my_sampler_config, - date_column="date_week", - channel_columns=["x1", "x2"], - control_columns=[ - "event_1", - "event_2", - "t", - ], - adstock_max_lag=8, - yearly_seasonality=2, -) -``` - -An important thing to note here is that in the new version of `DelayedSaturatedMMM`, we don't pass our dataset to the class constructor itself. This is due to a reason I've mentioned before - it supports `sklearn` transformers and validations that require a usual X, y split and typically expect the data to be passed to the `fit()` method. - -+++ - -## _Model Fitting_ - -+++ - -Let's split the dataset: - -```{code-cell} ipython3 -X = data.drop("y", axis=1) -y = data["y"] -``` - -All that's left now is to finally fit the model: - -As you can see below, you can still pass the sampler kwargs directly to `fit()` method. However, only those kwargs passed using `sampler_config` will be saved. Therefore, only these will be available after loading the model. - -```{code-cell} ipython3 -mmm.fit(X=X, y=y, random_seed=rng) -``` - -The `fit()` method automatically builds the model using the priors from `model_config`, and assigns the created model to our instance. You can access it as a normal attribute. - -```{code-cell} ipython3 -type(mmm.model) -``` - -```{code-cell} ipython3 -mmm.graphviz() -``` - -posterior trace can be accessed by `fit_result` attribute: - -```{code-cell} ipython3 -mmm.fit_result -``` - -If you wish to inspect the entire inference data, use the `idata` attribute. Within `idata`, you can find the entire dataset passed to the model under `fit_data`. - -```{code-cell} ipython3 -mmm.idata -``` - -## `Save` and `load` - -+++ - -All the data passed to the model on initialisation is stored in `idata.attrs`. This will be used later in the `save()` method to convert both this data and all the fit data into the netCDF format. - -+++ - -Simply specify the path to which you'd like to save your model: - -```{code-cell} ipython3 -mmm.save("my_saved_model.nc") -``` - -And pass it to the `load()` method when it's needed again on the target system: - -```{code-cell} ipython3 -loaded_model = DelayedSaturatedMMM.load("my_saved_model.nc") -``` - -```{code-cell} ipython3 -loaded_model.graphviz() -``` - -```{code-cell} ipython3 -loaded_model.idata -``` - -A model loaded in this way is ready to be used for sampling and prediction, and has access to all previous samples and data. - -```{code-cell} ipython3 -with loaded_model.model: - new_predictions = loaded_model.sample_posterior_predictive( - X, extend_idata=True, combined=False, random_seed=rng - ) -new_predictions -``` - -```{code-cell} ipython3 -az.plot_ppc(loaded_model.idata); -``` - -## Summary: - -+++ - -In summary, this article introduces the revolutionary ModelBuilder, a new [PyMC-experimental](https://github.com/pymc-devs/pymc-experimental) module that simplifies the deployment of PyMC Bayesian models. It addresses a historic challenge faced by users of PyMC and most PPLs by offering a user-friendly and efficient approach to model deployment. The ModelBuilder provides two straightforward methods, save() and load(), which streamline the model preservation and replication process post fitting. Users are offered flexibility in controlling the prior settings with `model_config` and customizing the sampling process via `sampler_config`. - -The use of an example model from the [MMM Example Notebook](https://www.pymc-marketing.io/en/stable/notebooks/index.html) demonstrates the practical implementation of `ModelBuilder`, emphasizing its ability to enhance model sharing among teams without the necessity for extensive domain knowledge about the model. The deployment improvements in [PyMC-Marketing](https://github.com/pymc-labs/pymc-marketing) brought about by ModelBuilder are not only user-friendly but also significantly enhance efficiency, making PyMC models more accessible for a wider audience. - -+++ - -Even though this introduction is using `DelayedSaturatedMMM`, functionalities from `ModelBuilder` are available in the CLV models as well. - -+++ - -## Authors -- Authored by [Michał Raczycki](https://github.com/michaelraczycki) in August 2023 - -```{code-cell} ipython3 -%load_ext watermark -%watermark -n -u -v -iv -w -p pytensor,aeppl,xarray -``` - -::: -{include} ../page_footer.md -::: diff --git a/examples/howto/model_builder.ipynb b/examples/howto/model_builder.ipynb new file mode 100644 index 000000000..0caab67fc --- /dev/null +++ b/examples/howto/model_builder.ipynb @@ -0,0 +1,692 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "8f00588f-6a28-4d93-b072-f464f78aae40", + "metadata": {}, + "source": [ + "# Using ModelBuilder class for deploying PyMC models \n", + ":::{post} Feb 22, 2023\n", + ":tags: deployment\n", + ":category: Advanced\n", + ":author: Shashank Kirtania, Thomas Wiecki, Michał Raczycki\n", + ":::" + ] + }, + { + "cell_type": "markdown", + "id": "1fdfb702-b893-4e63-8354-935f9742fdde", + "metadata": {}, + "source": [ + "## Motivation" + ] + }, + { + "cell_type": "markdown", + "id": "13a7e0ee-506c-4d5d-adb3-a52cc24cac50", + "metadata": {}, + "source": [ + "Many users face difficulty in deploying their PyMC models to production because deploying/saving/loading a user-created model is not well standardized. One of the reasons behind this is there is no direct way to save or load a model in PyMC like scikit-learn or TensorFlow. The new `ModelBuilder` class is aimed to improve this workflow by providing a scikit-learn inspired API to wrap your PyMC models.\n", + "\n", + "The new `ModelBuilder` class allows users to use methods to `fit()`, `predict()`, `save()`, `load()`. Users can create any model they want, inherit the `ModelBuilder` class, and use predefined methods." + ] + }, + { + "cell_type": "markdown", + "id": "94832375-dc7e-4b4f-ad2e-87363fc363db", + "metadata": {}, + "source": [ + "Let's go through the full workflow, starting with a simple linear regression PyMC model as it's usually written. Of course, this model is just a place-holder for your own model." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "48e35045", + "metadata": {}, + "outputs": [], + "source": [ + "from typing import Dict, List, Optional, Tuple, Union\n", + "\n", + "import arviz as az\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd\n", + "import pymc as pm\n", + "import xarray as xr\n", + "\n", + "from numpy.random import RandomState\n", + "\n", + "%config InlineBackend.figure_format = 'retina'\n", + "RANDOM_SEED = 8927\n", + "\n", + "rng = np.random.default_rng(RANDOM_SEED)\n", + "az.style.use(\"arviz-darkgrid\")" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "d6eccf65", + "metadata": {}, + "outputs": [], + "source": [ + "# Generate data\n", + "x = np.linspace(start=0, stop=1, num=100)\n", + "y = 0.3 * x + 0.5 + rng.normal(0, 1, len(x))" + ] + }, + { + "cell_type": "markdown", + "id": "291452ed", + "metadata": {}, + "source": [ + "## Standard syntax\n", + "Usually a PyMC model will have this form:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "84d07dc6", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Auto-assigning NUTS sampler...\n", + "Initializing NUTS using jitter+adapt_diag...\n", + "Initializing NUTS using jitter+adapt_diag...\n", + "Multiprocess sampling (4 chains in 4 jobs)\n", + "NUTS: [a, b, eps]\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Sampling 4 chains for 1_000 tune and 1_000 draw iterations (4_000 + 4_000 draws total) took 10 seconds.\n", + "Sampling: [a, b, eps, y_model]\n" + ] + } + ], + "source": [ + "with pm.Model() as model:\n", + " # priors\n", + " a = pm.Normal(\"a\", mu=0, sigma=1)\n", + " b = pm.Normal(\"b\", mu=0, sigma=1)\n", + " eps = pm.HalfNormal(\"eps\", 1.0)\n", + "\n", + " # observed data\n", + " y_model = pm.Normal(\"y_model\", mu=a + b * x, sigma=eps, observed=y)\n", + "\n", + " # Fitting\n", + " idata = pm.sample()\n", + " idata.extend(pm.sample_prior_predictive())\n", + "\n", + " # posterior predict\n", + " idata.extend(pm.sample_posterior_predictive(idata))" + ] + }, + { + "cell_type": "markdown", + "id": "eda28484", + "metadata": {}, + "source": [ + "How would we deploy this model? Save the fitted model, load it on an instance, and predict? Not so simple.\n", + "\n", + "`ModelBuilder` is built for this purpose. It is currently part of the `pymc-experimental` package which we can pip install with `pip install pymc-experimental`. As the name implies, this feature is still experimental and subject to change." + ] + }, + { + "cell_type": "markdown", + "id": "213ee05a", + "metadata": {}, + "source": [ + "## Model builder class" + ] + }, + { + "cell_type": "markdown", + "id": "36214695-5fb1-4450-a3ea-789f2e965746", + "metadata": {}, + "source": [ + "Let's import the `ModelBuilder` class." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "a1f5fa98-53d8-459a-827b-fa5179861918", + "metadata": {}, + "outputs": [], + "source": [ + "from pymc_experimental.model_builder import ModelBuilder" + ] + }, + { + "cell_type": "markdown", + "id": "ef0412fe-5aae-4bfa-8a1f-0e1e3762fc5f", + "metadata": {}, + "source": [ + "To define our desired model we inherit from the `ModelBuilder` class. There are a couple of methods we need to define." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "1c4b4575-630c-45a7-9eee-4790adf8924f", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "class LinearModel(ModelBuilder):\n", + " # Give the model a name\n", + " _model_type = \"LinearModel\"\n", + "\n", + " # And a version\n", + " version = \"0.1\"\n", + "\n", + " def build_model(self, X: pd.DataFrame, y: Union[pd.Series, np.ndarray], **kwargs):\n", + " \"\"\"\n", + " build_model creates the PyMC model\n", + "\n", + " Parameters:\n", + " model_config: dictionary\n", + " it is a dictionary with all the parameters that we need in our model example: a_loc, a_scale, b_loc\n", + " data: Dict[str, Union[np.ndarray, pd.DataFrame, pd.Series]]\n", + " Data we want our model fit on.\n", + " \"\"\"\n", + " # Check the type of X and y and adjust access accordingly\n", + " X_values = X[\"input\"].values\n", + " y_values = y.values if isinstance(y, pd.Series) else y\n", + " self._generate_and_preprocess_model_data(X_values, y_values)\n", + "\n", + " with pm.Model(coords=self.model_coords) as self.model:\n", + "\n", + " # Create mutable data containers\n", + " x_data = pm.MutableData(\"x_data\", X_values)\n", + " y_data = pm.MutableData(\"y_data\", y_values)\n", + "\n", + " # prior parameters\n", + " a_mu_prior = self.model_config.get(\"a_mu_prior\", 0.0)\n", + " a_sigma_prior = self.model_config.get(\"a_sigma_prior\", 1.0)\n", + " b_mu_prior = self.model_config.get(\"b_mu_prior\", 0.0)\n", + " b_sigma_prior = self.model_config.get(\"b_sigma_prior\", 1.0)\n", + " eps_prior = self.model_config.get(\"eps_prior\", 1.0)\n", + "\n", + " # priors\n", + " a = pm.Normal(\"a\", mu=a_mu_prior, sigma=a_sigma_prior)\n", + " b = pm.Normal(\"b\", mu=b_mu_prior, sigma=b_sigma_prior)\n", + " eps = pm.HalfNormal(\"eps\", eps_prior)\n", + "\n", + " obs = pm.Normal(\"y\", mu=a + b * x_data, sigma=eps, shape=x_data.shape, observed=y_data)\n", + "\n", + " def _data_setter(\n", + " self, X: Union[pd.DataFrame, np.ndarray], y: Union[pd.Series, np.ndarray] = None\n", + " ):\n", + " if isinstance(X, pd.DataFrame):\n", + " x_values = X[\"input\"].values\n", + " else:\n", + " # Assuming \"input\" is the first column\n", + " x_values = X[:, 0]\n", + "\n", + " with self.model:\n", + " pm.set_data({\"x_data\": x_values})\n", + " if y is not None:\n", + " pm.set_data({\"y_data\": y.values if isinstance(y, pd.Series) else y})\n", + "\n", + " @property\n", + " def default_model_config(self) -> Dict:\n", + " \"\"\"\n", + " default_model_config is a property that returns a dictionary with all the prior values we want to build the model with.\n", + " It supports more complex data structures like lists, dictionaries, etc.\n", + " It will be passed to the class instance on initialization, in case the user doesn't provide any model_config of their own.\n", + " \"\"\"\n", + " model_config: Dict = {\n", + " \"a_mu_prior\": 0.0,\n", + " \"a_sigma_prior\": 1.0,\n", + " \"b_mu_prior\": 0.0,\n", + " \"b_sigma_prior\": 1.0,\n", + " \"eps_prior\": 1.0,\n", + " }\n", + " return model_config\n", + "\n", + " @property\n", + " def default_sampler_config(self) -> Dict:\n", + " \"\"\"\n", + " default_sampler_config is a property that returns a dictionary with all most important sampler parameters.\n", + " It will be used in case the user doesn't provide any sampler_config of their own.\n", + " \"\"\"\n", + " sampler_config: Dict = {\n", + " \"draws\": 1_000,\n", + " \"tune\": 1_000,\n", + " \"chains\": 3,\n", + " \"target_accept\": 0.95,\n", + " }\n", + " return sampler_config\n", + "\n", + " @property\n", + " def output_var(self):\n", + " return \"y\"\n", + "\n", + " @property\n", + " def _serializable_model_config(self) -> Dict[str, Union[int, float, Dict]]:\n", + " \"\"\"\n", + " _serializable_model_config is a property that returns a dictionary with all the model parameters that we want to save.\n", + " as some of the data structures are not json serializable, we need to convert them to json serializable objects.\n", + " Some models will need them, others can just define them to return the model_config.\n", + " \"\"\"\n", + " return self.model_config\n", + "\n", + " def _save_input_params(self, idata) -> None:\n", + " \"\"\"\n", + " Saves any additional model parameters (other than the dataset) to the idata object.\n", + "\n", + " These parameters are stored within `idata.attrs` using keys that correspond to the parameter names.\n", + " If you don't need to store any extra parameters, you can leave this method unimplemented.\n", + "\n", + " Example:\n", + " For saving customer IDs provided as an 'customer_ids' input to the model:\n", + " self.customer_ids = customer_ids.values #this line is done outside of the function, preferably at the initialization of the model object.\n", + " idata.attrs[\"customer_ids\"] = json.dumps(self.customer_ids.tolist()) # Convert numpy array to a JSON-serializable list.\n", + " \"\"\"\n", + " pass\n", + "\n", + " pass\n", + "\n", + " def _generate_and_preprocess_model_data(\n", + " self, X: Union[pd.DataFrame, pd.Series], y: Union[pd.Series, np.ndarray]\n", + " ) -> None:\n", + " \"\"\"\n", + " Depending on the model, we might need to preprocess the data before fitting the model.\n", + " all required preprocessing and conditional assignments should be defined here.\n", + " \"\"\"\n", + " self.model_coords = None # in our case we're not using coords, but if we were, we would define them here, or later on in the function, if extracting them from the data.\n", + " # as we don't do any data preprocessing, we just assign the data givenin by the user. Note that it's very basic model,\n", + " # and usually we would need to do some preprocessing, or generate the coords from the data.\n", + " self.X = X\n", + " self.y = y" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "aa682cee-58b0-4c51-b5fd-f99d6afaea69", + "metadata": {}, + "source": [ + "Now we can create the `LinearModel` object. First step we need to take care of, is data generation:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "8658306c-f1eb-45a7-9c71-3fcee06183bc", + "metadata": {}, + "outputs": [], + "source": [ + "X = pd.DataFrame(data=np.linspace(start=0, stop=1, num=100), columns=[\"input\"])\n", + "y = 0.3 * x + 0.5\n", + "y = y + np.random.normal(0, 1, len(x))\n", + "\n", + "model = LinearModel()" + ] + }, + { + "cell_type": "markdown", + "id": "294cf57b-b51f-4c77-8e0b-5adaf0a63f2b", + "metadata": {}, + "source": [ + "After making the object of class `LinearModel` we can fit the model using the `.fit()` method." + ] + }, + { + "cell_type": "markdown", + "id": "3d4dead3", + "metadata": {}, + "source": [ + "## Fitting to data" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "e50eb992", + "metadata": {}, + "source": [ + "The `fit()` method takes one argument `data` on which we need to fit the model. The meta-data is saved in the `InferenceData` object where also the trace is stored. These are the fields that are stored:\n", + "\n", + "* `id` : This is a unique id given to a model based on model_config, sample_conifg, version, and model_type. Users can use it to check if the model matches to another model they have defined.\n", + "* `model_type` : Model type tells us what kind of model it is. This in this case it outputs **Linear Model** \n", + "* `version` : In case you want to improve on models, you can keep track of model by their version. As the version changes the unique hash in the `id` also changes.\n", + "* `sample_conifg` : It stores values of the sampler configuration set by user for this particular model.\n", + "* `model_config` : It stores values of the model configuration set by user for this particular model.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "a3708a8f-40f6-4a04-bcbf-284397f25450", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Auto-assigning NUTS sampler...\n", + "Initializing NUTS using jitter+adapt_diag...\n", + "Initializing NUTS using jitter+adapt_diag...\n", + "Multiprocess sampling (3 chains in 4 jobs)\n", + "NUTS: [a, b, eps]\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Sampling 3 chains for 1_000 tune and 1_000 draw iterations (3_000 + 3_000 draws total) took 7 seconds.\n", + "We recommend running at least 4 chains for robust computation of convergence diagnostics\n", + "Sampling: [a, b, eps, y]\n" + ] + } + ], + "source": [ + "idata = model.fit(X, y)" + ] + }, + { + "cell_type": "markdown", + "id": "ac975628", + "metadata": {}, + "source": [ + "## Saving model to file" + ] + }, + { + "cell_type": "markdown", + "id": "1649556a-13b6-409f-ac09-5c4b7e0277b7", + "metadata": {}, + "source": [ + "After fitting the model, we can probably save it to share the model as a file so one can use it again.\n", + "To `save()` or `load()`, we can quickly call methods for respective tasks with the following syntax." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "a965d738-60c5-4b4b-b872-f2613621851b", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "fname = \"linear_model_v1.nc\"\n", + "model.save(fname)" + ] + }, + { + "cell_type": "markdown", + "id": "490e8802-0395-42c7-a01a-18d9af272320", + "metadata": {}, + "source": [ + "This saves a file at the given path, and the name
\n", + "A NetCDF `.nc` file that stores the inference data of the model." + ] + }, + { + "cell_type": "markdown", + "id": "cf072612", + "metadata": {}, + "source": [ + "## Loading a model" + ] + }, + { + "cell_type": "markdown", + "id": "3e188eb0-c42e-4cd5-b70c-568d9cde71f0", + "metadata": {}, + "source": [ + "Now if we wanted to deploy this model, or just have other people use it to predict data, they need two things:\n", + "1. the `LinearModel` class (probably in a .py file)\n", + "2. the linear_model_v1.nc file\n", + "\n", + "With these, you can easily load a fitted model in a different environment (e.g. production):" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "fe2bccf2-1707-4b21-803b-50716e9298c3", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/michalraczycki/Documents/pymc-marketing/.conda/envs/pymc-marketing/lib/python3.10/site-packages/arviz/data/inference_data.py:153: UserWarning: fit_data group is not defined in the InferenceData scheme\n", + " warnings.warn(\n" + ] + } + ], + "source": [ + "model_2 = LinearModel.load(fname)" + ] + }, + { + "cell_type": "markdown", + "id": "27ac7c8f", + "metadata": {}, + "source": [ + "Note that `load()` is a class-method, we do not need to instantiate the `LinearModel` object." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "b67f25d6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "__main__.LinearModel" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(model_2)" + ] + }, + { + "cell_type": "markdown", + "id": "3dc1840c", + "metadata": {}, + "source": [ + "## Prediction" + ] + }, + { + "cell_type": "markdown", + "id": "1d7254f1-7a59-4623-a128-8a1dd48d0407", + "metadata": {}, + "source": [ + "Next we might want to predict on new data. The `predict()` method allows users to do posterior prediction with the fitted model on new data.\n", + "\n", + "Our first task is to create data on which we need to predict." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "3ecc8694-db5e-4d45-b8e0-78608b7eaa83", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "numpy.ndarray" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x_pred = np.random.uniform(low=1, high=2, size=10)\n", + "prediction_data = pd.DataFrame({\"input\": x_pred})\n", + "type(prediction_data[\"input\"].values)" + ] + }, + { + "cell_type": "markdown", + "id": "1b155d2d-0211-4d85-8b60-a728a62e3743", + "metadata": {}, + "source": [ + "`ModelBuilder` provides two methods for prediction:\n", + "1. point estimates (the mean) with `predict()`\n", + "2. full posterior prediction (samples) with `predict_posterior()`" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "6926eba3-52ed-4c6c-b58f-f2e0bba7b45a", + "metadata": {}, + "outputs": [], + "source": [ + "pred_mean = model_2.predict(prediction_data)\n", + "# samples\n", + "pred_samples = model_2.predict_posterior(prediction_data)" + ] + }, + { + "cell_type": "markdown", + "id": "cfb595b5-e237-4099-b16d-f00c4448307e", + "metadata": {}, + "source": [ + "After using the `predict()`, we can plot our data and see graphically how satisfactory our `LinearModel` is." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "a5375a1c-ed19-4e06-9d9f-74369877cac2", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABY8AAAWPCAYAAADgDAt2AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAB7CAAAewgFu0HU+AAEAAElEQVR4nOzddXgUV9sG8HuzG/eEBJcQILgEd3dogVKBFiq4Q6EtUKRIS8tbpBSHIIXi/uLursEiaBIsxF1Wvj/yZd7MSnY22Qhw/66Li8zsOWfOzM7sJs+ceY5Mo9FoQERERERERERERESUhUVBd4CIiIiIiIiIiIiICh8Gj4mIiIiIiIiIiIhIB4PHRERERERERERERKSDwWMiIiIiIiIiIiIi0sHgMRERERERERERERHpYPCYiIiIiIiIiIiIiHQweExEREREREREREREOhg8JiIiIiIiIiIiIiIdDB4TERERERERERERkQ4Gj4mIiIiIiIiIiIhIB4PHRERERERERERERKSDwWMiIiIiIiIiIiIi0sHgMRERERERERERERHpYPCYiIiIiIiIiIiIiHQweExEREREREREREREOhg8JiIiIiIiIiIiIiIdDB4TERERERERERERkQ4Gj4mIiIiIiIiIiIhIB4PHRERERERERERERKSDwWMiIiIS6devH3x8fIR/V65cKegu0Qdm4sSJonNw165d2ZbftWuXqPzEiRPzqad5r02bNqJ9CwsLK+guEVEOmfrZRvqZ+nvK+/wdQUSUHxQF3QEiIsofEydOxO7du42Wk8vlcHR0hJOTE8qXL48aNWqgVatWqF69ej70koiIiIiIiIgKCwaPiYhIRKVSISYmBjExMQgJCcHp06fx999/o3bt2vjxxx9Rt27dgu5inouLi8P69euFZUdHR3zzzTcF1yEieudcuXIFV69eFZYbNGiAhg0bFmCPiIiIiIhMx+AxERFJcvv2bfTr1w9jx47F4MGDC7o7eSouLg6LFy8WlkuWLMngMRGZ5OrVq6LPkZEjRzJ4TERERETvHAaPiYg+UOXKldMbEFWpVIiOjsa9e/dw6dIlpKamil6bN28eXFxc8Nlnn+Vjb4mIiIiIiIgovzF4TET0gfL09ESfPn2yLfP27VvMmjULR44cEa2fPXs2WrZsiaJFi+ZlF6mAbNiwoaC7QGSSXr16oVevXgXd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8UJYPnHiBEqVKlWAPSKi91FUVBTOnTuHW7duITg4GK9evUJ0dDRSU1NhaWkJZ2dnuLu7o0aNGmjYsCHatGkDW1vbgu42ERERvWcYPCYiIiIiIiIiIiIiHYan7SUiIiIiIiIiIiKiDxaDx0RERERERERERESkg8FjIiIiIiIiIiIiItLB4DERERERERERERER6WDwmIiIiIiIiIiIiIh0MHhMRERERERERERERDoUBd0BevdFR0cXdBfyjEwmg4uLCwAgJiYGGo2mYDtE9IHjNUlUuPCaJCo8eD0SFS68JokKlw/pmnR1dTVrexx5TEREREREREREREQ6GDwmIiIiIiIiIiIiIh0MHhMRERERERERERGRDgaPiYiIiIiIiIiIiEgHg8dEREREREREREREpIPBYyIiIiIiIiIiIiLSweAxEREREREREREREelg8JiIiIiIiIiIiIiIdDB4TEREREREREREREQ6GDwmIiIiIiIiIiIiIh0MHhMRERERERERERGRDgaPiYiIiIiIiIiIiEgHg8dEREREREREREREpIPBYyIiIiIiIiIiIiLSweAxEREREREREREREelg8JiIiIiIiIiIiIiIdDB4TEREREREREREREQ6GDwmIiIiIiIiIiIiIh0MHhMRERERERERERGRDgaPiYiIiIiIiIiIiEgHg8dEREREREREREREpIPBYyIiIiIiIiIiIiLSweAxEREREREREREREelg8JiIiIiIiIiIiIiIdDB4TEREREREREREREQ6GDwmIiIiIiIiIiIiIh0MHhMRERERERERERGRDgaPiYiIiIiIiIiIiEgHg8dEREREREREREREpIPBYyIiIiIiIiIiIiLSweAxEREREREREREREelg8JiIiIiIiIiIiIiIdDB4TEREREREREREREQ6GDwmIiIiIiIiIiIiIh0MHhMRERERERERERGRDkVBd4CIiHJn5syZOHjwIACgWLFi2LNnj8GyjRo1En4eMGAABg0alNfde+8NGzYMt27dAgDUqVMHy5YtK+AeEREREREREZkHRx4TERERERERERERkQ6OPCYionyzZcsWxMfHAwAqVaqEli1bFnCPiIiIiIiIiMgQBo+JiCjfbNmyBa9fvwYAdOnShcFjIiIiIiIiokKMwWMiog/I5cuXC7oLRERERERERPSOYM5jIiIiIiIi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0gc/+MEFT/TT1q9fr/vvv1/79+/PwMqA9ApSTd5777365je/mfRx27dv12c+8xlddtllaVgVkFlBqsnFGBoa0m233aZz584l3B+U9QHLFeSaHBsb05//+Z/rO9/5zqKP2bVr15LOtUBQBLEmX3jhBf3BH/yBTp8+vehjNm7cqM9+9rPas2dPGlcGpNerXvUqRSKRpI97zWteo09+8pNpbdi2tLTowx/+sC5cuHDJr62vr9fnP/95XX311Wlbz0pg8hir1tGjRxf8NGoldHV16QMf+EDCG9+ysjK97GUv06ZNm3Tu3Dn96le/iv17b2+vfv/3f1//+q//qquuumqllg2kRJBqsre3d85969ev1w033KCqqiqVlpaqr69Pjz76qE6dOhX7mqeeekq/+7u/q69//euqq6vL5JKBlAtSTS7Gpz/96TmNYyCbBLUmh4eHdccdd+ixxx5LuP/yyy/X7t27tXHjRjmOo3PnzunkyZN67rnnxPwRskHQarKnp0fvete7dPbs2YT7d+zYoeuuu07l5eUaGRnRqVOndOTIkdjVAWfPntX73/9+PfDAA9q+fftKLB1Ytvkasw0NDdq5c6cqKytVUFCg7u5uHTp0SN3d3bGv+dGPfqRz587pS1/6kgoKClK+rqefflp33313wrTxxo0bdfPNN6uyslJdXV166KGHNDg4KElqa2vT+9//fn37299WVVVVytezUmgeI6sUFRVpx44dOnny5LyXEqST67q65557Et743n777frkJz+p4uLi2H2Tk5O6//779c///M+SpNHRUd1999168MEHszojB7lpJWtSkkpKSvTa175Wb37zm7Vt27Z5v+bw4cP62Mc+pq6uLkneJUkf+tCH9K1vfUuGYWRyuUDarXRNXszRo0djE4wbNmygiYycsdI16bqu/uiP/iihcbxr1y7de++9uvbaa+c9pru7W//2b/+mJ598MlPLBDJmJWvyL//yLxMax5s2bdL9998/70Rxe3u7/viP/zhWu6Ojo/rTP/1Tfec73+H1K1a1mpoavfnNb9brX//6efelsW1b3/zmN/WXf/mXmpiYkCQdOXJEn/vc5/TRj340pWuZmJiY0zh+73vfqw996EMJvZvh4WHde++9evDBByV5H+j80R/9kb7+9a+ndD0rieYxVq2CggLt3LlT1157ra699lpdc8012rJli0zT1Mtf/vKMn+x/+tOf6sSJE7HbjY2N+uu//us5J+/8/Hz9t//23zQ4OKjvfve7kryT/7/+67/qne98Z0bXDKRSkGqyuLhYd911l+64445LXsK0b98+fe1rX9Ob3/xmnT9/XpL0xBNP6Mc//rFuu+22TCwXSIsg1eRCJicnde+998YmGf/7f//v+tCHPrTCqwJSL4g1+a1vfUu//vWvY7df/epX67Of/eyCm3Bt2rRJd9xxRyaWB6RVkGry3Llz+slPfhK7nZeXpy996Uu64oor5v36uro6felLX9LrXvc6tbe3S5JOnjypEydOaPfu3ZlYMpBS1dXVete73qXXve51C56DLMvSW9/6VlVXV+vOO++MRc585Stf0bvf/e6UTvs+8MADCfnnb3zjG+dtUK9du1b333+/+vr6dOjQIUnSo48+qp/97Gd6xStekbL1rCSax1i1PvvZz670EhJ84QtfiP3dNE3dd999C37q+7GPfUw//elPNTw8LEn6x3/8R73tbW9TKERZYnUKUk3+5V/+ZVK1VF1drT/6oz/Sn/7pn8bu+8lPfkLzGKtakGpyIX//93+vF198UZL0kpe8RL/5m79J8xhZKWg1eeHCBf31X/917PYVV1yh+++/f8E37UA2CVJNHj58OCF3+Td+4zcu2jietnbtWr3nPe/RJz/5ydh9hw4donmMVem73/1uUu/fbrnlFr3mNa/RD3/4Q0nS1NSUfvazn+ltb3tbStYzNTWl//2//3fsdklJyYKTzaZp6hOf+IRuvfXWWC3//d//fdY0j82VXgCQDSKRiJ5++unY7QMHDigcDi94TFlZmV7zmtfEbp87d07Hjh1L2xqBXLKUD2FuvfVWmebMafHxxx9P5ZIAzOOZZ57Rl7/8ZUlSYWGh/uzP/myFVwTkjn/913/VwMBA7PbHPvYx5eXlreCKgNzV09OTcHvXrl2LOu66665LuD07LxlYLZby/i2+nyJ5V4+mypEjRxJymG+//XaVlZUteEw4HFZjY2Ps9smTJ2NXBqx2NI+BFPjZz36WcPvVr371oo6bPdU4+3EAZE5JSYnWrVsXuz3fpnsAUsdxHN17772ampqSJN19991sVAlkiOu6sfg0SaqtrdWBAwdWcEVAboufOpakNWvWLOq4wsLChNvkHSOX1NfXJ9yejiBMhZ///OcJtxfb47n11lsTbmdLj4fmMZACsyeGZ38CfDHXXnttwqWBTB4DKys+244IGSC9vvKVr8T2Crjiiiv0nve8Z4VXBOSO48ePJ0xDvepVr1rB1QCora1NuN3Z2bmo4+LzWKW5zTQgm42MjCTcTuX7t/jejGVZ2rlz56KOm90LypYeD81jIAVOnz4d+3thYaEuv/zyRR23du3ahBP8iy++GNswCEBmtbW1JTSP59vdF0BqdHZ26nOf+5wkb0rqvvvu43J5IIPiN3mWpB07dqzQSgBI3gbO8efBH//4x7Jt+5LHPfjgg7G/G4ahW265JS3rA4LomWeeSbidqvdvjuOotbU1djscDqu4uHhRx27ZsiXhioD4XtFqRvMYWKapqSl1dHTEbm/atCmpy4Wqq6tjfx8bG1v0p8wAUusHP/hBwu19+/at0EqA7HfffffFPqx505vepD179qzwioDcMjsXcuvWrZK816L/7//9P73vfe/Ty1/+cu3evVsHDhzQm970Jn3qU5/Sk08+uRLLBbLeunXr9Ja3vCV2u7W1NWFDy/n8+7//u773ve/Fbt9+++267LLL0rVEIHDS9f7tzJkzGh8fj92O79lcimEYCU3s9vZ2RaPRlKxrJXFNLrBMvb29Cb8Mkv20q6qqKuF2d3e3ampqUrI2AIvT39+vr3zlKwn3zc4kB5AaP/zhD/XLX/5Skvdm+SMf+cgKrwjIPbMnoSorK/XII4/oox/96JzNfcbGxnTu3Dk98cQT+vKXv6xXv/rV+sQnPqGKiopMLhnIeh/+8If1+OOPxz7c+T//5//o1KlTete73qXdu3errKxMo6OjOnXqlL797W/r//2//xe7anXHjh1sOouccuTIER05ciR2u6SkJGXZ/bM3sJzds7mUqqqq2OTy1NSUent7k36MoKF5DCzT7JydxV7OcLGvj79sHkBm/I//8T/U398fu71v3z4mIYE06Ovr01/8xV/Ebn/sYx9TeXn5yi0IyFEDAwMJt5988kn9wR/8QWwDy4X85Cc/0alTp/RP//RPDDwAKVRcXKx/+Zd/0V/91V/pO9/5jmzbVktLi1paWi56TH5+vt761rfqQx/60KI32QNWu9HRUd17770J973nPe9JuhdzManu8cx+vNWI2ApgmWY3ewsKCpI6fvbX0zwGMuvb3/62fvjDH8ZuFxQU6OMf//gKrgjIXn/1V3+lCxcuSJL279+v3/qt31rhFQG5aWhoKOH2H//xH8cax7fddpu+8pWv6OjRozpx4oT+7d/+TXfffXdCYyoSieiee+7R5ORkRtcNZLvi4mL9+Z//ub72ta/F4mQuprKyUn/xF3+h//bf/huNY+SU++67LyGT+PLLL9cdd9yRsscfGxtLuE2Ph+YxsGwTExMJt/Pz85M6fvbXx2frAEivxx57TJ/4xCcS7vvoRz+qLVu2rNCKgOzV0tISy2bMz8/n8lpgBc1+Izs4OCjJe0P+uc99Tnv37lVpaakKCwt1xRVX6A//8A/1jW98Q+vWrYsd88QTT+hrX/taRtcNZLuhoSF9/OMf1zve8Q49//zzC37t+fPn9ZGPfES33367jh07lqEVAivrn/7pn/T9738/djs/P1+f/vSnk27wLmR2T4YeD81jYNlm/2JYzOV+8WZPbKTylx6Ai3vhhRd01113JdTgG97wBr397W9fwVUB2WlsbCxhov/3fu/32NQHWEHzvRF+wxveoLe+9a0XPeaqq67Sn//5nyfc98///M9yHCfl6wNyUWdnp17/+tfrG9/4Ruw95S233KIvfOELam5u1pNPPqkjR47oq1/9qt761rcqLy9PkvT888/rne98px588MGVXD6Qdg8++KA+9alPJdz3yU9+Utdcc01Kn2d2T4YeD81jYNlm59kk+6nS7MnloqKiZa8JwMK6u7v1vve9T319fbH7Xvayl815UwwgNf72b/82tgnXZZddpg984AMrvCIgt81+vWkYhu66665LHvfKV75SV199dex2V1eXnn766ZSvD8g1k5OTuvPOOxM2rPzEJz6hf/zHf9TLX/5yVVZWKi8vT2VlZbrxxht133336YEHHlBJSYkkybZt/cmf/ImeffbZlfoWgLRqaWnRn/zJnyR8YPnhD39Yr3/961P+XLPPkfR4aB4Dyzb7F0GyeTazw9Oz4RcLEGQXLlzQe97zHnV2dsbuu/HGG/U3f/M3CoXYRxZItZMnT+pf/uVfYrfvu+++pC//A5Bas4cftmzZovr6+kUd+7KXvSzh9mOPPZaydQG56pvf/KaeeeaZ2O23ve1t+p3f+Z0Fj9m1a5c++clPxm5PTU3p/vvvT9sagZVy4sQJ3X333QkTwO973/vSNoww+xy53B5PqjbyW0k0j4FlWr9+fULDqaurK6nje3p6Em5v2rQpJesCMNfw8LDuuOMOvfDCC7H7duzYoS9+8YtZcTkREESf/vSnZdu2JOl1r3ud9u3bt8IrAjD79eYVV1yx6GOvvPLKhNuzX8sCSN53v/vdhNuLbYrddtttCR/8/PKXv0y4sg5Y7Z599ll94AMfSGjgvvnNb9af/MmfpO05q6qqEm53d3cndXz8eTEUCmn9+vUpWddKYsQKWKb8/HzV1tbGdvvs7u6W67oyDGNRx8dPPxYWFqqmpiYdywRy3vj4uO68806dPHkydt/ll1+uL33pS1r7/7d3t7FVlmccwK9TKRUGVBCY7ECYLxlMUcPCWHxZSgpLNrNFYtwHdGijoBOzkoYuUckGy1xAOlgICYuSOdQYsyka7OYYZGxEZVEwZkxFkpFYQiMwhZYXmS3t2QezZ5w+xbbal0PP75c06XWf5z69vtw5Pf/znPseMWIAO4PB7ew3sS+++GLU19f3aH5jY2NceeWVSZ3NZmPbtm291h8Uo8svvzxef/31pB41alS355aXl+fVzc3NvdYXFKOWlpZ49913k3rSpEkxYcKEbs3NZDIxY8aMOHDgQERE5HK5ePvtt+PGG2/sk16hPx04cCDuuuuuaGpqSsa+853v5N1x3xey2WyUlZUl20+cndl0JZfL5YXNkyZNSvYnP5+58xh6wWWXXZb8/p///CfvrsZPc/LkyeSFPuKTfSC7GzoD3dfa2hrV1dWxa9euZCybzcbGjRvzTo4H+lZ7e3u0tbV1+dNRV48DPdPxTuOeHAbU8SAg29DA53Ps2LG817axY8f2aP64ceNSzwfnu8OHD0dVVVX8+9//TsYqKiqirq4uSkr6NsosKSmJL3/5y0nd0NDQ7a0r9u/fn7dH8uWXX97b7Q0I4TH0ghkzZuTV3d37bc+ePXn/KHR8HuDza29vjx//+MexY8eOZGz8+PHxxBNPpL6SBADF4Otf/3pe3ZOtJzp+fdeHsPD5dNw6reNhW105ffp0Xj1s2LDP3RMMpKNHj0ZVVVU0NjYmYzNnzox169b12128Z2czbW1t8Y9//KNb8zpmQR1fb89Xtq2AXlBZWRmrVq1K6i1btsStt97a5bwtW7bk1bNnz+713qDYLVu2LP70pz8l9ejRo+O3v/1tTJo0aQC7guKxefPmHs+ZMmVK8ns2m43t27f3ZktQ9L7yla/E5MmTo6GhISIi/vnPf0Zra2u33pR3fGN89rYyQM+Vl5fHkCFD4syZMxER8d5778WZM2e6fZDz/v378+rBsL8qxauzM2quvfbafj+jprKyMp5++umk3rJlS1x33XVdzhusGY87j6EXXHrppXlvdF999dXkn/FzaW5ujpdeeimpx44dO2g+lYJCsWrVqvj973+f1CNHjozHH388rrjiigHsCgAG3k033ZT8fvz48di6dWuXc5qamvL2HC8tLfXNOficMplMXH311Un90Ucfxd/+9rduzT18+HDetmxlZWU+0OG81dkZNVOnTo0NGzbEF77whX7tZebMmTF69Oik/uMf/xjHjx//1DkNDQ2xc+fOpL7qqqsGzQ1LwmM4hylTpuT9dOW+++5Lfm9vb4/ly5dHLpc75/UrV66MEydOJPXChQu7/ekyFKOerslHH300fvOb3yT18OHD47HHHvMPNfSSnq5JoG/1dE1WVVXFyJEjk7quri7vUKLOPPzww3n7Pt5yyy0OnYVz6MmarKyszKvr6uq6DKpyuVwsX748bx/y66+/vl/vzoTecubMmVi8eHHehyGXXnppPP7446mDWj+LgwcP5q3Hjmuuo6FDh8aCBQuS+sSJE7Fy5cpzXt/e3h7Lli2L9vb2ZGzRokWfu+9CITyGXvLtb3877xPjnTt3Rm1tbZw6dSrvupaWllixYkU8//zzyVg2m4158+b1W68w2P3ud7+LNWvWJHVZWVmsX78+vva1rw1gVwBQOC666KK8mx/ef//9uOOOO1JfgY/45GvEDz30UNTX1ydjo0aNypsPfHa33XZbXHTRRUn93nvvxe233x579+7t9PrDhw/HokWLUts63X///X3ZJvSJXC4XDzzwQN4d9xMnTownnnhiQLdh+cEPfhATJkxI6k2bNsUjjzySOjj25MmTsWTJkvj73/+ejE2fPj3mzJnTb732tUzu026NhALW2NgY3/rWtzp9rONJ7BdccEGn123cuDFmzpzZ6WMdPx3et29ft3r6/ve/Hx9++GEyVl5eHpWVlfHFL34xPvjgg9ixY0feiaHDhw+PZ555JqZOndrl80MhK6Q1WVlZmXfAQiaT+Uyn8m7bti2y2WyP50EhKKQ12VP2PGYwKsQ1mcvloqamJu9sgCFDhsTMmTNj6tSpMXTo0Dh48GC8/PLL0dzcnNff+vXrY9asWV3+DShUhbYmd+zYEYsW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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "image/png": { + "height": 711, + "width": 711 + } + }, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(figsize=(7, 7))\n", + "posterior = az.extract(idata, num_samples=20)\n", + "x_plot = xr.DataArray(np.linspace(1, 2, 100))\n", + "y_plot = posterior[\"b\"] * x_plot + posterior[\"a\"]\n", + "Line2 = ax.plot(x_plot, y_plot.transpose(), color=\"C1\")\n", + "Line1 = ax.plot(x_pred, pred_mean, \"x\")\n", + "ax.set(title=\"Posterior predictive regression lines\", xlabel=\"x\", ylabel=\"y\")\n", + "ax.legend(\n", + " handles=[Line1[0], Line2[0]], labels=[\"predicted average\", \"inferred regression line\"], loc=0\n", + ");" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "07fb64ed-f707-4e19-9e27-b0c2700c04f6", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Last updated: Wed Aug 23 2023\n", + "\n", + "Python implementation: CPython\n", + "Python version : 3.10.12\n", + "IPython version : 8.14.0\n", + "\n", + "pymc_experimental: 0.0.11\n", + "\n", + "xarray : 2023.7.0\n", + "arviz : 0.16.1\n", + "pandas : 2.0.3\n", + "numpy : 1.25.1\n", + "matplotlib: 3.7.2\n", + "pymc : 5.6.1\n", + "\n", + "Watermark: 2.4.3\n", + "\n" + ] + } + ], + "source": [ + "%load_ext watermark\n", + "%watermark -n -u -v -iv -w -p pymc_experimental" + ] + }, + { + "cell_type": "markdown", + "id": "4917782b", + "metadata": {}, + "source": [ + "## Authors\n", + "* Authored by Shashank Kirtania and Thomas Wiecki in 2023.\n", + "* Modified and updated by Michał Raczycki in 08/2023" + ] + }, + { + "cell_type": "markdown", + "id": "dab6cda6", + "metadata": {}, + "source": [ + ":::{include} ../page_footer.md\n", + ":::" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "pymc-marketing", + "language": "python", + "name": "pymc-marketing" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + }, + "toc-autonumbering": false, + "toc-showmarkdowntxt": true + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/howto/model_builder.myst.md b/examples/howto/model_builder.myst.md new file mode 100644 index 000000000..0747511aa --- /dev/null +++ b/examples/howto/model_builder.myst.md @@ -0,0 +1,350 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: pymc-marketing + language: python + name: pymc-marketing +--- + +# Using ModelBuilder class for deploying PyMC models +:::{post} Feb 22, 2023 +:tags: deployment +:category: Advanced +:author: Shashank Kirtania, Thomas Wiecki, Michał Raczycki +::: + ++++ + +## Motivation + ++++ + +Many users face difficulty in deploying their PyMC models to production because deploying/saving/loading a user-created model is not well standardized. One of the reasons behind this is there is no direct way to save or load a model in PyMC like scikit-learn or TensorFlow. The new `ModelBuilder` class is aimed to improve this workflow by providing a scikit-learn inspired API to wrap your PyMC models. + +The new `ModelBuilder` class allows users to use methods to `fit()`, `predict()`, `save()`, `load()`. Users can create any model they want, inherit the `ModelBuilder` class, and use predefined methods. + ++++ + +Let's go through the full workflow, starting with a simple linear regression PyMC model as it's usually written. Of course, this model is just a place-holder for your own model. + +```{code-cell} ipython3 +from typing import Dict, List, Optional, Tuple, Union + +import arviz as az +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import pymc as pm +import xarray as xr + +from numpy.random import RandomState + +%config InlineBackend.figure_format = 'retina' +RANDOM_SEED = 8927 + +rng = np.random.default_rng(RANDOM_SEED) +az.style.use("arviz-darkgrid") +``` + +```{code-cell} ipython3 +# Generate data +x = np.linspace(start=0, stop=1, num=100) +y = 0.3 * x + 0.5 + rng.normal(0, 1, len(x)) +``` + +## Standard syntax +Usually a PyMC model will have this form: + +```{code-cell} ipython3 +with pm.Model() as model: + # priors + a = pm.Normal("a", mu=0, sigma=1) + b = pm.Normal("b", mu=0, sigma=1) + eps = pm.HalfNormal("eps", 1.0) + + # observed data + y_model = pm.Normal("y_model", mu=a + b * x, sigma=eps, observed=y) + + # Fitting + idata = pm.sample() + idata.extend(pm.sample_prior_predictive()) + + # posterior predict + idata.extend(pm.sample_posterior_predictive(idata)) +``` + +How would we deploy this model? Save the fitted model, load it on an instance, and predict? Not so simple. + +`ModelBuilder` is built for this purpose. It is currently part of the `pymc-experimental` package which we can pip install with `pip install pymc-experimental`. As the name implies, this feature is still experimental and subject to change. + ++++ + +## Model builder class + ++++ + +Let's import the `ModelBuilder` class. + +```{code-cell} ipython3 +from pymc_experimental.model_builder import ModelBuilder +``` + +To define our desired model we inherit from the `ModelBuilder` class. There are a couple of methods we need to define. + +```{code-cell} ipython3 +:tags: [] + +class LinearModel(ModelBuilder): + # Give the model a name + _model_type = "LinearModel" + + # And a version + version = "0.1" + + def build_model(self, X: pd.DataFrame, y: Union[pd.Series, np.ndarray], **kwargs): + """ + build_model creates the PyMC model + + Parameters: + model_config: dictionary + it is a dictionary with all the parameters that we need in our model example: a_loc, a_scale, b_loc + data: Dict[str, Union[np.ndarray, pd.DataFrame, pd.Series]] + Data we want our model fit on. + """ + # Check the type of X and y and adjust access accordingly + X_values = X["input"].values + y_values = y.values if isinstance(y, pd.Series) else y + self._generate_and_preprocess_model_data(X_values, y_values) + + with pm.Model(coords=self.model_coords) as self.model: + + # Create mutable data containers + x_data = pm.MutableData("x_data", X_values) + y_data = pm.MutableData("y_data", y_values) + + # prior parameters + a_mu_prior = self.model_config.get("a_mu_prior", 0.0) + a_sigma_prior = self.model_config.get("a_sigma_prior", 1.0) + b_mu_prior = self.model_config.get("b_mu_prior", 0.0) + b_sigma_prior = self.model_config.get("b_sigma_prior", 1.0) + eps_prior = self.model_config.get("eps_prior", 1.0) + + # priors + a = pm.Normal("a", mu=a_mu_prior, sigma=a_sigma_prior) + b = pm.Normal("b", mu=b_mu_prior, sigma=b_sigma_prior) + eps = pm.HalfNormal("eps", eps_prior) + + obs = pm.Normal("y", mu=a + b * x_data, sigma=eps, shape=x_data.shape, observed=y_data) + + def _data_setter( + self, X: Union[pd.DataFrame, np.ndarray], y: Union[pd.Series, np.ndarray] = None + ): + if isinstance(X, pd.DataFrame): + x_values = X["input"].values + else: + # Assuming "input" is the first column + x_values = X[:, 0] + + with self.model: + pm.set_data({"x_data": x_values}) + if y is not None: + pm.set_data({"y_data": y.values if isinstance(y, pd.Series) else y}) + + @property + def default_model_config(self) -> Dict: + """ + default_model_config is a property that returns a dictionary with all the prior values we want to build the model with. + It supports more complex data structures like lists, dictionaries, etc. + It will be passed to the class instance on initialization, in case the user doesn't provide any model_config of their own. + """ + model_config: Dict = { + "a_mu_prior": 0.0, + "a_sigma_prior": 1.0, + "b_mu_prior": 0.0, + "b_sigma_prior": 1.0, + "eps_prior": 1.0, + } + return model_config + + @property + def default_sampler_config(self) -> Dict: + """ + default_sampler_config is a property that returns a dictionary with all most important sampler parameters. + It will be used in case the user doesn't provide any sampler_config of their own. + """ + sampler_config: Dict = { + "draws": 1_000, + "tune": 1_000, + "chains": 3, + "target_accept": 0.95, + } + return sampler_config + + @property + def output_var(self): + return "y" + + @property + def _serializable_model_config(self) -> Dict[str, Union[int, float, Dict]]: + """ + _serializable_model_config is a property that returns a dictionary with all the model parameters that we want to save. + as some of the data structures are not json serializable, we need to convert them to json serializable objects. + Some models will need them, others can just define them to return the model_config. + """ + return self.model_config + + def _save_input_params(self, idata) -> None: + """ + Saves any additional model parameters (other than the dataset) to the idata object. + + These parameters are stored within `idata.attrs` using keys that correspond to the parameter names. + If you don't need to store any extra parameters, you can leave this method unimplemented. + + Example: + For saving customer IDs provided as an 'customer_ids' input to the model: + self.customer_ids = customer_ids.values #this line is done outside of the function, preferably at the initialization of the model object. + idata.attrs["customer_ids"] = json.dumps(self.customer_ids.tolist()) # Convert numpy array to a JSON-serializable list. + """ + pass + + pass + + def _generate_and_preprocess_model_data( + self, X: Union[pd.DataFrame, pd.Series], y: Union[pd.Series, np.ndarray] + ) -> None: + """ + Depending on the model, we might need to preprocess the data before fitting the model. + all required preprocessing and conditional assignments should be defined here. + """ + self.model_coords = None # in our case we're not using coords, but if we were, we would define them here, or later on in the function, if extracting them from the data. + # as we don't do any data preprocessing, we just assign the data givenin by the user. Note that it's very basic model, + # and usually we would need to do some preprocessing, or generate the coords from the data. + self.X = X + self.y = y +``` + +Now we can create the `LinearModel` object. First step we need to take care of, is data generation: + +```{code-cell} ipython3 +X = pd.DataFrame(data=np.linspace(start=0, stop=1, num=100), columns=["input"]) +y = 0.3 * x + 0.5 +y = y + np.random.normal(0, 1, len(x)) + +model = LinearModel() +``` + +After making the object of class `LinearModel` we can fit the model using the `.fit()` method. + ++++ + +## Fitting to data + ++++ + +The `fit()` method takes one argument `data` on which we need to fit the model. The meta-data is saved in the `InferenceData` object where also the trace is stored. These are the fields that are stored: + +* `id` : This is a unique id given to a model based on model_config, sample_conifg, version, and model_type. Users can use it to check if the model matches to another model they have defined. +* `model_type` : Model type tells us what kind of model it is. This in this case it outputs **Linear Model** +* `version` : In case you want to improve on models, you can keep track of model by their version. As the version changes the unique hash in the `id` also changes. +* `sample_conifg` : It stores values of the sampler configuration set by user for this particular model. +* `model_config` : It stores values of the model configuration set by user for this particular model. + +```{code-cell} ipython3 +idata = model.fit(X, y) +``` + +## Saving model to file + ++++ + +After fitting the model, we can probably save it to share the model as a file so one can use it again. +To `save()` or `load()`, we can quickly call methods for respective tasks with the following syntax. + +```{code-cell} ipython3 +:tags: [] + +fname = "linear_model_v1.nc" +model.save(fname) +``` + +This saves a file at the given path, and the name
+A NetCDF `.nc` file that stores the inference data of the model. + ++++ + +## Loading a model + ++++ + +Now if we wanted to deploy this model, or just have other people use it to predict data, they need two things: +1. the `LinearModel` class (probably in a .py file) +2. the linear_model_v1.nc file + +With these, you can easily load a fitted model in a different environment (e.g. production): + +```{code-cell} ipython3 +model_2 = LinearModel.load(fname) +``` + +Note that `load()` is a class-method, we do not need to instantiate the `LinearModel` object. + +```{code-cell} ipython3 +type(model_2) +``` + +## Prediction + ++++ + +Next we might want to predict on new data. The `predict()` method allows users to do posterior prediction with the fitted model on new data. + +Our first task is to create data on which we need to predict. + +```{code-cell} ipython3 +x_pred = np.random.uniform(low=1, high=2, size=10) +prediction_data = pd.DataFrame({"input": x_pred}) +type(prediction_data["input"].values) +``` + +`ModelBuilder` provides two methods for prediction: +1. point estimates (the mean) with `predict()` +2. full posterior prediction (samples) with `predict_posterior()` + +```{code-cell} ipython3 +pred_mean = model_2.predict(prediction_data) +# samples +pred_samples = model_2.predict_posterior(prediction_data) +``` + +After using the `predict()`, we can plot our data and see graphically how satisfactory our `LinearModel` is. + +```{code-cell} ipython3 +fig, ax = plt.subplots(figsize=(7, 7)) +posterior = az.extract(idata, num_samples=20) +x_plot = xr.DataArray(np.linspace(1, 2, 100)) +y_plot = posterior["b"] * x_plot + posterior["a"] +Line2 = ax.plot(x_plot, y_plot.transpose(), color="C1") +Line1 = ax.plot(x_pred, pred_mean, "x") +ax.set(title="Posterior predictive regression lines", xlabel="x", ylabel="y") +ax.legend( + handles=[Line1[0], Line2[0]], labels=["predicted average", "inferred regression line"], loc=0 +); +``` + +```{code-cell} ipython3 +%load_ext watermark +%watermark -n -u -v -iv -w -p pymc_experimental +``` + +## Authors +* Authored by Shashank Kirtania and Thomas Wiecki in 2023. +* Modified and updated by Michał Raczycki in 08/2023 + ++++ + +:::{include} ../page_footer.md +::: From 92b2a5f68b3fc3f6e48fca6ff7cb1b09a7ca4433 Mon Sep 17 00:00:00 2001 From: Michal Raczycki Date: Fri, 1 Sep 2023 09:48:40 +0200 Subject: [PATCH 4/5] removing the mb folder, mb intro in examples/howto --- ...delBuilder in PyMC-Marketing context.ipynb | 17374 ---------------- 1 file changed, 17374 deletions(-) delete mode 100644 examples/model_builder/ModelBuilder in PyMC-Marketing context.ipynb diff --git a/examples/model_builder/ModelBuilder in PyMC-Marketing context.ipynb b/examples/model_builder/ModelBuilder in PyMC-Marketing context.ipynb deleted file mode 100644 index 11b7e71f8..000000000 --- a/examples/model_builder/ModelBuilder in PyMC-Marketing context.ipynb +++ /dev/null @@ -1,17374 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "1d74584c", - "metadata": {}, - "source": [ - "# Deploying MMMs and CLVs in Production: Saving and Loading Models" - ] - }, - { - "cell_type": "markdown", - "id": "3222ef04", - "metadata": {}, - "source": [ - "In this article, we'll tackle the historically challenging process of deploying Bayesian models built with PyMC. Introducing a revolutionary deployment module, we bring unprecedented simplicity and efficiency to the deployment of PyMC models. As we prioritize user-friendly solutions, let's delve into how this innovation can significantly elevate your data science projects." - ] - }, - { - "cell_type": "markdown", - "id": "ddb28436", - "metadata": {}, - "source": [ - "\n", - "Recent release of PyMC-Marketing by [Labs](https://www.pymc-labs.io) proves to be a big hit [(PyMC-Marketing)](https://www.pymc-labs.io/blog-posts/pymc-marketing-a-bayesian-approach-to-marketing-data-science/). In the feedback one could see an ongoing theme, many of you have been requesting easy and robust way of deploying models to production. It’s been a long-standing problem with PyMC ( and most other PPLs). The reason for that is that there’s no obvious way, and doesn’t matter which approach you try it proves to be tricky. That is why we’re happy to announce the release of `ModelBuilder`, brand new PyMC-experimental module that addresses this need, and improves on the deployment process significantly.\n", - "\n", - "The ModelBuilder module is a new feature of PyMC based models. It provides 2 easy-to-use methods: save() and load() that can be used after the model has been fit.save() allow easy preservation of the model to .netcdf format, and load() gives one-line replication of the original model. Users can control the prior settings with model_config, and customize the sampling process using sampler_config. Default values of those are working just fine, so first time give it a try without changing, and provide your own model_config and model_sampler if afterwards you want to try to customize it more for your use case!\n" - ] - }, - { - "cell_type": "markdown", - "id": "a808e36a", - "metadata": {}, - "source": [ - "For this notebook I'll use the example model used in [MMM Example Notebook](https://www.pymc-marketing.io/en/stable/notebooks/mmm/mmm_example.html), but ommit the details of data generation and plotting functionalities, since they're out of scope for this introduction, I highly recommend to see that part as well, but for now let's focus on today's topic: Groundbreaking deployment improvements in PyMC-Marketing!" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "id": "1050a937", - "metadata": {}, - "outputs": [], - "source": [ - "import arviz as az\n", - "import numpy as np\n", - "import pandas as pd\n", - "\n", - "from pymc_marketing.mmm import DelayedSaturatedMMM" - ] - }, - { - "cell_type": "markdown", - "id": "f37d808e", - "metadata": {}, - "source": [ - "Let's load the dataset:" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "id": "b7b1193f", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
date_weekyx1x2event_1event_2dayofyeartsin_order_1cos_order_1sin_order_2cos_order_2
02018-04-023984.6622370.3185800.0000000.00.09200.999930-0.011826-0.023651-0.999720
12018-04-093762.8717940.1123880.0000000.00.09910.991269-0.131859-0.261414-0.965227
22018-04-164466.9673880.2924000.0000000.00.010620.968251-0.249981-0.484089-0.875019
32018-04-233864.2193730.0713990.0000000.00.011330.931210-0.364483-0.678820-0.734304
42018-04-304441.6252780.3867450.0000000.00.012040.880683-0.473706-0.834370-0.551205
.......................................
1742021-08-023553.5461480.0330240.0000000.00.0214174-0.513901-0.8578490.8816990.471812
1752021-08-095565.5096820.1656150.8633490.00.0221175-0.613230-0.7899050.9687860.247898
1762021-08-164137.6514850.1718820.0000000.00.0228176-0.703677-0.7105200.9999530.009676
1772021-08-234479.0413510.2802570.0000000.00.0235177-0.783934-0.6208440.973402-0.229104
1782021-08-304675.9734390.4388570.0000000.00.0242178-0.852837-0.5221780.890665-0.454661
\n", - "

179 rows × 12 columns

\n", - "
" - ], - "text/plain": [ - " date_week y x1 x2 event_1 event_2 dayofyear \\\n", - "0 2018-04-02 3984.662237 0.318580 0.000000 0.0 0.0 92 \n", - "1 2018-04-09 3762.871794 0.112388 0.000000 0.0 0.0 99 \n", - "2 2018-04-16 4466.967388 0.292400 0.000000 0.0 0.0 106 \n", - "3 2018-04-23 3864.219373 0.071399 0.000000 0.0 0.0 113 \n", - "4 2018-04-30 4441.625278 0.386745 0.000000 0.0 0.0 120 \n", - ".. ... ... ... ... ... ... ... \n", - "174 2021-08-02 3553.546148 0.033024 0.000000 0.0 0.0 214 \n", - "175 2021-08-09 5565.509682 0.165615 0.863349 0.0 0.0 221 \n", - "176 2021-08-16 4137.651485 0.171882 0.000000 0.0 0.0 228 \n", - "177 2021-08-23 4479.041351 0.280257 0.000000 0.0 0.0 235 \n", - "178 2021-08-30 4675.973439 0.438857 0.000000 0.0 0.0 242 \n", - "\n", - " t sin_order_1 cos_order_1 sin_order_2 cos_order_2 \n", - "0 0 0.999930 -0.011826 -0.023651 -0.999720 \n", - "1 1 0.991269 -0.131859 -0.261414 -0.965227 \n", - "2 2 0.968251 -0.249981 -0.484089 -0.875019 \n", - "3 3 0.931210 -0.364483 -0.678820 -0.734304 \n", - "4 4 0.880683 -0.473706 -0.834370 -0.551205 \n", - ".. ... ... ... ... ... \n", - "174 174 -0.513901 -0.857849 0.881699 0.471812 \n", - "175 175 -0.613230 -0.789905 0.968786 0.247898 \n", - "176 176 -0.703677 -0.710520 0.999953 0.009676 \n", - "177 177 -0.783934 -0.620844 0.973402 -0.229104 \n", - "178 178 -0.852837 -0.522178 0.890665 -0.454661 \n", - "\n", - "[179 rows x 12 columns]" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "url = \"https://raw.githubusercontent.com/pymc-labs/pymc-marketing/main/datasets/mmm_example.csv\"\n", - "df = pd.read_csv(url)\n", - "df" - ] - }, - { - "cell_type": "markdown", - "id": "87deb70d", - "metadata": {}, - "source": [ - "But for our model we need much smaller dataset, many of the previous features were contributing to generation of others, now as our target variable is computed we can filter out not needed columns:" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "id": "52b6d127", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
date_weekyx1x2event_1event_2dayofyeart
02018-04-023984.6622370.3185800.00.00.0920
12018-04-093762.8717940.1123880.00.00.0991
22018-04-164466.9673880.2924000.00.00.01062
32018-04-233864.2193730.0713990.00.00.01133
42018-04-304441.6252780.3867450.00.00.01204
\n", - "
" - ], - "text/plain": [ - " date_week y x1 x2 event_1 event_2 dayofyear t\n", - "0 2018-04-02 3984.662237 0.318580 0.0 0.0 0.0 92 0\n", - "1 2018-04-09 3762.871794 0.112388 0.0 0.0 0.0 99 1\n", - "2 2018-04-16 4466.967388 0.292400 0.0 0.0 0.0 106 2\n", - "3 2018-04-23 3864.219373 0.071399 0.0 0.0 0.0 113 3\n", - "4 2018-04-30 4441.625278 0.386745 0.0 0.0 0.0 120 4" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "columns_to_keep = [\n", - " \"date_week\",\n", - " \"y\",\n", - " \"x1\",\n", - " \"x2\",\n", - " \"event_1\",\n", - " \"event_2\",\n", - " \"dayofyear\",\n", - "]\n", - "seed: int = sum(map(ord, \"mmm\"))\n", - "rng =np.random.default_rng(seed=seed)\n", - "\n", - "data = df[columns_to_keep].copy()\n", - "\n", - "data[\"t\"] = range(df.shape[0])\n", - "data.head()" - ] - }, - { - "cell_type": "markdown", - "id": "9518a885", - "metadata": {}, - "source": [ - "## _Model Creation_\n", - "After we have our dataset ready, we could proceed straight to our model definition, but first to show the full potential of one of the new features: `model_config` we need to use some of our data to define our prior for sigma parameter for each of the channels. `model_config` is a customizable dictionary with keys corresponding to priors within the model, and values containing a dictionaries with parameters necessary to initialize them. Later on we'll learn that through the `save()` method we can preserve our priors contained inside the `model_config`, to allow complete replication of our model." - ] - }, - { - "cell_type": "markdown", - "id": "4b52b2c1", - "metadata": {}, - "source": [ - "### model_config" - ] - }, - { - "cell_type": "markdown", - "id": "41021a72", - "metadata": {}, - "source": [ - "`default_model_config` attribute of every model inheriting from `ModelBuilder` will allow you to see which priors are available for customization. To see it simply initialize a dummy model:" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "id": "284bd558", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'intercept': {'mu': 0, 'sigma': 2},\n", - " 'beta_channel': {'sigma': 2, 'dims': ('channel',)},\n", - " 'alpha': {'alpha': 1, 'beta': 3, 'dims': ('channel',)},\n", - " 'lam': {'alpha': 3, 'beta': 1, 'dims': ('channel',)},\n", - " 'sigma': {'sigma': 2},\n", - " 'gamma_control': {'mu': 0, 'sigma': 2, 'dims': ('control',)},\n", - " 'mu': {'dims': ('date',)},\n", - " 'likelihood': {'dims': ('date',)},\n", - " 'gamma_fourier': {'mu': 0, 'b': 1, 'dims': 'fourier_mode'}}" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dummy_model = DelayedSaturatedMMM(date_column = '', channel_columns= '', adstock_max_lag = 4)\n", - "dummy_model.default_model_config" - ] - }, - { - "cell_type": "markdown", - "id": "f0fd248f", - "metadata": {}, - "source": [ - "You can change only the prior parameters that you wish, no need to alter all of them, unless you'd like to!\n", - "In this case we'll just simply replace our sigma for beta_channel with our computed one:" - ] - }, - { - "cell_type": "markdown", - "id": "19f075f0-4d3d-4509-a9c6-f15efdb9293d", - "metadata": {}, - "source": [ - "First, let's compute the share of spend per channel:" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "id": "4785596a-e333-4cd0-af15-1332e97b66d5", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "x1 0.65632\n", - "x2 0.34368\n", - "dtype: float64" - ] - }, - "execution_count": 35, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "total_spend_per_channel = data[[\"x1\", \"x2\"]].sum(axis=0)\n", - "\n", - "spend_share = total_spend_per_channel / total_spend_per_channel.sum()\n", - "\n", - "spend_share" - ] - }, - { - "cell_type": "markdown", - "id": "40d17642-1e21-4adc-97f4-633eede87915", - "metadata": {}, - "source": [ - "Next, we specify the `sigma`parameter per channel:" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "id": "672b36bd-3d08-46df-85b8-d67d3ade75d7", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[2.1775326025486734, 1.140260877391939]" - ] - }, - "execution_count": 36, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# The scale necessary to make a HalfNormal distribution have unit variance\n", - "HALFNORMAL_SCALE = 1 / np.sqrt(1 - 2 / np.pi)\n", - "\n", - "n_channels = 2\n", - "\n", - "prior_sigma = HALFNORMAL_SCALE * n_channels * spend_share.to_numpy()\n", - "\n", - "prior_sigma.tolist()" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "id": "bac9f587", - "metadata": {}, - "outputs": [], - "source": [ - "custom_beta_channel_prior = {'beta_channel': {'sigma': prior_sigma, 'dims': ('channel',)}}\n", - "my_model_config = dummy_model.default_model_config| custom_beta_channel_prior" - ] - }, - { - "cell_type": "markdown", - "id": "1aa435bf", - "metadata": {}, - "source": [ - "As mentioned in the original notebook: \"_For the prior specification there is no right or wrong answer. It all depends on the data, the context and the assumptions you are willing to make. It is always recommended to do some prior predictive sampling and sensitivity analysis to check the impact of the priors on the posterior. We skip this here for the sake of simplicity. If you are not sure about specific priors, the `DelayedSaturatedMMM` class has some default priors that you can use as a starting point._\"" - ] - }, - { - "cell_type": "markdown", - "id": "f195a79e", - "metadata": {}, - "source": [ - "The second feature that we can use for model definition is `sampler_config`. Similar to `model_config`, it's a dictionary that gets saved and contains things you'd usually pass to the `fit()` kwargs. It's not mandatory to create your own `sampler_config`; if not provided, both `model_config` and `sampler_config` will default to the forms specified by PyMC Labs experts, which allows for the usage of all model functionalities. The default `sampler_config` is left empty because the default sampling parameters usually prove sufficient for a start." - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "id": "0ab8140c", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{}" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dummy_model.default_sampler_config" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "id": "bf5a50f4", - "metadata": {}, - "outputs": [], - "source": [ - "my_sampler_config = {\n", - " 'tune':1000,\n", - " 'draws':1000,\n", - " 'chains':4,\n", - " 'target_accept':0.95,\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "f3bfe090", - "metadata": {}, - "source": [ - "Let's finally assemble our model!" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "id": "c7bd6909", - "metadata": {}, - "outputs": [], - "source": [ - "mmm = DelayedSaturatedMMM(\n", - " model_config = my_model_config,\n", - " sampler_config = my_sampler_config,\n", - " date_column=\"date_week\",\n", - " channel_columns=[\"x1\", \"x2\"],\n", - " control_columns=[\n", - " \"event_1\",\n", - " \"event_2\",\n", - " \"t\",\n", - " ],\n", - " adstock_max_lag=8,\n", - " yearly_seasonality=2,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "54095b1a", - "metadata": {}, - "source": [ - "An important thing to note here is that in the new version of `DelayedSaturatedMMM`, we don't pass our dataset to the class constructor itself. This is due to a reason I've mentioned before - it supports `sklearn` transformers and validations that require a usual X, y split and typically expect the data to be passed to the `fit()` method." - ] - }, - { - "cell_type": "markdown", - "id": "dec9b1b0", - "metadata": {}, - "source": [ - "## _Model Fitting_" - ] - }, - { - "cell_type": "markdown", - "id": "d5e64562-ba78-4497-a0f8-123b4bc88b79", - "metadata": {}, - "source": [ - "Let's split the dataset:" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "id": "ff23006b-a55b-4a22-9f34-4eeaddf47486", - "metadata": {}, - "outputs": [], - "source": [ - "X = data.drop('y',axis=1)\n", - "y = data['y']" - ] - }, - { - "cell_type": "markdown", - "id": "403e3ed2", - "metadata": {}, - "source": [ - "All that's left now is to finally fit the model:\n", - "\n", - "As you can see below, you can still pass the sampler kwargs directly to `fit()` method. However, only those kwargs passed using `sampler_config` will be saved. Therefore, only these will be available after loading the model." - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "id": "0f6ab0a8", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Auto-assigning NUTS sampler...\n", - "Initializing NUTS using jitter+adapt_diag...\n", - "Multiprocess sampling (4 chains in 4 jobs)\n", - "NUTS: [intercept, beta_channel, alpha, lam, sigma, gamma_control, gamma_fourier]\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - " \n", - " 100.00% [8000/8000 00:29<00:00 Sampling 4 chains, 0 divergences]\n", - "
\n", - " " - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Sampling 4 chains for 1_000 tune and 1_000 draw iterations (4_000 + 4_000 draws total) took 30 seconds.\n", - "Sampling: [alpha, beta_channel, gamma_control, gamma_fourier, intercept, lam, likelihood, sigma]\n", - "Sampling: [likelihood]\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - " \n", - " 100.00% [4000/4000 00:00<00:00]\n", - "
\n", - " " - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "
arviz.InferenceData
\n", - "
\n", - "
    \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:                    (chain: 4, draw: 1000, control: 3,\n",
      -       "                                fourier_mode: 4, channel: 2, date: 179)\n",
      -       "Coordinates:\n",
      -       "  * chain                      (chain) int64 0 1 2 3\n",
      -       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 995 996 997 998 999\n",
      -       "  * control                    (control) <U7 'event_1' 'event_2' 't'\n",
      -       "  * fourier_mode               (fourier_mode) <U11 'sin_order_1' ... 'cos_ord...\n",
      -       "  * channel                    (channel) <U2 'x1' 'x2'\n",
      -       "  * date                       (date) <U10 '2018-04-02' ... '2021-08-30'\n",
      -       "Data variables: (12/13)\n",
      -       "    intercept                  (chain, draw) float64 0.3381 0.3361 ... 0.3479\n",
      -       "    gamma_control              (chain, draw, control) float64 0.2968 ... 0.00...\n",
      -       "    gamma_fourier              (chain, draw, fourier_mode) float64 -0.002612 ...\n",
      -       "    beta_channel               (chain, draw, channel) float64 0.3718 ... 0.2628\n",
      -       "    alpha                      (chain, draw, channel) float64 0.4162 ... 0.2007\n",
      -       "    lam                        (chain, draw, channel) float64 4.26 ... 2.758\n",
      -       "    ...                         ...\n",
      -       "    channel_adstock            (chain, draw, date, channel) float64 0.1868 .....\n",
      -       "    channel_adstock_saturated  (chain, draw, date, channel) float64 0.3781 .....\n",
      -       "    channel_contributions      (chain, draw, date, channel) float64 0.1406 .....\n",
      -       "    control_contributions      (chain, draw, date, control) float64 0.0 ... 0...\n",
      -       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 -0.0...\n",
      -       "    mu                         (chain, draw, date) float64 0.4769 ... 0.5924\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:14.027598\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1\n",
      -       "    sampling_time:              29.821417093276978\n",
      -       "    tuning_steps:               1000

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:     (chain: 4, draw: 1000, date: 179)\n",
      -       "Coordinates:\n",
      -       "  * chain       (chain) int64 0 1 2 3\n",
      -       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999\n",
      -       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "Data variables:\n",
      -       "    likelihood  (chain, draw, date) float64 0.5039 0.439 ... 0.5873 0.6072\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:15.416164\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:                (chain: 4, draw: 1000)\n",
      -       "Coordinates:\n",
      -       "  * chain                  (chain) int64 0 1 2 3\n",
      -       "  * draw                   (draw) int64 0 1 2 3 4 5 ... 994 995 996 997 998 999\n",
      -       "Data variables: (12/17)\n",
      -       "    process_time_diff      (chain, draw) float64 0.008982 0.009454 ... 0.009203\n",
      -       "    step_size_bar          (chain, draw) float64 0.05522 0.05522 ... 0.06921\n",
      -       "    step_size              (chain, draw) float64 0.05862 0.05862 ... 0.07543\n",
      -       "    acceptance_rate        (chain, draw) float64 0.9987 0.9934 ... 0.8931 0.9167\n",
      -       "    index_in_trajectory    (chain, draw) int64 -12 20 43 -17 ... 42 20 -43 -29\n",
      -       "    tree_depth             (chain, draw) int64 6 6 6 6 7 6 6 7 ... 6 5 5 6 7 6 6\n",
      -       "    ...                     ...\n",
      -       "    energy_error           (chain, draw) float64 -0.01181 -0.02828 ... -0.01478\n",
      -       "    perf_counter_diff      (chain, draw) float64 0.009316 0.01008 ... 0.009355\n",
      -       "    n_steps                (chain, draw) float64 63.0 63.0 63.0 ... 63.0 63.0\n",
      -       "    diverging              (chain, draw) bool False False False ... False False\n",
      -       "    perf_counter_start     (chain, draw) float64 3.949e+06 ... 3.949e+06\n",
      -       "    lp                     (chain, draw) float64 355.1 355.2 ... 355.6 351.6\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:14.040220\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1\n",
      -       "    sampling_time:              29.821417093276978\n",
      -       "    tuning_steps:               1000

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:                    (chain: 1, draw: 500, fourier_mode: 4,\n",
      -       "                                date: 179, channel: 2, control: 3)\n",
      -       "Coordinates:\n",
      -       "  * chain                      (chain) int64 0\n",
      -       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 495 496 497 498 499\n",
      -       "  * fourier_mode               (fourier_mode) <U11 'sin_order_1' ... 'cos_ord...\n",
      -       "  * date                       (date) <U10 '2018-04-02' ... '2021-08-30'\n",
      -       "  * channel                    (channel) <U2 'x1' 'x2'\n",
      -       "  * control                    (control) <U7 'event_1' 'event_2' 't'\n",
      -       "Data variables: (12/13)\n",
      -       "    gamma_fourier              (chain, draw, fourier_mode) float64 1.28 ... 1...\n",
      -       "    intercept                  (chain, draw) float64 1.178 -2.005 ... 2.533\n",
      -       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 1.28...\n",
      -       "    mu                         (chain, draw, date) float64 0.8703 ... -44.96\n",
      -       "    channel_contributions      (chain, draw, date, channel) float64 0.4222 .....\n",
      -       "    control_contributions      (chain, draw, date, control) float64 0.0 ... -...\n",
      -       "    ...                         ...\n",
      -       "    gamma_control              (chain, draw, control) float64 1.547 ... -0.2666\n",
      -       "    channel_adstock            (chain, draw, date, channel) float64 0.3087 .....\n",
      -       "    alpha                      (chain, draw, channel) float64 0.03434 ... 0.1455\n",
      -       "    lam                        (chain, draw, channel) float64 2.558 ... 4.149\n",
      -       "    channel_adstock_saturated  (chain, draw, date, channel) float64 0.3755 .....\n",
      -       "    sigma                      (chain, draw) float64 0.05319 1.662 ... 1.212\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:15.159471\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:     (chain: 1, draw: 500, date: 179)\n",
      -       "Coordinates:\n",
      -       "  * chain       (chain) int64 0\n",
      -       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 492 493 494 495 496 497 498 499\n",
      -       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "Data variables:\n",
      -       "    likelihood  (chain, draw, date) float64 0.8725 3.274 6.447 ... -45.43 -45.69\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:15.164125\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:     (date: 179)\n",
      -       "Coordinates:\n",
      -       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "Data variables:\n",
      -       "    likelihood  (date) float64 0.4794 0.4527 0.5374 ... 0.4978 0.5388 0.5625\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:14.043853\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:       (date: 179, channel: 2, control: 3, fourier_mode: 4)\n",
      -       "Coordinates:\n",
      -       "  * date          (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "  * channel       (channel) <U2 'x1' 'x2'\n",
      -       "  * control       (control) <U7 'event_1' 'event_2' 't'\n",
      -       "  * fourier_mode  (fourier_mode) <U11 'sin_order_1' ... 'cos_order_2'\n",
      -       "Data variables:\n",
      -       "    channel_data  (date, channel) float64 0.3196 0.0 0.1128 ... 0.0 0.4403 0.0\n",
      -       "    target        (date) float64 0.4794 0.4527 0.5374 ... 0.4978 0.5388 0.5625\n",
      -       "    control_data  (date, control) float64 0.0 0.0 0.0 0.0 ... 0.0 0.0 178.0\n",
      -       "    fourier_data  (date, fourier_mode) float64 0.9999 -0.01183 ... -0.4547\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:14.045029\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:    (index: 179)\n",
      -       "Coordinates:\n",
      -       "  * index      (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      -       "Data variables:\n",
      -       "    date_week  (index) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "    x1         (index) float64 0.3186 0.1124 0.2924 ... 0.1719 0.2803 0.4389\n",
      -       "    x2         (index) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.8633 0.0 0.0 0.0\n",
      -       "    event_1    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      -       "    event_2    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      -       "    dayofyear  (index) int64 92 99 106 113 120 127 ... 207 214 221 228 235 242\n",
      -       "    t          (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      -       "    y          (index) float64 3.985e+03 3.763e+03 ... 4.479e+03 4.676e+03

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
\n", - "
\n", - " " - ], - "text/plain": [ - "Inference data with groups:\n", - "\t> posterior\n", - "\t> posterior_predictive\n", - "\t> sample_stats\n", - "\t> prior\n", - "\t> prior_predictive\n", - "\t> observed_data\n", - "\t> constant_data\n", - "\t> fit_data" - ] - }, - "execution_count": 42, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mmm.fit(X=X, y=y, random_seed=rng)" - ] - }, - { - "cell_type": "markdown", - "id": "c29a6461", - "metadata": {}, - "source": [ - "The `fit()` method automatically builds the model using the priors from `model_config`, and assigns the created model to our instance. You can access it as a normal attribute." - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "id": "c6b8e2af", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "pymc.model.Model" - ] - }, - "execution_count": 43, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "type(mmm.model)" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "id": "f046ee2c", - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "clusterdate (179) x channel (2)\n", - "\n", - "date (179) x channel (2)\n", - "\n", - "\n", - "clusterdate (179)\n", - "\n", - "date (179)\n", - "\n", - "\n", - "clusterchannel (2)\n", - "\n", - "channel (2)\n", - "\n", - "\n", - "clusterdate (179) x control (3)\n", - "\n", - "date (179) x control (3)\n", - "\n", - "\n", - "clustercontrol (3)\n", - "\n", - "control (3)\n", - "\n", - "\n", - "clusterdate (179) x fourier_mode (4)\n", - "\n", - "date (179) x fourier_mode (4)\n", - "\n", - "\n", - "clusterfourier_mode (4)\n", - "\n", - "fourier_mode (4)\n", - "\n", - "\n", - "\n", - "channel_contributions\n", - "\n", - "channel_contributions\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "mu\n", - "\n", - "mu\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "channel_contributions->mu\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "channel_data\n", - "\n", - "channel_data\n", - "~\n", - "MutableData\n", - "\n", - "\n", - "\n", - "channel_adstock\n", - "\n", - "channel_adstock\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "channel_data->channel_adstock\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "channel_adstock_saturated\n", - "\n", - "channel_adstock_saturated\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "channel_adstock->channel_adstock_saturated\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "channel_adstock_saturated->channel_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "target\n", - "\n", - "target\n", - "~\n", - "MutableData\n", - "\n", - "\n", - "\n", - "likelihood\n", - "\n", - "likelihood\n", - "~\n", - "Normal\n", - "\n", - "\n", - "\n", - "mu->likelihood\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "likelihood->target\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "intercept\n", - "\n", - "intercept\n", - "~\n", - "Normal\n", - "\n", - "\n", - "\n", - "intercept->mu\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "sigma\n", - "\n", - "sigma\n", - "~\n", - "HalfNormal\n", - "\n", - "\n", - "\n", - "sigma->likelihood\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "lam\n", - "\n", - "lam\n", - "~\n", - "Gamma\n", - "\n", - "\n", - "\n", - "lam->channel_adstock_saturated\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "alpha\n", - "\n", - "alpha\n", - "~\n", - "Beta\n", - "\n", - "\n", - "\n", - "alpha->channel_adstock\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "beta_channel\n", - "\n", - "beta_channel\n", - "~\n", - "HalfNormal\n", - "\n", - "\n", - "\n", - "beta_channel->channel_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "control_data\n", - "\n", - "control_data\n", - "~\n", - "MutableData\n", - "\n", - "\n", - "\n", - "control_contributions\n", - "\n", - "control_contributions\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "control_data->control_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "control_contributions->mu\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "gamma_control\n", - "\n", - "gamma_control\n", - "~\n", - "Normal\n", - "\n", - "\n", - "\n", - "gamma_control->control_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fourier_contributions\n", - "\n", - "fourier_contributions\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "fourier_contributions->mu\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fourier_data\n", - "\n", - "fourier_data\n", - "~\n", - "MutableData\n", - "\n", - "\n", - "\n", - "fourier_data->fourier_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "gamma_fourier\n", - "\n", - "gamma_fourier\n", - "~\n", - "Laplace\n", - "\n", - "\n", - "\n", - "gamma_fourier->fourier_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 44, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mmm.graphviz()" - ] - }, - { - "cell_type": "markdown", - "id": "c804b600", - "metadata": {}, - "source": [ - "posterior trace can be accessed by `fit_result` attribute" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "id": "66903965", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
<xarray.Dataset>\n",
-       "Dimensions:                    (chain: 4, draw: 1000, control: 3,\n",
-       "                                fourier_mode: 4, channel: 2, date: 179)\n",
-       "Coordinates:\n",
-       "  * chain                      (chain) int64 0 1 2 3\n",
-       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 995 996 997 998 999\n",
-       "  * control                    (control) <U7 'event_1' 'event_2' 't'\n",
-       "  * fourier_mode               (fourier_mode) <U11 'sin_order_1' ... 'cos_ord...\n",
-       "  * channel                    (channel) <U2 'x1' 'x2'\n",
-       "  * date                       (date) <U10 '2018-04-02' ... '2021-08-30'\n",
-       "Data variables: (12/13)\n",
-       "    intercept                  (chain, draw) float64 0.3381 0.3361 ... 0.3479\n",
-       "    gamma_control              (chain, draw, control) float64 0.2968 ... 0.00...\n",
-       "    gamma_fourier              (chain, draw, fourier_mode) float64 -0.002612 ...\n",
-       "    beta_channel               (chain, draw, channel) float64 0.3718 ... 0.2628\n",
-       "    alpha                      (chain, draw, channel) float64 0.4162 ... 0.2007\n",
-       "    lam                        (chain, draw, channel) float64 4.26 ... 2.758\n",
-       "    ...                         ...\n",
-       "    channel_adstock            (chain, draw, date, channel) float64 0.1868 .....\n",
-       "    channel_adstock_saturated  (chain, draw, date, channel) float64 0.3781 .....\n",
-       "    channel_contributions      (chain, draw, date, channel) float64 0.1406 .....\n",
-       "    control_contributions      (chain, draw, date, control) float64 0.0 ... 0...\n",
-       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 -0.0...\n",
-       "    mu                         (chain, draw, date) float64 0.4769 ... 0.5924\n",
-       "Attributes:\n",
-       "    created_at:                 2023-08-03T11:09:14.027598\n",
-       "    arviz_version:              0.16.1\n",
-       "    inference_library:          pymc\n",
-       "    inference_library_version:  5.6.1\n",
-       "    sampling_time:              29.821417093276978\n",
-       "    tuning_steps:               1000
" - ], - "text/plain": [ - "\n", - "Dimensions: (chain: 4, draw: 1000, control: 3,\n", - " fourier_mode: 4, channel: 2, date: 179)\n", - "Coordinates:\n", - " * chain (chain) int64 0 1 2 3\n", - " * draw (draw) int64 0 1 2 3 4 5 ... 995 996 997 998 999\n", - " * control (control) \n", - "
\n", - "
arviz.InferenceData
\n", - "
\n", - "
    \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:                    (chain: 4, draw: 1000, control: 3,\n",
      -       "                                fourier_mode: 4, channel: 2, date: 179)\n",
      -       "Coordinates:\n",
      -       "  * chain                      (chain) int64 0 1 2 3\n",
      -       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 995 996 997 998 999\n",
      -       "  * control                    (control) <U7 'event_1' 'event_2' 't'\n",
      -       "  * fourier_mode               (fourier_mode) <U11 'sin_order_1' ... 'cos_ord...\n",
      -       "  * channel                    (channel) <U2 'x1' 'x2'\n",
      -       "  * date                       (date) <U10 '2018-04-02' ... '2021-08-30'\n",
      -       "Data variables: (12/13)\n",
      -       "    intercept                  (chain, draw) float64 0.3381 0.3361 ... 0.3479\n",
      -       "    gamma_control              (chain, draw, control) float64 0.2968 ... 0.00...\n",
      -       "    gamma_fourier              (chain, draw, fourier_mode) float64 -0.002612 ...\n",
      -       "    beta_channel               (chain, draw, channel) float64 0.3718 ... 0.2628\n",
      -       "    alpha                      (chain, draw, channel) float64 0.4162 ... 0.2007\n",
      -       "    lam                        (chain, draw, channel) float64 4.26 ... 2.758\n",
      -       "    ...                         ...\n",
      -       "    channel_adstock            (chain, draw, date, channel) float64 0.1868 .....\n",
      -       "    channel_adstock_saturated  (chain, draw, date, channel) float64 0.3781 .....\n",
      -       "    channel_contributions      (chain, draw, date, channel) float64 0.1406 .....\n",
      -       "    control_contributions      (chain, draw, date, control) float64 0.0 ... 0...\n",
      -       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 -0.0...\n",
      -       "    mu                         (chain, draw, date) float64 0.4769 ... 0.5924\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:14.027598\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1\n",
      -       "    sampling_time:              29.821417093276978\n",
      -       "    tuning_steps:               1000

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:     (chain: 4, draw: 1000, date: 179)\n",
      -       "Coordinates:\n",
      -       "  * chain       (chain) int64 0 1 2 3\n",
      -       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999\n",
      -       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "Data variables:\n",
      -       "    likelihood  (chain, draw, date) float64 0.5039 0.439 ... 0.5873 0.6072\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:15.416164\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:                (chain: 4, draw: 1000)\n",
      -       "Coordinates:\n",
      -       "  * chain                  (chain) int64 0 1 2 3\n",
      -       "  * draw                   (draw) int64 0 1 2 3 4 5 ... 994 995 996 997 998 999\n",
      -       "Data variables: (12/17)\n",
      -       "    process_time_diff      (chain, draw) float64 0.008982 0.009454 ... 0.009203\n",
      -       "    step_size_bar          (chain, draw) float64 0.05522 0.05522 ... 0.06921\n",
      -       "    step_size              (chain, draw) float64 0.05862 0.05862 ... 0.07543\n",
      -       "    acceptance_rate        (chain, draw) float64 0.9987 0.9934 ... 0.8931 0.9167\n",
      -       "    index_in_trajectory    (chain, draw) int64 -12 20 43 -17 ... 42 20 -43 -29\n",
      -       "    tree_depth             (chain, draw) int64 6 6 6 6 7 6 6 7 ... 6 5 5 6 7 6 6\n",
      -       "    ...                     ...\n",
      -       "    energy_error           (chain, draw) float64 -0.01181 -0.02828 ... -0.01478\n",
      -       "    perf_counter_diff      (chain, draw) float64 0.009316 0.01008 ... 0.009355\n",
      -       "    n_steps                (chain, draw) float64 63.0 63.0 63.0 ... 63.0 63.0\n",
      -       "    diverging              (chain, draw) bool False False False ... False False\n",
      -       "    perf_counter_start     (chain, draw) float64 3.949e+06 ... 3.949e+06\n",
      -       "    lp                     (chain, draw) float64 355.1 355.2 ... 355.6 351.6\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:14.040220\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1\n",
      -       "    sampling_time:              29.821417093276978\n",
      -       "    tuning_steps:               1000

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:                    (chain: 1, draw: 500, fourier_mode: 4,\n",
      -       "                                date: 179, channel: 2, control: 3)\n",
      -       "Coordinates:\n",
      -       "  * chain                      (chain) int64 0\n",
      -       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 495 496 497 498 499\n",
      -       "  * fourier_mode               (fourier_mode) <U11 'sin_order_1' ... 'cos_ord...\n",
      -       "  * date                       (date) <U10 '2018-04-02' ... '2021-08-30'\n",
      -       "  * channel                    (channel) <U2 'x1' 'x2'\n",
      -       "  * control                    (control) <U7 'event_1' 'event_2' 't'\n",
      -       "Data variables: (12/13)\n",
      -       "    gamma_fourier              (chain, draw, fourier_mode) float64 1.28 ... 1...\n",
      -       "    intercept                  (chain, draw) float64 1.178 -2.005 ... 2.533\n",
      -       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 1.28...\n",
      -       "    mu                         (chain, draw, date) float64 0.8703 ... -44.96\n",
      -       "    channel_contributions      (chain, draw, date, channel) float64 0.4222 .....\n",
      -       "    control_contributions      (chain, draw, date, control) float64 0.0 ... -...\n",
      -       "    ...                         ...\n",
      -       "    gamma_control              (chain, draw, control) float64 1.547 ... -0.2666\n",
      -       "    channel_adstock            (chain, draw, date, channel) float64 0.3087 .....\n",
      -       "    alpha                      (chain, draw, channel) float64 0.03434 ... 0.1455\n",
      -       "    lam                        (chain, draw, channel) float64 2.558 ... 4.149\n",
      -       "    channel_adstock_saturated  (chain, draw, date, channel) float64 0.3755 .....\n",
      -       "    sigma                      (chain, draw) float64 0.05319 1.662 ... 1.212\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:15.159471\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:     (chain: 1, draw: 500, date: 179)\n",
      -       "Coordinates:\n",
      -       "  * chain       (chain) int64 0\n",
      -       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 492 493 494 495 496 497 498 499\n",
      -       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "Data variables:\n",
      -       "    likelihood  (chain, draw, date) float64 0.8725 3.274 6.447 ... -45.43 -45.69\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:15.164125\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:     (date: 179)\n",
      -       "Coordinates:\n",
      -       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "Data variables:\n",
      -       "    likelihood  (date) float64 0.4794 0.4527 0.5374 ... 0.4978 0.5388 0.5625\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:14.043853\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:       (date: 179, channel: 2, control: 3, fourier_mode: 4)\n",
      -       "Coordinates:\n",
      -       "  * date          (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "  * channel       (channel) <U2 'x1' 'x2'\n",
      -       "  * control       (control) <U7 'event_1' 'event_2' 't'\n",
      -       "  * fourier_mode  (fourier_mode) <U11 'sin_order_1' ... 'cos_order_2'\n",
      -       "Data variables:\n",
      -       "    channel_data  (date, channel) float64 0.3196 0.0 0.1128 ... 0.0 0.4403 0.0\n",
      -       "    target        (date) float64 0.4794 0.4527 0.5374 ... 0.4978 0.5388 0.5625\n",
      -       "    control_data  (date, control) float64 0.0 0.0 0.0 0.0 ... 0.0 0.0 178.0\n",
      -       "    fourier_data  (date, fourier_mode) float64 0.9999 -0.01183 ... -0.4547\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:14.045029\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:    (index: 179)\n",
      -       "Coordinates:\n",
      -       "  * index      (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      -       "Data variables:\n",
      -       "    date_week  (index) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "    x1         (index) float64 0.3186 0.1124 0.2924 ... 0.1719 0.2803 0.4389\n",
      -       "    x2         (index) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.8633 0.0 0.0 0.0\n",
      -       "    event_1    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      -       "    event_2    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      -       "    dayofyear  (index) int64 92 99 106 113 120 127 ... 207 214 221 228 235 242\n",
      -       "    t          (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      -       "    y          (index) float64 3.985e+03 3.763e+03 ... 4.479e+03 4.676e+03

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
\n", - " \n", - " " - ], - "text/plain": [ - "Inference data with groups:\n", - "\t> posterior\n", - "\t> posterior_predictive\n", - "\t> sample_stats\n", - "\t> prior\n", - "\t> prior_predictive\n", - "\t> observed_data\n", - "\t> constant_data\n", - "\t> fit_data" - ] - }, - "execution_count": 46, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mmm.idata" - ] - }, - { - "cell_type": "markdown", - "id": "8b433c7f-0f0d-40b2-bcfb-a19555b528bd", - "metadata": {}, - "source": [ - "## `Save` and `load`" - ] - }, - { - "cell_type": "markdown", - "id": "7b0a35f4", - "metadata": {}, - "source": [ - "All the data passed to the model on initialisation is stored in `idata.attrs`. This will be used later in the `save()` method to convert both this data and all the fit data into the netCDF format." - ] - }, - { - "cell_type": "markdown", - "id": "45948f46", - "metadata": {}, - "source": [ - "Simply specify the path to which you'd like to save your model:" - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "id": "b3abe93a", - "metadata": {}, - "outputs": [], - "source": [ - "mmm.save('my_saved_model.nc')" - ] - }, - { - "cell_type": "markdown", - "id": "8a5eba79", - "metadata": {}, - "source": [ - "And pass it to the `load()` method when it's needed again on the target system:" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "id": "0421bae8", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/michalraczycki/Documents/pymc-marketing/.conda/envs/pymc-marketing/lib/python3.10/site-packages/arviz/data/inference_data.py:153: UserWarning: fit_data group is not defined in the InferenceData scheme\n", - " warnings.warn(\n" - ] - } - ], - "source": [ - "loaded_model = DelayedSaturatedMMM.load('my_saved_model.nc')" - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "id": "a8b666d3", - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "clusterdate (179) x channel (2)\n", - "\n", - "date (179) x channel (2)\n", - "\n", - "\n", - "clusterdate (179)\n", - "\n", - "date (179)\n", - "\n", - "\n", - "clusterchannel (2)\n", - "\n", - "channel (2)\n", - "\n", - "\n", - "clusterdate (179) x control (3)\n", - "\n", - "date (179) x control (3)\n", - "\n", - "\n", - "clustercontrol (3)\n", - "\n", - "control (3)\n", - "\n", - "\n", - "clusterdate (179) x fourier_mode (4)\n", - "\n", - "date (179) x fourier_mode (4)\n", - "\n", - "\n", - "clusterfourier_mode (4)\n", - "\n", - "fourier_mode (4)\n", - "\n", - "\n", - "\n", - "channel_contributions\n", - "\n", - "channel_contributions\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "mu\n", - "\n", - "mu\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "channel_contributions->mu\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "channel_data\n", - "\n", - "channel_data\n", - "~\n", - "MutableData\n", - "\n", - "\n", - "\n", - "channel_adstock\n", - "\n", - "channel_adstock\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "channel_data->channel_adstock\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "channel_adstock_saturated\n", - "\n", - "channel_adstock_saturated\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "channel_adstock->channel_adstock_saturated\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "channel_adstock_saturated->channel_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "target\n", - "\n", - "target\n", - "~\n", - "MutableData\n", - "\n", - "\n", - "\n", - "likelihood\n", - "\n", - "likelihood\n", - "~\n", - "Normal\n", - "\n", - "\n", - "\n", - "mu->likelihood\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "likelihood->target\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "intercept\n", - "\n", - "intercept\n", - "~\n", - "Normal\n", - "\n", - "\n", - "\n", - "intercept->mu\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "sigma\n", - "\n", - "sigma\n", - "~\n", - "HalfNormal\n", - "\n", - "\n", - "\n", - "sigma->likelihood\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "lam\n", - "\n", - "lam\n", - "~\n", - "Gamma\n", - "\n", - "\n", - "\n", - "lam->channel_adstock_saturated\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "alpha\n", - "\n", - "alpha\n", - "~\n", - "Beta\n", - "\n", - "\n", - "\n", - "alpha->channel_adstock\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "beta_channel\n", - "\n", - "beta_channel\n", - "~\n", - "HalfNormal\n", - "\n", - "\n", - "\n", - "beta_channel->channel_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "control_data\n", - "\n", - "control_data\n", - "~\n", - "MutableData\n", - "\n", - "\n", - "\n", - "control_contributions\n", - "\n", - "control_contributions\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "control_data->control_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "control_contributions->mu\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "gamma_control\n", - "\n", - "gamma_control\n", - "~\n", - "Normal\n", - "\n", - "\n", - "\n", - "gamma_control->control_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fourier_contributions\n", - "\n", - "fourier_contributions\n", - "~\n", - "Deterministic\n", - "\n", - "\n", - "\n", - "fourier_contributions->mu\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fourier_data\n", - "\n", - "fourier_data\n", - "~\n", - "MutableData\n", - "\n", - "\n", - "\n", - "fourier_data->fourier_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "gamma_fourier\n", - "\n", - "gamma_fourier\n", - "~\n", - "Laplace\n", - "\n", - "\n", - "\n", - "gamma_fourier->fourier_contributions\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 49, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "loaded_model.graphviz()" - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "id": "cfb64a2c", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "
arviz.InferenceData
\n", - "
\n", - "
    \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:                    (chain: 4, draw: 1000, control: 3,\n",
      -       "                                fourier_mode: 4, channel: 2, date: 179)\n",
      -       "Coordinates:\n",
      -       "  * chain                      (chain) int64 0 1 2 3\n",
      -       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 995 996 997 998 999\n",
      -       "  * control                    (control) object 'event_1' 'event_2' 't'\n",
      -       "  * fourier_mode               (fourier_mode) object 'sin_order_1' ... 'cos_o...\n",
      -       "  * channel                    (channel) object 'x1' 'x2'\n",
      -       "  * date                       (date) object '2018-04-02' ... '2021-08-30'\n",
      -       "Data variables: (12/13)\n",
      -       "    intercept                  (chain, draw) float64 ...\n",
      -       "    gamma_control              (chain, draw, control) float64 ...\n",
      -       "    gamma_fourier              (chain, draw, fourier_mode) float64 ...\n",
      -       "    beta_channel               (chain, draw, channel) float64 ...\n",
      -       "    alpha                      (chain, draw, channel) float64 ...\n",
      -       "    lam                        (chain, draw, channel) float64 ...\n",
      -       "    ...                         ...\n",
      -       "    channel_adstock            (chain, draw, date, channel) float64 ...\n",
      -       "    channel_adstock_saturated  (chain, draw, date, channel) float64 ...\n",
      -       "    channel_contributions      (chain, draw, date, channel) float64 ...\n",
      -       "    control_contributions      (chain, draw, date, control) float64 ...\n",
      -       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 ...\n",
      -       "    mu                         (chain, draw, date) float64 ...\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:14.027598\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1\n",
      -       "    sampling_time:              29.821417093276978\n",
      -       "    tuning_steps:               1000

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:     (chain: 4, draw: 1000, date: 179)\n",
      -       "Coordinates:\n",
      -       "  * chain       (chain) int64 0 1 2 3\n",
      -       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999\n",
      -       "  * date        (date) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "Data variables:\n",
      -       "    likelihood  (chain, draw, date) float64 ...\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:15.416164\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:                (chain: 4, draw: 1000)\n",
      -       "Coordinates:\n",
      -       "  * chain                  (chain) int64 0 1 2 3\n",
      -       "  * draw                   (draw) int64 0 1 2 3 4 5 ... 994 995 996 997 998 999\n",
      -       "Data variables: (12/17)\n",
      -       "    process_time_diff      (chain, draw) float64 ...\n",
      -       "    step_size_bar          (chain, draw) float64 ...\n",
      -       "    step_size              (chain, draw) float64 ...\n",
      -       "    acceptance_rate        (chain, draw) float64 ...\n",
      -       "    index_in_trajectory    (chain, draw) int64 ...\n",
      -       "    tree_depth             (chain, draw) int64 ...\n",
      -       "    ...                     ...\n",
      -       "    energy_error           (chain, draw) float64 ...\n",
      -       "    perf_counter_diff      (chain, draw) float64 ...\n",
      -       "    n_steps                (chain, draw) float64 ...\n",
      -       "    diverging              (chain, draw) bool ...\n",
      -       "    perf_counter_start     (chain, draw) float64 ...\n",
      -       "    lp                     (chain, draw) float64 ...\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:14.040220\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1\n",
      -       "    sampling_time:              29.821417093276978\n",
      -       "    tuning_steps:               1000

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:                    (chain: 1, draw: 500, fourier_mode: 4,\n",
      -       "                                date: 179, channel: 2, control: 3)\n",
      -       "Coordinates:\n",
      -       "  * chain                      (chain) int64 0\n",
      -       "  * draw                       (draw) int64 0 1 2 3 4 5 ... 495 496 497 498 499\n",
      -       "  * fourier_mode               (fourier_mode) object 'sin_order_1' ... 'cos_o...\n",
      -       "  * date                       (date) object '2018-04-02' ... '2021-08-30'\n",
      -       "  * channel                    (channel) object 'x1' 'x2'\n",
      -       "  * control                    (control) object 'event_1' 'event_2' 't'\n",
      -       "Data variables: (12/13)\n",
      -       "    gamma_fourier              (chain, draw, fourier_mode) float64 ...\n",
      -       "    intercept                  (chain, draw) float64 ...\n",
      -       "    fourier_contributions      (chain, draw, date, fourier_mode) float64 ...\n",
      -       "    mu                         (chain, draw, date) float64 ...\n",
      -       "    channel_contributions      (chain, draw, date, channel) float64 ...\n",
      -       "    control_contributions      (chain, draw, date, control) float64 ...\n",
      -       "    ...                         ...\n",
      -       "    gamma_control              (chain, draw, control) float64 ...\n",
      -       "    channel_adstock            (chain, draw, date, channel) float64 ...\n",
      -       "    alpha                      (chain, draw, channel) float64 ...\n",
      -       "    lam                        (chain, draw, channel) float64 ...\n",
      -       "    channel_adstock_saturated  (chain, draw, date, channel) float64 ...\n",
      -       "    sigma                      (chain, draw) float64 ...\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:15.159471\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:     (chain: 1, draw: 500, date: 179)\n",
      -       "Coordinates:\n",
      -       "  * chain       (chain) int64 0\n",
      -       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 492 493 494 495 496 497 498 499\n",
      -       "  * date        (date) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "Data variables:\n",
      -       "    likelihood  (chain, draw, date) float64 ...\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:15.164125\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:     (date: 179)\n",
      -       "Coordinates:\n",
      -       "  * date        (date) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "Data variables:\n",
      -       "    likelihood  (date) float64 ...\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:14.043853\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:       (date: 179, channel: 2, control: 3, fourier_mode: 4)\n",
      -       "Coordinates:\n",
      -       "  * date          (date) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "  * channel       (channel) object 'x1' 'x2'\n",
      -       "  * control       (control) object 'event_1' 'event_2' 't'\n",
      -       "  * fourier_mode  (fourier_mode) object 'sin_order_1' ... 'cos_order_2'\n",
      -       "Data variables:\n",
      -       "    channel_data  (date, channel) float64 ...\n",
      -       "    target        (date) float64 ...\n",
      -       "    control_data  (date, control) float64 ...\n",
      -       "    fourier_data  (date, fourier_mode) float64 ...\n",
      -       "Attributes:\n",
      -       "    created_at:                 2023-08-03T11:09:14.045029\n",
      -       "    arviz_version:              0.16.1\n",
      -       "    inference_library:          pymc\n",
      -       "    inference_library_version:  5.6.1

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
  • \n", - " \n", - " \n", - "
    \n", - "
    \n", - "
      \n", - "
      \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
      <xarray.Dataset>\n",
      -       "Dimensions:    (index: 179)\n",
      -       "Coordinates:\n",
      -       "  * index      (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      -       "Data variables:\n",
      -       "    date_week  (index) object '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
      -       "    x1         (index) float64 0.3186 0.1124 0.2924 ... 0.1719 0.2803 0.4389\n",
      -       "    x2         (index) float64 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.8633 0.0 0.0 0.0\n",
      -       "    event_1    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      -       "    event_2    (index) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0\n",
      -       "    dayofyear  (index) int64 92 99 106 113 120 127 ... 207 214 221 228 235 242\n",
      -       "    t          (index) int64 0 1 2 3 4 5 6 7 ... 171 172 173 174 175 176 177 178\n",
      -       "    y          (index) float64 3.985e+03 3.763e+03 ... 4.479e+03 4.676e+03

      \n", - "
    \n", - "
    \n", - "
  • \n", - " \n", - "
\n", - "
\n", - " " - ], - "text/plain": [ - "Inference data with groups:\n", - "\t> posterior\n", - "\t> posterior_predictive\n", - "\t> sample_stats\n", - "\t> prior\n", - "\t> prior_predictive\n", - "\t> observed_data\n", - "\t> constant_data\n", - "\t> fit_data" - ] - }, - "execution_count": 50, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "loaded_model.idata" - ] - }, - { - "cell_type": "markdown", - "id": "ab64be46-7fe5-4f39-b72b-36da1419f809", - "metadata": {}, - "source": [ - "A model loaded in this way is ready to be used for sampling and prediction, and has access to all previous samples and data." - ] - }, - { - "cell_type": "code", - "execution_count": 51, - "id": "dd59d056-6ac7-431c-85ee-99e7a8eefd8a", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Sampling: [likelihood]\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - " \n", - " 100.00% [4000/4000 00:00<00:00]\n", - "
\n", - " " - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
<xarray.Dataset>\n",
-       "Dimensions:     (chain: 4, draw: 1000, date: 179)\n",
-       "Coordinates:\n",
-       "  * chain       (chain) int64 0 1 2 3\n",
-       "  * draw        (draw) int64 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999\n",
-       "  * date        (date) <U10 '2018-04-02' '2018-04-09' ... '2021-08-30'\n",
-       "Data variables:\n",
-       "    likelihood  (chain, draw, date) float64 0.4907 0.4282 ... 0.5548 0.5396\n",
-       "Attributes:\n",
-       "    created_at:                 2023-08-03T11:09:22.139450\n",
-       "    arviz_version:              0.16.1\n",
-       "    inference_library:          pymc\n",
-       "    inference_library_version:  5.6.1
" - ], - "text/plain": [ - "\n", - "Dimensions: (chain: 4, draw: 1000, date: 179)\n", - "Coordinates:\n", - " * chain (chain) int64 0 1 2 3\n", - " * draw (draw) int64 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999\n", - " * date (date) " - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "az.plot_ppc(loaded_model.idata);" - ] - }, - { - "cell_type": "markdown", - "id": "e8e807f9", - "metadata": {}, - "source": [ - "## Summary:" - ] - }, - { - "cell_type": "markdown", - "id": "61f232c1", - "metadata": {}, - "source": [ - "In summary, this article introduces the revolutionary ModelBuilder, a new PyMC-experimental module that simplifies the deployment of PyMC Bayesian models. It addresses a historic challenge faced by users of PyMC and most PPLs by offering a user-friendly and efficient approach to model deployment. The ModelBuilder provides two straightforward methods, save() and load(), which streamline the model preservation and replication process post fitting. Users are offered flexibility in controlling the prior settings with model_config and customizing the sampling process via sampler_config.\n", - "\n", - "The use of an example model from the MMM Example Notebook demonstrates the practical implementation of ModelBuilder, emphasizing its ability to enhance model sharing among teams without the necessity for extensive domain knowledge about the model. The deployment improvements in PyMC-Marketing brought about by ModelBuilder are not only user-friendly but also significantly enhance efficiency, making PyMC models more accessible for a wider audience." - ] - }, - { - "cell_type": "markdown", - "id": "b8ad333d", - "metadata": {}, - "source": [ - "Even though this introduction is using `DelayedSaturatedMMM`, functionalities from `ModelBuilder` are available in the CLV models as well." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "pymc-marketing", - "language": "python", - "name": "pymc-marketing" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.12" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From d12b00b66f05d54f6e91788bdf36bfcea7f09390 Mon Sep 17 00:00:00 2001 From: Michal Raczycki Date: Fri, 1 Sep 2023 11:23:06 +0200 Subject: [PATCH 5/5] updating .myst.md file --- examples/howto/model_builder.myst.md | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/howto/model_builder.myst.md b/examples/howto/model_builder.myst.md index 477c91e98..0747511aa 100644 --- a/examples/howto/model_builder.myst.md +++ b/examples/howto/model_builder.myst.md @@ -344,7 +344,6 @@ ax.legend( * Authored by Shashank Kirtania and Thomas Wiecki in 2023. * Modified and updated by Michał Raczycki in 08/2023 - +++ :::{include} ../page_footer.md