【问题标题】:Select element from array with probability proportional to its value从数组中选择概率与其值成正比的元素
【发布时间】:2013-05-05 13:29:58
【问题描述】:

我有一个双精度数组,我想从中选择一个值,每个值被选择的概率与其值成反比。例如:

arr[0] = 100
arr[1] = 200

在此示例中,元素 0 将有 66% 的机会被选中,元素 1 的机会为 33%。我很难对此进行编码。到目前为止,我所做的是计算数组的总值(示例为 300),然后在计算它们占总数的百分比之前,我一直在反转数字。我什么都做不了。最后我希望:

new randomNumber
for(int y=0; y < probabilities.length; y++){
     if(randomNumber < probabilities[y]){
          Select probabilities[y]
     }
}

或者有什么影响。有什么帮助吗?编码是用 Java 编写的,但我可以修改任何伪代码。

【问题讨论】:

    标签: arrays numpy select random weighted


    【解决方案1】:

    通常的技术是将数组转换为累积和的数组:

     [10 60 5 25]  --> [10 70 75 100]
    

    在从零到累计总数的范围内选择一个随机数(在示例中:0 &lt;= x &lt; 100)。然后,在累积数组上使用bisection 将索引定位到原始数组中:

    Random variable x      Index in the Cumulative Array      Value in Original Array
    -----------------      -----------------------------      ----------------------
     0 <= x < 10                      0                            10
    10 <= x < 70                      1                            60
    70 <= x < 75                      2                             5
    75 <= x < 100                     3                            25 
    

    例如,如果随机变量 x 为 4,则将累积数组二等分得到位置索引 0,对应于原始数组中的 10。

    并且,如果随机变量 x 为 72,则将累积数组二等分得到位置索引 2,对应于原始数组中的 5。

    对于反比例,该技术完全相同,只是您将数组初始转换为其倒数,然后构建累积和数组:

    [10 60 5 25]  -->  [1/10  1/60  1/5  1/25]  -->  [1/10  7/60  19/60  107/300]
    

    【讨论】:

    【解决方案2】:

    对于反比例:

    1. 对数组求和
    2. 在 0 和 (n-1)*sum -1 之间选择一个随机数
    3. 从头开始累积 sum-value 直到 >= 到随机值。

    这是为了比例

    注意:所有值都必须为正数才能正常工作。

    1. 对数组求和
    2. 在 0 和 sum-1 之间选择一个随机数
    3. 从数组的开头开始累积值,直到 >= 到随机值。

    【讨论】:

    • 谢谢,但这不会产生成比例的而不是成反比的随机性吗?数字越小,选择的可能性就越大。
    • 感谢您抽出宝贵时间来做这件事。我早期对反比例的想法是对数组求和,然后在数组上循环,执行:arraySum - arr[x],这样我们就可以为小值获得大值,反之亦然。然而,将其转化为功能性的东西..
    • 是的,我也是这么想的,但是当我在数组中使用超过 2 个值时被绊倒了。您还必须调整随机值范围(见编辑)
    • 对于比例算法,随机数应该在0和sum之间,而不是0和sum-1之间。对于这个数组:{1, 1, 1],第三个元素永远不会被选中。如果数组总和的值
    【解决方案3】:

    php代码:

    /**
     * Returns a random item from an array based on a weighted value.
     * @param array $array ['foo' => 70, 'bar' => 30] Foo has a 70 percent chance of being returned
     * @return int|string
     */
    public function randomize(array $array)
    {
        $sumOfWeights = array_sum($array);
    
        $random = rand(1, $sumOfWeights);
        foreach ($array as $name => $weight) {
            $random -= $weight;
    
            if ($random <= 0) {
                return $name;
            }
        }
    
    }
    

    求数组中所有元素的总和。然后在这个范围内生成一个随机数。最终选择将是上述函数返回的索引中的元素。

    【讨论】:

      【解决方案4】:

      我遇到了同样的问题并想出了一些简单的解决方案。不是完美的,但适用于某些情况。

      您有一些数字 [1,2,3,...] 的数组,您需要选择一个具有一定概率 [10,5,20,...] 的值,只需创建新数组并将每个值重复为它的概率是它的两倍,例如

      arr[] = [1,1,1,1,...(10 times),2,2,2,..(5 times),3,3,3,3,...(20 times)];
      

      他们只是得到从 0 到新数组长度的随机数,并以期望的概率得到你的值。

      int r = Random(0,arr.count);
      int value = arr[r];
      

      正如我提到的,它并不完美,也不是内存高效算法,但它确实有效。

      【讨论】:

        猜你喜欢
        • 2023-03-09
        • 2020-01-13
        • 2012-01-07
        • 2011-01-13
        • 2021-12-08
        • 1970-01-01
        • 1970-01-01
        • 2019-09-27
        • 1970-01-01
        相关资源
        最近更新 更多