PyMC-Marketing

repository·main·Indexed 22 days ago

https://github.com/pymc-labs/pymc-marketing

An open-source library providing Bayesian tools for marketing analytics. It features specialized modules for Marketing Mix Modeling (MMM) with adstock and saturation transformations, Customer Lifetime Value (CLV) using models like BG/NBD and Pareto/NBD, and Customer Choice Analysis (CSA) including Multivariate Interrupted Time Series (MVITS), Bass Diffusion, and Discrete Choice Models.

Tokens
40.4K
Snippets
106
Records
136
Agent score
78%

What's inside pymc-marketing

  1. Overview of PyMC-Marketing capabilities

    main

    PyMC-Marketing is an open-source Bayesian marketing analytics library designed to help businesses maximize ROI through data-driven decisions. It provides tools for several key analytical domains:

    • Marketing Mix Modeling (MMM): Analyzing the impact of various marketing channels on sales.
    • Customer Lifetime Value (CLV): Predicting the long-term value of customers.
    • Customer Choice Analysis (CSA): Modeling customer decision-making processes.
  2. Features of the Bayesian MMM API

    main

    The pymc-marketing MMM API provides several advanced Bayesian modeling capabilities:

    • Custom Priors and Likelihoods: Incorporate domain knowledge via prior distributions.
    • Adstock Transformation: Optimize carry-over effects in marketing channels.
    • Saturation Effects: Model diminishing returns on media investments.
    • Custom Functions: Implement your own adstock and saturation functions.
    • Time-varying Intercept/Media Contribution: Capture baseline and efficiency changes over time using Gaussian processes.
    • Causal Identification: Use directed acyclic graphs (DAGs) to identify meaningful variables.
    • Inference Algorithms: Choose between various NUTS samplers like BlackJax, NumPyro, and Nutpie.
    • Out-of-sample Predictions: Forecast future performance for scenario planning.
    • Budget Optimization: Efficiently allocate spend across channels for maximum ROI.
    • Experiment Calibration: Integrate lift tests to fine-tune the model.
  3. Explore the PyMC-Marketing API modules

    main

    The pymc_marketing package is organized into several specialized modules for Bayesian marketing analytics. You can access specific functionalities by importing from these submodules:

    • mmm: Marketing Mix Modeling tools.
    • clv: Customer Lifetime Value modeling.
    • customer_choice: Customer Choice Analysis (CSA).
    • bass: Bass diffusion models.
    • causal_utils: Utilities for causal inference.
    • data: Data handling and processing.
    • model_builder: Tools for constructing models.
    • model_config: Configuration management for models.
    • model_graph: Model graph representations.
    • prior & special_priors: Bayesian prior specifications.
    • metrics: Evaluation metrics.
    • plot: Visualization tools.
    • serialization & serialization_migration: Saving and loading models.
    • mlflow: Integration with MLflow for experiment tracking.
    • utils, pytensor_utils, paths, hsgp_kwargs, pie: Various helper and utility modules.
  4. Supported CLV Model Types

    main

    The CLV API supports various settings based on the nature of the customer relationship and transaction frequency:

    SettingContinuous (e.g., online purchases)Discrete (e.g., concerts)
    Non-contractualBG/NBD, Pareto/NBD, Shifted BG, Modified BG/NBD
    Contractual(e.g., ad conversion time)(e.g., recurring subscriptions)

    Specific models available include:

    • BG/NBD
    • Pareto/NBD
    • Gamma-Gamma
    • Shifted BG
    • Modified BG/NBD
  5. Understand Customer Lifetime Value (CLV) modeling options

    main

    PyMC-Marketing provides several Bayesian CLV models designed for different business scenarios based on whether the relationship is contractual or non-contractual, and whether transactions are continuous or discrete.

    Model Selection Guide

    ScenarioNon-contractualContractual
    Continuouse.g., online purchasese.g., ad conversion time
    Discretee.g., concerts & sports eventse.g., recurring subscriptions

    Supported Models

    • BG/NBD model: For non-contractual settings.
    • Pareto/NBD model: For non-contractual settings.
    • Gamma-Gamma model: Often used in conjunction with BG/NBD to model transaction value.
    • Shifted BG model: For specific non-contractual variations.
    • Modified BG/NBD model: For specialized non-contractual scenarios.
  6. Compare the MMM class vs. Custom pm.Model implementation

    main

    Deciding whether to use the high-level MMM class or a custom pm.Model depends on your modeling requirements.

    Use the MMM class if you need:

    • Built-in scaling for channels and targets.
    • Automated visualization (e.g., plot.waterfall_components_decomposition(), plot.contributions_over_time()).
    • Integration with BudgetOptimizerWrapper.
    • Built-in add_lift_test_measurements() and TimeSliceCrossValidator.
    • Easy save() and load() functionality.

    Use a custom pm.Model if you need:

    • Arbitrary hierarchical structures beyond supported dimensions.
    • Custom likelihood functions (the MMM class defaults to Normal).
    • Custom intercepts like splines or changepoints.
    • Sum-to-zero constraints (using pm.ZeroSumNormal).
    • Multi-equation or linked models.

    Note: If you move to a custom model, you must manually reimplement scaling, contribution decomposition, and optimization.

  7. When to use custom models instead of the MMM class

    main

    The MMM class in pymc-marketing is a high-level wrapper that provides scaling, plotting, budget optimization, and serialization. You should only build a custom model using pm.Model and standalone components when the MMM class cannot express your specific requirements.

    Common reasons to go custom include:

    • Non-standard hierarchical structures: e.g., partial pooling across both geography and product lines simultaneously.
    • Custom time-varying baselines: e.g., spline-based intercepts, changepoint models, or non-GP approaches.
    • Custom likelihoods: e.g., Student-t, ZeroInflatedPoisson, or mixture likelihoods.
    • Missing components: e.g., custom covariate transformations or non-linear interactions not yet in the MMM class.
    • Full parameterization control: e.g., manual centering or sum-to-zero constraints on seasonality.
    • Multi-equation models: e.g., linking an MMM to a separate demand or pricing model.
  8. Enable Time-Varying Parameters (TVP)

    main

    You can enable time-varying intercepts and media multipliers using Hilbert Space Gaussian Processes (HSGP). This is useful when residuals show irregular temporal variation not explained by seasonality or controls. Use HSGPKwargs within the model_config to tune the GP parameters.

    from pymc_marketing.hsgp_kwargs import HSGPKwargs
    
    mmm = MMM(
        ...,
        time_varying_intercept=True,
        time_varying_media=True,
        model_config={
            "intercept_tvp_config": HSGPKwargs(m=500, L=188, eta_lam=5.0, ls_mu=5.0, ls_sigma=10.0),
            "media_tvp_config": HSGPKwargs(ls_mu=11.0, ls_sigma=5.0),
        },
    )
  9. Define Budget Bounds for Optimization

    main

    Budget bounds constrain per-channel (and optionally per-geo) allocation. Bounds are specified as xr.DataArray objects. You can define single-geo bounds, multidimensional (Channel x Geo) bounds, or use the optimizer_xarray_builder helper.

    Single-Geo Bounds Structure:

    • Dimensions: ["channel", "bound"]
    • Coordinates: channel (list of channel names), bound (["lower", "upper"])

    Multidimensional Bounds (Channel x Geo) Structure:

    • Dimensions: ["channel", "geo", "bound"]
    • Coordinates: channel, geo, bound
    import numpy as np
    import xarray as xr
    from pymc_marketing.mmm.budget_optimizer import optimizer_xarray_builder
    
    # Option 1: Manual Single-Geo Bounds
    budget_bounds = xr.DataArray(
        data=np.array([
            [0.5, 1.5],   # tv: 50%-150% of equal share
            [0.3, 2.0],   # radio: 30%-200%
            [0.5, 1.5],   # social
        ]) * equal_share_per_channel,
        dims=["channel", "bound"],
        coords={
            "channel": channel_columns,
            "bound": ["lower", "upper"],
        },
    )
    
    # Option 2: Multidimensional Bounds (Channel x Geo)
    budget_bounds = xr.DataArray(
        data=np.stack([
            np.full((n_channels, n_geos), 0.0),       # lower bounds
            np.full((n_channels, n_geos), max_budget),  # upper bounds
        ], axis=-1),
        dims=["channel", "geo", "bound"],
        coords={
            "channel": channel_columns,
            "geo": geos,
            "bound": ["lower", "upper"],
        },
    )
    
    # Option 3: Using the Builder Helper
    budget_bounds = optimizer_xarray_builder(
        value=np.array([
            [0.5 * equal_share, 1.5 * equal_share],   # tv
            [0.3 * equal_share, 2.0 * equal_share],   # radio
            [0.5 * equal_share, 1.5 * equal_share],   # social
        ]),
        channel=channel_columns,
        bound=["lower", "upper"],
    )
  10. How the PyMC-Marketing gallery is built

    main

    The gallery is managed using a configuration-driven approach:

    • Source of Truth: gallery.yaml defines the layout, including sections, subsections, card titles, and notebook paths.
    • Rendering: scripts/generate_gallery.py processes the YAML to render gallery.md and extracts thumbnails from each notebook into the images/ directory.
    • Validation: A pre-commit hook named gallery-in-sync prevents commits if gallery.md does not match gallery.yaml.
    • Thumbnails: Thumbnails are PNG files (roughly 4:3 aspect ratio, ~600x450px). By default, the filename matches the notebook's stem (e.g., my_notebook.ipynb -> images/my_notebook.png), but this can be overridden in gallery.yaml using the thumb: key. The grid layout is powered by the Sphinx Design extension.
  11. Advanced Optimization: Custom Constraints and Temporal Budgeting

    main

    Custom Constraints

    Use pymc_marketing.mmm.constraints.Constraint to implement logic beyond simple bounds (e.g., spend ratios). Pass a list of these to optimize_budget.

    Custom Budget Distribution (Flighting)

    By default, budget is distributed equally. To implement temporal patterns (flighting), pass a budget_distribution_over_period xr.DataArray to both optimize_budget and sample_response_distribution. Values along the date dimension must sum to 1 for each combination of other dimensions.

    Fixing Channels

    Pass a boolean xr.DataArray to budgets_to_optimize to decide which channels to optimize and which to keep at a fixed budget.

    # Custom Constraint Example: tv must be at least 2x radio
    import pytensor.tensor as pt
    from pymc_marketing.mmm.constraints import Constraint
    
    def tv_ge_2x_radio(budgets_sym, total_budget_sym, optimizer):
        tv_idx = list(channel_columns).index("tv")
        radio_idx = list(channel_columns).index("radio")
        return budgets_sym[tv_idx] - 2 * budgets_sym[radio_idx]
    
    constraint = Constraint(
        key="tv_ge_2x_radio",
        constraint_type="ineq",
        constraint_fun=tv_ge_2x_radio,
    )
    
    # Applying constraints
    allocation, result = optimizable_model.optimize_budget(
        budget=budget_per_period,
        budget_bounds=budget_bounds,
        constraints=[constraint],
        minimize_kwargs={"method": "SLSQP"},
    )
  12. Predict campaign incrementality with PIE (alpha)

    main

    The pymc_marketing.pie module implements Predicted Incrementality by Experimentation (PIE).

    PIE uses a Bayesian BART model to learn the relationship between campaign features and measured incrementality from historical experiments (like geo tests or ghost-ad holdouts). It then predicts the full posterior of incrementality for campaigns that have not yet undergone an experiment.

    Warning: The pymc_marketing.pie module is currently in alpha. The API and default parameters are subject to change between releases.