我正在尝试从范围(低= 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?我该怎么办?
答案 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个尾数的任何尾数。
现在,遍历列表,扔掉所有不等于所需数量的元素。现在,您有了一个新列表,其中只有一组数字,这些数字应该平均所需的方式,并且它们都应该是伪随机的(或足够随机的)。由于您的起始数字池很大,因此除非您选择的起始范围很差,否则此列表不应为空。
生成一个新的随机数,该随机数将成为列表中的索引,您将从该索引中声明最终的数字组。希望有道理!