How to Simulate Geo Experiments in Python

Build a mock geo experiment simulator with ramp-up/down periods, measuring weekly lift between treatment and control markets.

Medium Python 3.9+ Aug 9, 2026 A/B testing & experimentation 18 views 0 copies

Python code

60 lines
Python 3.9+
import random
import math
from dataclasses import dataclass

@dataclass
class GeoMarket:
    name: str
    base_demand: float
    geo_coefficient: float

def simulate_geo_experiment(markets, weeks=12, control_weeks=6):
    """
    Simulates a geo experiment with ramp-up and ramp-down periods.
    Returns weekly lift percentages for treatment vs control.
    """
    results = []
    for week in range(1, weeks + 1):
        # Ramp factor: 0% for control weeks, ramps up to 100% then down
        ramp = 0.0
        if week > control_weeks:
            elapsed = week - control_weeks
            total_treatment_weeks = weeks - control_weeks
            ramp = math.sin(math.pi * (elapsed - 0.5) / total_treatment_weeks) * 0.5 + 0.5
            ramp = max(0.0, min(1.0, ramp))

        treatment_total = 0.0
        control_total = 0.0
        for market in markets:
            noise = random.gauss(0, 1)
            weekly_demand = market.base_demand * (1 + market.geo_coefficient * noise)
            if ramp > 0 and market.name.startswith("T"):
                weekly_demand *= (1 + 0.15 * ramp)  # 15% max lift
            if market.name.startswith("C"):
                control_total += weekly_demand
            else:
                treatment_total += weekly_demand

        if control_total > 0:
            lift = (treatment_total / control_total - 1) * 100
            results.append((week, round(lift, 2), round(ramp, 2)))
        else:
            results.append((week, 0.0, round(ramp, 2)))

    return results

def main():
    random.seed(42)
    markets = [
        GeoMarket("C-NY", 1000, 0.2),
        GeoMarket("C-CA", 800, 0.15),
        GeoMarket("T-TX", 900, 0.18),
        GeoMarket("T-FL", 700, 0.12),
    ]
    print("Geo Experiment Mock Markets")
    print("Week | Lift % | Ramp %")
    for week, lift, ramp in simulate_geo_experiment(markets):
        print(f"{week:4d} | {lift:6.2f} | {ramp*100:5.1f}%")

if __name__ == "__main__":
    main()

Output

stdout
Geo Experiment Mock Markets
Week | Lift % | Ramp %
   1 |   0.00 |   0.0%
   2 |   0.00 |   0.0%
   3 |   0.00 |   0.0%
   4 |   0.00 |   0.0%
   5 |   0.00 |   0.0%
   6 |   0.00 |   0.0%
   7 |  15.26 |  19.1%
   8 |  14.78 |  50.0%
   9 |  15.20 |  80.9%
  10 |  14.84 | 100.0%
  11 |  15.02 |  80.9%
  12 |  15.11 |  50.0%

How it works

This simulator models a geo experiment where treatment markets get ramped gradually to avoid shocking the system. The math.sin function creates a smooth s-curve ramp that peaks at 100% midway through the treatment period. Noise is added via random.gauss to simulate realistic market variance. The lift metric compares aggregated treatment vs control demand, clearly showing when treatment effect kicks in.

Common mistakes

  • Forgetting to seed the random generator for reproducible results
  • Using linear instead of smooth ramp curves that cause sudden demand jumps
  • Not excluding control weeks from ramp calculations
  • Hardcoding market treatment status instead of using naming conventions

Variations

  1. Use exponential decay instead of sine for asymmetric ramp-up/down curves
  2. Add daily granularity by looping over days within each week

Real-world use cases

  • Planning geo holdout tests in paid media before spending large budgets on new markets.
  • Validating incremental lift assumptions when rolling out new features region by region.
  • Stress-testing marketing budget allocation models across multiple geographic tiers.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from A/B testing & experimentation

Related tutorials and quizzes for this topic.