О синтаксисе вероятности Монте-Карло

Пусть 20 человек, в том числе ровно 3 женщины, случайным образом сядут за 4 столика (обозначены (A, B, C, D)) по 5 человек каждый, причем все расстановки будут одинаково вероятными. Пусть X будет количеством столов, за которыми не сидят женщины. Напишите числовое моделирование методом Монте-Карло, чтобы оценить математическое ожидание X, а также оценить вероятность p того, что ни одна женщина не сядет за стол A. Запустите моделирование для 3 случаев (100,1000,10000)

Я хотел бы определить функцию, которая использует функцию numpy random.permutation для вычисления ожидаемого значения X с учетом переменного количества испытаний. Я понимаю, как это сделать на бумаге и ручке, повторяя мою коллекцию вероятностей и умножая их на каждую. другое, чтобы я мог рассчитать полную вероятность события. Это то, что у меня есть

T = 4       # number of tables
N = 20      # number of persons. Assumption: N is a multiple of T.
K = 5       # capacity per table
W = 3       # number of women. Assumption: first W of N persons are women.
M =100      #number of trials

collection = []

for i in range(K):


    x = (((N-W)-i)/(N-i))

    collection.append(x)

Если я исследую свою коллекцию, это будет мой результат: [0.85, 0.8421052631578947, 0.8333333333333334, 0.8235294117647058, 0.8125]


person Adam    schedule 20.03.2019    source источник
comment
Вы очищаете свою коллекцию каждый цикл. collection = [] должен быть вне цикла. То же самое для count = 0. Почему вы используете count вместо i?   -  person ALFA    schedule 20.03.2019
comment
Я новичок в python и хотел убедиться, что мой счетчик имеет нулевое значение. Я не был уверен, что я был проиндексирован на 0. Но ваше предложение значительно улучшило мой код.   -  person Adam    schedule 20.03.2019
comment
Да, Python имеет индекс 0   -  person jlandercy    schedule 20.03.2019
comment
Кроме того, теперь, когда у меня есть независимые вероятности, как мне просмотреть свою коллекцию и умножить каждое значение друг на друга?   -  person Adam    schedule 20.03.2019
comment
Обновите свой вопрос и добавьте новый код и свою проблему с коллекцией. Было бы здорово, если бы вы показали нам пример вывода!   -  person ALFA    schedule 20.03.2019
comment
@Adam, см. Возможно более простой код в ответе ниже.   -  person Inon Peled    schedule 20.03.2019
comment
@inonPeled, я не думаю, что вывод приведенного ниже кода правильный. Мои расчеты показывают, что вероятность того, что 5 человек сядут за стол, равна (91/228), а E (x) равна (91/57). У меня возникли проблемы с составлением функции, которая принимает переменное количество испытаний и выводит это наружу.   -  person Adam    schedule 20.03.2019
comment
@ Адам, я согласен с твоими расчетами E[x]~1.6 и p~0.4.   -  person jlandercy    schedule 20.03.2019


Ответы (3)


Реализация

Вот наивная реализация вашей симуляции Монте-Карло. Он не рассчитан на высокую производительность, вместо этого он позволяет вам перекрестно проверить настройку и увидеть детали:

import collections
import numpy as np

def runMonteCarlo(nw=3, nh=20, nt=4, N=20):
    """
    Run Monte Carlo Simulation
    """

    def countWomen(c, nt=4):
        """
        Count Number of Women per Table
        """
        x = np.array(c).reshape(nt, -1).T  # Split permutation into tables
        return np.sum(x, axis=0)           # Sum woman per table

    # Initialization:
    comp = np.array([1]*nw + [0]*(nh-nw)) # Composition: 1=woman, 0=man
    x = []                                # Counts of tables without any woman
    p = 0                                 # Probability of there is no woman at table A  

    for k in range(N):
        c = np.random.permutation(comp)   # Random permutation, table composition
        w = countWomen(c, nt=nt)          # Count Woman per table
        nc = np.sum(w!=0)                 # Count how many tables with women 
        x.append(nt - nc)                 # Store count of tables without any woman
        p += int(w[0]==0)                 # Is table A empty?
        #if k % 100 == 0:
            #print(c, w, nc, nt-nc, p)

    # Rationalize (count->frequency)
    r = collections.Counter(x)
    r = {k:r.get(k, 0)/N for k in range(nt+1)}
    p /= N
    return r, p

Выполнение работы:

for n in [100, 1000, 10000]:
    s = runMonteCarlo(N=n)
    E = sum([k*v for k,v in s[0].items()])
    print('N=%d, P(X=k) = %s, p=%s, E[X]=%s' % (n, *s, E))

Возврат:

N=100, P(X=k) = {0: 0.0, 1: 0.43, 2: 0.54, 3: 0.03, 4: 0.0}, p=0.38, E[X]=1.6
N=1000, P(X=k) = {0: 0.0, 1: 0.428, 2: 0.543, 3: 0.029, 4: 0.0}, p=0.376, E[X]=1.601
N=10000, P(X=k) = {0: 0.0, 1: 0.442, 2: 0.5235, 3: 0.0345, 4: 0.0}, p=0.4011, E[X]=1.5924999999999998

Построение графика распределения приводит к:

import pandas as pd
axe = pd.DataFrame.from_dict(s[0], orient='index').plot(kind='bar')
axe.set_title("Monte Carlo Simulation")
axe.set_xlabel('Random Variable, $X$')
axe.set_ylabel('Frequency, $F(X=k)$')
axe.grid()

