Как байесовское мышление влияет на принятие решений в вероятностном мире

Мы живем в неопределенности, и время от времени нам приходится делать выбор, когда у нас есть несколько вариантов, о которых мы мало знаем. И со временем, если мы сталкиваемся с одними и теми же вариантами снова и снова, мы сможем узнать, какой вариант имеет тенденцию давать нам максимальное вознаграждение, какой из них является вторым лучшим и т. Д. В общем, это можно сказать о человеческий процесс обучения, руководствуясь нашей целью максимизировать общее вознаграждение (или минимизировать общие потери или сожаления).

Более того, таким же образом можно смоделировать некоторые важные бизнес-приложения. Подумайте о следующих ситуациях:

(1) Учитывая множество биржевых тикеров, каждый из которых имеет разную доходность, как бы вы рационально выбрали те, которые позволили бы максимизировать вашу доходность?

(2) Есть три дизайна целевой страницы веб-сайта, которые вы хотели бы опробовать. Как бы вы выбрали дизайн, который максимизирует ваш показатель, например коэффициент конверсии?

(3) Предположим, вы хотите продвигать свой бизнес и иметь три разных места для рекламы. Как бы вы выбрали одно место, которое дает вам наилучшую отдачу от вашего бюджета?

Все эти реалистичные бизнес-проблемы можно легко абстрагировать в следующем сценарии:

Предположим, у вас есть N игровых автоматов (или бандитов), каждый из которых со своей вероятностью предоставит вам награду R. Как вы определяете, какой игровой автомат выбрать с течением времени, чтобы получить как можно большую награду?

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

Байесовские бандиты

Байесовские бандиты предлагают интуитивное решение проблемы. Как правило, это следующие шаги:

  1. Сделайте свое первоначальное предположение о вероятности того, что каждый бандит даст награду. На языке статистики это означает предположение об определенном предварительном распределении по поведению (давать или нет) каждого бандита. И поскольку мы пытаемся моделировать вероятности, удобным предварительным распределением будет бета-распределение, которое обычно используется для моделирования случайной величины от 0 до 1. Обратите внимание, что если вы абсолютно ничего не знаете о базовом распределении поведения бандитов, ваше рациональным предположением было бы рассматривать каждого бандита как равного, а именно предполагать равномерное распределение, которое является частным случаем бета-распределения.
  2. Возьмите выборку от каждого бандита на основе его текущего распределения.
  3. Сосредоточьтесь на бандите с наивысшей пробой; определите размер вознаграждения (сожаления), которое вы получите, выбрав его, и соответствующим образом обновите распределение бандитов. На языке статистики у вас есть предварительное распределение с определенными параметрами по случайной величине, и теперь, когда у вас есть новое наблюдение за значением случайной переменной, вы можете обновить свое прежнее мнение о случайной величине. переменная, применяя правило Байеса для выявления апостериорного распределения; Конечным результатом является новый набор параметров распределения для учета нового наблюдения:

Предварительное распределение: P (A)

Новое наблюдение: x

Апостериорное распределение: P (A | x) ~ P (x | A) * P (A)

а именно, апостериорное распределение пропорционально правдоподобию * априорному распределению

4. Вернитесь к шагу 2 и повторите.

Моделирование

Давайте посмотрим на конкретный пример с некоторым кодом.

Перво-наперво, давайте импортируем необходимые пакеты:

import numpy as np
from scipy.stats import beta
import matplotlib.pyplot as plt

Давайте определимся с нашими бандитами; эти числа обозначают вероятность того, что соответствующий бандит выдаст награду, и вы можете свободно изменять эти числа и запускать различные симуляции:

bandits = np.array([0.75, 0.5, 0.6])

Теперь, когда основные принципы очищены, следующая функция иллюстрирует ядро ​​байесовских бандитов:

def experiment(accumulated_rewards_per_bandit, times_chosen_per_bandit, bandits, num_draws=1):
    
    for _ in range(num_draws):
        bandit_chosen =    np.argmax(np.random.beta(1+accumulated_rewards_per_bandit, 1+times_chosen_per_bandit-accumulated_rewards_per_bandit))
        reward = get_reward_from_bandit_i(bandits, bandit_chosen)
        
        accumulated_rewards_per_bandit[bandit_chosen] += reward
        times_chosen_per_bandit[bandit_chosen] += 1
    a = 1+accumulated_rewards_per_bandit
    b = 1+times_chosen_per_bandit-accumulated_rewards_per_bandit
    return a, b

Давайте разберем функцию построчно. Прежде всего, давайте укажем входные аргументы:

Accumulated_rewards_per_bandit: общее количество наград, накопленных на бандита за испытания в одном эксперименте, размер которого равен количеству бандитов.

