Python模拟抽5张牌得红桃A黑桃A概率不符 求排查及代码优化
问题原因分析
1. 模拟结果偏差的核心原因
- 牌堆构造错误:你定义的
values只到12,缺少了代表K的13,整副牌只有48张而非标准的52张。这种情况下对应的理论概率为C(46,3)/C(48,5)≈0.0089,和你模拟得到的0.0081~0.0092区间完全吻合,属于统计误差范围内的正常结果。 - 冗余操作:你每次循环先调用
shuffle(deck)再sample是多余的,sample本身就会实现无放回的随机抽样,无需提前洗牌。
2. 你的理论概率公式是正确的
标准52张牌抽5张同时拿到红桃A和黑桃A的概率公式C(50,3)/C(52,5)计算无误,结果约为0.0075,只要修正牌堆构造,模拟结果就会和这个值吻合。
精简后的代码实现
from random import sample from itertools import product # 构造标准52张牌堆 suits = ["s", "d", "h", "c"] values = [str(i) for i in range(1, 14)] # 修正为1-13覆盖所有牌面值 deck = list(product(values, suits)) sim_times = 100000 hit_count = 0 target_aces = {("1", "h"), ("1", "s")} for _ in range(sim_times): hand = set(sample(deck, 5)) # 直接用集合子集判断是否同时拿到两张目标A if target_aces.issubset(hand): hit_count += 1 print(hit_count / sim_times)
优化点说明
- 移除了不必要的洗牌操作,减少运算开销
- 用集合的
issubset方法判断两张A是否都在手牌中,省略了嵌套循环和状态变量定义 - 修正了牌堆的面值范围,符合标准52张牌设定
- 只导入需要用到的函数,避免
import *带来的命名空间污染 - 变量命名更符合Python惯例,可读性更强
内容的提问来源于stack exchange,提问作者The anime kid
相关产品推荐
相关产品推荐

