agentsclimarketplace

Mmm modeling

Skill afelipeg/Anthropic-Skills-for-enterprise-marketing-os/skills/mmm-modeling

30 connected Claude Skills for enterprise marketing ops. Install in-house to replace fragmented tools or reclaim outsourced operations. Marketing & Comms [working & non-working media]· CRM & Growth · Shopper & Trade · RGM · Finance.

Install
npx -y skills add afelipeg/Anthropic-Skills-for-enterprise-marketing-os --skill mmm-modeling

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Bayesian Media Mix Modeling with PyMC-Marketing + custom fallback. Acid-test validation (Holt-Winters, Granger, VIF), industry-calibrated priors, trade marketing decomposition, Meridian scenario planning, budget optimization. TRIGGERS: MMM, marketing mix model, media mix, ROI, marketing attribution, budget optimization, channel contribution, adstock, saturation curve, incrementality, ROAS, scenario planning, lift test, sensitivity analysis, marginal ROI, diminishing returns, media-driven sales, trade marketing Use when: analyzing channel ROI, optimizing budgets, measuring incremental contribution, building saturation curves, scenario planning, decomposing KPI drivers (base+media+trade), calibrating with lift tests, geo-hierarchical modeling, validating MMM integrity

SKILL.md

17.7 KB, as published. Nobody here has run it

Media Mix Modeling (MMM) Skill

Bayesian Media Mix Modeling using PyMC-Marketing (primary) with a custom scipy-based fallback for restricted environments. Includes Meridian-inspired scenario planning patterns for forward-looking budget optimization.

Architecture

LayerEngineWhen
Primarypymc-marketing MMM classDefault. Full Bayesian MCMC, geo-hierarchical, lift calibration, HSGP TVP
FallbackCustom scipy (scripts/)When pymc-marketing unavailable. MLE + bootstrap CIs
ScenarioAdapted from Meridian patternsBudget sweeps, fixed/flexible optimization, flighting

Detection logic — try import pymc_marketing first; if ImportError, fall back to custom scripts.

Agency Growth OS Integration

This skill operates within the 17-skill Agency Growth OS. Its position in the three cycles:

Execution Cycle

media-routing-planner → mmm-modeling → measurement-incrementality
                                     ↘ budget_optimization → media-routing-planner (re-optimize)

Intelligence Cycle

weekly-control-tower → performance-diagnosis → mmm-modeling (if root cause is channel mix)
mmm-modeling → qbr-generator (quarterly decomposition + scenario slides)
mmm-modeling → client-memory-synthesizer (store model parameters + integrity score)

Chain Routing

After mmm-modeling completes, suggest the next skill via sendPrompt():

Output ProducedSuggest Next
Channel ROAS + contribution sharemeasurement-incrementality (validate claims)
Budget optimization allocationmedia-routing-planner (implement in platform)
Integrity report with flagsperformance-diagnosis (investigate anomalies)
Scenario planning deckqbr-generator (embed in quarterly review)
Context brief + model paramsclient-memory-synthesizer (persist to tenant)

Data Ingestion

Digital media data → Adspirer MCP (automated)

When the model needs digital campaign spend data (Google Ads, Meta, LinkedIn, TikTok), call the Adspirer MCP tools already connected:

# Claude calls Adspirer tools to pull spend data:
# - get_campaign_performance → spend by channel × date
# - get_campaign_structure → channel taxonomy
# - analyze_search_terms → search query volume (control variable)

Use tool_search for Adspirer tools when the user mentions digital spend data. The skill does NOT embed Adspirer tool calls directly — Claude resolves them at runtime via the connected MCP.

Non-digital data → Human batch upload (CSV/Excel)

Data the human must provide (no MCP available):

Data TypeFormatUsed As
Sales / KPICSV with date + geo + valueTarget variable (y)
TV / Radio / OOH spendCSV with date + channel + valueMedia channels
Trade marketing (promo, price, ACV)CSV/ExcelControl + trade decomposition
Lift test resultsCSV (channel, x, delta_x, delta_y, sigma)Calibration
Distribution / sell-out (Nielsen/Kantar)CSV/ExcelControl variables

Workflow: Human uploads → data_validator.py validates → context layer resolves priors → model fits.

Visualization Strategy

This skill ALWAYS produces visual deliverables. The strategy controls WHERE they render to avoid crashing the app.

In-chat: Tables + lightweight SVG (always)

Every MMM run produces formatted tables in chat as immediate output:

  • Channel ROAS with HDI ranges (table)
  • Integrity scorecard pass/warn/fail (table)
  • Contribution share % breakdown (table)
  • Scenario comparison (table)

