使用自定义范围并求和为所需值,生成随机数列表

时间:2018-07-20 18:13:43

标签: python numpy random

我实际上想做this answer中所述的非常相似的事情。我想创建一个总计给定目标值的随机数列表。如果我不在乎范围,可以使用答案所提示的内容:

>>> 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]]

但是,我希望能够控制各个参数的范围和目标。我想提供每个参数的范围。例如,我将传递三个元组的列表,每个元组指定均匀分布的上下边界。 target关键字参数将描述总和。

get_rnd_numbers([(0.0, 1.0), (0.2, 0.5), (0.3, 0.8)], target=0.9)

例如,输出可能如下所示:

[0.2, 0.2, 0.5]

那怎么实现?

更新

  1. 规范化(即除以所有随机数的总和)是不可接受的,就像distort the distribution一样。
  2. 该解决方案应使用任意数量的参数/元组。
  3. 正如评论中提到的,this question实际上非常相似,但是使用另一种编程语言。

2 个答案:

答案 0 :(得分:0)

from random import uniform

while( True ):
    a = uniform(0.0 ,1.0)
    b = uniform(0.2 , 0.5)
    c = 0.9 - a - b
    if(c > 0.3 and c <0.8):
        break

print(a,b,c)

先找到两个随机数。从边界中减去以获得第三个“随机数”。检查以确保它满足边界条件。

答案 1 :(得分:0)

好,这是一些想法/代码。

我们将从Dirichlet中采样,因此自动实现了总和目标。

然后对于从Dirichlet采样的每个x i ,我们应用具有不同下边界l i 但具有相同缩放参数s的线性变换。

v i = l i + s * x i

从求和目标(S i 表示对i的求和)和事实,Dirichlet采样值总和为1

S i v i =目标

我们可以计算s

s =目标-S i l i

让每个v i 的平均值放到间隔的中间。

E [v i ] = l i + s * E [x i ] =(l i + h i )/ 2

E [x i ] =(h i -l i )/ 2 / s

然后介绍基本上与Dirichlets的反方差成正比的旋钮,因此旋钮越大,均值附近的随机采样值越紧。

对于Dirichlet分布alpha参数数组

alpha i = E [x i ] * vscale

其中,vscale是用户定义的方差比例因子。我们将检查采样值是否违反下限或上限条件,如果存在,则拒绝采样。

代码,Python 3.6,Anaconda 5.2

import numpy as np

boundaries = np.array([[0.0, 1.0], [0.2, 0.5], [0.3, 0.8]])
target = 0.9

def get_rnd_numbers(boundaries, target, vscale):
    lo = boundaries[:, 0]
    hi = boundaries[:, 1]
    s = target - np.sum(lo)
    alpha_i = ( 0.5 * (hi-lo) / s ) * vscale
    print(np.sum(alpha_i))

    x_i = np.random.dirichlet(alpha_i, size=1)
    v_i = lo + s*x_i

    good_lo = not np.any(v_i < lo)        
    good_hi = not np.any(v_i > hi)

    return (good_lo, good_hi, v_i)

vscale = 3.0
gl, gh, v = get_rnd_numbers(boundaries, target, vscale)
print((gl, gh, v, np.sum(v)))
if gl and gh:
    print("Good sample, use it")

gl, gh, v = get_rnd_numbers(boundaries, target, vscale)
print((gl, gh, v, np.sum(v)))
if gl and gh:
    print("Good sample, use it")

gl, gh, v = get_rnd_numbers(boundaries, target, vscale)
print((gl, gh, v, np.sum(v)))
if gl and gh:
    print("Good sample, use it")

您可以使用不同的转换思路,也许将平均条件删除或替换为更明智的方法。我建议您不要忘记旋钮,这样您可以收紧采样范围。