Многорукие бандиты vs A/B-тест

Что такое многорукие бандиты

Представьте ряд игровых автоматов (one-armed bandits) в казино. У каждого автомата своя вероятность выигрыша, но вы её не знаете. Ваша задача — за N попыток заработать максимум. Если всё время играть на одном автомате — можете выбрать не лучший. Если всё время пробовать новые — потратите попытки на разведку вместо заработка.

Это и есть задача многоруких бандитов (multi-armed bandit, MAB): найти баланс между exploration (исследование новых вариантов) и exploitation (использование лучшего из известных).

В аналитике MAB — это альтернатива классическому A/B-тесту. Вместо того чтобы делить трафик 50/50 и ждать N дней, бандитский алгоритм динамически перераспределяет трафик в пользу лучшего варианта.

Exploration vs exploitation

Это центральная дилемма MAB. Два крайних подхода:

  • Чистая эксплуатация: после 10 наблюдений выбираете вариант с лучшей конверсией и направляете на него 100% трафика. Проблема: 10 наблюдений — это шум, а не сигнал. Вы можете зафиксировать неоптимальный вариант.
  • Чистое исследование: распределяете трафик поровну между вариантами всё время. Это классический A/B-тест. Проблема: вы «теряете» трафик на заведомо худших вариантах.

Бандитские алгоритмы находят золотую середину: больше трафика направляется на перспективные варианты, но и плохие получают шанс «реабилитироваться».

Алгоритмы MAB

Epsilon-greedy

Самый простой. С вероятностью (1 - epsilon) выбираем лучший вариант (exploitation), с вероятностью epsilon — случайный (exploration).

import numpy as np

class EpsilonGreedy:
    def __init__(self, n_arms, epsilon=0.1):
        self.counts = np.zeros(n_arms)
        self.values = np.zeros(n_arms)
        self.epsilon = epsilon

    def select_arm(self):
        if np.random.random() < self.epsilon:
            return np.random.randint(len(self.values))
        return np.argmax(self.values)

    def update(self, arm, reward):
        self.counts[arm] += 1
        n = self.counts[arm]
        self.values[arm] += (reward - self.values[arm]) / n

Плюс: прост как доска. Минус: epsilon фиксирован. В начале нужно больше exploration, в конце — меньше. Решение — decay epsilon (уменьшать со временем).

UCB (Upper Confidence Bound)

Идея: выбираем вариант с максимальной верхней границей доверительного интервала. Варианты с малым количеством наблюдений имеют широкий интервал — и получают бонус за неопределённость.

class UCB:
    def __init__(self, n_arms):
        self.counts = np.zeros(n_arms)
        self.values = np.zeros(n_arms)

    def select_arm(self, t):
        # Сначала попробовать каждый вариант хотя бы раз
        for arm in range(len(self.counts)):
            if self.counts[arm] == 0:
                return arm

        ucb_values = self.values + np.sqrt(
            2 * np.log(t) / self.counts
        )
        return np.argmax(ucb_values)

    def update(self, arm, reward):
        self.counts[arm] += 1
        n = self.counts[arm]
        self.values[arm] += (reward - self.values[arm]) / n

Формула UCB: среднее вознаграждение + бонус за неопределённость. Чем меньше наблюдений у варианта, тем выше бонус. Со временем бонус уменьшается, и алгоритм фокусируется на лучших вариантах.

Thompson Sampling

Самый мощный и элегантный алгоритм. Использует байесовский подход: для каждого варианта поддерживаем апостериорное распределение вероятности успеха. На каждом шаге сэмплируем из распределения каждого варианта и выбираем вариант с максимальным сэмплом.

class ThompsonSampling:
    def __init__(self, n_arms):
        # Beta-распределение: alpha = успехи + 1, beta = неудачи + 1
        self.alpha = np.ones(n_arms)
        self.beta = np.ones(n_arms)

    def select_arm(self):
        samples = np.random.beta(self.alpha, self.beta)
        return np.argmax(samples)

    def update(self, arm, reward):
        if reward == 1:
            self.alpha[arm] += 1
        else:
            self.beta[arm] += 1

Почему это работает: если у варианта мало данных — его распределение широкое, и иногда сэмпл будет высоким (exploration). Если вариант стабильно хороший — его распределение узкое и сдвинуто вправо (exploitation). Баланс возникает автоматически.

MAB vs A/B-тест: сравнение

Критерий A/B-тест MAB
Распределение трафика Фиксированное (50/50) Динамическое
Статистическая строгость Высокая (контроль ошибок I и II рода) Ниже (нет чёткого p-value)
Потери на тесте Выше (50% трафика на худшем варианте) Ниже (трафик смещается к лучшему)
Время до результата Фиксированное (по расчёту выборки) Адаптивное
Интерпретируемость Высокая Средняя
Количество вариантов 2-3 (больше — сложнее) Десятки (естественное масштабирование)
Стационарность Предполагается Может адаптироваться к изменениям

