How To Create L Lists Of N Non-zero Random Decimals Where Each List Sums To 1.0?
Solution 1:
This should be very fast, as it uses numpy.
It will automatically repeat the randomization if it gets any 0.0's, but that is unlikely. The while loop was written before the OP adjusted the non-zero requirement to be above 0.01. To fix this you can modify the while block to include the entire subsequent code, and calculate the number of violations of any desired constraint at the end in a manner similar to what is shown for detecting zeros. But that may get slow when L is large compared to the probability of violating the constraint. In some sense it is easiest to comply with the original requirement of >0.0
.
After the while loop, each element of an L x n matrix is uniformly distributed on (0.0,1.0) without any 0s or 1s. Each row is summed and used to form a scale matrix, that is then matrix multiplied by the random matrix to obtain rows that automatically sum to 1.0
import numpy as np
def random_proportions(L,n):
zeros = 1
while zeros>0:
x = np.random.random(size=(L,n))
zeros = np.sum(x==0.0)
sums = x.sum(axis=1)
scale = np.diag(1.0/sums)
return np.dot(scale, x)
EDIT: The above produces an LxL matrix for scale, which is memory-inefficient. It will OOM before L=10**6. We can fix that by using the broadcasting normalization procedure suggested by this answer
import numpy as np
def random_proportions(L,n):
zeros = 1
while zeros>0:
x = np.random.random(size=(L,n))
zeros = np.sum(x==0.0)
sums = x.sum(axis=1).reshape(L,1) # reshape for "broadcasting" effect
return x/sums
This 2nd version will calculate 1 millions lists of size 10 in about 1/3 of a second on an AMD FX-8150 with 16GB ram:
%timeit l = random_proportions(1000000,10)
1 loops, best of 3: 347 ms per loop
Solution 2:
Here's how you get n
numbers that add up to one: Select n
random numbers in an arbitrary range of your choice (for example, from 1 to 10), then divide them all by their sum.
Solution 3:
This should do the trick:
import random
def floatPartition(n, total):
answer = []
for _ in range(n-1):
num = random.uniform(0, total)
answer.append(num)
total -= num
answer.append(total)
return answer
def paritions(n,L):
return [floatPartition(n, 1) for _ in range(L)]
if __name__ == "__main__":
answer = paritions(6,200)
Solution 4:
I didn't check against the others for speed, but this algorthim produces 1,000,000 lists of length 10 with elements 0.01 - 0.99 in increments of 0.01 in 20 seconds:
import random
def rand_list(n):
sub_list = []
max_val = 100 - n + 1 # max needs to be n-1 less than 100
for repetition in xrange(n-1):
sub_list += [random.randrange(1, max_val)]
max_val -= (sub_list[-1] - 1) # decrease the range by the latest element added - 1
sub_list += [max_val] # use the remainder for the last value, this way it adds to 100
return [round(x/100.0, 2) for x in sub_list] # convert to 0.01 - 0.99 with list comprehension
Post a Comment for "How To Create L Lists Of N Non-zero Random Decimals Where Each List Sums To 1.0?"