Generating random numbers to obtain a fixed sum(py

2020-05-09 00:28发布

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?

2条回答
Evening l夕情丶
2楼-- · 2020-05-09 00:38

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.

查看更多
唯我独甜
3楼-- · 2020-05-09 00:43

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]]

查看更多
登录 后发表回答