固定比例选择

时间:2012-01-24 12:28:04

标签: php algorithm math probability

我有一组元素,我需要从中选择任何一个元素。每个元素都与百分比机会相关联。百分比增加到100。

我需要从这些元素中选择一个元素,以便选择元素的几率等于百分比值。因此,如果一个元素有25%的几率,它应该有25%的机会被选中。换句话说,如果我们选择1 mil的元素,那么该元素应该选择接近250k次。

2 个答案:

答案 0 :(得分:5)

您所描述的是一个多项过程。

http://en.wikipedia.org/wiki/Multinomial_distribution#Sampling_from_a_multinomial_distribution

他们生成这样的随机过程的方式是这样的: (我将使用伪代码,但应该很容易将其用于实际代码。)

  1. 按照概率的相反顺序对“框”进行排序: (不需要。它只是一个优化) 所以你有例如值= [0.45,0.3,0.15,0.1]

  2. 然后创建'累积'分布,它是索引< = i的所有元素的总和。 伪代码:

    cumulant=[0,0,0,0]    // initiate it
    s=0
    for j=0 to size()-1 {
       s=s+values[i] ; 
       cumulant[i]=s
    }
    

    在我们的案例中累积量= [0.45,0.70,0.85,1]

  3. 制作0到1之间的均匀随机数x。 对于php:http://php.net/manual/en/function.rand.php

  4. 得到的随机框索引i是

    累积量[i]< X

  5. 伪代码:

    for j=0 to size()-1 {
      if !(cumulant[i]<){
         print "your index is ",i
         break;
      }
    

    就是这样。通过回到第3点获得另一个随机索引。

    如果您按照上面的建议排序,这意味着最终搜索会更快。例如,如果你有这个概率向量:0.001 0.001 0.001 0.001 0.996那么,当你对它进行排序时,你几乎总是只需要看索引i = 0,因为随机数x几乎总是低于0.996 。如果排序得到回报,取决于你是否反复使用相同的“盒子”。所以,是的250k尝试它会有很大帮助。请记住,你获得的盒子索引是针对排序后的矢量。

答案 1 :(得分:1)

我想我写它比你向我们展示你到目前为止做的更快。

可能不是最好的解决方案,但就目前而言,看起来它是你唯一的解决方案。

你走了:

$elements = array(
    'This' => 25,
    'is' => 15,
    'a' => 15,
    'crappy' => 20,
    'list' => 25
);

asort($elements);
$elements = array_reverse($elements);

// Precalc cumulative value
$cumulant = 0;
foreach ($elements as $key => &$value) {
    $cumulant += $value;
    $value = $cumulant;
}

function pickAnElement($elements) {
    $random = rand(1, 100);
    foreach ($elements as $key => $value) {
        if ($random <= $value) {
            return $key;
        }
    }
}

$picks = array();

for ($i = 0; $i < 10000; $i++) {
    $element = pickAnElement($elements);
    if (!array_key_exists($element, $picks)) {
        $picks[$element] = 0;
    }
    $picks[$element]++;
}

var_dump($picks);

受Johans回答的启发,我添加了一个循环来排序和预先计算累积量。