生成随机数列表,求和为1

2024-05-23 14:24:51 发布

您现在位置:Python中文网/ 问答频道 /正文

我如何列出N个随机数(比如说100个),使它们的和为1?

我可以用

r = [ran.random() for i in range(1,100)]

我将如何修改它,使列表总和为1(这是一个概率模拟)。


Tags: in列表forrangerandom概率总和ran
3条回答

最好的方法是简单地列出你想要的数字,然后把它们全部除以和。它们完全是随机的。

r = [ran.random() for i in range(1,100)]
s = sum(r)
r = [ i/s for i in r ]

或者,按照@TomKealy的建议,将总和和创建保持在一个循环中:

rs = []
s = 0
for i in range(100):
    r = ran.random()
    s += r
    rs.append(r)

要获得最快的性能,请使用numpy

import numpy as np
a = np.random.random(100)
a /= a.sum()

对于概率分布,可以给随机数任何分布:

a = np.random.normal(size=100)
a /= a.sum()

----时间----

In [52]: %%timeit
    ...: r = [ran.random() for i in range(1,100)]
    ...: s = sum(r)
    ...: r = [ i/s for i in r ]
   ....: 
1000 loops, best of 3: 231 µs per loop

In [53]: %%timeit
   ....: rs = []
   ....: s = 0
   ....: for i in range(100):
   ....:     r = ran.random()
   ....:     s += r
   ....:     rs.append(r)
   ....: 
10000 loops, best of 3: 39.9 µs per loop

In [54]: %%timeit
   ....: a = np.random.random(100)
   ....: a /= a.sum()
   ....: 
10000 loops, best of 3: 21.8 µs per loop

最简单的解决方法就是取N个随机值除以和。

一个更通用的解决方案是使用Dirichlet分布 http://en.wikipedia.org/wiki/Dirichlet_distribution 在纽比有售。

通过改变分布的参数,你可以改变个别数字的“随机性”

>>> import numpy as np, numpy.random
>>> print np.random.dirichlet(np.ones(10),size=1)
[[ 0.01779975  0.14165316  0.01029262  0.168136    0.03061161  0.09046587
   0.19987289  0.13398581  0.03119906  0.17598322]]

>>> print np.random.dirichlet(np.ones(10)/1000.,size=1)
[[  2.63435230e-115   4.31961290e-209   1.41369771e-212   1.42417285e-188
    0.00000000e+000   5.79841280e-143   0.00000000e+000   9.85329725e-005
    9.99901467e-001   8.37460207e-246]]

>>> print np.random.dirichlet(np.ones(10)*1000.,size=1)
[[ 0.09967689  0.10151585  0.10077575  0.09875282  0.09935606  0.10093678
   0.09517132  0.09891358  0.10206595  0.10283501]]

根据主参数的不同,Dirichlet分布要么给出所有值都接近1的向量,要么给出向量的长度N,要么给出向量的大多数值都是~0的向量,其中只有一个1,要么给出介于这些可能性之间的某个值。

编辑(原始答案5年后):关于Dirichlet分布的另一个有用的事实是,如果生成一个Gamma分布的随机变量集,然后将它们除以它们的和,自然会得到它。

将每个数字除以总数可能无法得到所需的分布。例如,对于两个数字,对x,y=random.random(),random.random()在正方形0<;=x<;1,0<;=y<;1上均匀地拾取一个点。除以从(x,y)到原点的直线x+y=1上的点“投影”之和。接近(0.5,0.5)的点比接近(0.1,0.9)的点可能性大得多。

对于两个变量,x=random.random(),y=1-x沿几何线段给出均匀分布。

使用3个变量,可以在立方体中拾取一个随机点并进行投影(径向投影,穿过原点),但是三角形中心附近的点比顶点附近的点更有可能。结果点位于x+y+z平面上的三角形上。如果需要在三角形中无偏地选择点,缩放就不好。

这个问题在n维变得复杂,但你可以得到一个低精度(但高精度,为所有你的实验室科学爱好者!)从所有n个非负整数的n元组集合中均匀地选取n个整数,然后将每个整数除以n

我最近想出了一个算法来处理中等大小的n,n。它应该对n=100和n=1000000有效,从而给出6位数的随机数。请看我的答案:

Create constrained random numbers?

相关问题 更多 >