1

I have a value (a sum) (in the implementation it is n) that I want to distribute "randomly" to become a list of 12 elements summing up to that value (sum), I wrote the following method to achieve that:

def create_list_summing_up_to(n): 
    values = []
    for i in range(1,13):
        value = random.randint(0, int(n / i))
        values.append(value)
        n -= value
        if n<=0 and i<12:
            values.extend(np.zeros(12-i).tolist())
            break
    if n>0:
        for idx,el in enumerate(values):
            values[idx] = values[idx]+int (n/12)
    return values

My question is: is the method efficient even for large sums (of the order of millions)? How could it be more efficient?

Sam
  • 308
  • 2
  • 7
  • 3
    Does this answer your question? [Generate random numbers summing to a predefined value](https://stackoverflow.com/questions/3589214/generate-random-numbers-summing-to-a-predefined-value) – Mechanic Pig Jul 03 '23 at 15:33

3 Answers3

1

Try this code

import random

def create_list_summing_up_to(n):
    # Generate a list of random values between 0 and 1
    values = [random.random() for _ in range(12)]
    
    # Calculate the sum of the random values
    total = sum(values)
    
    # Scale the values proportionally to ensure they sum up to n
    values = [int(value / total * n) for value in values]
    
    # Adjust the last element to ensure the sum is exact
    values[-1] += n - sum(values)
    
    return values

print(create_list_summing_up_to(150000000))

For more ways you can check this

codester_09
  • 5,622
  • 2
  • 5
  • 27
  • 1
    This will create a non-uniform distribution [stackoverflow.com/a/8068956/2075003](https://stackoverflow.com/questions/8064629/random-numbers-that-add-to-100-matlab/8068956#8068956) – Mechanic Pig Jul 03 '23 at 15:44
0

You can use numpy.random.multinomial:

The multinomial distribution is a multivariate generalization of the binomial distribution. Take an experiment with one of p possible outcomes. An example of such an experiment is throwing a dice, where the outcome can be 1 through 6. Each sample drawn from the distribution represents n such experiments. Its values, X_i = [X_0, X_1, ..., X_p], represent the number of times the outcome was i.

import numpy as np
np.random.multinomial(20, [1/12.]*12, size=1)

array([[1, 1, 2, 3, 1, 1, 0, 3, 0, 3, 2, 3]])  # random

import numpy as np
np.random.multinomial(30, [1/12.]*12, size=1)

array([[4, 1, 2, 2, 3, 4, 2, 2, 1, 3, 2, 4]])  # random

Similarly for n:

import numpy as np
np.random.multinomial(n, [1/12.]*12, size=1)
jared
  • 4,165
  • 1
  • 8
  • 31
Talha Tayyab
  • 8,111
  • 25
  • 27
  • 44
0

Your question is not well formed. You do not "pick a random number". You pick a random number from a given distribution. Such a distribution might be uniform between 0 and 1, or Gaussian, or Poisson distribution.

You're asking us to pick 12 random numbers, and then ensure that they have a specific total. That is not really possible. (The probability is 0 that the total is correct.) The best you can hope for is to pick 12 random numbers and then scale them in some way to reach your total. Again, there are many possibilities from linear scaling to more exotic scalings. And it depends on your original distribution and scaling method whether the resulting 12 numbers are still members of the original distribution.

So what you think is an easy question really isn't.


From your response, it is clear you didn't get the point I was making: there is no such thing as "pick a random number".

Suppose I asked you to pick a random integer. Whatever number you pick is going to be impossibly small. The vast majority of integers are unbelievably large, and the fact you can even think it in your head means you've limited yourself. I can ask you "pick a number between 1 and 100". No matter what, I have to explicitly or implicitly give you a probability for each integer, and those probabilities have to add up to 1. I might even say: pick 0 with probability 1/2, pick 1 with probability 1/2, pick 2 with probability 1/4, .... that's legal.

Likewise for picking a floating point number. I have to give you a non-negative curve, f and the area under the curve has to total 1. The probability of your picking a number in the "neighborhood" of x is the value of f(x) times the width of the neighborhood. (Yeah, calculus.)

There is no such thing as "just a random number".

Frank Yellin
  • 9,127
  • 1
  • 12
  • 22
  • I never said it is easy, also I don't want to use a specific distribution as that would lessen the randomness of numbers – Sam Jul 03 '23 at 16:30
  • @Sam. There is no such thing as just a "random number". You must have a distribution. That's the point. – Frank Yellin Jul 03 '23 at 18:35