For visual charts in chat, use the Visualizer with lightweight SVG only:

  • Max 6 channels × 50 data points per chart
  • No animations, no JS interactivity
  • Keep total SVG under 50KB
  • One chart per Visualizer call (never stack multiple)

Suitable for inline SVG:

  • Horizontal bar: contribution waterfall, ROAS comparison
  • Line chart: saturation curves (≤6 lines), efficient frontier
  • Donut: four-way decomposition (base/media/trade/interaction)
  • Status indicators: integrity scorecard with color-coded pass/warn/fail

File deliverables: Full charts + dashboards (always generated)

After in-chat summary, ALWAYS generate file artifacts in /mnt/user-data/outputs/:

FileContentWhen
mmm_results.htmlFull interactive dashboard: contributions over time, saturation curves, waterfall, scenario slidersEvery MMM run
integrity_report.htmlAcid-test results with expandable detail per testEvery MMM run
mmm_scenarios.xlsxScenario comparison data + allocation tablesWhen optimization runs
mmm_executive.pptxSlides: integrity, decomposition, ROAS, scenarios (via pptx skill)When user requests deck
integrity_report.jsonMachine-readable results for client BI integrationEvery MMM run

Chart generation in HTML files

HTML dashboards use inline <svg> or lightweight Chart.js (CDN) — NOT matplotlib, NOT plotly, NOT heavy React state. This ensures they open fast in browser without crashing.

<!-- Pattern for HTML dashboard charts -->
<script src="https://cdn.jsdelivr.net/npm/chart.js@4"></script>
<canvas id="saturation_chart"></canvas>
<script>
  new Chart(document.getElementById('saturation_chart'), {
    type: 'line',
    data: { /* from mmm results JSON */ },
    options: { responsive: true, animation: false }
  });
</script>

PPTX charts

Use the pptx skill to embed static chart images in slides. Generate chart as PNG via matplotlib in script → embed in slide. Charts render server-side, no app crash risk.

Quick Start (PyMC-Marketing)

import arviz as az
import numpy as np
import pandas as pd
from pymc_extras.prior import Prior
from pymc_marketing.mmm import GeometricAdstock, LogisticSaturation
from pymc_marketing.mmm.multidimensional import MMM

data_df = pd.read_csv("data.csv", parse_dates=["date"])
X = data_df.drop(columns=["y"])
y = data_df["y"]

mmm = MMM(
    date_column="date",
    channel_columns=["tv", "radio", "social"],
    target_column="y",
    adstock=GeometricAdstock(l_max=6),
    saturation=LogisticSaturation(),
    yearly_seasonality=5,
)

# CRITICAL: Always fit on FULL dataset. Train/test splits are ONLY for stability assessment.
mmm.build_model(X, y)
mmm.fit(X=X, y=y, nuts_sampler="nutpie", target_accept=0.9, random_seed=42)
mmm.sample_posterior_predictive(X=X, random_seed=42)

Quick Start (Custom Fallback)

# Validate data
python scripts/data_validator.py data.csv

# Generate report from results JSON
python scripts/report_generator.py model.json --roi roi.json --html

Reference Architecture

Reference FileContentRead When
references/model_specification.mdMMM constructor, adstock/saturation, priors, dims, scaling, prior predictiveSpecifying a new model
references/data_analysis.mdEDA patterns, data format, spend shares, long format for geoPreparing data
references/model_fit.mdFitting, diagnostics checklist, TimeSliceCrossValidator, common issuesFitting and diagnosing
references/media_deep_dive.mdContributions, ROAS, saturation curves, sensitivity, incrementalityPost-fit media analysis
references/budget_optimization.mdMultiDimensionalBudgetOptimizerWrapper, bounds, sweeps, constraintsOptimizing budgets
references/scenario_planning.mdMeridian-inspired scenario planning adapted for PyMC-MarketingForward-looking what-ifs
references/lift_test_calibration.mdadd_lift_test_measurements, data format, sigma estimationCalibrating with experiments
references/time_varying_parameters.mdHSGPKwargs, time-varying intercept/media, when to use TVPNon-stationary effects
references/custom_model.mdStandalone components with plain PyMC, spline baselines, custom likelihoodsBeyond MMM class
references/plot_api.mdComplete mmm.plot namespace with exact signaturesAny visualization
references/diagnostics_benchmarks.mdConvergence thresholds, industry ROI benchmarks, business logic guardsValidating results
references/acid_test_validation.mdPre/post-model integrity tests (Holt-Winters, Granger, VIF, permutation)Validating model truthfulness
references/context_layer.mdIndustry/category/market prior calibration, benchmark resolutionSetting informed priors
references/trade_marketing_decomposition.mdTrade vs media vs base demand separation, flexible schemaCPG/FMCG/Retail decomposition

