【问题标题】:Weighted Random Selection With Dynamic Probabilities具有动态概率的加权随机选择
【发布时间】:2016-03-11 17:58:05
【问题描述】:

我一直在寻找一种很好的算法来从具有不同加权概率的对象列表中选择一个随机对象,并且通过将每个对象放入一个数组中找到了一个名副其实的可能性宝库 n 次,对包含离散累积密度函数 (CDF) 的数组执行二进制搜索,将 CDF 放入桶中,以及一些更令人困惑的响应,特别是由 Weighted random selection from array 提供。

但是,所有回复似乎都集中在进行随机选择的效率上,而不是动态构建或调整权重的成本。由于我的应用程序似乎需要在运行时调整权重几乎与进行选择一样频繁,那么允许对概率权重进行动态调整的最有效算法是什么?将新对象添加到列表中可能只会在初始化时完成,但删除对象可能比仅仅更改值更不频繁(也许将概率设置为零就足够了)。

我最初的印象是使用 CDF 数组是我最好的选择;在目标概率之后对所有内容应用相同的调整似乎微不足道,但是例如,对于 CDF 存储桶,我没有看到任何如此简单的事情。有任何想法吗?

如果有人关心,我正在使用 haxe 来实现它。

【问题讨论】:

  • 您可以使用 Fenwick tree 进行 O(log n) 时间的样本和更新,但取决于调整的内容,您可能会做得更好。

标签: arrays algorithm random


【解决方案1】:

假设您有一个对象数组 {O.1, O.2, ... , O.N} 和一组相关的概率权重 {w.1, w.2, ..., w.N}

您可以根据每个权重设置 0 到 1 之间的值范围(“桶”),然后只需在 0 到 1 之间选择一个随机值(均匀分布)。随机值将落在您定义的存储桶之一。如果它落在第 i 个桶中,则从数组中选择第 i 个对象。

对不起,我不知道haxe,但这里有一些java代码来说明:

    Random mRandom = new Random();

double[] weights = {0.3, 0.2, 0.1, 0.5}; //Make sure these sum to 1!!  But at least you can change these at run-time.


int getRandomObject() {

    double randNum = mRandom.nextDouble();

    double sumOfWeightSoFar = 0;
    int currentIndex = 0;
    while (true) {
        if (randNum < weights[currentIndex] + sumOfWeightSoFar)
            return currentIndex;
        else {
            currentIndex++;
            sumOfWeightSoFar = sumOfWeightSoFar + weights[currentIndex];
        }
    }
    //If your weights don't sum to 1 or more, then "currentIndex" will eventually exceed your array bounds.  But you get the idea.
}

【讨论】:

  • 这并不能解决问题。他的概率在变化,所以他每次进行选择时都需要重建这张表。而且,即使您有固定的概率,这也不是一个好的实现;二叉树可以让您更快地查找,并且大多数库都有一个 API 来执行选择,而无需额外的代码。
  • 我认为他的观点是现有的实现在固定概率下效果最好,他想要一些他可以在运行时改变的东西。设置“weights[]”数组的值可以在运行时完成。当然有人可以想出一个更有效的实现,但这个概念已经说明......除非我完全错过了这个问题。
  • 谢谢,但这似乎是对我在问题中所说的内容的重申,即我目前认为最好的选择是,减去更改时的二进制搜索和计算 CDF。
猜你喜欢
  • 2013-06-19
  • 2022-01-08
  • 2012-10-13
  • 2020-09-14
  • 1970-01-01
  • 2011-09-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多