I'm either looking for an algorithm or a suggestion to improve my code to generate a list of random numbers that their sum equals some arbitrary number. With my code below, it'll always be biased as the first numbers will tend to be higher.
Is there a way to have the number selection more efficient?
#!/usr/bin/python
'''
Generate a list of 'numbs' positive random numbers whose sum = 'limit_sum'
'''
import random
def gen_list(numbs, limit_sum):
my_sum = []
for index in range(0, numbs):
if index == numbs - 1:
my_sum.append(limit_sum - sum(my_sum))
else:
my_sum.append(random.uniform(0, limit_sum - sum(my_sum)))
return my_sum
#test
import pprint
pprint.pprint(gen_list(5, 20))
pprint.pprint(gen_list(10, 200))
pprint.pprint(gen_list(0, 30))
pprint.pprint(gen_list(1, 10))
THE OUTPUT
## output
[0.10845093828525609,
16.324799712999706,
0.08200162072303821,
3.4534885160590041,
0.031259211932997744]
[133.19609626532952,
47.464880208741029,
8.556082341110228,
5.7817325913462323,
4.6342577008233716,
0.22532341156764768,
0.0027495225618908918,
0.064738336208217895,
0.028888697891734455,
0.045250924420116689]
[]
[10]
Method #2 : Using random.sample() + sum() This single utility function performs the exact required as asked by the problem statement, it generated N no. of random numbers in a list in the specified range and returns the required list. The task of performing sum is done using sum().
You could use the RAND() function to generate N numbers (8 in your case) in column A. Then, in column B you could use the following formula B1=A1/SUM(A:A)*320 , B2=A2/SUM(A:A)*320 and so on (where 320 is the sum that you are interested into). So you can just enter =RAND() in A1, then drag it down to A8.
Why not just generate the right number of uniformly distributed random numbers, tot them up and scale ?
EDIT: To be a bit clearer: you want N numbers which sum to S ? So generate N uniformly distributed random numbers on the interval [0,1) or whatever your RNG produces. Add them up, they will total s (say) whereas you want them to total S, so multiply each number by S/s. Now the numbers are uniformly randomly distributed on [0,S/s) I think.
Here's how I would do it:
max
]max
and the first interval will start at 0 and end at the first number in the list.Now, the lengths of those intervals will always sum up to max
, since they simply represent segments inside [0,max
].
Code (in Python):
#! /usr/bin/env python
import random
def random_numbers(n,sum_to):
values=[0]+[random.randint(0,sum_to) for i in xrange(n-1)]+[sum_to]
values.sort()
intervals=[values[i+1]-values[i] for i in xrange(len(values)-1)]
return intervals
if __name__=='__main__':
print random_numbers(5,100)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With