Когда использовать A/B-тест

  • Нужна строгая статистическая валидность (запуск новой фичи, изменение pricing).
  • Важен точный размер эффекта (ATE) с доверительным интервалом.
  • Есть достаточно трафика, чтобы позволить себе ошибки в A/B-тестах были маловероятны.
  • Результат должен быть воспроизводим и документирован.

Когда использовать MAB

  • Персонализация: рекомендации, заголовки, баннеры — нужно быстро находить лучший вариант для каждого сегмента.
  • Много вариантов: 10+ версий лендинга — A/B-тест потребует огромного трафика, MAB справится.
  • Цена ошибки — упущенная выручка: каждый показ худшего варианта — потерянные деньги (реклама, e-commerce).
  • Нестационарная среда: предпочтения пользователей меняются со временем, и MAB адаптируется.

Преимущества и недостатки MAB

Преимущества:

  • Минимизирует regret — суммарные потери от показа неоптимальных вариантов.
  • Естественно масштабируется на много вариантов.
  • Быстрее «находит» лучший вариант и начинает его эксплуатировать.

Недостатки:

  • Нет чёткого момента «тест закончен» — сложнее принять финальное решение.
  • Труднее оценить статистическую значимость и размер эффекта.
  • Сложнее объяснить бизнесу: «мы не знаем точный uplift, но мы минимизировали потери».
  • Неприменим, когда нужно понять долгосрочный эффект (LTV, retention) — бандит оптимизирует краткосрочную метрику.

Практические применения

  • Яндекс, Google: подбор вариантов рекламных объявлений. Тысячи вариантов заголовков — A/B-тест невозможен, бандит находит лучшие.
  • Netflix, Кинопоиск: персонализация обложек фильмов. Разным пользователям — разные обложки. MAB определяет, какая обложка лучше конвертирует в просмотр.
  • E-commerce: динамическое ценообразование. MAB подбирает оптимальную цену, балансируя между исследованием (попробовать новую цену) и заработком (продавать по лучшей).
  • Push-уведомления: выбор оптимального времени отправки для каждого пользователя.

Вопросы с собеседований

Чем многорукие бандиты отличаются от A/B-теста?

A/B-тест — фиксированное распределение трафика на весь период эксперимента, строгая статистическая валидность, чёткий момент принятия решения. MAB — динамическое перераспределение трафика в пользу лучшего варианта, минимизация потерь, но без строгих статистических гарантий.

Что такое Thompson Sampling?

Байесовский алгоритм MAB. Для каждого варианта поддерживаем апостериорное распределение вероятности успеха (обычно Beta-распределение). На каждом шаге сэмплируем из каждого распределения и выбираем вариант с максимальным сэмплом. Автоматически балансирует exploration и exploitation.

Когда MAB не подходит?

Когда нужна строгая оценка размера эффекта с доверительным интервалом. Когда важен долгосрочный эффект (бандит оптимизирует краткосрочную метрику). Когда результат эксперимента должен быть воспроизводим и задокументирован для принятия стратегического решения.

Что такое regret в контексте MAB?

Regret — разница между суммарным вознаграждением при всегда оптимальном выборе и реальным суммарным вознаграждением. Чем лучше алгоритм, тем ниже regret. Thompson Sampling и UCB имеют regret порядка O(log N), epsilon-greedy — O(N) при фиксированном epsilon.

FAQ

Можно ли совместить MAB и A/B-тест?

Да. Распространённый подход: сначала запустить классический A/B-тест для строгой оценки эффекта, а затем перейти на MAB для оптимизации. Или использовать MAB для предварительного скрининга 20 вариантов, а потом A/B-тестировать топ-2.

Thompson Sampling или UCB — что лучше?

На практике Thompson Sampling обычно показывает лучшие результаты, особенно при малом числе наблюдений. UCB более «агрессивен» в exploration. Thompson Sampling проще масштабируется на задачи с контекстом (contextual bandits). Для начала — Thompson Sampling.

Используют ли MAB в российских компаниях?

Да. Яндекс использует бандитов в рекламных системах и рекомендациях. Тинькофф — для персонализации предложений. Ozon — для подбора сортировки и рекомендаций. На собеседованиях в эти компании вопросы про MAB — не редкость.


Потренируйте вопросы по A/B-тестам и статистике на реальных задачах — откройте тренажёр. 1500+ вопросов, которые спрашивают на собеседованиях аналитика. Бесплатно.