我有一组与许多“点”相对应的活动。看起来像这样:
[ {"c1":4, "c2":8, "c3":25} ]
我想从这个集合中随机选择一个广告系列。我假设 rand() 会在某个时候发挥作用。但是,我希望每个的价值都会影响其被选中的机会。
因此,例如,广告系列“c2”的选择频率应该是广告系列“c1”的两倍(大约)。“c3”将是国王,最有可能被选中。
每次脚本运行时,活动的数量和相应的值可能相同,也可能不同。
有什么好的方法来解决这个问题?
我有一组与许多“点”相对应的活动。看起来像这样:
[ {"c1":4, "c2":8, "c3":25} ]
我想从这个集合中随机选择一个广告系列。我假设 rand() 会在某个时候发挥作用。但是,我希望每个的价值都会影响其被选中的机会。
因此,例如,广告系列“c2”的选择频率应该是广告系列“c1”的两倍(大约)。“c3”将是国王,最有可能被选中。
每次脚本运行时,活动的数量和相应的值可能相同,也可能不同。
有什么好的方法来解决这个问题?
这很容易。只需为每个活动创建另一个具有 CDF 值的地图。对于您的示例,它将是:
0.108: C1
0.324: C2
1: C3
然后得到一个介于 0 和 1 之间的随机数。遍历映射并找到大于随机数的最小数字(您可以对其进行二进制搜索或创建一个排序哈希映射,它也可以给出最小的较大数字)
请注意,通过添加概率,最后一个条目可能不会加到 1(可以是 0.999)。只需手动将其设置为 1。
这是一个为您解决这个问题的函数。它创建了一个加权数组,您可以将其与随机数一起使用,以根据每个项目的加权值正确加权每个项目。
var campaigns = {"c1":4, "c2":8, "c3":24};
function getWeightedRandomCampaign(list) {
var weighting = [];
var total = 0;
for (var item in list) {
weighting.push({key: item, value: list[item]});
total += list[item];
}
// generate random number between 1 and total
var rand = Math.floor(Math.random() * total);
// figure out which weighted slot it fits in
var cum = 0;
for (var i = 0; i < weighting.length; i++) {
cum += weighting[i].value;
if (rand < cum) {
return(weighting[i].key);
}
}
return(weighting[weighting.length - 1]);
}
你可以在这里看到它的工作原理:http: //jsfiddle.net/jfriend00/ffwqQ/
这是它的工作原理。
它从活动对象和权重值开始。
var campaigns = {"c1":4, "c2":8, "c3":24};
然后,它构建一个临时数据结构,如下所示:
var weighting = [{key: "c1", value: 4}, {key: "c2", value: 8}, {key: "c3", value: 24}];
在创建该数据结构时,它会跟踪所有权重值的运行总计。
然后它会创建一个介于 0 和该总数之间的随机数。
然后,它遍历加权数组,将这些值相加,以找到第一个超过随机数的累积值。当它发现时,这就是被选中的插槽。