pytyche.analysis.thompson_allocation¶
- pytyche.analysis.thompson_allocation(posterior, segments, epsilon=0.02)[source]¶
Per-segment traffic split: each arm’s weight is the posterior probability that it is the segment’s best arm.
This is Thompson sampling at segment granularity. Each posterior draw casts one vote per segment: the draw’s treatment-vs-control contrasts are averaged over the segment’s members, and the vote goes to the treatment with the largest contrast — or to control, when no contrast is positive. An arm’s weight is the fraction of draws it wins. Where the posterior is confident, traffic concentrates on the winner; where arms are still close, traffic stays spread across the contenders, so the next round collects evidence exactly where the decision is open.
- Parameters:
posterior (
HurdleBCFResult|ContinuousBCFResult|BinaryBCFResult) – One of the three posterior result types, carrying observed data (raises otherwise).segments (
Sequence[DiscoveredSegment]) – Segments to allocate over — typicallyfit_policy_tree(...).segments. Onlyidandruleare consumed. Membership is each segment’s rule applied to the concatenated visitor rows (all ofvariants[0]’s rows, thenvariants[1]’s, and so on — the same row order every per-visitor sample array uses).epsilon (
float) – Safety-net exploration floor: arms whose win frequency falls belowepsilon / Kare raised to exactlyepsilon / Kand the rest rescaled to preserve sum-to-1, iterating until stable — so no arm’s traffic is starved to zero. Inert when every arm is already above the floor;0.0returns raw win frequencies verbatim. This is NOT the dial for how much traffic stays on control — that ismin_control_weight/min_explore_weightonpt.sequential_experiment. In the canonical Control + Explore + Optimized cell structure this floor is mostly redundant; rarely worth overriding.
- Return type:
dict[int,dict[str,float]]- Returns:
{segment.id: {variant_name: weight}}— inner dicts in variant order (control first), control included, summing to 1.- Raises:
ValueError – When
posterior.observedisNone; when epsilon is outside[0, 1](the floor-clip is only well-defined on that range —epsilon > 1would demand per-arm floors that cannot sum to 1); or when a segment’s rule matches zero visitors (an empty mean over members would silently produce NaN weights).TypeError – When posterior is not an accepted result type.