I want to generate a list of random distribution of numbers so their sum would be equal to a randomly chosen number. For example, if randomly chosen number is 5, the distrib
Consider doing it continuously first. And for a moment we do not care about final number, so let's sample uniformly X_i in the interval [0...1] so that their sum is equal to 1
X_1 + X_2 + ... X_n = 1
This is well-known distribution called Dirichlet Distribution, or gamma variate, or simplex sampling. See details and discussion at Generating N uniform random numbers that sum to M. One can use random.gammavariate(a,1)
or for correct handling of corners gamma variate with parameter 1 is equivalent exponential distribution, with direct sampling code below
def simplex_sampling(n):
r = []
sum = 0.0
for k in range(0,n):
x = random.random()
if x == 0.0:
return (1.0, make_corner_sample(n, k))
t = -math.log(x)
r.append(t)
sum += t
return (sum, r)
def make_corner_sample(n, k):
r = []
for i in range(0, n):
if i == k:
r.append(1.0)
else:
r.append(0.0)
return r
So from simplex_sampling
you have vector and the sum to be used as normalization.
Thus, to use it for, say, N=5
N = 5
sum, r = simplex_sampling(N)
norm = float(N)/sum
# normalization together with matching back to integers
result = []
for k in range(N):
# t is now float uniformly distributed in [0.0...N], with sum equal to N
t = r[k] * norm
# not sure if you could have zeros,
# and check for boundaries might be useful, but
# conversion to integers is trivial anyway:
# values in [0...1) shall be converted to 0,
# values in [1...2) shall be converted to 1, etc
result.append( int(t) )