我想生成一个由15个整数组成的列表,它们的总和为12,最小值为0,最大值为6。
我尝试了以下代码
def generate(low,high,total,entity):
while sum(entity)!=total:
entity=np.random.randint(low, high, size=15)
return entity
但是上述功能无法正常工作。这太浪费时间了。 请让我知道生成此类数字的有效方法吗?
答案 0 :(得分:4)
从严格意义上讲,以上内容将起作用。但是对于介于0和6之间的15个数字,生成12的几率并不高。实际上,我们可以使用以下方法计算可能性的数量:
对于0≤s≤6,F(s,1)= 1 和
F(s,n)=Σ 6 i = 0 F(s-i,n-1)。
我们可以使用以下值进行计算:
from functools import lru_cache
@lru_cache()
def f(s, n, mn, mx):
if n < 1:
return 0
if n == 1:
return int(mn <= s <= mx)
else:
if s < mn:
return 0
return sum(f(s-i, n-1, mn, mx) for i in range(mn, mx+1))
这意味着在4'747'561'509'943个总可能性中,有9'483'280个可能性总和为12,即0.00019975%。因此,大约需要500'624次迭代才能得出这样的解决方案。
因此,我们应该更好地寻求找到一种简单的方法来生成这种序列。我们可以通过每次计算生成数字的概率来做到这一点:将 i 作为数字生成的概率作为 n 个数字序列中第一个数字的总和为< em> s 是 F(si,n-1,0,6)/ F(s,n,0,6)。这将确保我们在可能性列表上生成一个 uniform 列表,如果我们每次绘制一个统一数字,那么它将不会在与给定值匹配的整个值列表中与统一分布匹配条件:
我们可以递归地做到这一点:
from numpy import choice
def sumseq(n, s, mn, mx):
if n > 1:
den = f(s, n, mn, mx)
val, = choice(
range(mn, mx+1),
1,
p=[f(s-i, n-1, mn, mx)/den for i in range(mn, mx+1)]
)
yield val
yield from sumseq(n-1, s-val, mn, mx)
elif n > 0:
yield s
使用上述功能,我们可以生成numpy数组:
>>> np.array(list(sumseq(15, 12, 0, 6)))
array([0, 0, 0, 0, 0, 4, 0, 3, 0, 1, 0, 0, 1, 2, 1])
>>> np.array(list(sumseq(15, 12, 0, 6)))
array([0, 0, 1, 0, 0, 1, 4, 1, 0, 0, 2, 1, 0, 0, 2])
>>> np.array(list(sumseq(15, 12, 0, 6)))
array([0, 1, 0, 0, 2, 0, 3, 1, 3, 0, 1, 0, 0, 0, 1])
>>> np.array(list(sumseq(15, 12, 0, 6)))
array([5, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1])
>>> np.array(list(sumseq(15, 12, 0, 6)))
array([0, 0, 0, 0, 4, 2, 3, 0, 0, 0, 0, 0, 3, 0, 0])
答案 1 :(得分:2)
您可以尝试以不同的方式实现它。
index.html
此外,如果您使用np.random.randint,您的最高分实际上将是高1
答案 2 :(得分:2)
嗯,有一个简单自然的解决方案-使用分配,根据定义,它为您提供具有固定总和的值数组。最简单的是Multinomial Distribution。添加的唯一代码是,如果某些采样值大于最大值,则检查并拒绝(并重复采样)。
沿线
import numpy as np
def sample_sum_interval(n, p, maxv):
while True:
q = np.random.multinomial(n, p)
v = np.where(q > maxv)
if len(v[0]) == 0: # if len(v) > 0, some values are outside the range, reject
return q
return None
np.random.seed(32345)
k = 15
n = 12
maxv = 6
p = np.full((k), np.float64(1.0)/np.float64(k), dtype=np.float64) # probabilities
q = sample_sum_interval(n, p, maxv)
print(q)
print(np.sum(q))
q = sample_sum_interval(n, p, maxv)
print(q)
print(np.sum(q))
q = sample_sum_interval(n, p, maxv)
print(q)
print(np.sum(q))
更新
我迅速查看了@WillemVanOnsem提出的方法,我相信它与我自己使用的多项式不同。
如果我们查看多项式PMF,并假设所有k
个数字的概率相等,
p 1 = ... = p k = 1 / k,那么我们可以将PMF编写为
PMF(x 1 ,... x k )= n!/(x 1 !... x k !)p 1 x 1 ... p k x k = n!/(x 1 !... x k !)k -x 1 ... k -x k = n!/(x 1 !... x k !)k -Sum i x i = n!/(x 1 !... x k !)k -n
很明显,由于分母的阶乘(当然是模排列),特定的x 1 ... x k 组合的概率会彼此不同。我认为@WillemVanOnsem方法与@WillemVanOnsem方法不同,后者的所有人都有相同的出现概率。
故事的道德-这些方法产生不同的分布。