我知道这个标题听起来很无聊,因为很多人已经问过这个话题了。我希望它能帮助我了解随机模块是如何工作的。问题是,我写了两个不同的函数,我认为应该是相同的,但是我得到的结果不一样,我不明白为什么。
我希望最终得到一个“洗牌好的牌组”,我只关心牌是红色还是黑色,所以我的牌组非常简单。我叫“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 in
2**M
(0和1在第一个M
位置中的每个位置中的可能性相等)。一般来说,
(2*M)-choose-M
比2**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/