簡體   English   中英

關於蒙特卡洛概率語法

[英]On Monte Carlo Probability syntax

讓20個人(包括恰好3位女性)隨機坐在4張桌子(分別表示(A,B,C,D))中,每張桌子由5個人組成,所有布置的可能性均等。 令X為沒有女人坐在的桌子數。 編寫一個numpy的蒙特卡洛模擬,以估計X的期望值,並還估計沒有女性坐在表A上的概率p 。運行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]

履行

這是您的蒙特卡洛模擬的簡單實施。 它並非旨在提高性能,而是允許您交叉檢查設置並查看詳細信息:

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

第二個版本趨向另一個價值,並且顯然不等同於第一個版本,它沒有回答相同的問題。

在此處輸入圖片說明 在此處輸入圖片說明 在此處輸入圖片說明

討論

為了區分哪種實現是正確的,我計算了兩種實現的采樣空間和概率 第一個版本似乎是正確的版本,因為它考慮到女性坐在一張桌子旁的可能性取決於之前被選中的人。 第二個版本沒有考慮到這一點,這就是為什么它不需要知道每桌有多少人以及可以坐多少人的原因。

這是一個很好的問題,因為兩個答案都提供了接近的結果。 工作的重要部分是正確設置蒙特卡洛輸入。

您可以在Python 3.x中使用functools.reduce在集合中functools.reduce項目。

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

然后,您可以使用結果完成代碼。

您是否必須明確模擬坐姿? 如果不是,則簡單地隨機繪制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)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM