繁体   English   中英

生成总和为 1 的 N 个数字

[英]Generating N numbers that sum to 1

给定一个大小为n的数组,我想为每个索引生成随机概率,使得Sigma(a[0]..a[n-1])=1

一种可能的结果可能是:

0     1     2     3     4
0.15  0.2   0.18  0.22  0.25

另一个完全合法的结果可以是:

0     1     2     3     4
0.01  0.01  0.96  0.01  0.01

如何轻松快速地生成这些? 任何语言的答案都很好,首选 Java。

获取 n 个随机数,计算它们的总和,并通过将每个数字除以总和将总和归一化为 1。

你试图完成的任务无异于从 N 维单位单纯形中抽取一个随机点。

http://en.wikipedia.org/wiki/Simplex#Random_sampling可能会对您有所帮助。

一个简单的解决方案可能如下:

public static double[] getArray(int n)
    {
        double a[] = new double[n];
        double s = 0.0d;
        Random random = new Random();
        for (int i = 0; i < n; i++)
        {
           a [i] = 1.0d - random.nextDouble();
           a [i] = -1 * Math.log(a[i]);
           s += a[i];
        }
        for (int i = 0; i < n; i++)
        {
           a [i] /= s;
        }
        return a;
    }

为了从 N 维单位单纯形中均匀地绘制一个点,我们必须取一个指数分布的随机变量向量,然后通过这些变量的总和对其进行归一化。 为了得到一个指数分布的值,我们取一个均匀分布值的负log

这是相对较晚的,但为了显示对@dreeves 指出的@Kobi 在本文中给出的简单而直接的答案的修正,这使得采样统一。 方法(如果我理解清楚的话)是

  1. 从范围 [1, 2, ... , M-1] 生成 n-1 个不同的值。
  2. 对结果向量进行排序
  3. 添加 0 和 M 作为结果向量的第一个和最后一个元素。
  4. 通过计算 x i - x i-1生成一个新向量,其中 i = 1,2, ... n。 也就是说,新向量由旧向量的连续元素之间的差异组成。
  5. 将新向量的每个元素除以 M。你有你的均匀分布!

我很想知道生成不同的随机值并通过除以它们的总和将它们归一化为 1 是否也会产生均匀分布。

如果您想有效地从正态分布生成值,请尝试Box Muller 变换

获取 n 个随机数,计算它们的总和,并通过将每个数字除以总和将总和归一化为 1。

扩展 Kobi 的答案,这里有一个 Java 函数可以做到这一点。

public static double[] getRandDistArray(int n)  {
    double randArray[] = new double[n];
    double sum = 0;

    // Generate n random numbers
    for (int i = 0; i < randArray.length; i++) {
        randArray[i] = Math.random();
        sum += randArray[i];
    }

    // Normalize sum to 1
    for (int i = 0; i < randArray.length; i++) {
        randArray[i] /= sum;
    }
    return randArray;
}

在测试运行中, getRandDistArray(5)返回以下内容

[0.1796505603694718, 0.31518724882558813, 0.15226147256596428, 0.30954417535503603, 0.043356542883939767]
public static double[] array(int n){

    double[] a = new double[n];
    double flag = 0;

    for(int i=0;i<n;i++){
        a[i] = Math.random();
        flag += a[i];
    }

    for(int i=0;i<n;i++) a[i] /= flag;

    return a;
}

在这里,首先a存储随机数。 并且flag将保留所有生成的数字的总和,以便在下一个 for 循环中生成的数字将除以flag ,最后数组将具有概率分布的随机数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM