三门问题与神奇的贝叶斯大脑

原文地址

三门问题,也叫蒙提霍尔问题(Monty Hall Problem)

以电视节目 - Let's make a deal的主持人蒙提霍命名的一个反直觉问题。

游戏简介

假设有3个门。 其中一个后面藏着宝藏,其余2个都是空门(美国节目中1个后面有汽车,其余的2个是山羊)。 

游戏开始:

首先你先选择一张门,

选好后,主持人帮你在其余2扇没有被选择的门中打开一扇没奖的门。


 

这时候你有一个选择权, 换门还是不换门?

直觉上换不换几率都是50%,那到底几率是多少? 换是不是得奖的机会大一些?



Mueser 和 Granberg 透过厘清细节,以及对主持人的行为加上明确的介定,提出了对这个问题的一种不含糊的陈述 ︰

  • 现在有三扇门,只有一扇门有汽车,其余两扇门的都是山羊。

  • 汽车事前是等可能地被放置于三扇门的其中一扇后面。

  • 参赛者在三扇门中挑选一扇。他在挑选前并不知道任意一扇门后面是什麽。

  • 主持人知道每扇门后面有什么。

  • 如果参赛者挑了一扇有山羊的门,主持人必须挑另一扇有山羊的门。

  • 如果参赛者挑了一扇有汽车的门,主持人等可能地在另外两扇有山羊的门中挑一扇门。

  • 参赛者会被问是否保持他的原来选择,还是转而选择剩下的那一扇门。

转换选择可以增加参赛者拿到汽车的机会吗?





你可以在可汗学院上学习相应的内容:

https://www.khanacademy.org/math/precalculus/prob-comb/dependent-events-precalc/v/monty-hall-problem


下面我们分别用Matlab和Python来实现解答这个问题:

Matlab:


trials = 1000;


% 首先你随机从1,2,3个门和隐藏的车中做随机的选择。


car_door = randi(3,trials,1);


% 你做一个猜测选择一个门,那个地方有一个车

choice = randi(3,trials,1);

% 让我们看一下前五次的选择

T = table(car_door,choice);

disp(T(1:5,:))


%Monty 打开一个未选择的门,并显示一只山羊。 如果车门和选择的门不同,

%Monty 只有一个选择。


goat_door = zeros(trials,1);
goat_door(car_door + choice == 3) = 3;
goat_door(car_door + choice == 4 & car_door ~= choice) = 2;
goat_door(car_door + choice == 5) = 1;
goat_door(goat_door == 0 & choice == 1)
 = randsample([2,3],1);
goat_door(goat_door == 0 & choice == 2) 
 = randsample([1,3],1);
goat_door(goat_door == 0 & choice == 3) 
 = randsample([1,2],1);


T = table(car_door,choice,goat_door);

disp(T(1:5,:))

  car_door    choice    goat_door
    ________    ______    _________
    3           2         1        
    3           2         1        
    1           3         2        
    3           1         2        
    2           2         3        


simulation = zeros(3,1);

simulation(1) = sum((car_door - choice) == 0)/trials*100;

fprintf('Win Rate if stick to your original choice: %.2f%%\n',simulation(1))


Win Rate if stick to your original choice: 33.70%

我们看看如何能把胜率提高呢?

switch_choice = zeros(trials,1);
switch_choice(goat_door + choice == 3) = 3;
switch_choice(goat_door + choice == 4) = 2;
switch_choice(goat_door + choice == 5) = 1;

我们更新一个算法来解决这个问题。

T = table(car_door,choice,goat_door,switch_choice);
disp(T(1:5,:))

simulation(3) = 
    sum((car_door - switch_choice) == 0)/trials*100;
fprintf('Win Rate if switch your choice: %.2f%%\n',simulation(3))
    car_door    choice    goat_door    switch_choice
    ________    ______    _________    _____________
    3           2         1            3            
    3           2         1            3            
    1           3         2            1            
    3           1         2            3            
    2           2         3            1            
Win Rate if switch your choice: 66.30%

这个胜率怎么提高的呢?

 这是我们最熟悉的公式了。