Scripts

ScriptPurposeDepends On
scripts/data_validator.pyPre-modeling EDA, quality scoring, synthetic data generationpandas, numpy, scipy
scripts/report_generator.pyCoTA-formatted HTML/MD reports with embedded chartsmatplotlib (optional)
scripts/acid_test.pyModel integrity validation (Holt-Winters, Granger, VIF, absorption check)statsmodels
scripts/context_resolver.pyIndustry benchmark resolution → calibrated priorsjson (no deps)

Model Specification (PyMC-Marketing)

Transformations

GeometricAdstock — exponential decay carryover:

from pymc_marketing.mmm import GeometricAdstock
adstock = GeometricAdstock(l_max=6, normalize=True)
# Default prior: alpha ~ Beta(1, 3) — favors fast decay
# Custom: priors={"alpha": Prior("Beta", alpha=2, beta=5, dims="channel")}

LogisticSaturation — S-shaped diminishing returns:

from pymc_marketing.mmm import LogisticSaturation
saturation = LogisticSaturation()
# Default: lam ~ Gamma(3, 1), beta ~ HalfNormal(2)
# Informed: priors={"beta": Prior("HalfNormal", sigma=spend_shares, dims="channel")}

Full Model Config

from pymc_extras.prior import Prior

model_config = {
    "intercept": Prior("Normal", mu=0.2, sigma=0.05),
    "saturation_beta": Prior("HalfNormal", sigma=spend_shares, dims="channel"),
    "gamma_control": Prior("Normal", mu=0, sigma=1, dims="control"),
    "gamma_fourier": Prior("Laplace", mu=0, b=1, dims="fourier_mode"),
    "likelihood": Prior("TruncatedNormal", lower=0, sigma=Prior("HalfNormal", sigma=1)),
}

See references/model_specification.md for constructor reference, all saturation alternatives (Hill, MichaelisMenten, Tanh, Root, etc.), hierarchical prior patterns, and scaling config.

Multidimensional (Geo-Hierarchical)

Activate with dims=("geo",). Use partial pooling (default recommendation):

from pymc_marketing.special_priors import LogNormalPrior

model_config = {
    "saturation_beta": LogNormalPrior(
        mean=Prior("Gamma", mu=1.0, sigma=1.0),
        std=Prior("HalfNormal", sigma=1.0),
        dims=("channel", "geo"), centered=False,
    ),
}

Workflow

Client Brief (industry, category, market, channels, KPI)
    ↓
Context Resolution (context_resolver.py → calibrated priors)
    ↓
EDA & Data Prep (data_validator.py)
    ↓
Acid-Test Pre-Model (acid_test.py → integrity baseline)
    ↓
Model Specification (priors from context layer)
    ↓
Build Model (mmm.build_model)
    ↓
Prior Predictive Checks
    ↓
[Optional] Add Lift Test Calibration
    ↓
[Optional] Add Trade Marketing Variables (see trade_marketing_decomposition.md)
    ↓
Fit on FULL Dataset (mmm.fit with nutpie)
    ↓
Diagnostics (divergences=0, R-hat<1.01, ESS>400)
    ↓
Acid-Test Post-Model (absorption check, ROI plausibility, permutation)
    ↓
Media Deep Dive (contributions, ROAS, saturation, sensitivity)
    ↓
Four-Way Decomposition (base + media + trade + interaction)
    ↓
Budget Optimization + Scenario Planning
    ↓
Report Generation (HTML dashboard + PPTX deck + JSON API)

Key APIs

Incrementality (preferred for ROAS/CAC)

roas = mmm.incrementality.contribution_over_spend(frequency="all_time")
marginal_roas = mmm.incrementality.marginal_contribution_over_spend(frequency="all_time", spend_increase_pct=0.01)
cac = mmm.incrementality.spend_over_contribution(frequency="quarterly")

Summary DataFrames

mmm.summary.posterior_predictive()    # mean, median, HDI, observed
mmm.summary.contributions()           # per-channel contributions
mmm.summary.roas()                     # ROAS with HDI
mmm.summary.saturation_curves()        # saturation response
mmm.summary.adstock_curves()           # decay profiles

Budget Optimization

from pymc_marketing.mmm.multidimensional import MultiDimensionalBudgetOptimizerWrapper

