Javascript 如何生成元素的随机加权分布

Javascript 如何生成元素的随机加权分布,javascript,arrays,algorithm,Javascript,Arrays,Algorithm,我想返回一个数组,它有一组根据自定义频率随机分布的唯一元素。我的真实世界用例是基于这些图像受欢迎程度的定性加权的旋转木马图像的重复 例如,假设我有5个带权重的元素: A、 20% B、 50% C、 80% D、 10% 我想写一个函数,给定一个长度,尝试近似一个序列,这样C出现的频率是D的八倍;D的出现频率比B少5倍;A的出现频率比C低三倍。有一个非常简单的解决方案。 random()方法返回一个介于0和1之间(包括0和1)的数字 例如,如果返回的数字大于0.2,则输出C(即80%的概率)。要

我想返回一个数组,它有一组根据自定义频率随机分布的唯一元素。我的真实世界用例是基于这些图像受欢迎程度的定性加权的旋转木马图像的重复

例如,假设我有5个带权重的元素:

A、 20% B、 50% C、 80% D、 10%


我想写一个函数,给定一个长度,尝试近似一个序列,这样C出现的频率是D的八倍;D的出现频率比B少5倍;A的出现频率比C低三倍。

有一个非常简单的解决方案。 random()方法返回一个介于0和1之间(包括0和1)的数字


例如,如果返回的数字大于0.2,则输出C(即80%的概率)。

要扩展a_gupta的答案:

function pick_bin(binProbabilities){     // e.g. [0.1, 0.3, 0.3, 0.3]
  var cumulative = [];                   // e.g. [0.1, 0.4, 0.7, 1]
  var accumulator = 0;

  // Iterating over an array with forEach:
  binProbabilities.forEach(function(item, index){
    var prob = Number(item);
    accumulator += prob;
    cumulative[index] = accumulator;
  })

  if(accumulator !== 1){
    throw new Error('Sum of binProbabilities must equal 1')
  }

  var n = binProbabilities.length;
  var rFloat = Math.random();

  // Iterating over an array with for:
  for(var i=0; i<n; i++){
    var pcI = cumulative[i];      // cumulative probability of this index
    if(pcI >= rFloat){            // Found the first bin fitting the random number
      console.log(i);
      return i;
    }
  }
}

pick_bin([1]); // returns 0 every time
pick_bin([.5, .5]) // returns 0,1 50/50
pick_bin([0.1, 0.3, 0.3, 0.3])
C的出现频率是D的八倍;D的出现频率比B少5倍;A的出现频率比C低三倍

您可以使用元素的加权数组来实现这一点:

var elems = ["A", "B", "C", "D"];
var weights = [2, 5, 8, 1]; // weight of each element above
var totalWeight = weights.reduce(add, 0); // get total weight (in this case, 16)

function add(a, b) { return a + b; } // helper function

var weighedElems = [];
var currentElem = 0;
while (currentElem < elems.length) {
  for (i = 0; i < weights[currentElem]; i++)
    weighedElems[weighedElems.length] = elems[currentElem];
  currentElem++;
}

console.log(weighedElems);
资源:


假设您将分发编号作为一个对象数组,如下所示:

var items = [
    {item: "A", weight: 20}, 
    {item: "B", weight: 50}, 
    {item: "C", weight: 80},
    {item: "D", weight: 10}
];
这就消除了你的权重加起来等于100%的假设——它们可能是点击数、投票数或你喜欢的任何其他值。然后你可以这样做:

function weightedSelect(items) {
    // Get the total, and make the weights cummulative
    var total = items.reduce(function(sum, item){
        item.weight = item.weight + sum;
        return item.weight;
    },0);

    var r = Math.random() * total;

    // Can't use .forEach() here because we want early termination
    for (var i = 0; i < items.length; i++) {
         if (r < items[i].weight)
             return items[i].item;
    }
}
功能权重选择(项目){
//求出总数,并将权重累加起来
var总计=项目。减少(函数(总和,项目){
item.weight=item.weight+总和;
返回项目。重量;
},0);
var r=Math.random()*总计;
//无法在此处使用.forEach(),因为我们希望提前终止
对于(变量i=0;i

我不确定这与其他实现的效率相比如何,但它很简洁。

您的百分比总和应该是100吗?一种方法是,每10%我在随机生成的数字域中插入一个数字。例如:A-->1或2,B-->3 4 5 6 7,D-->8,C-->。。。根据准确度的不同,你可以在域中为每1%、5%、10%添加1个数字……旁注:如果你使用更常见的名称“随机加权分布”,你会在所有新存在的语言中得到大量答案:)加权随机数:根据受欢迎程度更改单个图像的显示时间是否更有效?例如,A显示2秒,B显示5秒,C显示8秒,D显示1秒?是。但是,你的问题有点模糊。如果所有的百分比加起来都必须达到100,那么这就是您要寻找的。实际上,唯一的技巧就是了解random()方法。如果它们不必相加到100,那么逻辑就要复杂一些。如果返回的数字大于0.2,并且返回C,那么如何输出B?
var items = [
    {item: "A", weight: 20}, 
    {item: "B", weight: 50}, 
    {item: "C", weight: 80},
    {item: "D", weight: 10}
];
function weightedSelect(items) {
    // Get the total, and make the weights cummulative
    var total = items.reduce(function(sum, item){
        item.weight = item.weight + sum;
        return item.weight;
    },0);

    var r = Math.random() * total;

    // Can't use .forEach() here because we want early termination
    for (var i = 0; i < items.length; i++) {
         if (r < items[i].weight)
             return items[i].item;
    }
}