wbr*_*tra 2 python random algorithm shuffle
我知道标题听起来很无聊,因为很多人已经问过这个话题了.我希望它可以帮助我深入了解随机模块的工作原理.问题是,我写的,我认为应该是相同的两个不同的功能,但我得到的结果是不相同的,我不明白为什么.
我希望最终得到一个"洗得很好的套牌".我只关心卡片是红色还是黑色,所以我的套牌非常简单.我称之为"1"红色和"0"黑色.
我的想法是通过附加1(红色),如果random.random()是> .5,或者除了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
Run Code Online (Sandbox Code Playgroud)
注意:在写这个问题的时候,我发现了random.shuffle列表操作符,它与我的第二个函数做了同样的事情,所以当然让洗牌后的表变得容易.但我仍然想知道为什么我的原始代码不会做同样的事情.
编辑:抱歉对deckmaker()的确切问题含糊不清.问题是,我并不完全明白什么是错的.它与它产生的甲板上的事实有关,当你逐一"翻转"卡片时,有一些策略可以让你预测"下一张牌"是红色还是黑色不是使用random.shuffle创建的套牌
编辑2: [更多信息]我将解释我如何确定甲板制造商不起作用,以防重要.我在写这个程序模型拼图张贴在这里: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)
Run Code Online (Sandbox Code Playgroud)
结果超过一半的卡我正在(投入列表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
Run Code Online (Sandbox Code Playgroud)
这是一个小司机:
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]
Run Code Online (Sandbox Code Playgroud)
运行:
(0, 1) 495
(1, 0) 505
Run Code Online (Sandbox Code Playgroud)
所以这两种可能性大致相同.好!现在尝试一个4号甲板; 只需更改相关行:
c[tuple(deckmaker(4))] += 1
Run Code Online (Sandbox Code Playgroud)
运行:
(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
Run Code Online (Sandbox Code Playgroud)
哎呀!如果你愿意的话,你可以进行正式的卡方检验,但通过检查可以看出两个排列(第一个和最后一个)的可能性是其他四个的两倍.所以输出甚至没有接近可以说是随机的.
这是为什么?考虑一下;-)
暗示
对于一个大小的牌组2*M,第一个M条目全部为0 的几率是多少?有两个答案:
如果所有M0和M1的排列可能相等,则机会为1 in (2*M)-choose-M(选择M零位置的方式的数量).
在函数构造牌组的方式中,机会为1英寸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
Run Code Online (Sandbox Code Playgroud)
因此,"以26个零开始"的可能性超过应有的700多万倍.酷:-)
"一次一个"地做
那么有可能一次正确地选择0或1吗?对!你只需要使用正确的概率:当nzero剩余的零被挑选时,nremaining剩下的总"卡"将被挑选,选择零概率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
Run Code Online (Sandbox Code Playgroud)
请注意,没有必要计算.当nzero变为0.0时,if测试永远不会成功(random() < 0.0不可能发生); 一旦我们选择了n/2一个,那nzero == nremaining将是真的,if测试将永远成功(random() < 1.0总是如此).它真可爱 ;-)