times_chosen_per_bandit: количество раз, когда каждый бандит был выбран за испытания в одном эксперименте, его размер равен количеству бандитов.

бандиты: наши бандиты с разной вероятностью вознаграждения.

num_draws: количество испытаний в одном эксперименте

Напомним, что по сути мы стремимся лучше понять вероятности вознаграждения различных бандитов, что означает, что мы пытаемся получить все более и более точную оценку основных распределений, которые в нашем случае все являются бета-распределениями.

Обратите внимание, что бета-распределение однозначно определяется двумя параметрами a и b, которые в нашем примере обозначают количество испытаний, за которые бандит получает вознаграждение (равное накопленным вознаграждениям в нашем пример) и количество испытаний, в которых бандит не получил награды соответственно.

Таким образом, наша цель состоит в том, чтобы вести точный подсчет этих двух величин в ходе испытаний.

Теперь должно быть ясно, чего мы пытаемся достичь в функции выше. Перебирая количество испытаний, мы сначала определяем бандита, который дает наибольшую выборку, а затем определяем, получаем ли мы какую-либо награду, выбирая этого бандита в следующей строке:

reward = get_reward_from_bandit_i(bandits, bandit_chosen)

Здесь я использую следующую наивную реализацию для определения вознаграждения:

def get_reward_from_bandit_i(bandits, i):
    return np.random.rand() < bandits[i]

Вы можете видеть, что эта реализация приводит к вознаграждению, равному 1 или 0. На практике вы можете разработать свой собственный механизм вознаграждения, отражающий характер вашей проблемы.

После получения награды (или ее отсутствия) мы можем обновить накопленные награды и время, выбранное для нашего отобранного бандита, которые будут служить в качестве обновленных параметров бета-распределения a и b в следующей итерации.

Наконец, пройдя все испытания, мы получаем полностью обновленные параметры распределения и возвращаем их.

Теперь у нас есть основные компоненты байесовских бандитов, и давайте приступим к запуску моделирования, используя следующий фрагмент кода:

if __name__ == "__main__":
    bandits = np.array([0.75, 0.5, 0.6])
    num_draws_per_experiment = [300]
    accumulated_rewards_per_bandit = np.zeros(bandits.size)
    times_chosen_per_bandit = np.zeros(bandits.size)
    for i in num_draws_per_experiment:
        a, b = experiment(accumulated_rewards_per_bandit, times_chosen_per_bandit, bandits, i)

Полученные результаты

Похоже, нам нужен способ определить, насколько хорошо мы делаем. В этой статье давайте попробуем построить функции плотности вероятности для каждого набора параметров бета-распределения и посмотреть, показывают ли они какие-либо заметные закономерности.

Давайте задействуем эту функцию:

def plot_beta(x_range, a, b, filename):
    x = x_range
    y0 = beta.pdf(x, a[0], b[0])
    y1 = beta.pdf(x, a[1], b[1])
    y2 = beta.pdf(x, a[2], b[2])
    plt.plot(x, y0, color='red', lw=2, ls='-', alpha=0.5, label='pdf: 1st bandit')
    plt.plot(x, y1, color='green', lw=2, ls='-', alpha=0.5, label='pdf: 2nd bandit')
    plt.plot(x, y2, color='blue', lw=2, ls='-', alpha=0.5, label='pdf: 3rd bandit')
    plt.legend()
    plt.savefig(filename)

Запустив функцию построения графика для разного количества испытаний, мы получим следующие графики в формате pdf:

Обратите внимание, как первый бандит (красный), с максимальной вероятностью вознаграждения 0,75, постепенно побеждает после 100 испытаний, поскольку форма его бета-распределения сужается и достигает пика около 0,75 от истинного значения, тогда как формы распределений другого два бандита по-прежнему относительно плоские и рассредоточенные, что намекает на неопределенность.

Хотя при достаточно большом количестве испытаний распределение для каждого бандита будет иметь тенденцию достигать пика около истинного значения вероятности вознаграждения, в этой задаче нас больше интересует поиск лучшего бандита, а не точный вывод скрытых вероятностей вознаграждения. В нашу симуляцию можно внести несколько улучшений: например, скорость обучения (›1 или‹ 1) может быть применена к обновлению накопленных вознаграждений, чтобы точно настроить, будем ли мы придерживаться текущего хорошего варианта или изучите другие варианты подробнее.

В следующих статьях я продемонстрирую, как байесовские бандиты помогают построить динамический инвестиционный портфель акций, который можно смоделировать как бандитов с лежащими в основе вероятностями вознаграждения, которые меняются со временем. Так что следите за мной и следите за новостями.