Javascript 生成具有非均匀概率的随机整数的函数
Javascript function to generate random integers with nonuniform probabilities
在javascript(或jquery)中是否有一个简单的函数有四个整数及其概率值:1|0.41, 2|0.29, 3|0.25, 4|0.05
如何根据概率生成这四个数字?
此问题与此处发布的问题非常相似:generate random integers with probabilities
但是那里发布了解决方案:
function randomWithProbability() {
var notRandomNumbers = [1, 1, 1, 1, 2, 2, 2, 3, 3, 4];
var idx = Math.floor(Math.random() * notRandomNumbers.length);
return notRandomNumbers[idx];
}
在评论中说明"create notRandomNumbers dynamically (given the numbers and their weight/probability)"
这不足以满足我的需要。当概率为 10%、20%、60%、10% 时,这很有效。
在那种情况下,构造具有所需分布的 notRandomNumbers 很容易,而且数组大小很小。但在一般情况下,概率可能是 20.354%、30.254% 等,数组大小对于正确模拟情况来说将是巨大的。
这个更普遍的问题是否有一个干净的解决方案?
编辑:谢谢 Georg,已接受解决方案,这是我的最终版本,可能对其他人有用。我已将累积的计算拆分到一个单独的函数中,以避免在每次调用时额外添加以获得新的随机数。
function getRandomBinFromCumulative(cumulative) {
var r = Math.random();
for (var i = 0; i < cumulative.length; i++) {
if (r <= cumulative[i])
return i;
}
}
function getCummulativeDistribution(probs) {
var cumulative = [];
var sum = probs[0];
probs.forEach(function (p) {
cumulative.push(sum);
sum += p;
});
// the next 2 lines are optional
cumulative[cumulative.length - 1] = 1; //force to 1 (if input total was <>1)
cumulative.shift(); //remove the first 0
return cumulative;
}
function testRand() {
var probs = [0.1, 0.3, 0.3, 0.3];
var c = getCummulativeDistribution(probs);
console.log(c);
for (var i = 0; i < 100; i++) {
console.log(getRandomBinFromCumulative(c));
}
}
只需累加概率和 return 一项 current_sum >= random_number
:
probs = [0.41, 0.29, 0.25, 0.05];
function item() {
var r = Math.random(), s = 0;
for(var i = 0; i < probs.length; i++) {
s += probs[i];
if(r <= s)
return i;
}
}
// generate 100000 randoms
a = [];
c = 0;
while(c++ < 100000) {
a.push(item());
}
// test actual distibution
c = {}
a.forEach(function(x) {
c[x] = (c[x] || 0) + 1;
});
probs.forEach(function(_, x) {
document.write(x + "=" + c[x] / a.length + "<br>")
});
由于 A. J. Walker(Electronics Letters 10, 8 (1974), 127-128;ACM Trans. Math Software 3 (1977), 253-256),有一个只需要一次比较的优雅解决方案,描述于Knuth,TAOCP 卷。 2、120-121。
您还可以在此处找到描述,generate random numbers within a range with different probabilities.
创建第二个具有相应权重的并行数组,并使用"wheel"算法获取索引。
function randomWithProbability()
{
var notRandomNumbers = [1,2,3,4];
var w = [0.41, 0.29, 0.25, 0.05];
var placehldr = 0;
var maxProb = 0.41;
var index = Math.floor(Math.random() * w.length);
var i = 0;
placehldr = Math.random() * (maxProb * 2);
while(placehldr > index )
{
placehldr -= w[index];
index = (index + 1) % w.length
}
return (notRandomNumbers[index]);
}
这个视频很好地解释了它为什么有效,通过视觉表示更容易理解。
https://www.youtube.com/watch?v=wNQVo6uOgYA
在javascript(或jquery)中是否有一个简单的函数有四个整数及其概率值:1|0.41, 2|0.29, 3|0.25, 4|0.05
如何根据概率生成这四个数字?
此问题与此处发布的问题非常相似:generate random integers with probabilities
但是那里发布了解决方案:
function randomWithProbability() {
var notRandomNumbers = [1, 1, 1, 1, 2, 2, 2, 3, 3, 4];
var idx = Math.floor(Math.random() * notRandomNumbers.length);
return notRandomNumbers[idx];
}
在评论中说明"create notRandomNumbers dynamically (given the numbers and their weight/probability)"
这不足以满足我的需要。当概率为 10%、20%、60%、10% 时,这很有效。
在那种情况下,构造具有所需分布的 notRandomNumbers 很容易,而且数组大小很小。但在一般情况下,概率可能是 20.354%、30.254% 等,数组大小对于正确模拟情况来说将是巨大的。
这个更普遍的问题是否有一个干净的解决方案?
编辑:谢谢 Georg,已接受解决方案,这是我的最终版本,可能对其他人有用。我已将累积的计算拆分到一个单独的函数中,以避免在每次调用时额外添加以获得新的随机数。
function getRandomBinFromCumulative(cumulative) {
var r = Math.random();
for (var i = 0; i < cumulative.length; i++) {
if (r <= cumulative[i])
return i;
}
}
function getCummulativeDistribution(probs) {
var cumulative = [];
var sum = probs[0];
probs.forEach(function (p) {
cumulative.push(sum);
sum += p;
});
// the next 2 lines are optional
cumulative[cumulative.length - 1] = 1; //force to 1 (if input total was <>1)
cumulative.shift(); //remove the first 0
return cumulative;
}
function testRand() {
var probs = [0.1, 0.3, 0.3, 0.3];
var c = getCummulativeDistribution(probs);
console.log(c);
for (var i = 0; i < 100; i++) {
console.log(getRandomBinFromCumulative(c));
}
}
只需累加概率和 return 一项 current_sum >= random_number
:
probs = [0.41, 0.29, 0.25, 0.05];
function item() {
var r = Math.random(), s = 0;
for(var i = 0; i < probs.length; i++) {
s += probs[i];
if(r <= s)
return i;
}
}
// generate 100000 randoms
a = [];
c = 0;
while(c++ < 100000) {
a.push(item());
}
// test actual distibution
c = {}
a.forEach(function(x) {
c[x] = (c[x] || 0) + 1;
});
probs.forEach(function(_, x) {
document.write(x + "=" + c[x] / a.length + "<br>")
});
由于 A. J. Walker(Electronics Letters 10, 8 (1974), 127-128;ACM Trans. Math Software 3 (1977), 253-256),有一个只需要一次比较的优雅解决方案,描述于Knuth,TAOCP 卷。 2、120-121。 您还可以在此处找到描述,generate random numbers within a range with different probabilities.
创建第二个具有相应权重的并行数组,并使用"wheel"算法获取索引。
function randomWithProbability()
{
var notRandomNumbers = [1,2,3,4];
var w = [0.41, 0.29, 0.25, 0.05];
var placehldr = 0;
var maxProb = 0.41;
var index = Math.floor(Math.random() * w.length);
var i = 0;
placehldr = Math.random() * (maxProb * 2);
while(placehldr > index )
{
placehldr -= w[index];
index = (index + 1) % w.length
}
return (notRandomNumbers[index]);
}
这个视频很好地解释了它为什么有效,通过视觉表示更容易理解。 https://www.youtube.com/watch?v=wNQVo6uOgYA