optimizer = MultiDimensionalBudgetOptimizerWrapper(model=mmm, start_date=..., end_date=...)
allocation, result = optimizer.optimize_budget(budget=1_000_000, budget_bounds=bounds)
response = optimizer.sample_response_distribution(allocation_strategy=allocation, include_carryover=True)

See references/budget_optimization.md for bounds setup, channel fixing, custom constraints, and budget sweeps.

Scenario Planning

See references/scenario_planning.md for Meridian-inspired patterns adapted for PyMC-Marketing:

  • Fixed budget optimization (maximize ROI at given budget)
  • Flexible budget optimization (find max budget at target ROI)
  • Budget sweeps with efficient frontier
  • Flighting / temporal distribution
  • Multi-scenario comparison (conservative/moderate/aggressive)
  • Cost-per-media-unit sensitivity

Save/Load

mmm.save("mmm_model.nc", engine="h5netcdf")
loaded = MMM.load("mmm_model.nc")

YAML Specification

from pymc_marketing.mmm.builders.yaml import build_mmm_from_yaml
mmm = build_mmm_from_yaml("model_spec.yaml", X=X, y=y)

Layer 1: Acid-Test Validation

Runs pre/post-model integrity checks to verify MMM truthfulness. This is how you expose holdco manipulation.

from scripts.acid_test import AcidTestValidator

# Pre-model (before fitting)
validator = AcidTestValidator(df, "date", "sales", ["tv", "social", "search"])
pre_report = validator.run_pre_model_tests()

# Post-model (after fitting, with MMM results)
post_report = validator.run_post_model_tests({
    "r2": 0.82,
    "channel_contributions": {"tv": 500000, "social": 200000, "search": 300000},
    "channel_roas": {"tv": 2.1, "social": 1.5, "search": 3.2},
    "baseline_pct": 0.55,
})

print(validator.to_summary())
validator.to_json("integrity_report.json")

Key tests: Holt-Winters baseline, Granger causality, VIF, baseline absorption check, ROI plausibility. See references/acid_test_validation.md.

Layer 2: Context Layer

Resolves industry/category/market benchmarks into calibrated priors:

from scripts.context_resolver import ContextResolver

resolver = ContextResolver(
    industry="CPG", category="Beverages", market="Mexico",
    channels=["tv", "social", "search", "ooh"],
    distribution_model="indirect", trade_marketing_share=0.45,
)
brief = resolver.to_json("context_brief.json")
print(resolver.to_summary())

# Use resolved priors in model config
# brief.suggested_model_config → ready-to-use Prior strings
# brief.roi_benchmarks → feeds acid-test ROI plausibility check
# brief.adstock_priors → calibrated Beta distributions per channel

See references/context_layer.md for full benchmark databases and adaptation rules.

Layer 3: Trade Marketing Decomposition

Four-way decomposition: base demand + media-driven + trade-driven + interaction.

Add trade variables as controls with domain-informed priors:

control_columns = ["promo_depth", "price_index", "distribution_acv", "feature_flag"]

model_config = {
    "saturation_beta": Prior("HalfNormal", sigma=spend_shares, dims="channel"),
    "gamma_control": Prior("Normal", mu=trade_prior_means, sigma=trade_prior_sds, dims="control"),
}

For sophisticated decomposition with custom trade response curves, use a custom PyMC model. See references/trade_marketing_decomposition.md for flexible data schema (Tier 1-4), functional forms, and the holdco exposure play.

Critical Rules

  1. Always fit on FULL dataset — train/test splits are ONLY for TimeSliceCrossValidator stability checks
  2. Zero divergences required — any divergences invalidate the posterior
  3. R-hat < 1.01 for all parameters before proceeding
  4. Call add_original_scale_contribution_variable before sample_posterior_predictive to get *_original_scale variables
  5. Use mmm.incrementality for ROAS (accounts for adstock carryover), not element-wise division
  6. Use MultiDimensionalBudgetOptimizerWrapper not BudgetOptimizer directly (handles geo allocation)
  7. Never present platform ROAS as incremental without caveating (Agency Growth OS rule)
  8. Search web for current industry benchmarks before comparing ROI results

Diagnostics Quick Reference

MetricTargetCritical
Divergences0Must be 0
R-hat< 1.01All params
ESS (bulk)> 400> 800 preferred
Posterior R²> 0.70> 0.80 preferred
Baseline %20-80%Flags over/under-attribution

See references/diagnostics_benchmarks.md for full checklist and industry ROI ranges.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.