Ответ 1
Здесь полезный трюк: -)
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];
}
Я немного озадачен тем, как генерировать целочисленные значения с вероятностями.
В качестве примера у меня есть четыре целых числа с их значениями вероятности: 1 | 0,4, 2 | 0,3, 3 | 0,2, 4 | 0,1
Как я могу сгенерировать эти четыре числа с учетом их вероятностей?
Здесь полезный трюк: -)
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];
}
Простым наивным подходом может быть:
function getRandom(){
var num=Math.random();
if(num < 0.3) return 1; //probability 0.3
else if(num < 0.6) return 2; // probability 0.3
else if(num < 0.9) return 3; //probability 0.3
else return 4; //probability 0.1
}
Более гибкое решение, основанное на ответе @bhups. Это использует массив значений вероятности (веса). Сумма элементов "весов" должна равняться 1.
var weights = [0.3, 0.3, 0.3, 0.1]; // probabilities
var results = [1, 2, 3, 4]; // values to return
function getRandom () {
var num = Math.random(),
s = 0,
lastIndex = weights.length - 1;
for (var i = 0; i < lastIndex; ++i) {
s += weights[i];
if (num < s) {
return results[i];
}
}
return results[lastIndex];
};
Я предлагаю использовать непрерывную проверку вероятности и остальной части случайного числа.
Эта функция сначала устанавливает возвращаемое значение в последний возможный индекс и выполняет итерацию до тех пор, пока остальная часть случайного значения не станет меньше фактической вероятности.
Вероятности должны быть суммированы с одним.
function getRandomIndexByProbability(probabilities) {
var r = Math.random(),
index = probabilities.length - 1;
probabilities.some(function (probability, i) {
if (r < probability) {
index = i;
return true;
}
r -= probability;
});
return index;
}
var i,
probabilities = [0.4, 0.3, 0.2, 0.09, 0.01 ],
count = {},
index;
probabilities.forEach(function (a) { count[a] = 0; });
for (i = 0; i < 1e6; i++) {
index = getRandomIndexByProbability(probabilities);
count[probabilities[index]]++
}
console.log(count);
Это решение, которое я считаю наиболее гибким, для выбора в любом наборе объектов с вероятностями:
// set of object with probabilities:
const set = {1:0.4,2:0.3,3:0.2,4:0.1};
// get probabilities sum:
var sum = 0;
for(let j in set){
sum += set[j];
}
// choose random integers:
console.log(pick_random());
function pick_random(){
var pick = Math.random()*sum;
for(let j in set){
pick -= set[j];
if(pick <= 0){
return j;
}
}
}