Generating random numbers to obtain a fixed sum(python)
Solution 1
This might not be the most efficient way but it will work
totals = [54, 1536, 36, 14]
nums = []
x = np.random.randint(0, i, size=(6,))
for i in totals:
while sum(x) != i: x = np.random.randint(0, i, size=(6,))
nums.append(x)
print(nums)
[array([ 3, 19, 21, 11, 0, 0]), array([111, 155, 224, 511, 457, 78]), array([ 8, 5, 4, 12, 2, 5]), array([3, 1, 3, 2, 1, 4])]
This is a way more efficient way to do this
totals = [54,1536,36,14,9,360, 0]
nums = []
for i in totals:
if i == 0:
nums.append([0 for i in range(6)])
continue
total = i
temp = []
for i in range(5):
val = np.random.randint(0, total)
temp.append(val)
total -= val
temp.append(total)
nums.append(temp)
print(nums)
[[22, 4, 16, 0, 2, 10], [775, 49, 255, 112, 185, 160], [2, 10, 18, 2, 0, 4], [10, 2, 1, 0, 0, 1], [8, 0, 0, 0, 0, 1], [330, 26, 1, 0, 2, 1], [0, 0, 0, 0, 0, 0]]
Solution 2
Generating a list of random numbers that sum to a certain integer is a very difficult task. Keeping track of the remaining quantity and generating items sequentially with the remaining available quantity results in a non-uniform distribution, where the first numbers in the series are generally much larger than the others. On top of that, the last one will always be different from zero because the previous items in the list will never sum up to the desired total (random generators usually use open intervals in the maximum). Shuffling the list after generation might help a bit but won't generally give good results either.
A solution could be to generate random numbers and then normalize the result, eventually rounding it if you need them to be integers.
import numpy as np
totals = np.array([54,1536,36,14]) # don't use Sum because sum is a reserved keyword and it's confusing
a = np.random.random((6, 4)) # create random numbers
a = a/np.sum(a, axis=0) * totals # force them to sum to totals
# Ignore the following if you don't need integers
a = np.round(a) # transform them into integers
remainings = totals - np.sum(a, axis=0) # check if there are corrections to be done
for j, r in enumerate(remainings): # implement the correction
step = 1 if r > 0 else -1
while r != 0:
i = np.random.randint(6)
if a[i,j] + step >= 0:
a[i, j] += step
r -= step
Each column of a
represents one of the lists you want.
Hope this helps.
Related videos on Youtube
IndigoChild
Updated on June 04, 2022Comments
-
IndigoChild almost 2 years
I have the following list:
Sum=[54,1536,36,14,9,360]
I need to generate 4 other lists, where each list will consist of 6 random numbers starting from 0, and the numbers will add upto the values in sum. For eg;
l1=[a,b,c,d,e,f] where a+b+c+d+e+f=54 l2=[g,h,i,j,k,l] where g+h+i+j+k+l=1536
and so on upto l6. And I need to do this in python. Can it be done?
-
abarnert about 6 yearsOf course it can be done, but first you have to decide how you plan to choose the random numbers. Can I just do
[random.randrange(2) for _ in range(5)]
and then add1536 - sum(those five numbers)
for my last random number? If not, why not? What's the rule here? -
KuboAndTwoStrings about 6 yearsIs this a homework question? Please show us what you have tried so far in terms of code.
-
IndigoChild about 6 years@abertnet, no such rule, just that the numbers have to be random
-
Rao Sahab about 6 yearsIs there any constraint like number should not be repeated, or something like that?
-
-
IndigoChild about 6 yearshi, for a list of len 1000, I get this error: ValueError: low >= high
-
JahKnows about 6 yearsCan you post your list so that I can test that please?
-
JahKnows about 6 yearsThe problem is the negative values in your list actually.
-
IndigoChild about 6 yearsHi, I just checked, there are no negative values..
-
JahKnows about 6 yearsCan you add print(i) right in the for loop to find out what value is causing the problem please.
-
IndigoChild about 6 yearsHi ,print(i) returns 4
-
IndigoChild about 6 yearsI've edited the questionn to include the 5th ad 6th value
-
JahKnows about 6 yearsWorks for me with all these values. Please append the problematic values.
-
IndigoChild about 6 yearsI just realized, there are a few 1s and 2s here..could that be the problem?
-
JahKnows about 6 years1s should be fine, however 0s will cause that error too. Are their 0s?
-
JahKnows about 6 yearsI made an edit to account for 0s to remove that error.
-
IndigoChild about 6 yearsworked perfectly, thanks a lot buddy for the ffort :)
-
Richard over 3 yearsThis does not generate a uniform distribution
-
Richard almost 3 yearsA multinomial distribution is a superior way to do this.