2013-12-18 30 views
2

我知道標題聽起來很無聊,因爲很多人已經問過這個話題。我希望它能幫助我深入瞭解隨機模塊的工作原理。問題是,我寫了兩個不同的函數,我認爲它們應該是相同的,但是我得到的結果並不完全相同,我不明白爲什麼。調試:在Python中亂序卡片/隨機

我希望最後得到一個「洗好的甲板」。我只關心卡片是紅色還是黑色,所以我的卡組非常簡單。我叫「1」紅色和「0」黑色。

我的想法是通過附加1(紅色)if if 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 

注:在寫這個問題,我發現了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) 

結果超過一半,我正在(投入列表mycards)爲「紅色」,因此我採取了卡後,5個紅色卡在實現卡一排被畫出來。這沒有意義,所以我尋找不同的方式來創建甲板,並得到更正常的結果。但我仍然不知道我原來的套牌有什麼問題。

+1

「甲板製造商不能正常工作」...它有什麼問題?它似乎爲我工作。 – mgilson

+0

對不起,我絕對應該更具體一些,但我自己並不完全明白這個問題。如果有幫助,我將添加我用來確定問題存在的代碼。 – wbruntra

+0

這是另一種提問方式:當你說「甲板製造者不能正常工作」時,是什麼讓你得出這個結論?該程序產生的輸出是否與您期望的不同,如果是,輸出是什麼,您認爲它會做什麼? –

回答

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的機會呢?有兩個答案到:

  1. 如果M零和M以外的所有排列都是相等的可能,機會是(2*M)-choose-M 1(的方式來挑M零的位置數)。

  2. 在函數構造卡組的方式中,2**M中的機會是1(0和1在第一個M位置中的每一箇中的可能性相同)。

一般來說,(2*M)-choose-M2**M大得多,因此函數構建起全0甲板遠遠往往比「應該」。對於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總「卡」剩餘採摘,採摘零的概率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變爲0.0時,if測試永遠不會成功(random() < 0.0不會發生);並且一旦我們選取n/2個,nzero == nremaining將爲真,並且if測試將始終成功(random() < 1.0始終爲真)。這很可愛;-)

+0

很簡單。我認爲這裏很好地解釋了這個問題(並提供了對「非隨機性」原因的洞察) - 也許我沒有仔細考慮過這個問題,但這讓我想起了[Berand's Box Paradox](http: //en.wikipedia.org/wiki/Bertrand's_box_paradox) – mgilson

+1

明白了!當用一副牌進行真正的洗牌時,在第一張牌是紅色後,第二張牌不太可能是紅色的,但是我的功能每次都有50%的概率構建牌組。所以結果都是棘手的。謝謝你的幫助。 – wbruntra

+1

@wbruntra,卓越見識!你得到它:-) –

2

我不確定這是什麼意思,但我認爲由第一種方法生成的最後一張牌不成比例地可能是相同的。

從50個或更少的樣本中獲得26個或26個零的機會似乎很大(我認爲您可以使用交換二項式分佈來計算它)。即使很小的機會也意味着你應該賭最後的牌是相同的(因此其他牌是相反的)顏色。

你可以做的只是添加零和直到有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張牌的差距較小,但這個想法依然如此。