我知道这个标题听起来很无聊,因为很多人已经问过这个话题了。我希望它能帮助我了解随机模块是如何工作的。问题是,我写了两个不同的函数,我认为应该是相同的,但是我得到的结果不一样,我不明白为什么。
我希望最终得到一个“洗牌好的牌组”,我只关心牌是红色还是黑色,所以我的牌组非常简单。我叫“1”红色和“0”黑色。
我的想法是,如果random.random()大于0.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不工作,以防这是重要的。
我写这个程序是为了模拟贴在这里的拼图:http://www.thebigquestions.com/2013/12/17/tuesday-puzzle-4/
我的策略是记住最后几张牌,并利用这些信息来决定何时拿下下下一张牌我想也许在连续得到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张红色卡片后拿下卡片的结果。这毫无意义,所以我寻找了一种不同的方法来创建甲板,得到了一个更正常的结果。但我还是不知道我原来的甲板出了什么问题。

最佳答案

一般来说,除非你能严格证明随机化方法是正确的,否则你永远不应该相信它是正确的。这通常很难。
为了深入了解您的问题,让我们概括一下有问题的函数:

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

所以这两种可能性几乎是一样的很好!现在试试4号的一副牌,把相关的线改成这样:
c[tuple(deckmaker(4))] += 1

运行:
(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一的所有置换都是相等的,则机会为1 in(2*M)-choose-M(选择M零位置的方法的数目)。
在函数构造一个甲板的方式中,机会是1 in2**M(0和1在第一个M位置中的每个位置中的可能性相等)。
一般来说,(2*M)-choose-M2**M大得多,因此函数构造一个从所有零开始的数据组的频率远远高于“它应该”一副52张牌(M == 26):
>>> from math import factorial as f
>>> one = f(52) // f(26)**2
>>> two = 2**26
>>> float(one) / two
7389761.998476148

所以“从26个零开始”的可能性比应该的高出700万倍酷:-)
一次一个地做
那么,一次选择0或1是否可以正确执行此操作?是的!你只需要使用正确的概率:当还有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

注意,不需要计算。当nzero / nremaining变为0.0时,nzero测试将永远不会成功(if不可能发生);一旦选择random() < 0.0测试,n/2将为真,nzero == nremaining测试将始终成功(if始终为真)很可爱;-)

关于python - 调试:使用Python/随机洗牌,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20650030/

10-15 18:38