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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值