【发布时间】:2017-07-05 01:52:49
【问题描述】:
我想从数组中选择随机项目,但具有一定的概率分布。
目前我做:
myarray =[5,5,5,95]
这让我有 75% 的机会获得 5 分和 25% 的机会获得 95 分。
虽然我有更多的数字,但写出所有这些数字需要太多时间,有没有更快/更好的方法来做到这一点?
【问题讨论】:
标签: javascript arrays random
我想从数组中选择随机项目,但具有一定的概率分布。
目前我做:
myarray =[5,5,5,95]
这让我有 75% 的机会获得 5 分和 25% 的机会获得 95 分。
虽然我有更多的数字,但写出所有这些数字需要太多时间,有没有更快/更好的方法来做到这一点?
【问题讨论】:
标签: javascript arrays random
您可以拥有一个对象数组,其中包含任何 value 和一个数字形式的 weight 属性。
// data
const samples = [
{ value: 5, weight: 75 },
{ value: 95, weight: 25 }
];
// requested method
function randomSample (samples) {
// [0..1) * sum of weight
let sample =
Math.random() *
samples.reduce((sum, { weight }) => sum + weight, 0);
// first sample n where sum of weight for [0..n] > sample
const { value } = samples.find(
({ weight }) => (sample -= weight) < 0
);
return value;
}
// demo
const counts = { 5: 0, 95: 0 };
Array
// take a million random samples
.from({ length: 1000000 }, () => randomSample(samples))
// count each sample
.forEach(value => { counts[value]++; });
console.log(counts);
数据不必按任何特定顺序排列,权重也不必相加为任何特定总和。
【讨论】:
function weightedChoice(array, weights) {
let s = weights.reduce((a, e) => a + e);
let r = Math.random() * s;
return array.find((e, i) => (r -= weights[i]) < 0);
}
let randomArray =
Array.apply(null, Array(32)).
map(() => weightedChoice([5, 95], [75, 25]));
console.log(JSON.stringify(randomArray));
编辑:帕特里克比我快一点,所以我会赞同他的回答,我只是补充一点,你并不绝对需要总和为 1,你可以通过找出总和来标准化权重自己一个人。
编辑编辑:如果您真的担心在需要许多具有相同权重的随机值的情况下的性能,这会做得更好(通过尽可能多地预先计算):
class WeightedSampler {
constructor(elements, weights) {
this.total = 0;
this.elements = Array.from(elements);
this.cweights = weights.map(weight => this.total += weight);
}
get() {
let random = Math.random() * this.total;
return this.elements.find((element, index) => random < this.cweights[index]);
}
}
const sampler = new WeightedSampler(["M", "I", " "], [3, 9, 1]);
let randomArray = Array.apply(null, Array(32)).map(() => sampler.get());
console.log(randomArray.join(""));
【讨论】:
Array(32).fill().map(...)