调试:在Python/random中洗牌

调试:在Python/random中洗牌,python,algorithm,random,shuffle,Python,Algorithm,Random,Shuffle,我知道这个标题听起来很无聊,因为很多人已经问过这个话题了。我希望它能帮助我了解随机模块是如何工作的。问题是,我写了两个不同的函数,我认为应该是相同的,但是我得到的结果不一样,我不明白为什么 我希望最终得到一副“洗得很好的牌”。我只关心牌是红的还是黑的,所以我的牌非常简单。我叫“1”为红色,叫“0”为黑色 我的想法是,如果random.random()大于.5,则添加1(红色),否则添加0(黑色),然后在达到一种颜色的26(一半)时,自动添加1或0。但有些地方出了问题。deckmaker()无法正

我知道这个标题听起来很无聊,因为很多人已经问过这个话题了。我希望它能帮助我了解随机模块是如何工作的。问题是,我写了两个不同的函数,我认为应该是相同的,但是我得到的结果不一样,我不明白为什么

我希望最终得到一副“洗得很好的牌”。我只关心牌是红的还是黑的,所以我的牌非常简单。我叫“1”为红色,叫“0”为黑色

我的想法是,如果random.random()大于.5,则添加1(红色),否则添加0(黑色),然后在达到一种颜色的26(一半)时,自动添加1或0。但有些地方出了问题。deckmaker()无法正常工作,尽管deckmaker2()可以正常工作。谁能提供见解

import random

def deckmaker():
    deck = []
    for i in range(52):
        if deck.count(0) == 26:
            deck.append(1)
        elif deck.count(1) == 26:
            deck.append(0)
        elif random.random() > .5:
            deck.append(0)
        else:
            deck.append(1)
    return deck

def deckmaker2():
    newdeck = []
    for i in range(26):
        newdeck.append(0)
    for i in range(26):
        newdeck.append(1)
    deck = []
    for i in range(52):
        x = random.randint(0,len(newdeck)-1)
        deck.append(newdeck.pop(x))
    return deck
注意:在写这个问题时,我发现了random.shuffle list操作符,它的作用与我的第二个函数相同,因此获得洗牌组当然很容易。但是我仍然想知道为什么我的原始代码没有做同样的事情

编辑:很抱歉对deckmaker()的确切问题含糊其辞。问题是,我不太明白怎么了。这与这样一个事实有关,即在它生成的牌组上,当你一张一张地“翻转”牌时,有一些策略可以让你预测“下一张牌”是红色还是黑色,而这些策略不适用于使用random.shuffle创建的牌组

编辑2:[更多信息]我将解释我如何确定deckmaker不起作用,以防这很重要。 我写这个程序是为了模拟贴在这里的谜题:

我的策略是记住最后几张牌,并利用这些信息来决定何时下一张牌。我想,在连续获得5张“黑”牌之后,这是预测“红”的好时机。我这样实施:

mycards = []

for j in range(1000):
    mydeck = deckmaker(52)
    mem_length = 5
    mem = []
    for c in range(mem_length):
        mem.append(4)
    for i in range(len(mydeck)):
        if mem.count(0) == mem_length:
            mycards.append(mydeck[i])
            break
        elif i == len(mydeck)-1:
            mycards.append(mydeck[i])
            break
        else:
            mem.append(mydeck[i])
            mem.pop(0)


x = float(mycards.count(1))

print x/len(mycards)

结果是,我拿的牌中有一半以上是“红色的”,这是我在连续抽了5张红牌之后拿牌的结果。这毫无意义,所以我寻找了一种不同的方法来创建甲板,得到了一个更正常的结果。但我仍然不知道我原来的牌组出了什么问题。

我不确定你的意思是什么,但我认为第一种方法生成的最后一张牌很可能是相同的

从50个或更少的样本中得到26个1或26个0的可能性似乎很大(我认为可以使用交换二项分布来计算它)。即使是很小的机会也意味着你应该赌最后几张牌的颜色相同(因此其他牌的颜色相反)

你所能做的就是把零和一相加,直到有52张牌,然后在最后把随机的一变成零(或者反过来),直到每张牌都有26张

