用Python模拟10000次,我彻底搞懂了那个反直觉的“三门问题”
用Python模拟10000次我彻底搞懂了那个反直觉的“三门问题”第一次听说三门问题时我和大多数人一样坚信“换不换都一样”——直到我用代码模拟了上万次游戏过程。作为程序员我们习惯用数据说话这次我将带你用Python彻底拆解这个经典概率谜题看看为什么直觉会欺骗我们。1. 三门问题背后的数学原理三门问题Monty Hall问题源自美国电视节目《Lets Make a Deal》其反直觉特性曾让无数数学家和统计学家栽跟头。让我们先理清游戏规则三扇门后分别藏着两羊一车玩家初始随机选择一扇门主持人知道门后情况会打开一扇有山羊的未选门玩家可选择坚持原选或更换到剩余未开门最终揭晓是否赢得汽车关键争议点在于主持人行为是否改变了初始概率分布让我们用集合论视角分析初始选择正确的概率1/3初始选择错误的概率2/3此时主持人被迫打开唯一剩下的山羊门# 概率分布可视化 import matplotlib.pyplot as plt labels [初始选择正确, 初始选择错误] sizes [1/3, 2/3] plt.pie(sizes, labelslabels, autopct%1.1f%%) plt.title(初始选择概率分布) plt.show()当主持人打开一扇门后情况发生了微妙变化初始选择主持人行为换门结果不换结果正确(1/3)随机开一羊得羊得车错误(2/3)必须开特定羊门得车得羊这个条件概率变化正是反直觉的核心——主持人提供的信息实际上浓缩了概率空间。2. 构建Python模拟实验让我们用面向对象的方式构建模拟器确保代码可扩展性和可读性import random from collections import defaultdict class MontyHallSimulator: def __init__(self): self.doors [goat, goat, car] random.shuffle(self.doors) def simulate(self, switchFalse): choice random.randint(0, 2) remaining_doors [i for i in range(3) if i ! choice] # 主持人必须打开有山羊的门 for door in remaining_doors: if self.doors[door] goat: host_open door break if switch: final_choice [i for i in range(3) if i ! choice and i ! host_open][0] else: final_choice choice return self.doors[final_choice] car测试单次模拟sim MontyHallSimulator() print(换门获胜 if sim.simulate(switchTrue) else 换门失败) print(不换获胜 if sim.simulate(switchFalse) else 不换失败)3. 大规模模拟与结果分析进行万次级模拟才能得到稳定统计结果def run_simulation(trials10000): switch_wins 0 stay_wins 0 for _ in range(trials): sim MontyHallSimulator() if sim.simulate(switchTrue): switch_wins 1 if sim.simulate(switchFalse): stay_wins 1 return switch_wins/trials, stay_wins/trials switch_prob, stay_prob run_simulation() print(f换门胜率: {switch_prob:.2%}) print(f不换胜率: {stay_prob:.2%})典型输出结果换门胜率: 66.72% 不换胜率: 33.28%用可视化对比更直观import numpy as np import matplotlib.pyplot as plt strategies [换门, 不换] probabilities [switch_prob, stay_prob] x np.arange(len(strategies)) plt.bar(x, probabilities) plt.xticks(x, strategies) plt.ylabel(获胜概率) plt.title(不同策略获胜概率对比) plt.ylim(0, 1) for i, v in enumerate(probabilities): plt.text(i, v0.02, f{v:.2%}, hacenter) plt.show()4. 深入探讨与边界情况4.1 主持人行为的影响原始问题的关键前提常被忽视主持人必须打开有山羊的门主持人知道门后情况主持人不会打开玩家选择的门如果改变这些规则概率会如何变化主持人行为换门胜率数学解释随机开门(可能开出门)50%变成传统条件概率问题总是优先开特定编号门66.6%保留原始问题特性有时会故意开门变化引入博弈论因素4.2 门数量扩展实验增加门数量会放大概率差异def extended_simulation(n_doors5, trials10000): switch_wins 0 stay_wins 0 for _ in range(trials): doors [goat]*(n_doors-1) [car] random.shuffle(doors) choice random.randint(0, n_doors-1) # 主持人打开n_doors-2个山羊门 host_opens [] for i in range(n_doors): if i ! choice and doors[i] goat and len(host_opens) n_doors-2: host_opens.append(i) if len(host_opens) n_doors-2: continue # 无法满足主持人开门规则 remaining [i for i in range(n_doors) if i ! choice and i not in host_opens][0] # 测试换门策略 if doors[remaining] car: switch_wins 1 # 测试不换策略 if doors[choice] car: stay_wins 1 return switch_wins/trials, stay_wins/trials doors_range range(3, 10) switch_probs [] stay_probs [] for n in doors_range: s, t extended_simulation(n_doorsn) switch_probs.append(s) stay_probs.append(t) plt.plot(doors_range, switch_probs, label换门) plt.plot(doors_range, stay_probs, label不换) plt.xlabel(门数量) plt.ylabel(获胜概率) plt.title(不同门数量下的策略胜率) plt.legend() plt.grid() plt.show()4.3 心理学因素分析为什么这个结果如此反直觉人类认知存在几个盲点概率守恒谬误认为概率必须始终平均分配信息忽略低估主持人行为提供的信息量锚定效应过度依赖初始选择结果等效错觉认为剩下两门等同于随机二选一在代码仓库中我还添加了交互式Jupyter notebook版本可以实时调整参数观察概率变化。有个有趣的发现当门数量增加到100扇主持人打开98扇山羊门后几乎所有人都会选择换门——这时直觉终于与数学达成一致。