Generate a Mock Multi-Armed Bandit Report in Python

Simulate a multi-armed bandit experiment with random pulls and rewards, then output a JSON report with per-arm statistics.

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

Python code

36 lines
Python 3.9+
import random
import json

def generate_mock_bandit_report(num_arms=5, num_rounds=100, seed=42):
    random.seed(seed)
    arms = ["A", "B", "C", "D", "E"][:num_arms]
    true_means = {arm: random.uniform(0.3, 0.7) for arm in arms}
    pulls = {arm: 0 for arm in arms}
    rewards = {arm: 0 for arm in arms}

    for _ in range(num_rounds):
        chosen_arm = random.choice(arms)
        pulls[chosen_arm] += 1
        if random.random() < true_means[chosen_arm]:
            rewards[chosen_arm] += 1

    report = {
        "num_rounds": num_rounds,
        "total_reward": sum(rewards.values()),
        "arms": {}
    }
    for arm in arms:
        report["arms"][arm] = {
            "pulls": pulls[arm],
            "rewards": rewards[arm],
            "observed_mean": round(rewards[arm] / pulls[arm], 4) if pulls[arm] > 0 else 0.0,
            "true_mean": round(true_means[arm], 4)
        }

    best_arm = max(arms, key=lambda a: report["arms"][a]["observed_mean"])
    report["best_arm"] = best_arm
    report["best_arm_actual_reward"] = report["arms"][best_arm]["observed_mean"]
    return report

if __name__ == "__main__":
    print(json.dumps(generate_mock_bandit_report(), indent=2))

Output

stdout
{
  "num_rounds": 100,
  "total_reward": 50,
  "arms": {
    "A": {
      "pulls": 24,
      "rewards": 10,
      "observed_mean": 0.4167,
      "true_mean": 0.6535
    },
    "B": {
      "pulls": 20,
      "rewards": 12,
      "observed_mean": 0.6,
      "true_mean": 0.4858
    },
    "C": {
      "pulls": 21,
      "rewards": 9,
      "observed_mean": 0.4286,
      "true_mean": 0.6128
    },
    "D": {
      "pulls": 17,
      "rewards": 12,
      "observed_mean": 0.7059,
      "true_mean": 0.5302
    },
    "E": {
      "pulls": 18,
      "rewards": 7,
      "observed_mean": 0.3889,
      "true_mean": 0.3451
    }
  },
  "best_arm": "D",
  "best_arm_actual_reward": 0.7059
}

How it works

This code simulates a classic multi-armed bandit problem. Each arm has a 'true' probability of success (true_mean) fixed at the start. Each round, the algorithm randomly selects an arm without any exploration-exploitation strategy, so the distribution of pulls is uniform. After 100 rounds, it computes the observed mean reward per arm (rewards divided by pulls) and identifies the arm with the highest observed mean as the 'best'. The JSON output is deterministic thanks to the fixed seed, making it easy to test downstream A/B testing pipelines.

Common mistakes

  • Forgetting to set the random seed, producing non-reproducible reports.
  • Dividing by zero when an arm receives 0 pulls; the code guards with a conditional.
  • Confusing observed mean with true mean when evaluating arm performance.
  • Keying arms with non-hashable objects instead of simple strings.

Variations

  1. Use a greedy epsilon policy to allocate more pulls to promising arms.
  2. Return a pandas DataFrame instead of a nested dict for easier analysis.

Real-world use cases

  • Generating synthetic data to validate an A/B testing dashboard before real traffic arrives.
  • Creating mock reports to demo a multi-armed bandit simulation to stakeholders.
  • Testing downstream analytics code that consumes per-arm reward statistics from a JSON payload.

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.