I have seen other posts addressing similar problem. I know how to generate N positive integers. I also know how to restrict the sum of randomly generated integers. The only problem is satisfying the condition that none of the N values fall out of the specified range.
e.g. generate_ints(n, total, low, high)
should generate n value array such that each value is between low and high and the sum adds up to the total. Any pointers/ help would be greatly appreciated.
e.g.generate_ints(4, 40, 4, 15)
should generate something like
[7,10,13,10]
I don't care if the numbers are repeated, as long as they are not highly skewed. I am using np.randon.randint(5,15,n)
to select the integer.
So far, I have tried the following, but it doesn't work -
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)
Thanks again.
If I understand the specifications correctly, you wish to randomly generate restricted integer compositions such that each possible composition has an equal likelihood of being chosen.
We can adapt this answer to the problem of uniformly generating a random integer partition to solve this problem exactly for small input values. We simply need a way to count restricted k-compositions. There's a recursive formulation in this answer on Mathematics to a related problem, but it turns out that there is a more explicit formula mentioned as part of this answer that uses binomial coefficients. Here's a implementation in pure Python:
To select a random composition, we simply generate a random index smaller than the total number of possible compositions, and then construct the
i-th
lexicographic composition (see the linked questions for explanations of the recurrence relations used). This should produce all possible outcomes with equal probability.However, because
C1(n, k, a, b)
grows exponentially, this method is pretty slow for large values ofn
andk
. For large values, an approximate solution will serve you better.Here's my attempt which I will explain.
Inside the function, I've set two constants,
randys
andbegin
. In the innerwhile
loop, as long asbegin
is less thann
it generatesn
random integers betweenlow
andhigh
. If the sum is equivalent to thetotal
, exit out of the outerwhile
loop, otherwise it needs to reset the constants.Just returning
randys
will give a list of NumPyarray
s. Using thetolist()
method, this produces a list instead.Now we have a list of lists. I've flattened it using a short and sweet list comprehension. Finally
return
that list and output as desired.HTH.
result :