numpy數值模擬----三門問題(蒙提霍爾悖論)

案例:數值模擬 - 三門問題(蒙提霍爾悖論)

三門問題,亦稱爲蒙提霍爾問題,出自美國的電視遊戲節目Let’s Make a Deal。問題的名字來自該節目的主持人蒙提·霍爾(Monty Hall)

1:參賽者面前有三扇關閉着的門,其中一扇的後面是一輛汽車,而另外兩扇門後面則各藏有一隻山羊,選中後面有車的那扇門就可以贏得該汽車
2:當參賽者選定了一扇門,但未去開啓它的時候,主持人會開啓剩下兩扇門中的一扇,露出其中一隻山羊。然後問參賽者要不要改變選擇,選另一扇仍然關着的門
3:問題:參賽者應不應該改變選擇?

1/3,2/3,1/2


所需知識點:

  • 生成隨機數數組,np.random.randint()
  • 布爾索引
  • 根據值反查索引,np.where(),np.argmax()
  • 自定義運算 apply_along_axis()
  • 集合運算,對稱差,setxor1d()
  • 隨機洗牌,np.permutation()
  • 隨機抽取,np.random.choice()
import numpy as np

第一步:遊戲生成三個值,觀衆猜測

生成三門數據

c = 100000
game = np.zeros((c, 3))
game
array([[0., 0., 0.],
       [0., 0., 0.],
       [0., 0., 0.],
       ...,
       [0., 0., 0.],
       [0., 0., 0.],
       [0., 0., 0.]])
game[:, 2] = 1
game
array([[0., 0., 1.],
       [0., 0., 1.],
       [0., 0., 1.],
       ...,
       [0., 0., 1.],
       [0., 0., 1.],
       [0., 0., 1.]])
game.shape
(100000, 3)
# 將三門數據降維
def f(x):
    return np.random.permutation(x)

game2 = np.apply_along_axis(f, 1, game)
game2[:20]
array([[0., 1., 0.],
       [0., 0., 1.],
       [0., 0., 1.],
       [0., 1., 0.],
       [1., 0., 0.],
       [0., 1., 0.],
       [1., 0., 0.],
       [0., 0., 1.],
       [0., 1., 0.],
       [0., 0., 1.],
       [0., 0., 1.],
       [0., 0., 1.],
       [0., 1., 0.],
       [0., 1., 0.],
       [0., 1., 0.],
       [0., 0., 1.],
       [0., 1., 0.],
       [0., 0., 1.],
       [0., 0., 1.],
       [0., 1., 0.]])
np.sum(game2[:, 0])
np.sum(game2[:, 1])
np.sum(game2[:, 2])
33405.0
np.sum(game2[:, 0] == 0)  # 第0列出現0的個數
66630
def _(a):
    one = np.sum(a) / c
    zero = np.sum(a == 0) / c
    return one, zero


np.apply_along_axis(_, 0, game2)
array([[0.3337 , 0.33225, 0.33405],
       [0.6663 , 0.66775, 0.66595]])

三門問題中汽車所在的索引

game2[:10]
array([[0., 1., 0.],
       [0., 0., 1.],
       [0., 0., 1.],
       [0., 1., 0.],
       [1., 0., 0.],
       [0., 1., 0.],
       [1., 0., 0.],
       [0., 0., 1.],
       [0., 1., 0.],
       [0., 0., 1.]])
np.argmax(game2, axis=1)  # 汽車出現的索引
array([1, 2, 2, ..., 1, 1, 0], dtype=int64)
game2 == 1
threeMax = np.where(game2 == 1)[1]
threeMax
array([1, 2, 2, ..., 1, 1, 0], dtype=int64)

生成用戶猜測數據

# 隨機猜測
guess = np.random.randint(0, 3, c)
guess
array([0, 0, 0, ..., 1, 0, 0])
# 方法2:全部猜2
guess2 = np.full(c, 2)
guess2
array([2, 2, 2, ..., 2, 2, 2])

計算勝率

np.sum(threeMax == guess) / c 
0.3344
np.sum(threeMax == guess2) / c 
0.33405

猜固定值和隨機值的概率差不多

第二步:主持人告知一個錯誤值

aa = np.array([0, 1, 2])  # 假設汽車的索引值爲2
aa
array([0, 1, 2])

# 猜對的情況

# 用戶猜測的索引值,正是汽車的索引值
bb = [2, 2]

cc = np.setxor1d(aa, bb)
cc

# 兩個錯誤值,二選一輸出
np.random.choice(cc)
0
# 猜錯的情況
bb = [1, 2]

# 返回
cc = np.setxor1d(aa, bb)
cc



array([0])
# 猜錯的情況
bb = [0, 2]

# 返回
cc = np.setxor1d(aa, bb)
cc
array([1])
def sError(x):
    aa = [0, 1, 2]  # 遊戲數據的集合
    bb = [x[0], x[1]]  # 汽車所在索引,用戶猜測索引
    cc = np.setxor1d(aa, bb)  # 對稱差
    return np.random.choice(cc)  # 二選一


sayError = np.apply_along_axis(sError, 0, (threeMax, guess))
sayError

array([2, 1, 1, ..., 2, 2, 2], dtype=int64)
game2[:10]
array([[0., 1., 0.],
       [0., 0., 1.],
       [0., 0., 1.],
       [0., 1., 0.],
       [1., 0., 0.],
       [0., 1., 0.],
       [1., 0., 0.],
       [0., 0., 1.],
       [0., 1., 0.],
       [0., 0., 1.]])
guess[:10]
array([0, 0, 0, 0, 2, 0, 1, 1, 2, 2])
sayError[:10]
array([2, 1, 1, 2, 1, 2, 2, 0, 0, 1], dtype=int64)

3 問題: 參賽者應不應該改變選擇

aa
array([0, 1, 2])
# 猜對的情況
bb = [2, 1]  # 用戶猜測索引,主持人告知的錯誤索引

# 
np.setxor1d(aa, bb)
array([0])
bb = [1, 0]
np.setxor1d(aa, bb)
array([2])

def change(x):
    aa = np.array([0, 1, 2])
    bb = [x[0], x[1]]
    return np.setxor1d(aa, bb)


change2 = np.apply_along_axis(change, 0, (guess, sayError))[0]  # 用戶猜測索引,主持人告知錯誤索引
change2
array([1, 2, 2, ..., 0, 1, 1], dtype=int64)
game2[:10]
array([[0., 1., 0.],
       [0., 0., 1.],
       [0., 0., 1.],
       [0., 1., 0.],
       [1., 0., 0.],
       [0., 1., 0.],
       [1., 0., 0.],
       [0., 0., 1.],
       [0., 1., 0.],
       [0., 0., 1.]])
guess[:10]
array([0, 0, 0, 0, 2, 0, 1, 1, 2, 2])
sayError[:10]
array([2, 1, 1, 2, 1, 2, 2, 0, 0, 1], dtype=int64)
change2[:10]
array([1, 2, 2, 1, 0, 1, 0, 2, 1, 0], dtype=int64)

計算不改變選擇和改變選擇的勝率

# 不改變選擇的勝率
np.sum(guess == threeMax) / c
0.3344
# 改變選擇的勝率
np.sum(change2 == threeMax) / c
0.6656

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章