【问题标题】:Is randint function in Python different from % trick?Python中的randint函数与%技巧不同吗?
【发布时间】:2021-03-25 17:25:19
【问题描述】:

提前感谢您的帮助。

我用python写了一个概率计算器。我要计算的概率是:当你尝试 6 次获胜机会为 1% 的游戏时,获胜的概率是多少。所以下面这段代码就是我写的。

import random as rand

total = 0
count = 0

p = pSum = 0

k = 6
n = 10000
m = 100

def pick(attemptPerIteration):
    global total, count
    for _ in range(attemptPerIteration):
        temp = rand.randint(1, 100)
        if (temp == 1):
            count += 1
            total += 1
            return 0
    return 1

for t in range(m):
    for u in range(n):
        total += pick(k)
    p = count / total
    print(str(t + 1) + ": " + str(p * 100))
    pSum += p
    p = 0
print(pSum / m * 100)

在这段代码中,我使用了 randint 函数来模拟 100 分之一的机会。我预期的概率约为 5.8%,但该程序的输出约为 6.3%。但是如果我只使用 randint(1, 1000) % 6 + 1 insted randint(1, 6),程序会告诉我概率是 5.8,这是我的预期。

这个 randint 函数到底发生了什么?为什么旧的 % 技巧有效,而 randint 无效?

这个问题的数学公式是这样的:

【问题讨论】:

  • 因为randint(a,b) 返回的数字从a 包含到b 不包含。
  • @CaptainTrojan 请参阅doc python 的 randint 包括两端。这是 Numpy 的 randint,不包括 b
  • 顺便说一句,我认为1-(1-0.01)^6 是对获胜机会的更简洁定义。
  • 首先,感谢您的帮助。我真是个白痴!当 temp == 1 时,我不应该计算总数,因为我想要的概率不是在总尝试中出现多少 1,而是在每场比赛中出现 1。所以,我应该删除那部分。而且我什至没有在每次尝试结束时重置 count var。另外,我可以只使用 n 进行总尝试; var total 实际上根本没有必要!结论:randint 函数完全可以解决这个问题,这是人为错误 lol
  • 注意:您应该期望在 95% 的时间内获得 [5.4%, 6.32%] 范围内的结果。您可以使用scipy.stats.binom.ppf([0.025, 0.975], n, 1-0.99**6) / n 计算此值。尝试更改 n 以查看置信区间如何变化

标签: python random probability modulo


【解决方案1】:

看起来您在递增 counttotal 时犯了错误。我更改了您的代码以计算正确的结果:

Try it online!

import random as rand

total = 0
count = 0

p = pSum = 0

k = 6
n = 10000
m = 100

def pick(attemptPerIteration):
    for _ in range(attemptPerIteration):
        temp = rand.randint(1, 100)
        if (temp == 1):
            return 1
    return 0

for t in range(m):
    for u in range(n):
        count += pick(k)
        total += 1
    p = count / total
    print(str(t + 1) + ": " + str(p * 100))
    pSum += p
    p = 0
print(pSum / m * 100)

输出:

.......
90: 5.822555555555556
91: 5.8221978021978025
92: 5.822608695652174
93: 5.824193548387097
94: 5.822446808510638
95: 5.822631578947368
96: 5.824166666666667
97: 5.825670103092784
98: 5.8254081632653065
99: 5.826969696969697
100: 5.8306
5.825542887205491

【讨论】:

    【解决方案2】:

    看起来m = 100n = 10000 太少,无法收敛。

    import random
    
    def did_win(attempts):
        return any(random.random() < .01 for attempt in range(attempts))
    
    tries = [did_win(6) for x in range(1_000_000)]
    print(tries.count(True) / len(tries))
    

    打印出0.058039,这似乎足够接近。

    如果您想更实时地观察解决方案的收敛情况,

    import random
    import itertools
    
    
    def did_win(attempts):
        return any(random.random() < 0.01 for attempt in range(attempts))
    
    
    wins = 0
    for x in itertools.count(0):
        if did_win(6):
            wins += 1
        if x and x % 10_000 == 0:
            print(x, wins / x)
    

    (按 ctrl-c 打断它——否则它会愉快地永远运行)。

    【讨论】:

      【解决方案3】:

      实际上,公式要简单得多。 获胜的概率是(99 / 100) ** 6,也就是大约0.941。它的补充是获胜的概率1 - 0.941... = 0.058...

      因为您正在以一种奇怪的方式增加全局计数,所以很可能您在多个地方都出现了一个错误。比如

      total += pick(k)
      

      其中pick 也修改了total...

      您应该只返回 0 或 1,然后从外部计数。

      【讨论】:

        猜你喜欢
        • 2011-12-16
        • 2022-08-18
        • 1970-01-01
        • 2021-02-07
        • 2020-12-12
        • 2022-08-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多