【问题标题】:Decreasing chance of choosing a number from a list of consecutive numbers减少从连续数字列表中选择数字的机会
【发布时间】:2017-07-13 14:28:14
【问题描述】:

例如,给我一个号码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,并且如果以某种方式可能的话,它们都不相同。

【问题讨论】:

  • 如果给定的数字是 10,你会期望什么?您是如何选择 0.5、0.8 和 0.95 的数字的?
  • 这些数字是我随机选择的。如果以某种方式可能的话,我可能希望它能够均匀分布。 @assylias
  • 我对你所说的均匀分布的数字的意思有点困惑——这不是意味着每个数字都具有相同的被选中概率吗?既然如此,那它和普通的随机性有什么区别呢?至少,这会导致均匀分布(平均而言),这似乎首先违背了权重的目的。
  • 显然只是随便举个例子。 “均匀”可以表示“相同的百分比”或“相同的绝对数量”。

标签: java random percentage


【解决方案1】:

这似乎是您想要使用可以根据自己的喜好扩展其域的通用概率分布。您可以选择任何函数,例如 f(0) = 0f(1) = 1。对于这个例子,我将使用f(x) = x^2

要从这里获得一个随机数 - 更多的值集中在更接近 0 的位置 - 我们可以执行以下操作:

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

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

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

请注意,随着整数变大,选择整数的机会越来越小 - 即 ceil(max*f(x)) 等于“最长”1 和“最短”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

【讨论】:

  • 我有点明白你在说什么,而且它似乎会起作用,但你介意举个例子来说明我将如何在代码中实现它吗?顺便谢谢你的回答!
  • @JacquesMarais,你是什么意思?已有代码版本,选择f()即可。所有其他方法都在java.jang.Math
【解决方案2】:

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

我不会再解释那里写了什么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 次迭代:

【讨论】:

  • 这个答案也有效,但我已经选择了另一个答案。不过还是谢谢你的回答!
  • 这也是一个很好的答案。我会使用nextGaussian(),但正在寻找操纵分布本身形状的灵活性——即选择一个 f(x)。
【解决方案3】:

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

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

【讨论】:

  • 您可能需要详细说明一下,例如它是如何工作的以及为什么这可以解决 OP 的问题。
【解决方案4】:

“均匀”可以表示“每个连续数字的概率减少固定数量”或“每个连续数字的概率减少固定百分比”。例如,如果您使用 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

请注意,我使用&lt; 而不是&lt;= 这一事实非常重要。例如,您不希望 0.0

后一种策略的弱点是您必须调整其中一个概率以使它们加起来为 1.0。

【讨论】:

    猜你喜欢
    • 2019-06-28
    • 2018-02-09
    • 1970-01-01
    • 2021-06-25
    • 1970-01-01
    • 2019-06-30
    • 2016-08-26
    • 1970-01-01
    • 2013-12-30
    相关资源
    最近更新 更多