P(H)

汽车隐藏在三个门后的任意一个,你选择了门1.门1是车门的概率是1/3。 这是先验的,或P(H)。

prior = ones(3,1)*1/3
prior =
      0.33333
      0.33333
      0.33333


如果汽车在门1后面,那么蒙蒂可以选择门2或3。
所以他选择门2的可能性是1/2。
如果汽车行为门2,那么蒙蒂不能选择它。 
所以概率是0.困惑? 我将在下面回顾这个例子。
如果汽车在门3后面,那么蒙蒂不得不选择门2.
所以他选择门2的可能性是1。

P(E|H


)



likelihood = [1/2;0;1]
likelihood =
          0.5
            0
            1


joint_prob = likelihood .* prior
joint_prob =
      0.16667
            0
      0.33333

在这一点上,您可以坚持使用您的原始选择或开关。 我的直觉是,这将是一个50/50的命题。 如果你选择留下来,这里是模拟胜率。

simulation = zeros(3,1);
simulation(1) = 
    sum((car_door - choice) == 0)/trials*100;
fprintf('Win Rate if stick to your original choice: %.2f%%\n',simulation(1))

后验P(H | E)应该非常接近模拟结果。

posterior = joint_prob/sum(joint_prob);
compare = table(posterior,simulation,
    'RowNames',{'Stay','N/A','Switch'});
disp(compare([1 3],:))
              posterior    simulation
              _________    __________
    Stay      0.33333      33.7      
    Switch    0.66667      66.3      


下面我们看下python在这个问题上的解决:


1.这个可以用 random.randint来实现。 randint(start, end, size) 随机选择的3个门中间的一个

1 def simulate_prizedoor(nsim):
 
2 return np.random.randint(0, 3, (nsim))

2.然后我们可以定义下,一开始选择的一扇门。 这里可以用固定选择法,也可以用随机法,数据大的情况下差别不大。这里我们直接用了固定选择第一扇门(0)

1 def simulate_guess(nsim):
 
2 return np.zeros(nsim, dtype=np.int)

3.然后我们 模拟主持人,开一扇没有奖品的门。


1 def goat_door(prizedoors, guesses):
 
2     result = np.random.randint(0, 3, prizedoors.size)

3     while True:
 
4         bad = (result == prizedoors) | (result == guesses)
 
5         if not bad.any():
 
6             return result
 
7         result[bad] = np.random.randint(0, 3, bad.sum())


这里要实现的逻辑是, 先生成一个0到2的随机数。 然后匹配直到 不等于 我们一开始的选择的那扇门 或 宝藏存在的那扇门。 

 

4.然后模拟,我们假如我们在主持人打开门之后, 选择换一张门。

1 def switch_guess(guesses, goatdoors):
 
2     result = np.random.randint(0, 3, guesses.size)

3     while True:
 
4         bad = (result == guesses) | (result == goatdoors)
 
5         if not bad.any():
 
6             return result
 
7         result[bad] = np.random.randint(0, 3, bad.sum())


看得出来实现的代码和上面是一样的。 我们换的这扇门,不能是原来那扇,而且也不能是开了的那扇。

5.计算胜率。

1 def win_percentage(guesses, prizedoors):
 
2     return 100 * (guesses == prizedoors).mean()

这里需要注意, 如果单纯的bool type的数据是没有mean这个函数的。 np 把真假转换成了1,0这样才可以计算平均数。mean = 总值/数组的总数

 

6.最后我们就可以测试下,换和不换的区别了。 因为大数定律,我们测试100000遍


 1 pd = simulate_prizedoor(nsim) 
 2 guess = simulate_guess(nsim) 
 3 goats = goat_door(pd, guess) 
 4 guess = switch_guess(guess, goats) 
 5 nsim = 100000 
 
print "Win percentage when keeping original door" 
print win_percentage(simulate_prizedoor(nsim), simulate_guess(nsim))          print "Win percentage when switching doors" 
print win_percentage(pd, guess).mean()



感兴趣的加微信immanuelzhu 一起讨论。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值