введите здесь описание изображения

Расхождение с альтернативной версией

Внимание: этот метод не решает поставленную задачу!

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

import random
import collections

def runMonteCarlo2(nw=3, nh=20, nt=4, N=20):
    """
    Run Monte Carlo Simulation
    """

    def one_experiment(nt, nw):
        """
        Table setup (suggested by @Inon Peled)
        """
        return set(random.randint(0, nt-1) for _ in range(nw)) # Sample nw times from 0 <= k <= nt-1

    c = collections.Counter()             # Empty Table counter
    p = 0                                 # Probability of there is no woman at table A  

    for k in range(N):
        exp = one_experiment(nt, nw)      # Select table with at least one woman
        c.update([nt - len(exp)])         # Update Counter X distribution
        p += int(0 not in exp)            # There is no woman at table A (table 0)

    # Rationalize:
    r = {k:c.get(k, 0)/N for k in range(nt+1)}
    p /= N

    return r, p

Он возвращает:

N=100, P(X=k) = {0: 0.0, 1: 0.41, 2: 0.51, 3: 0.08, 4: 0.0}, p=0.4, E[X]=1.67
N=1000, P(X=k) = {0: 0.0, 1: 0.366, 2: 0.577, 3: 0.057, 4: 0.0}, p=0.426, E[X]=1.691
N=1000000, P(X=k) = {0: 0.0, 1: 0.37462, 2: 0.562787, 3: 0.062593, 4: 0.0}, p=0.42231, E[X]=1.687973

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

введите здесь описание изображения  введите описание изображения здесь  введите описание изображения здесь

Обсуждение

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

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

person jlandercy    schedule 20.03.2019

Вы можете умножать элементы внутри коллекции, используя functools.reduce в Python 3.x.

from functools import reduce
event_probability = reduce(lambda x, y: x*y, collection)

Итак, в вашем коде:

from functools import reduce

T = 4       # number of tables
N = 20      # number of persons. Assumption: N is a multiple of T.
K = 5       # capacity per table
W = 3       # number of women. Assumption: first W of N persons are women.
M = 100      #number of trials

collection = []

for i in range(K):
    x = (((N-W)-i)/(N-i))
    collection.append(x)

event_probability = reduce(lambda x, y: x*y, collection)

print(collection)
print(event_probability)

Выход:

[0.85, 0.8421052631578947, 0.8333333333333334, 0.8235294117647058, 0.8125] # collection
0.3991228070175438 # event_probability

Затем вы можете использовать результат для завершения своего кода.

person ALFA    schedule 20.03.2019

Вам нужно явно моделировать сеансы? Если нет, то просто нарисуйте 3 раза наугад с заменой от 1..4, чтобы имитировать одно сидение, то есть:

def one_experiment():
    return set(random.randint(1, 4) for _ in range(3))  # Distinct tables with women.

Затем желаемые значения получаются следующим образом, где N - количество экспериментов для любого случая.

expectation_of_X = sum(4 - len(one_experiment()) for _ in range(N)) / float(N)
probability_no_women_table_1 = sum(1 not in one_experiment() for _ in range(N)) / float(N)

Для большого N получаемые значения должны быть примерно p = (3/4) ^ 3 и E [X] = (3 ^ 3) / (4 ^ 2).

person Inon Peled    schedule 20.03.2019
comment
Мне нужно явно смоделировать сеансы, где я могу пройти по количеству испытаний - person Adam; 20.03.2019
comment
Вы уверены в своих формулах для E[x] и p? Есть 4 стола, а не 5. - person jlandercy; 20.03.2019
comment
inonPeled, я не думаю, что вывод приведенного ниже кода правильный. Мои расчеты показывают, что вероятность того, что 5 человек сядут за стол, равна (91/228), а E (x) равна (91/57). У меня возникли проблемы с составлением функции, которая принимает переменное количество испытаний и выводит этот результат - person Adam; 20.03.2019
comment
5 - len(one_experiment()) возвращает 2 пустые таблицы (вместо 1), когда 3 женщины за 3 разными столами, это, скорее всего, ошибка. - person jlandercy; 20.03.2019
comment
Я изменил количество таблиц в своем ответе с 5 на 4, извините за ошибку. Что касается вероятности таблицы без женщин, то это вероятность p того, что каждая женщина случайным образом выберет любую из трех других таблиц, и математическое ожидание X следует как 4p. - person Inon Peled; 20.03.2019
comment
Да такая опечатка бывает. В любом случае я думал о вашей реализации и обнаружил, что она расходится с моей. Подсчитывая, я знаю почему, и это может указать на то, что ваш ответ не совсем решает заявленную проблему. Подробности см. здесь. - person jlandercy; 22.03.2019
comment
@jlandercy Хорошая ссылка. Я вижу свою ошибку: я предполагал, что выбор женщин независим, но после того, как он был заказан, на последующий выбор влияет прежний выбор, потому что остается меньше мест. - person Inon Peled; 23.03.2019
comment
Верный. Мне понравилось исследовать эту проблему. Забавный факт в том, что ответы относительно близки друг к другу, поэтому легко убедить себя, что это может быть правильно, пока вы не обнаружите основную причину. Хорошее упражнение. - person jlandercy; 23.03.2019