利用不均勻硬幣產生等概率

利用不均勻硬幣產生等概率

問題描述:有一枚不均勻的硬幣,已知拋出此硬幣後,正面向上的概率爲p(0 < p < 1)。請利用這枚硬幣產生出概率相等的兩個事件。

這個問題跟之前的利用等概率Rand5產生等概率Rand3非常像,但卻簡單的多。幾個月前還爲這個事情頭疼了一下,現在想來真是不應該。

某一次拋出硬幣,正面向上的概率是p,反面向上的概率是1 - p,當p不等於0.5時,這兩個事件的概率就不一樣了。怎麼能湊出等概率呢?還是要利用概率的加法和乘法法則。這裏用乘法,也就是連續的獨立事件。

連續拋兩次硬幣,正反面的出現有四種情況,概率依次爲:

  1. 兩次均爲正面:p * p
  2. 第一次正面,第二次反面:p * (1 - p)
  3. 第一次反面,第二次正面:(1 - p) * p
  4. 兩次均爲反面:(1 - p) * (1 - p)

這不,中間兩種情況的概率是完全一樣的。於是問題的解法就是連續拋兩次硬幣,如果兩次得到的相同則重新拋兩次;否則根據第一次(或第二次)的正面反面情況,就可以得到兩個概率相等的事件。

用Python程序模擬一下這個過程,首先是一個叫做UnbalancedCoin的類,用來模擬這枚不均勻的硬幣。Flip方法表示拋一次硬幣,返回值True代表正面,False代表反面。根據要求,這個函數返回True和False的概率分別是p和1 - p。函數MakeEqualProb利用參數coin(這枚不均勻硬幣)構造出兩個事件(依舊用True和False表示),並且這兩個事件的概率都是0.5。

# -*- coding:utf-8 -*-
from random import Random
import numpy as np


class UnbalancedCoin:
    def __init__(self, p, rand=None):
        assert 0.0 < p < 1.0, 'invalid p'
        self._p = p
        if rand is None:
            rand = Random()
        self._rand = rand

    def Flip(self):
        return self._rand.random() < self._p


def MakeEqualProb(coin):
    while True:
        a = coin.Flip()
        if a != coin.Flip():
            return a


coin = UnbalancedCoin(0.7)

result = []
for i in range(10000):
    res = MakeEqualProb(coin)
    result.append(res)

res = np.array(result)
print(res.sum() / res.size)

對於不同的p值,模擬實驗十萬次,得到如下的(結果爲True的)概率分佈,其中藍線是不均勻硬幣拋出後正面向上的概率,紅線是構造出來的兩個事件之一(第一次正面向上,第二次反面向上)的概率。

如果問題改變一下,把「一枚」改成「一種」,那解決辦法就更簡單有趣了,把兩枚同樣的不均勻硬幣正面相對粘在一起,就可以得到一個均勻的組合幣,拋出這枚組合幣就可以得到等概率的兩個事件。