寻找一种快速的方法来创建n个和为1的小数的L个列表。每个数字应>= 0.01
所需输出:where L = 200, n = 6
[0.20, 0.22, 0.10, 0.06, 0.04, 0.38]
[0.32, 0.23, 0.18, 0.07, 0.05, 0.15]
...
# There are 200 of these
where L = 200, n = 3
[0.90, 0.10, 0.10]
[0.35, 0.25, 0.30]
...
# There are also 200 of these
我想不出一个实际解决方案的棘手部分是确保每个列表中没有零。当n
达到很大的数值时,这变得特别困难。如何相应地分配值1的片段呢?
这应该是非常快的,因为它使用numpy。
如果得到任何0.0,它将自动重复随机化,但这不太可能。在OP将非零要求调整为高于0.01之前编写while循环。要解决这个问题,您可以修改while块,使其包含整个后续代码,并在末尾以类似于检测零的方式计算违反任何所需约束的次数。但是当L比违反约束的概率大时,它可能会变慢。从某种意义上说,符合>0.0
的原始要求是最容易的。
while循环后,L x n矩阵的每个元素均匀分布在(0.0,1.0)上,不存在0和1。对每一行求和,形成一个比例矩阵,然后矩阵乘以随机矩阵,得到自动和为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:上面的代码生成一个LxL矩阵用于缩放,这是内存效率低下的。它将在L=10**6之前OOM。我们可以通过使用这个答案
建议的广播规范化过程来解决这个问题。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
这第二个版本将在1/3秒内计算100万个大小为10的列表,AMD FX-8150具有16GB ram:
%timeit l = random_proportions(1000000,10)
1 loops, best of 3: 347 ms per loop
如何得到加起来为1的n
数字:在您选择的任意范围内(例如,从1到10)选择n
随机数,然后将它们全部除以它们的总和。
这应该能奏效:
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)
我没有检查其他算法的速度,但是这个算法在20秒内产生1,000,000个长度为10的列表,其中元素为0.01 - 0.99,增量为0.01:
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