Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Non biased return a list of n random positive numbers (>=0) so that their sum == total_sum

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]
like image 975
dassouki Avatar asked Oct 18 '10 12:10

dassouki


People also ask

How do you sum a random list in Python?

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().

How do you generate random numbers whose sum is constant k?

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.


2 Answers

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.

like image 188
High Performance Mark Avatar answered Oct 13 '22 18:10

High Performance Mark


Here's how I would do it:

  1. Generate n-1 random numbers, all in the range [0,max]
  2. Sort those numbers
  3. For each pair made up of the i-th and (i+1)-th number in sorted list, create an interval (i,i+1) and compute its length. The last interval will start at the last number and end at 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)
like image 30
MAK Avatar answered Oct 13 '22 17:10

MAK