减少从连续数字列表中选择数字的机会
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) = 0
和 f(1) = 1
等任何函数。对于这个例子,我将采用 f(x) = x^2
.
要从此处获取随机数 - 更多值集中在更接近 0 的位置 - 我们可以执行以下操作:
numbers = ceil(max * f(rand()))
其中ceil
是上限函数,max
是你想要的最高输出,f()
是你选择的函数,rand()
给出一个随机数在零和一之间。请注意,此函数的输出范围为 1
到 max
,而不是 0
到 max
。
下图应该可以让您了解为什么这实际上有效:
请注意,随着整数变大,选择整数的机会越来越小 - 即 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(如果你想知道更多细节的话)
所以实际上你想要 0
和 n
之间的值:
该方法将给出如下值:
- 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 次迭代:
比如说我得到了号码 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) = 0
和 f(1) = 1
等任何函数。对于这个例子,我将采用 f(x) = x^2
.
要从此处获取随机数 - 更多值集中在更接近 0 的位置 - 我们可以执行以下操作:
numbers = ceil(max * f(rand()))
其中ceil
是上限函数,max
是你想要的最高输出,f()
是你选择的函数,rand()
给出一个随机数在零和一之间。请注意,此函数的输出范围为 1
到 max
,而不是 0
到 max
。
下图应该可以让您了解为什么这实际上有效:
请注意,随着整数变大,选择整数的机会越来越小 - 即 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(如果你想知道更多细节的话)
所以实际上你想要 0
和 n
之间的值:
该方法将给出如下值:
- 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 次迭代: