将numpy.random中的两个样本组合在一起并不会以随机顺序结束

时间:2017-04-26 22:10:57

标签: python random

我实现了Wald-Wolfowitz runs test但是在测试期间我遇到了奇怪的行为,我采取的步骤如下:

  1. 我从同一个发行版中取出两个样本:

    import numpy as np
    list_dist_A = np.random.chisquare(2, 1000)
    list_dist_B = np.random.chisquare(2, 1000)
    
  2. 我连接两个列表并对它们进行排序,同时记住哪个数字来自哪个样本。以下函数执行此操作并返回标签列表[“A”,“B”,“A”,“A”,...“B”]

    def _get_runs_list(list1, list2):
         # Add labels  
         l1 = list(map(lambda x: (x, "A"), list1))
         l2 = list(map(lambda x: (x, "B"), list2))
         # Concatenate
         lst = l1 + l2
         # Sort
         sorted_list = sorted(lst, key=lambda x: x[0])
         # Return only the labels:
         return [l[1] for l in sorted_list]
    
  3. 现在我想计算运行次数(连续的相同标签序列)。 e.g:

    • a,b,a,b有4次运行
    • a,a,a,b,b有2次运行
    • a,b,b,b,a,a有3次运行

    为此,我使用以下代码:

    def _calculate_nruns(labels):
        nruns = 0
        last_seen = None
    
        for label in labels:
            if label != last_seen:
                nruns += 1
            last_seen = label
    
        return nruns
    
  4. 由于所有元素都是随机绘制的,我认为我应该大致以序列a,b,a,b,a,b...结束。所以这意味着运行次数大约是2000。 然而,可以看出in this snippet on "repl.it"情况并非如此,它总是大约在1000左右。

    任何人都可以解释为什么会这样吗?

2 个答案:

答案 0 :(得分:4)

~1000是预期的结果。 Following the Wikipedia article在此统计测试中,您有Np = Nn = 1000N = Np + Nn = 2000。这意味着运行次数的预期值为mu = 2 * Np * Nn / N + 1,即1001。

答案 1 :(得分:2)

哦,这让我想起了Gambler's fallacy

我不是统计学家,但要获得2000次运行,您需要A跟随BB跟随A的可能性为100%。这表明PRNG对先前的抽奖有某种记忆。那不太好......

OTOH,假设您绘制了一个标记为A的值,那么有50%的几率绘制另一个A,并有50%的机会绘制B。因此,绘制长度一次运行的机会实际上只有50%,获得长度为2的运行的机会是25%,长度为3,它是12.5%,长度为4,它是6.25,依此类推。

最后一部分可以轻松验证:

import numpy as np
list_dist_A = np.random.chisquare(2, 1000)
list_dist_B = np.random.chisquare(2, 1000)

listA = [(value, 'A') for value in list_dist_A]
listB = [(value, 'B') for value in list_dist_B]
combined = sorted(listA+listB, key=lambda x: x[0])
combined = [x[1] for x in combined]

from itertools import groupby
from collections import Counter

runlengths = [len(list(it)) for _, it in groupby(combined)]  # lengths of the individual runs
print(Counter(runlengths))  # similar to a histogram
# Counter({1: 497, 2: 234, 3: 131, 4: 65, 5: 29, 6: 20, 7: 11, 8: 2, 10: 1, 14: 1})

所以这实际上非常接近预期(如上所述:1: 500, 2: 250, 3: 125, 4:62, ...)。如果您的假设是正确的,那么它将更接近1:2000, 2: 0, ...