В этой статье учимся использовать метод Монте-Карло для прогнозирования вероятностей. Что такое моделирование методом Монте-Карло? Моделирование Монте-Карло – это тип вычислительного алгоритма, оценивающий вероятность возникновения неопределенного события из-за участия случайных величин. Алгоритм основан на повторной случайной выборке в попытке определить вероятность. Это означает моделирование событий со случайными входными данными большое число раз для получения оценки. Также определяются и другие факторы, которые будут видны на примере. Моделирование по методу Монте-Карло используется в экономике, азартных играх, машиностроении, энергетической отрасли. Поэтому знание этого метода будет полезно для многих областей. Модель Монте-Карло легко понять на примере игры в кости. Игра в кости В этой игре будут задействованы 2 шестигранных кубика. Для выигрыша игроку требуется выбросить одинаковое число на обоих кубиках. Шестигранный кубик имеет 6 возможных исходов (1, 2, 3, 4, 5 и 6). С двумя кубиками 36 возможных исходов (1 и 1, 1 и 2, 1 и 3 и т. д., или 6 х 6 = 36 вариантов). В этой игре у заведения больше шансов на победу (30 исходов против 6 у игроков), следовательно, у заведения значительное преимущество. Предположим, игрок начинает с баланса в 1000$ и готов проиграть все, поэтому ставит 1$ на каждый бросок (оба кубика) и решает сделать 1000 бросков. Предположим, что заведение щедрое и выплата будет в 4 раза больше ставки, когда игрок выигрывает. Например, если игрок выиграет первый бросок, баланс увеличится на 4$, и раунд закончится с 1004$. Если чудом получится выиграть серию из 1000 бросков, то итого получится 5000$. В случае каждого неудачного раунда получится 0$. Импорт библиотек Python Смоделируем игру, чтобы выяснить, сделал ли игрок правильный выбор. Начнем код с импорта необходимых библиотек Python: Pyplot из Matplotlib и random. Для визуализации результатов будет использоваться библиотека Pyplot, для моделирования броска шестигранной игральной кости – random. # Импорт библиотек import matplotlib.pyplot as plt import random Функция броска кубиков Далее определим функцию, которая будет выдавать случайное целое число от 1 до 6 для обеих костей (имитация броска). Функция будет сравнивать значение обеих костей и возвращать логическое значение – одинаковы броски или нет. Позже это значение будет использоваться для определения действий в коде. # Создаем функцию броска кубика def roll_dice(): die_1 = random.randint(1, 6) die_2 = random.randint(1, 6) # Определим является ли значение на костях одинаковым if die_1 == die_2: same_num = True else: same_num = False return same_num Входные данные и отслеживаемые переменные Каждое моделирование методом Монте-Карло требует знание входных данных и информации, которую требуется получить. Входные данные определены, когда описывалась игра. Количество бросков за игру 1000 раз, сумма за бросок 1$. В дополнение требуется определить – сколько раз игра будет моделироваться. В качестве счетчика Монте-Карло используем переменную num_simulations. Чем больше это число, тем точнее прогнозируемая вероятность соответствует истинному значению. Число переменных, которые возможно отслеживать, растет с ростом сложности проекта, поэтому требуется определить, какая информация нужна. В данном примере будет отслеживаться вероятность выигрыша (выигрыш за игру, деленный на общее число бросков) и конечный баланс для каждой симуляции (игры). Эти переменные будут инициализироваться, как списки и будут обновляться в конце каждой игры. # Входные данные num_simulations = 10000 max_num_rolls = 1000 bet = 1 # Отслеживаемые переменные win_probability = [] end_balance = [] Настройка фигуры Следующий шаг – это настройка фигуры перед запуском симуляции: это позволит добавлять линии к рисунку после каждой игры. После запуска всех симуляций отобразим график, чтобы показать результаты. # Создание фигуры, для симуляции баланса fig = plt.figure() plt.title("Monte Carlo Dice Game [" + str(num_simulations) + " simulations]") plt.xlabel("Roll Number") plt.ylabel("Balance [$]") plt.xlim([0, max_num_rolls]) Моделирование Монте-Карло В коде ниже 2 цикла: внешний, который перебирает заданное кол-во симуляций (10000) и вложенный, который запускает каждую игру (1000 бросков). Перед запуском каждого цикла while инициализируется: баланс игрока как 1000$(в виде списка для построения графиков); количество бросков и выигрышей. Цикл while будет моделировать игру на 1000 бросков. Внутри этого цикла бросаются кости, используя логическую переменную, возвращаемую функцией roll_dice() для определения результата. Если кости одинаковые – в список баланса добавляется 4-кратная ставка и выигрыш к счету игрока. Если кости разные – вычитается ставка из списка баланса. В конце каждого броска добавляем счетчик в список num_rolls. Как только количество бросков достигло 1000, рассчитываем вероятность выигрыша игрока, как количество выигрышей, деленное на общее количество бросков. Сохраняем конечный баланс завершенной игры в отслеживаемой переменной end_balance. # Цикл for запускает желаемое количество симуляций for i in range(num_simulations): balance = [1000] num_rolls = [0] num_wins = 0 # Выполняется до тех пор пока игрок не выкинет 1000 раз while num_rolls[-1] < max_num_rolls: same = roll_dice() # Результат если кости одинаковые if same: balance.append(balance[-1] + 4 * bet) num_wins += 1 # Результат если кости разные else: balance.append(balance[-1] - bet) num_rolls.append(num_rolls[-1] + 1) # Сохраняем отслеживаемую переменную и добавляем строку к рисунку win_probability.append(num_wins/num_rolls[-1]) end_balance.append(balance[-1]) plt.plot(num_rolls, balance) Получение результатов Последний шаг – вывод осмысленных данных из отслеживаемых переменных. Отобразим фигуру (показанную ниже), созданную в цикле for. Также рассчитаем и отобразим общую вероятность выигрыша и конечный баланс, усредняя списки win_probability и end_balance. # Выведем график после завершения моделирования plt.show() # Усредненная вероятность выигрыша и конечного баланса overall_win_probability = sum(win_probability)/len(win_probability) overall_end_balance = sum(end_balance)/len(end_balance) # Вывод средних значений print("Average win probability after " + str(num_simulations) + " runs: " + str(overall_win_probability)) print("Average ending balance after " + str(num_simulations) + " runs: $" + str(overall_end_balance)) Моделирование игры в кости: Average win probability after 10000runs: 0.16666139999999954 Average ending balance after 10000runs: $833.307 Анализ результатов Сделаем вывод из результатов. Из рисунка выше возможно определить, что игрок редко получает прибыль после 1000 бросков. Средний конечный баланс 10000 симуляций составляет 833,66$ (из-за рандомизации, возможны различия результатов). Казино остается в выигрыше даже, если выплачивает в четыре раза больше при победе игрока. Также заметим, что вероятность выигрыша составляет 0.1667 или 1/6. Выше было отмечено, что у игрока 6 выигрышных исходов из 36 возможных. Используя эти 2 числа ожидаемо, что игрок выиграет 6 из 36 бросков, или 1/6 бросков, что соответствует прогнозу Монте-Карло. *** Материалы по теме 🎲 Зачем в науке о данных нужны теория вероятностей и статистика Тест по теории вероятностей, который заставит поломать голову Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека питониста» Интересно, перейти к каналу
Моделирование Монте-Карло – это тип вычислительного алгоритма, оценивающий вероятность возникновения неопределенного события из-за участия случайных величин. Алгоритм основан на повторной случайной выборке в попытке определить вероятность. Это означает моделирование событий со случайными входными данными большое число раз для получения оценки. Также определяются и другие факторы, которые будут видны на примере. Моделирование по методу Монте-Карло используется в экономике, азартных играх, машиностроении, энергетической отрасли. Поэтому знание этого метода будет полезно для многих областей. Модель Монте-Карло легко понять на примере игры в кости.
В этой игре будут задействованы 2 шестигранных кубика. Для выигрыша игроку требуется выбросить одинаковое число на обоих кубиках. Шестигранный кубик имеет 6 возможных исходов (1, 2, 3, 4, 5 и 6). С двумя кубиками 36 возможных исходов (1 и 1, 1 и 2, 1 и 3 и т. д., или 6 х 6 = 36 вариантов). В этой игре у заведения больше шансов на победу (30 исходов против 6 у игроков), следовательно, у заведения значительное преимущество.
Предположим, игрок начинает с баланса в 1000$ и готов проиграть все, поэтому ставит 1$ на каждый бросок (оба кубика) и решает сделать 1000 бросков. Предположим, что заведение щедрое и выплата будет в 4 раза больше ставки, когда игрок выигрывает. Например, если игрок выиграет первый бросок, баланс увеличится на 4$, и раунд закончится с 1004$. Если чудом получится выиграть серию из 1000 бросков, то итого получится 5000$. В случае каждого неудачного раунда получится 0$.
Смоделируем игру, чтобы выяснить, сделал ли игрок правильный выбор. Начнем код с импорта необходимых библиотек Python: Pyplot из Matplotlib и random. Для визуализации результатов будет использоваться библиотека Pyplot, для моделирования броска шестигранной игральной кости – random.
Pyplot
Matplotlib
random
# Импорт библиотек import matplotlib.pyplot as plt import random
Далее определим функцию, которая будет выдавать случайное целое число от 1 до 6 для обеих костей (имитация броска). Функция будет сравнивать значение обеих костей и возвращать логическое значение – одинаковы броски или нет. Позже это значение будет использоваться для определения действий в коде.
# Создаем функцию броска кубика def roll_dice(): die_1 = random.randint(1, 6) die_2 = random.randint(1, 6) # Определим является ли значение на костях одинаковым if die_1 == die_2: same_num = True else: same_num = False return same_num
Каждое моделирование методом Монте-Карло требует знание входных данных и информации, которую требуется получить. Входные данные определены, когда описывалась игра. Количество бросков за игру 1000 раз, сумма за бросок 1$. В дополнение требуется определить – сколько раз игра будет моделироваться. В качестве счетчика Монте-Карло используем переменную num_simulations. Чем больше это число, тем точнее прогнозируемая вероятность соответствует истинному значению.
num_simulations
Число переменных, которые возможно отслеживать, растет с ростом сложности проекта, поэтому требуется определить, какая информация нужна. В данном примере будет отслеживаться вероятность выигрыша (выигрыш за игру, деленный на общее число бросков) и конечный баланс для каждой симуляции (игры). Эти переменные будут инициализироваться, как списки и будут обновляться в конце каждой игры.
# Входные данные num_simulations = 10000 max_num_rolls = 1000 bet = 1 # Отслеживаемые переменные win_probability = [] end_balance = []
Следующий шаг – это настройка фигуры перед запуском симуляции: это позволит добавлять линии к рисунку после каждой игры. После запуска всех симуляций отобразим график, чтобы показать результаты.
# Создание фигуры, для симуляции баланса fig = plt.figure() plt.title("Monte Carlo Dice Game [" + str(num_simulations) + " simulations]") plt.xlabel("Roll Number") plt.ylabel("Balance [$]") plt.xlim([0, max_num_rolls])
В коде ниже 2 цикла: внешний, который перебирает заданное кол-во симуляций (10000) и вложенный, который запускает каждую игру (1000 бросков). Перед запуском каждого цикла while инициализируется:
while
Цикл while будет моделировать игру на 1000 бросков. Внутри этого цикла бросаются кости, используя логическую переменную, возвращаемую функцией roll_dice() для определения результата. Если кости одинаковые – в список баланса добавляется 4-кратная ставка и выигрыш к счету игрока. Если кости разные – вычитается ставка из списка баланса. В конце каждого броска добавляем счетчик в список num_rolls.
roll_dice()
num_rolls
Как только количество бросков достигло 1000, рассчитываем вероятность выигрыша игрока, как количество выигрышей, деленное на общее количество бросков. Сохраняем конечный баланс завершенной игры в отслеживаемой переменной end_balance.
end_balance
# Цикл for запускает желаемое количество симуляций for i in range(num_simulations): balance = [1000] num_rolls = [0] num_wins = 0 # Выполняется до тех пор пока игрок не выкинет 1000 раз while num_rolls[-1] < max_num_rolls: same = roll_dice() # Результат если кости одинаковые if same: balance.append(balance[-1] + 4 * bet) num_wins += 1 # Результат если кости разные else: balance.append(balance[-1] - bet) num_rolls.append(num_rolls[-1] + 1) # Сохраняем отслеживаемую переменную и добавляем строку к рисунку win_probability.append(num_wins/num_rolls[-1]) end_balance.append(balance[-1]) plt.plot(num_rolls, balance)
Последний шаг – вывод осмысленных данных из отслеживаемых переменных. Отобразим фигуру (показанную ниже), созданную в цикле for. Также рассчитаем и отобразим общую вероятность выигрыша и конечный баланс, усредняя списки win_probability и end_balance.
for
win_probability
# Выведем график после завершения моделирования plt.show() # Усредненная вероятность выигрыша и конечного баланса overall_win_probability = sum(win_probability)/len(win_probability) overall_end_balance = sum(end_balance)/len(end_balance) # Вывод средних значений print("Average win probability after " + str(num_simulations) + " runs: " + str(overall_win_probability)) print("Average ending balance after " + str(num_simulations) + " runs: $" + str(overall_end_balance))
Моделирование игры в кости:
Average win probability after 10000runs: 0.16666139999999954 Average ending balance after 10000runs: $833.307
Сделаем вывод из результатов. Из рисунка выше возможно определить, что игрок редко получает прибыль после 1000 бросков. Средний конечный баланс 10000 симуляций составляет 833,66$ (из-за рандомизации, возможны различия результатов). Казино остается в выигрыше даже, если выплачивает в четыре раза больше при победе игрока.
Также заметим, что вероятность выигрыша составляет 0.1667 или 1/6. Выше было отмечено, что у игрока 6 выигрышных исходов из 36 возможных. Используя эти 2 числа ожидаемо, что игрок выиграет 6 из 36 бросков, или 1/6 бросков, что соответствует прогнозу Монте-Карло.
***
Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека питониста» Интересно, перейти к каналу
Ваш адрес email не будет опубликован. Обязательные поля помечены *
Сохранить моё имя, email и адрес сайта в этом браузере для последующих моих комментариев.
Δ
Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.