从(x,y)的范围内随机采样n位数字,平均为k?

时间:2018-11-06 22:14:37

标签: python numpy random

我正在尝试从范围(低= 3,高= 7)中随机抽取n = 15位数字,当对采样的15位数字求和时,它们的平均值为5。

到目前为止,我仅设法对某些范围内的n位数字进行了随机采样,例如:

n = 15
low  = 3
high = 8
range=[i for i in range(low,high)]
list =np.random.choice(range, n)

这将生成随机的15位整数,范围为3、4、5、6、7。但是,我希望对其进行随机采样,但是n位数字总和的平均值等于5?我该怎么办?

3 个答案:

答案 0 :(得分:2)

我不确定这是否适合您的需求,但这是实现这一目标的一种方法。

import random

def kind_of_random(low, high, k, n):
    """
    Generate a list of n numbers between low and high
    with a mean of exactly k.
    """  
    assert k < high
    values = [low] * n
    to_add = (k - low) * n
    for _ in range(to_add):
        i = random.randint(0, n-1)
        # Don't want to add to a value that's already the max
        while values[i] == high:
            i = random.randint(0, n-1)
        values[i] += 1
    return values

ns = kind_of_random(3, 7, 5, 15)

我敢肯定,这种想法会有更有效的变化-我认为您可以通过启动n * [k]而不是n * [low]并进行一些成对的加/减运算来更快地完成此操作,但这对于小的n应该足够好了。

答案 1 :(得分:1)

好吧,我们可以使用分布,其结果自然会合计为已知值,并且 采样数固定的平均值也将是固定的。 5的平均值和15的样本数意味着总数的总和应始终等于75。

最简单的是Multinomial,因此请从NumPy中使用它。我们将等概率设置为1/15,在[0 ... 30]范围内进行采样,如果任何值超出所需范围,则拒绝进行采样。

它比@jbch提出的方法快,没有求和平均值的手动平衡,并且如果关心它,分布直方图更接近对称

代码

import numpy as np

def multiSum(n, p, maxv):
    while True:
        v  = np.random.multinomial(n, p, size=1)
        q  = v[0]
        a,  = np.where(q > maxv) # are there any values above max
        if len(a) == 0: # accept only samples below or equal to maxv
            return q

N = 15
p = np.full((N), 1.0/np.float64(N))

mean  = 5
start = 3
stop  = 7
n = N*mean - N*start

h = np.zeros((5), dtype=np.int64)
print(h)
for k in range(0, 10000):
    ns = multiSum(n, p, stop-start) + start # result in [3...7]
    #print(np.mean(ns))
    for v in ns:
        h[v-start] += 1

print(h)

计算机上的典型输出直方图

[15698 38107 44584 33719 17892]

@jbch输出直方图

[17239 39237 42188 28957 22379]

答案 2 :(得分:0)

您想要的东西似乎是矛盾的。但是,有一种方法可以使结果看起来像您想要的那样。

不要在一个范围内仅创建15个随机数字,而是创建更多数字。也许有成千上万。如果数字确实是随机的,请确保选择一个范围,其中平均值应约为所需的平均值。然后,一次取15个数字并将其放入列表中。丢掉不适合15个尾数的任何尾数。

现在,遍历列表,扔掉所有不等于所需数量的元素。现在,您有了一个新列表,其中只有一组数字,这些数字应该平均所需的方式,并且它们都应该是伪随机的(或足够随机的)。由于您的起始数字池很大,因此除非您选择的起始范围很差,否则此列表不应为空。

生成一个新的随机数,该随机数将成为列表中的索引,您将从该索引中声明最终的数字组。希望有道理!