编辑: 假设这副牌有4张牌。前两种颜色是随机的:

25% (0, 0)
25% (0, 1)
25% (1, 0)
25% (1, 1)
但是对于
(0,0)
(1,1)
,最后两张卡已经确定,分别是
(1,1)
(0,0)
。其他人还需要一个数字来确定结果:

25.0% (0, 0, 1, 1)
12.5% (0, 1, 0) > (0, 1, 0, 1)
12.5% (0, 1, 1) > (0, 1, 1, 0)
12.5% (1, 0, 0) > (1, 0, 0, 1)
12.5% (1, 0, 1) > (1, 0, 1, 0)
25.0% (1, 1, 0, 0)

因此,正如您所看到的,并非所有选项都具有相同的可能性。当然,52张卡片的差异较小,但想法仍然相同。

一般来说,除非你能严格证明随机方法是正确的,否则你永远不应该相信它是正确的。这通常很难

为了深入了解您的问题,让我们概括一下有问题的函数:

import random

def deckmaker(n):
    half = n // 2
    deck = []
    for i in range(n):
        if deck.count(0) == half:
            deck.append(1)
        elif deck.count(1) == half:
            deck.append(0)
        elif random.random() > .5:
            deck.append(0)
        else:
            deck.append(1)
    return deck
这里有一个小司机:

from collections import Counter
c = Counter()
for i in range(1000):
    c[tuple(deckmaker(2))] += 1
for t in sorted(c):
    print t, c[t]
运行以下命令:

(0, 1) 495
(1, 0) 505
(0, 0, 1, 1) 236
(0, 1, 0, 1) 127
(0, 1, 1, 0) 133
(1, 0, 0, 1) 135
(1, 0, 1, 0) 130
(1, 1, 0, 0) 239
因此,这两种可能性大致相同。好!!现在试试4号的甲板;只需更改相关行,如下所示:

c[tuple(deckmaker(4))] += 1
运行以下命令:

(0, 1) 495
(1, 0) 505
(0, 0, 1, 1) 236
(0, 1, 0, 1) 127
(0, 1, 1, 0) 133
(1, 0, 0, 1) 135
(1, 0, 1, 0) 130
(1, 1, 0, 0) 239
哎呀!如果你愿意,你可以做一个正式的卡方检验,但通过检验,两个排列(第一个和最后一个)的可能性是其他四个的两倍,这是非常明显的。因此,输出甚至不可能是随机的

为什么呢?想想看;-)

提示

对于大小为
2*M
的组,第一个
M
条目全部为0的可能性有多大?对此有两个答案:

  • 如果
    M
    零和
    M
    一的所有排列可能相等,则概率为
    (2*M)-选择-M
    (选择
    M
    零位置的方法的数量)

  • 在函数构造数据组的方式中,概率为1 In
    2**M
    (0和1在第一个
    M
    位置的概率相等)

  • 一般来说,
    (2*M)-choose-M
    2**M
    大得多,因此该函数构建一个以全零开始的数据组的频率远远高于“它应该”的频率。对于一副52张卡片(
    M==26
    ):

    所以“从26个零开始”的可能性是它应该的700多万倍。酷:-)

    一次做一个”

    那么,是否有可能一次正确地选择一个0或1?是的!您只需使用正确的概率:当仍有
    nzero
    0个待拾取,且
    nremaining
    total“cards”剩余待拾取时,以概率选择0个
    nzero/nremaining

    def deckmaker(n=52):
        deck = [None] * n
        nremaining = float(n)
        nzero = nremaining / 2.0
        for i in range(n):
            if random.random() < nzero / nremaining:
                deck[i] = 0
                nzero -= 1.0
            else:
                deck[i] = 1
            nremaining -= 1.0
        return deck
    
    def deckmaker(n=52): 甲板=[无]*n n保持=浮动(n) nzero=nremaining/2.0 对于范围(n)中的i: 如果random.random() 注意,不需要计数。当
    nzero
    变为0.0时,
    if
    测试将永远不会成功(
    random()<0.0
    不会发生);一旦我们选择了
    n/2个
    1个,