寻找快速创建L量的n位小数列表,其总和为1.每个数字应为> = 0.01
期望输出:
其中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
其中L = 200,n = 3
[0.90, 0.10, 0.10]
[0.35, 0.25, 0.30]
...
# There are also 200 of these
我无法想到实际解决方案的棘手部分是确保每个列表中没有零。当n
达到大数时,这变得尤为困难。你如何相应地分配价值1的碎片?
答案 0 :(得分:2)
这应该非常快,因为它使用numpy。
如果获得任何0.0分,它会自动重复随机化,但这不太可能。在OP调整非零要求之前写入while循环,使其高于0.01。要解决此问题,您可以修改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)
编辑:上面产生了一个LxL矩阵用于缩放,这是一个内存效率低下的矩阵。在L = 10 ** 6之前它将是OOM。我们可以通过使用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
第二个版本将在AMD FX-8150(16GB内存)的1/3秒内计算出100万个10号的列表:
%timeit l = random_proportions(1000000,10)
1 loops, best of 3: 347 ms per loop
答案 1 :(得分:1)
以下是您获得n
个数字的方法:在您选择的任意范围内选择n
个随机数(例如,从1到10),然后将它们全部除以总和。
答案 2 :(得分:1)
这应该可以解决问题:
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)
答案 3 :(得分:1)
我没有检查其他人的速度,但是这个algorthim产生了1,000,000个长度为10的列表,其元素为0.01 - 0.99,增量为0.01,在20秒内:
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