python随机.randint与随机选择:使用相同值的不同结果

2024-04-20 11:39:58 发布

您现在位置:Python中文网/ 问答频道 /正文

我让我的学生写一个python程序,在这个程序中,一对6面骰子的100掷骰子的结果存储在一个列表中,然后绘制成一个直方图。在

我一直认为random.choice(1,2,3,4,5,6)不如{},直到我注意到使用{}的学生的直方图更好地反映了预期结果。例如,在几乎所有使用random.randint(1,6)的学生的柱状图中,12(6+6)的滚动出现率都很高。有人知道发生了什么吗?在


Tags: 程序列表绘制random直方图骰子学生randint
3条回答

在Python中生成随机整数的最快方法实际上令我吃惊:

import random

die = int(random.random() * 6) + 1  # The equivalent to 'die = random.randint(1, 6)

看看它,它看起来更复杂,但速度差是相当明显的。在

我用MONTY算法测试了这两种方法,使用int时,它们的速度提高了大约200%(随机。随机)方法。在

也比随机选择下降幅度。在

From the documentation

Almost all module functions depend on the basic function random(), which generates a random float uniformly in the semi-open range [0.0, 1.0). Python uses the Mersenne Twister as the core generator. It produces 53-bit precision floats and has a period of 2**19937-1. The underlying implementation in C is both fast and threadsafe. The Mersenne Twister is one of the most extensively tested random number generators in existence. However, being completely deterministic, it is not suitable for all purposes, and is completely unsuitable for cryptographic purposes.

所以结果上不应该有任何真正的区别。然而,我不同意random.choice()不如{},事实上,随机选择实际上在生成随机数方面更快。当您查看源代码时:

def randint(self, a, b):
    return self.randrange(a, b+1)

def randrange(self, start, stop=None, step=1, _int=int, _maxwidth=1L<<BPF):
    istart = _int(start)
    if istart != start:
        # not executed
    if stop is None:
        # not executed

    istop = _int(stop)
    if istop != stop:
        # not executed
    width = istop - istart
    if step == 1 and width > 0:
        if width >= _maxwidth:
            # not executed
        return _int(istart + _int(self.random()*width))

对于choice()

^{pr2}$

您可以看到randint()使用randrange()的额外开销

编辑正如@abarnert在评论中指出的那样,这里的性能几乎没有差别,randint(1,6)是表示掷骰子的一种清晰直观的方式

我都运行了10000卷,没有发现任何偏差,所以您的输入样本可能太小了:

enter image description here

这是一个掷两次骰子的分布,也是非常均匀的:

enter image description here

我从这两个有用的答案中借用了这个片段:Performance of choice vs randintIs Pythons random.randint statistically random?,有助于进一步阅读。在

你是对的,你在学生的直方图中观察到的12的数量比理论上滚12的概率要高,但不是因为你认为的原因。在

一个实验:

import random

def roll_dice(method):
    if method == "choice":
        return random.choice([1,2,3,4,5,6]) + random.choice([1,2,3,4,5,6])
    else:
        return random.randint(1,6) + random.randint(1,6)

def est_prob(n,k,method):
    rolls = [roll_dice(method) for _ in range(k)]
    return rolls.count(n)/k

def test12(n,k,method):
    return sum(1 if est_prob(12,n,method) > 1/36 else 0 for _ in range(k))/k

注意,test12(100,10000,"randint")估计了基于randint的100个骰子的直方图代表12的和的概率。在

典型运行:

^{pr2}$

这在统计学意义上大于50%(10000次试验是估计概率的相当多的试验)。在

所以有偏见的证据,不是吗?别这么快:

>>> test12(100,10000,"choice")
0.5342

使用random.choice()你会看到同样的情况。这并不奇怪,因为大多数基于100掷骰子的掷骰子直方图高估了12的概率。在

当你掷一对骰子100次时,预期掷骰子的数量是100/36=2.78。但你只能观察到一个12秒的整数,观察到的12秒数等于或大于3的概率(从而导致直方图超过12)是P(X>;=3),其中X是一个二项式随机变量,参数为P=1/36,n=100。这个概率可以算出

P(X >= 3) = 1 - P(X<=2) 
          = 1 - P(0) - P(1) - P(2)
          = 1 - 0.0598 - 0.1708 - 0.2416
          = 0.5278

因此,大约53%的这样的直方图有“太多”12s,这是你在random.choice()和{}中都能看到的。在

似乎你在randint的上下文中注意到了这一现象,把它解释为偏见(尽管它不是),并假设它是{}的缺陷。在

相关问题 更多 >