python - 调试 : Shuffle deck of cards in Python/random

标签 python algorithm random shuffle

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

我希望最终得到一个“洗牌良好的套牌”。我只关心牌是红的还是黑的,所以我的套牌很简单。我称“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 列表运算符,它与我的第二个函数做同样的事情,所以当然得到洗牌很容易。但我仍然想知道为什么我的原始代码没有做同样的事情。

已编辑:很抱歉对 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)

结果我拿的牌(放入列表 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?有两个答案:

  1. 如果 M 的所有排列零和 M可能性相等,机会是 (2*M)-choose-M 中的 1 (选择 M 零位置的方法数)。

  2. 在函数构造一副牌的方式中,2**M 中的机会为 1 (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剩余的“卡片”总数,概率为零 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 始终为真)。很可爱 ;-)

关于python - 调试 : Shuffle deck of cards in Python/random,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20650030/

相关文章:

c# - 随机输出文件夹中的文件

objective-c - 打乱 NSString 顺序的快速方法?

python - Tensorflow急切执行-计算顺序模型的两层之间的梯度

algorithm - 为 Web 服务器设计一个数据结构来存储访问页面的历史记录

python - 如何计算最佳列宽?

algorithm - 推荐系统如何工作?

Scala:如何根据预期分布生成数字?

Python 嵌套循环验证问题

python - numpy 中球坐标创建四元数

python - 如何使用 TensorFlow 将预测值添加到 CSV 文件中的空列?