Python 生成N个和为M的均匀随机数

Python 生成N个和为M的均匀随机数,python,algorithm,random,distribution,Python,Algorithm,Random,Distribution,这个问题以前有人问过,但我从来没有看到过一个好的答案 我想生成8个随机数,总和为0.5 我希望从均匀分布中随机选择每个数字(即,下面的简单函数不起作用,因为这些数字不会均匀分布) 代码应该是可归纳的,这样您就可以生成N个统一的随机数,其总和为M(其中M是正浮点)。如果可能的话,请您解释一下(或用图表显示)为什么您的解决方案会在适当的范围内均匀地生成随机数 没有抓住重点的相关问题: (当前接受的答案不统一——另一个统一的答案只适用于整数) (Java中的同一个问题,目前接受的答案完全错误,也没有

这个问题以前有人问过,但我从来没有看到过一个好的答案

  • 我想生成8个随机数,总和为0.5

  • 我希望从均匀分布中随机选择每个数字(即,下面的简单函数不起作用,因为这些数字不会均匀分布)

  • 代码应该是可归纳的,这样您就可以生成N个统一的随机数,其总和为M(其中M是正浮点)。如果可能的话,请您解释一下(或用图表显示)为什么您的解决方案会在适当的范围内均匀地生成随机数

    没有抓住重点的相关问题:

    (当前接受的答案不统一——另一个统一的答案只适用于整数)

    (Java中的同一个问题,目前接受的答案完全错误,也没有统一分布的答案)

    (同一个问题,但在R中是正态分布——不是均匀分布)


    非常感谢您的帮助。

    对于完全通用的解决方案(“我想要
    n
    介于
    low
    high
    之间的数字,总和为
    m
    ):


    我们可以从范围为“0-M”的均匀分布中选择“n-1”随机区间,而不是从总和为“M”的均匀分布中选择“n”个数字,然后我们可以提取区间

    from random import uniform as rand
    
    def randConstrained(n, M):
         splits = [0] + [rand(0, 1) for _ in range(0,n-1)] + [1]
         splits.sort()
         diffs = [x - splits[i - 1] for i, x in enumerate(splits)][1:]
         result = map(lambda x:x*M, diffs)
         return result
    
    res = randConstrained(8,0.5)
    print res
    print sum(res)
    
    输出

    [0.0004411388173262698,
     0.014832306834761111,
     0.009695872790939863,
     0.04539251424140245,
     0.18791325446494067,
     0.07615024971405443,
     0.07792489571128014,
     0.08764976742529507]
    
    0.5
    

    你所要求的似乎是不可能的

    然而,我将重新解释你的问题,使其更有意义并有可能解决。你需要的是七维超平面上的概率分布
    x_1+x_2+…+x_8=0.5
    。由于超平面的范围是无限的,所以在整个超平面上的均匀分布将不起作用。你可能(?)want是超平面的一块,其中所有的
    x_i>0
    。该区域是一个单纯形,是三角形的推广,单纯形上的均匀分布是Dirichlet分布的一个特例

    您可能会发现Dirichlet Distribution Wikipedia文章的这一部分特别有启发性

    实施

    Wikipedia文章在本节中给出了以下Python实现:

    你可能想要的是这样一种情况,即所有
    ai=1
    ,这导致单纯形上的均匀分布。这里
    k
    对应于你问题中的数字
    N
    。要使样本和
    M
    而不是
    1
    ,只需将
    sample
    乘以
    M

    更新

    感谢塞韦林·帕帕德乌斯指出伽马变量在罕见的情况下可以返回无穷大,这在数学上是“不可能的”但是可以作为实现的工件出现在浮点数方面。我对处理该案例的建议是在首次计算
    sample
    后进行检查;如果
    sample
    的任何组件为无穷大,则将所有非无穷大组件设置为0,并将所有无穷大组件设置为1。然后,当计算
    xi
    时,像
    xi=1,所有其他x=0
    ,或
    xi=1/2,xj=1/2,所有其他x=0
    这样的结果将共同产生“角点样本”和“边缘样本”


    另一个很低的可能性是gammavariates之和溢出。我想我们可以遍历整个底层伪随机数序列,但看不到这种情况发生,但理论上是可能的(取决于底层伪随机数生成器)。这种情况可以通过重新缩放
    sample
    来处理,例如,在计算gammavariates之后但在计算x之前,将
    sample
    的所有元素除以
    N
    。就我个人而言,我不会费心,因为可能性很低;由于其他原因导致程序崩溃的概率更高。

    这被称为单纯形抽样,它与狄里克莱分布密切相关。和(x_i)=1,其中每个x_i是U(0,1)。在单纯形采样后,只需将每个x_i乘以0.5即可

    无论如何,将C++代码转换成Python(希望不会有太多的错误)

    它能正确处理无穷大

    def simplex_sampling(n):
        r = []
        sum = 0.0
        for k in range(0,n):
            x = random.random()
            if x == 0.0:
                return (1.0, make_corner_sample(n, k))
    
            t = -math.log(x)
            r.append(t)
            sum += t
    
         return (sum, r)
    
    def make_corner_sample(n, k):
        r = []
        for i in range(0, n):
            if i == k:
                r.append(1.0)
            else:
                r.append(0.0)
    
        return r
    
     # main
     sum, r = simplex_sampling(8)
    
     norm = 0.5 / sum # here is your 0.5 total
    
     for k in range(0, 8):
         r[k] *= norm
    

    与k4vin的解相同,但没有导入错误,我在random.uniform上得到

    import random
    
    def rand_constrained(n, total):
        # l is a sorted list of n-1 random numbers between 0 and total
        l = sorted([0] + [total * random.random() for i in range(n - 1)] + [total])
        # Return the intervals between each successive element
        return [l[i + 1] - l[i] for i in range(n)]
    
    print(rand_constrained(3, 10))
    # [0.33022261483938276, 8.646666440311822, 1.0231109448487956]
    

    但是matplotlib安装受阻,因此我现在无法绘制出来。

    您可能需要将此问题交给math stackexchange人员解决。此问题通常遇到的问题是无法明确指定所需的联合分发。为什么你甚至确定你想要的属性可以同时持有?@Xīcò:虽然这个问题非常相关(并且比这个问题提出的更严格),但这个问题中的分布所需的属性与这里所需的属性并不相同。特别是,当整个向量均匀分布在所有可能的向量上时,没有一个组件是均匀分布的。@user2357112我不确定我想要的属性是否可以同时保持。昨晚我想了很多,意识到这不是一个小问题。也许这是不可能的。
    random.random
    不接受参数。更好,但是
    low
    high
    的处理是错误的,分布系统性地将太多的权重放在生成的第一个数字中。@inspectorG4dget As OP request每个数字不是从随机分布中选择的,例如,您直接选择的是最后一个数字。不可能保证随机选择的数字加起来就是所需的总和。至少有一个数字的决定论是不可避免的。另一种可能性是允许使用负数。关键是要注意,
    res
    的各个分量都不是均匀分布的。Tha
    [0.0004411388173262698,
     0.014832306834761111,
     0.009695872790939863,
     0.04539251424140245,
     0.18791325446494067,
     0.07615024971405443,
     0.07792489571128014,
     0.08764976742529507]
    
    0.5
    
    params = [a1, a2, ..., ak]
    sample = [random.gammavariate(a,1) for a in params]
    sample = [v/sum(sample) for v in sample]
    
    def simplex_sampling(n):
        r = []
        sum = 0.0
        for k in range(0,n):
            x = random.random()
            if x == 0.0:
                return (1.0, make_corner_sample(n, k))
    
            t = -math.log(x)
            r.append(t)
            sum += t
    
         return (sum, r)
    
    def make_corner_sample(n, k):
        r = []
        for i in range(0, n):
            if i == k:
                r.append(1.0)
            else:
                r.append(0.0)
    
        return r
    
     # main
     sum, r = simplex_sampling(8)
    
     norm = 0.5 / sum # here is your 0.5 total
    
     for k in range(0, 8):
         r[k] *= norm
    
    import random
    
    def rand_constrained(n, total):
        # l is a sorted list of n-1 random numbers between 0 and total
        l = sorted([0] + [total * random.random() for i in range(n - 1)] + [total])
        # Return the intervals between each successive element
        return [l[i + 1] - l[i] for i in range(n)]
    
    print(rand_constrained(3, 10))
    # [0.33022261483938276, 8.646666440311822, 1.0231109448487956]