【问题标题】:Random values with non-uniform distribution具有非均匀分布的随机值
【发布时间】:2010-07-09 04:06:37
【问题描述】:

我想要一个非均匀分布的随机数生成器,即:

// prints 0 with 0.1 probability, and 1 with 0.9 probability
echo probRandom(array(10, 90));

这就是我现在拥有的:

/**
 * method to generated a *not uniformly* random index
 *
 * @param array $probs int array with weights 
 * @return int a random index in $probs
 */
function probRandom($probs) {
    $size = count($probs);

    // construct probability vector
    $prob_vector = array();
    $ptr = 0;
    for ($i=0; $i<$size; $i++) {
        $ptr += $probs[$i]; 
        $prob_vector[$i] = $ptr;
    }

    // get a random number
    $rand = rand(0, $ptr);
    for ($i=0, $ret = false; $ret === false; $i++) {
        if ($rand <= $prob_vector[$i])
            return $i;
    }   
}

谁能想到更好的方法?可能不需要我进行预处理?

【问题讨论】:

    标签: php random


    【解决方案1】:

    如果您知道$probs 中所有元素的总和,则无需预处理即可。

    像这样:

    $max = sum($probs);
    $r = rand(0,$max-1);
    $tot = 0;
    for ($i = 0; $i < length($probs); $i++) {
        $tot += $probs[$i];
        if ($r < $tot) {
            return $i;
        }
    }
    

    这将在 O(N) 时间内完成您想要的操作,其中 N 是数组的长度。这是此类算法的算法运行时间的固定下限,因为必须考虑输入中的每个元素。

    假设rand 函数返回给定范围内的独立均匀分布整数,选择给定索引$i 的概率为$probs[$i]/sum($probs)。

    【讨论】:

    • 这是一个愚蠢的问题,但我想知道排序 $probs 数组是否对算法的结果有任何好处?
    • @ramayac:是的,将较大的元素放在首位会提高该算法的性能,但除非数组已经排序或者您多次运行此数组,否则您将失败。这是 O(N),排序会更费力。
    【解决方案2】:

    在您的解决方案中,您会生成一个累积概率向量,这非常有用。

    我有两个改进建议:

    • 如果$probs 是静态的,即每次生成随机数时它都是同一个向量,则只需对$prob_vector 进行一次预处理并保留它。
    • 您可以对$i 使用二分搜索(牛顿二分法)

    编辑:我现在看到你要求一个没有预处理的解决方案。

    如果不进行预处理,您最终会得到最坏情况下的线性运行时间(即向量长度加倍,运行时间也会加倍)。

    这是一种不需要预处理的方法。但是,它确实要求您知道 $probs 中元素的最大限制:

    拒绝方法

    • 在0 和max($probs)-1 之间选择一个随机索引$i 和一个随机数X(一致)。
    • 如果X 小于$probs[$i],你就完成了 - $i 是你的随机数
    • 否则reject $i(因此是方法的名称)并重新启动。

    【讨论】:

      猜你喜欢
      • 2011-08-23
      • 2017-07-16
      • 2011-03-02
      • 1970-01-01
      • 1970-01-01
      • 2011-05-31
      • 2014-02-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多