减少从连续数字列表中选择数字的机会

Decreasing chance of choosing a number from a list of consecutive numbers

比如说我得到了号码 3。然后我必须从 0 到 3 中选择一个随机数,但是 0 比 1 被选中的机会更大,1 被选中的机会比 2 更大,2 被选中的机会比 3 更大。

我已经知道选择 0 到 3 之间的特定数字的百分比机会可以通过执行以下操作来实现:

double r = Math.random();
int n = 0;
if (r < 0.5) {
    n = 0;
    // 50% chance of being 0
} else if (r < 0.8) {
    n = 1;
    // 30% chance of being 1
} else if (r < 0.95) {
    n = 2;
    // 15% chance of being 2
} else {
    n = 3;
    // 5% chance of being 3
}

问题是 3 可以是任何东西。我该怎么做?

注:0.5、0.8、0.95这几个数字是我随便选的。我希望这些数字会减少,以便所有数字的总和等于 1,并且其中 none 是相同的,如果以某种方式可能的话。

您可以对随机数应用一个函数,以减少接近 1 的数字出现的几率。 然后你乘以你的(无法达到的)最大数量:在这个例子中是 4

int n = 4 * (1 - Math.sqrt(Math.random()))

您似乎想要使用一般概率分布,其域可以根据您的喜好进行缩放。您可以选择 f(0) = 0f(1) = 1 等任何函数。对于这个例子,我将采用 f(x) = x^2.

要从此处获取随机数 - 更多值集中在更接近 0 的位置 - 我们可以执行以下操作:

numbers = ceil(max * f(rand()))

其中ceil是上限函数,max是你想要的最高输出,f()是你选择的函数,rand()给出一个随机数在零和一之间。请注意,此函数的输出范围为 1max,而不是 0max

下图应该可以让您了解为什么这实际上有效:

请注意,随着整数变大,选择整数的机会越来越小 - 即 ceil(max*f(x)) 等于 "longest" 的 1 和 [=54= 的 10 ].

如果您想要所选数字与其大小之间的直接关系,您只需选择一个不同的 f(x)。然而,在这一点上,这比其他任何问题都更像是一个数学问题。我会寻找合适的 f(x) - 如果我至少了解您在寻找什么并回复您。我猜现在 f(x) 将是 e^x 但我会仔细检查。

希望对您有所帮助!


快速代码示例:

public int weightedRandom(int max, Random rand) {
     return Math.ceil(((double) max) * Math.pow(rand.nextDouble(), 2));
}

我还在 java 程序中打印了一对,得到了以下列表,其中 max == 10:

2.0, 6.0, 8.0, 3.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 7.0, 1.0, 4.0, 1.0, 1.0, 6.0, 8.0, 9.0, 7.0, 5.0

"Evenly" 可能表示 "the probability of each successive number decreases by a fixed amount" 或 "the probability of each successive number decreases by a fixed percentage." 例如,如果您使用 50% 的固定百分比在 4 个数字之间随机选择:

  • 100%的50%是50%,所以第一个数的概率是50%。
  • 50%的50%是25%,所以第二个数的概率是25%。'
  • 25%的50%是12.5%,所以第三个数的概率是12.5%。
  • 您需要概率加起来为 100%,因此最后一个数字 (#4) 的概率等于倒数第二个数字 (#3) 的概率 - 即 12.5%。

如果你想每次减少一个随机的(但减少的)百分比,你可以只生成一个随机数,其概率小于前一个的概率 - 即如果第一个的概率是0.5,第二个的概率是0.0 < p < 0.5。不过,您可能想要比这更复杂一点,否则您可能会冒最后几项的百分比很小的风险。例如,如果你对第二项随机 select 0.1,那么第三项的概率是 0.0 < p < 0.1 范围内的随机数,这个范围很小,而且只会越来越差.您可能希望使连续项目的概率同时具有最小值和最大值(例如,第二项的概率为 0.3 < p < 0.5)。

请注意,我使用 < 而不是 <= 这一事实 非常 重要。例如,您不希望 0.0 <= p <= 0.5,因为这意味着第二个项目可能与第三个项目(您不想要)具有相同的概率,而且也有可能所有后续项目的概率将等于 0.0(即第一个数字的概率为 100%,任何其他数字的概率为 0%,这根本不是您想要的)。

后一种策略的缺点是您必须调整其中一个概率,使它们相加为 1.0。

我建议使用 : public double nextGaussian() 来自 java.util.Random 的方法 这允许在平均值附近有更多元素的分布

那里写的什么我就不解释了Javamex nextGaussian(如果你想知道更多细节的话)

所以实际上你想要 0n 之间的值:

该方法将给出如下值:

  • 70%,偏离平均值 1 个
  • 95%,偏离平均值 2 次
  • 99% 偏离平均值 3 个

偏差为1,什么都没有


 Random r = new Random();
 int n = 10;
 int res = (int) Math.min(n, Math.abs(r.nextGaussian()) * n / 3);

所以:

  • 乘以n:偏差变为n
  • 除以 4:使用这样一个事实,即您可以比偏差更远的值(99% 在 3 偏差),大约 99% 的值将低于偏差(您的 n
  • 使用Math.abs因为它是对称的,中间为0
  • 使用 Math.min 作为最终检查以防值高于 n

测试 10 000 次迭代: