在python中,在一个范围内生成N个正整数,加起来等于总数
我看到其他帖子也在讨论类似的问题。我知道如何生成N个正整数。我还知道如何限制随机生成的整数之和。唯一的问题是满足N个值都不超出指定范围的条件 e、 g.在python中,在一个范围内生成N个正整数,加起来等于总数,python,python-2.7,numpy,random,range,Python,Python 2.7,Numpy,Random,Range,我看到其他帖子也在讨论类似的问题。我知道如何生成N个正整数。我还知道如何限制随机生成的整数之和。唯一的问题是满足N个值都不超出指定范围的条件 e、 g.generate_int(n,total,low,high)应生成n值数组,使每个值介于low和high之间,且总和等于总和。如有任何建议/帮助,将不胜感激 e、 g.generate_int(4,40,4,15)应该生成如下内容 [7,10,13,10] 我不在乎这些数字是否重复,只要它们不是高度倾斜的。我使用np.randon.randin
generate_int(n,total,low,high)
应生成n值数组,使每个值介于low和high之间,且总和等于总和。如有任何建议/帮助,将不胜感激
e、 g.generate_int(4,40,4,15)
应该生成如下内容
[7,10,13,10]
我不在乎这些数字是否重复,只要它们不是高度倾斜的。我使用np.randon.randint(5,15,n)
选择整数
到目前为止,我已经尝试了以下方法,但不起作用-
import numpy as np
import random
from random import uniform as rand
total=50
n=10
low=2
high=15
result=[]
m=0
nobs=1
while nobs <= n:
if m >= (total - low):
last_num= total -new_tot
result.append(last_num)
else:
next_num=np.random.randint(low,high,1)
new_tot = sum(result) + next_num
result.append(next_num)
m=new_tot
nobs +=1
print result
print sum(result)
将numpy导入为np
随机输入
从随机导入统一为rand
总数=50
n=10
低=2
高=15
结果=[]
m=0
nobs=1
而nobs=(总量-低):
最后数量=总数-新总数
result.append(最后一个)
其他:
next_num=np.random.randint(低、高、1)
新总数=总和(结果)+下一个总数
result.append(下一个\u num)
m=新的
nobs+=1
打印结果
打印总和(结果)
再次感谢。以下是我的尝试,我会解释
import numpy as np
def sampler(samples, sum_to , range_list):
assert range_list[0]<range_list[1], "Range should be a list, the first element of which is smaller than the second"
arr = np.random.rand(samples)
sum_arr = sum(arr)
new_arr = np.array([int((item/sum_arr)*sum_to) if (int((item/sum_arr)*sum_to)>range_list[0]and int((item/sum_arr)*sum_to)<range_list[1]) \
else np.random.choice(range(range_list[0],range_list[1]+1)) for item in arr])
difference = sum(new_arr) - sum_to
while difference != 0:
if difference < 0 :
for idx in np.random.choice(range(len(new_arr)),abs(difference)):
if new_arr[idx] != range_list[1] :
new_arr[idx] += 1
if difference > 0:
for idx in np.random.choice(range(len(new_arr)), abs(difference)):
if new_arr[idx] != 0 and new_arr[idx] != range_list[0] :
new_arr[idx] -= 1
difference = sum(new_arr) - sum_to
return new_arr
new_arr = sampler (2872,30000,[5,15])
print "Generated random array is :"
print new_arr
print "Length of array:", len(new_arr)
print "Max of array: ", max(new_arr)
print "min of array: ", min(new_arr)
print "and it sums up to %d" %sum(new_arr)
import numpy as np
def generate_ints(n, total, low, high):
begin = 0
randys = []
correctTotal = False
while correctTotal is False:
while begin < n:
r1 = np.random.randint(low, high, 1)
randys.append(r1)
begin += 1
if sum(randys) == total:
correctTotal = True
else:
begin = 0
del randys[:]
generated_list = np.array(randys).tolist()
gen = [g[0] for g in generated_list]
return gen
my_list = generate_ints(4, 40, 4, 15)
print "Generated list '{}' with sum {}.".format(my_list, sum(my_list))
将numpy导入为np
def生成积分(n、总计、低、高):
开始=0
兰迪斯=[]
correctTotal=False
虽然correctTotal为False:
当开始
在函数内部,我设置了两个常量,randys
和begin
。在内部while
循环中,只要begin
小于n
它就会在low
和high
之间生成n
随机整数。如果总和等于总数
,则在循环时退出外部,否则需要重置常量。
只需返回randys
将给出NumPyarray
s的列表。使用tolist()
方法,将生成一个列表。
现在我们有一个列表。我用一个简短的列表把它压平了。最后,返回所需的列表和输出。
HTH.如果我正确理解了规范,您希望随机生成受限整数,这样每个可能的组合被选择的可能性相等
对于小的输入值,我们可以适应均匀生成随机整数的问题来精确地解决这个问题。我们只需要一种方法来计算受限的k-组合。在《数学论》中有一个相关问题的递归公式,但事实证明,其中提到了一个更明确的公式,它使用了二项式系数。下面是纯Python的一个实现:
import functools
import random
@functools.lru_cache(1 << 10)
def C1(n, k, a, b):
"Counts the compositions of `n` into `k` parts bounded by `a` and `b`"
return C2(n - k*(a - 1), k, b - (a - 1))
def C2(n, k, b):
"Computes C(n, k, 1, b) using binomial coefficients"
total = 0
sign = +1
for i in range(0, k + 1):
total += sign * choose(k, i) * choose(n - i*b - 1, k - 1)
sign = -sign
return total
def choose(n, k):
"Computes the binomial coefficient of (n, k)"
if k < 0 or k > n:
return 0
if k == 0 or k == n:
return 1
k = min(k, n - k)
c = 1
for i in range(k):
c = c * (n - i) // (i + 1)
return c
def check_pre_and_post_conditions(f):
def wrapper(n, k, a, b):
assert 1 <= k <= n, (n, k)
assert 1 <= a <= b <= n, (n, a, b)
assert k*a <= n <= k*b, (n, k, a, b)
comp = f(n, k, a, b)
assert len(comp) == k, (len(comp), k, comp)
assert sum(comp) == n, (sum(comp), n, comp)
assert all(a <= x <= b for x in comp), (a, b, comp)
return comp
return functools.wraps(f)(wrapper)
@check_pre_and_post_conditions
def random_restricted_composition(n, k, a, b):
"Produces a random composition of `n` into `k` parts bounded by `a` and `b`"
total = C1(n, k, a, b)
which = random.randrange(total)
comp = []
while k:
for x in range(a, min(b, n) + 1):
count = C1(n - x, k - 1, a, b)
if count > which:
break
which -= count
comp.append(x)
n -= x
k -= 1
return comp
导入工具
随机输入
@functools.lru\u缓存(1 n:
返回0
如果k==0或k==n:
返回1
k=最小值(k,n-k)
c=1
对于范围(k)内的i:
c=c*(n-i)/(i+1)
返回c
def检查前和后条件(f):
def包装(n、k、a、b):
断言1将我的代码添加到问题中。thanks@idjaw“只要它们不是高度倾斜的”我认为这是不可能实现的,除非你做到这一点。理想的是一个均匀的分布。这是一个很好的理想,但是除非你能指定如何,这个问题实在太宽了。(在这些范围内添加的n个数字等于目标);统一采样一个(这当然不是实践中要追求的方法)运行1000次,得到177到177的结果183@FranciscoCouzo修正此方法不统一(在我看来有一些偏差),但可能足以完成某些任务(与拒绝抽样相比速度更快)@sumoka如果答案回答了您的问题,请单击该答案()的复选标记接受它,以便其他人注意到它在第一次查看时会起作用。它似乎不适用于较大的人群,例如低=5,高=15,n=2872,总计=30000。我看到它生成随机整数,但不在范围内。代码没有那么简洁(例如,使用循环绘制多个随机数;它是开箱即用的)这种方法对于较大的n或麻烦的边界是不可行的,但是这种方法是无偏差的,如果生成输出,它是一致的。使用的一般算法框架称为拒绝采样。@sascha很有趣,我不知道提供了这种方法!如果我的答案是不可行的,很抱歉,坦率地说,我只有很少的knNowledge of numpy,但我会更深入地了解这一点。事实上,我对它投了更高的票是因为这种方法(这不是一个容易的问题)。不确定是谁因为哪些原因投了反对票(尽管我没有测试你的代码)。谢谢,我同意这不是一个容易的问题,尤其是生成具有特定分布的数据。我正在寻找一种方法来获得“总数”一个“n”的函数和“low”和“high”的边界。这两种解决方案都解决了这个问题。我不是100%清楚它是如何工作的,但我会逐行解码。再次感谢。
import functools
import random
@functools.lru_cache(1 << 10)
def C1(n, k, a, b):
"Counts the compositions of `n` into `k` parts bounded by `a` and `b`"
return C2(n - k*(a - 1), k, b - (a - 1))
def C2(n, k, b):
"Computes C(n, k, 1, b) using binomial coefficients"
total = 0
sign = +1
for i in range(0, k + 1):
total += sign * choose(k, i) * choose(n - i*b - 1, k - 1)
sign = -sign
return total
def choose(n, k):
"Computes the binomial coefficient of (n, k)"
if k < 0 or k > n:
return 0
if k == 0 or k == n:
return 1
k = min(k, n - k)
c = 1
for i in range(k):
c = c * (n - i) // (i + 1)
return c
def check_pre_and_post_conditions(f):
def wrapper(n, k, a, b):
assert 1 <= k <= n, (n, k)
assert 1 <= a <= b <= n, (n, a, b)
assert k*a <= n <= k*b, (n, k, a, b)
comp = f(n, k, a, b)
assert len(comp) == k, (len(comp), k, comp)
assert sum(comp) == n, (sum(comp), n, comp)
assert all(a <= x <= b for x in comp), (a, b, comp)
return comp
return functools.wraps(f)(wrapper)
@check_pre_and_post_conditions
def random_restricted_composition(n, k, a, b):
"Produces a random composition of `n` into `k` parts bounded by `a` and `b`"
total = C1(n, k, a, b)
which = random.randrange(total)
comp = []
while k:
for x in range(a, min(b, n) + 1):
count = C1(n - x, k - 1, a, b)
if count > which:
break
which -= count
comp.append(x)
n -= x
k -= 1
return comp