在python中,在一个范围内生成N个正整数,加起来等于总数

在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

我看到其他帖子也在讨论类似的问题。我知道如何生成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.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
将给出NumPy
array
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