Skip to content
AI360XpertBeta

Multi-Armed Bandits

One state, several levers, unknown payouts: the smallest possible setup that still forces you to choose between cashing in and finding out.

Two levers after twelve pulls: arm1 pays 0.70 over 8 pulls for a UCB of 1.4882 while arm2 pays 0.50 over 2 pulls for 2.0764, so uncertainty wins the next pull
Two levers after twelve pulls: arm1 pays 0.70 over 8 pulls for a UCB of 1.4882 while arm2 pays 0.50 over 2 pulls for 2.0764, so uncertainty wins the next pull

Why Does This Exist?

Every agent faces one tension before all others: play the current best or test the rest. Full RL tangles that tension with states, transitions, and delayed rewards. Bandits isolate it. One state, kk actions called arms, each paying from a fixed unknown distribution with true mean μa\mu_a. Pull for TT rounds, keep the total. That is the whole problem, named for the casino row of lever machines in Sutton and Barto (Chapter 2).

Solving it well matters beyond casinos: trial allocation, ad placement, and any A/B choice with a cost per sample. The rules invented here, UCB1 from Auer and colleagues (2002) and Thompson sampling from Thompson (1933), became the selection rules inside tree search and exploration bonuses everywhere. For the general tension see exploration vs exploitation; for the two smart rules see upper confidence bound and Thompson sampling.

The one idea you need first

An action value Q(a)Q(a) estimates the mean payout μa\mu_a of one arm. The agent pulls, observes a reward, and nudges the estimate. Everything on this page is about which arm to pull next given those estimates, nothing about states or futures.

Think of It Like This

Checkout lanes at a huge grocery store

Your store has twelve lanes. Lane 3 has a veteran cashier and usually moves fast. Lane 7 just opened with someone new who might be faster. Every visit you pick one lane. Always picking lane 3 is exploitation: steady, but you never learn about lane 7. Trying lane 7 is exploration with a real price: a slow cart ahead of you.

A good rule mixes both: mostly lane 3, plus lane 7 exactly when it has been ignored long enough that its unknown speed outweighs its average. That bonus for the long ignored lane is the uncertainty term in UCB.

Where it stops: store lanes drift with crowds and staffing, while the basic bandit assumes fixed payout rates. Shoppers also see queue lengths before choosing, but a bandit agent sees only its own past rewards.

How It Actually Works

Each arm aa pays rewards with unknown mean μa\mu_a. The agent tracks Q(a)Q(a), usually the sample average, updated incrementally so no history is stored. After the nnth pull of arm aa pays RR:

Q(a)←Q(a)+R−Q(a)nQ(a) \leftarrow Q(a) + \frac{R - Q(a)}{n}

The new reward moves the average by one nnth of the surprise. Estimates in hand, three standard rules pick the next arm:

  • Epsilon-greedy. With probability 1−ε1 - \varepsilon pull the current best arm, else pull uniformly at random. One knob, no memory of which arm needs testing most.
  • UCB1. Pull arg⁡max⁡a(Q(a)+2ln⁡t/N(a))\arg\max_a \left( Q(a) + \sqrt{2 \ln t / N(a)} \right) with tt total pulls and N(a)N(a) pulls of arm aa. The bonus is large for rarely pulled arms and decays for tested ones: optimism in the face of uncertainty.
  • Thompson sampling. Keep a posterior belief over each μa\mu_a, sample one plausible mean per arm, pull the highest sample. Winners get pulled more, losers still get sampled when beliefs overlap.

Success is measured by regret: the gap between always pulling the true best arm and what the rule actually banked. Good rules keep expected regret growing sublinearly, typically O(ln⁡T)O(\ln T) for UCB1, so the average shortfall per round shrinks toward zero.

Worked example

Arm estimates after 1212 total pulls: arm1 at Q=0.70Q = 0.70 over n=8n = 8, arm2 at Q=0.50Q = 0.50 over n=2n = 2. Since ln⁡12≈2.4849\ln 12 \approx 2.4849:

UCB(arm1)=0.70+2×2.4849/8=0.70+0.7882=1.4882\text{UCB}(\text{arm1}) = 0.70 + \sqrt{2 \times 2.4849 / 8} = 0.70 + 0.7882 = 1.4882 UCB(arm2)=0.50+2×2.4849/2=0.50+1.5764=2.0764\text{UCB}(\text{arm2}) = 0.50 + \sqrt{2 \times 2.4849 / 2} = 0.50 + 1.5764 = 2.0764

The next pull goes to arm2 despite the worse average: two pulls is too little evidence. Suppose arm2 then pays 3.003.00 on its 3rd counted pull while its average sat at 1.501.50 after earlier rounds. The incremental update gives 1.50+(3.00−1.50)/5=1.801.50 + (3.00 - 1.50) / 5 = 1.80 when that reward is the 5th observation. One surprise moves a young average fast and an old average barely, which is exactly what the 1/n1/n step does. The diagram draws the 1.48821.4882 against 2.07642.0764 decision.

Code

This snippet replays the worked example: one incremental average update and one UCB1 decision.

import math

def incremental_mean(q: float, n_new: int, reward: float) -> float:    """Fold the newest reward into the average; n_new counts this pull."""    return q + (reward - q) / n_new

def ucb1(q: float, n: int, t: int) -> float:    """UCB1 score for one arm after t total pulls."""    return q + math.sqrt(2 * math.log(t) / n)

print(f"Q new={incremental_mean(1.50, 5, 3.00):.4f}")  # -> Q new=1.8000print(f"arm1={ucb1(0.70, 8, 12):.4f}")  # -> arm1=1.4882print(f"arm2={ucb1(0.50, 2, 12):.4f}")  # -> arm2=2.0764

The printout matches the hand arithmetic: 1.801.80 for the update and 1.48821.4882 against 2.07642.0764 for the decision, so arm2 gets the next pull.

Watch Out For

Averaging with 1/n after the payouts move

The incremental rule weights every reward equally, which is only right when μa\mu_a never changes. If payouts drift, ancient rewards anchor the average and the agent keeps pulling a dead arm. Symptom: the estimated best lags reality by weeks while fresh rewards disagree with it. Fix: replace 1/n1/n with a constant step α\alpha, so recent rewards count more and the estimate tracks the drift.

Exploring uniformly forever with epsilon-greedy

Fixed ε\varepsilon keeps spending the same share of pulls on random arms even after the ranking is certain, so regret grows linearly instead of logarithmically. Symptom: total reward trails UCB1 by a widening gap as TT grows, with no late recovery. Fix: decay ε\varepsilon over time, or switch to UCB1 or Thompson sampling, which concentrate exploration exactly where uncertainty remains.

The Quick Version

  • A bandit is one state with kk unknown payout distributions, isolating the choice between cashing in and finding out.
  • Averages update incrementally with Q←Q+(R−Q)/nQ \leftarrow Q + (R - Q)/n, so no reward history needs storing.
  • Epsilon-greedy explores blindly, UCB1 adds an uncertainty bonus 2ln⁡t/N(a)\sqrt{2 \ln t / N(a)}, Thompson sampling pulls the best of sampled beliefs.
  • Regret measures the shortfall against always playing the true best arm; UCB1 keeps it growing only logarithmically.
  • Fixed payout rates are assumed; drifting payouts need a constant step size so estimates track instead of anchor.