按重量,高级返回随机项目

时间:2016-09-06 09:46:23

标签: algorithm random

有许多典型问题,例如http://rmarkdown.rstudio.com/developer_parameterized_reports.html

想象一下更高级的问题。

您有N对(item_id, weight)对的来源。我们称之为 Shards 。碎片包含对(item_id, weight)对的列表。

你有中心节点,我们称之为 Central

问题是:在Central上根据所有权重的权重,从“大列表”中选择随机项(该列表虚拟地从所有分片上的所有列表中合并)。

例如,我们有两个分片:

+-------+---------+--------+ | shard | item_id | weight | +-------+---------+--------+ | 1 | 1 | 7 | | 1 | 2 | 4 | | 1 | 3 | 2 | | 2 | 4 | 5 | | 2 | 5 | 1 | +-------+---------+--------+

(让item_id在所有分片中都是唯一的。)

第一个问题

如何随机选择item_id但是通过所有分片加权? 即total_weight == 7+4+2+5+1 == 19,因此1的选择概率为7/19,2 - 4/19,3 - 2/19,依此类推。

第二个问题

如何随机排列所有碎片中的所有项目,但是对所有碎片进行加权?

即。理想的范围是:1, 4, 2, 3, 5(根据其权重),

但可能会有另一个范围,例如1, 2, 4, 3, 5,但比之前的频率略低,

...

和最坏情况5, 3, 2, 4, 1也可能出现,但概率非常小。

计算机科学是否存在常见问题?

2 个答案:

答案 0 :(得分:1)

对于第一个问题,您可以执行类似

的操作
// Your pairs (item_id, weight).
ArrayList<Pair> theBigList;
// The total weight of your data. Get it updated.
int totalWeight;

public int weightedSearch() {
    // Local copy of the value.
    int total = totalWeight;
    Random r = new Random();
    // Random integer in the interval [1 - total]
    int random = r.nextInt(total) + 1;
    for (int i = 0; true; i++) {
        if (theBigList.get(i).weigth < total)
            total -= theBigList.get(i).weigth;
        else
            return theBigLits.get(i).itemId;
    }
}

随机搜索,但加权,由生成的随机整数给出。在您的示例中,如果random介于1到7之间(7/19 prob。),则会返回您的第一个元素;如果它在8到11之间(4/19概率),则返回第二个元素,等等。

提示:在开始时获取重物,这样你就有可能更快地返回加权搜索(你的循环在之前结束)。

答案 1 :(得分:1)

我认为你的两个问题是独立的,应该是一个单独的问题。另外,我不确定我是否正确理解它们。但是我们走了:

分片加权随机查询

如果您对分片的引用与在多个网络主机上分配项目存储并尝试进行某种网络并行随机选择有关,那么您可以使用我在最后概述的修改后的reservoir sample算法this answer

该算法最初是为在冗余网络中使用而开发的,其中各种存储主机不一定直接从中央主机到达,连接是图形而不是树。在这种情况下,您需要能够处理不响应的主机(这将偏向于单个查询,但如果网络故障很少且随机,则希望不会偏向一长串查询)。还有必要处理主机被查询两次的可能性;在概述的算法中,我假设如果查询到达主机,则忽略第二个和后续查询,然后可能会将响应返回给查询主机。这可能是完全错误的,但它使问题变得更加容易,并且它可能会在足够大量的查询中无偏见。

如果没有复杂性,如果中央主机可以可靠地连接到每个存储主机,则该算法是直截了当的。中央主机并行查询所有存储主机,每个存储主机返回其存储的对象总权重的元组,以及根据这些权重随机选择的一个对象。 (它使用一些标准的加权随机选择算法来做到这一点。使用哪种算法取决于对象和权重的变化频率。)

中央主机维护两个变量:total,来自已响应的服务器(最初为0)的权重之和,以及candidate,一个可能返回的随机对象(最初是一些指示“的哨兵”)没有对象“)。

它以任何顺序(例如接收它们的顺序)一次处理一个响应。对于每个回复<weight, object>,它会执行以下操作:

  • totaltotal + weight
  • r[0, total)
  • 范围内的随机整数
  • if r&lt; weightcandidateobject

当它确定所有远程服务器都已响应时,它将返回candidate

加权随机随机播放

(至少,我认为你要求加权随机改组)。

我打算建议使用带有权重修改的标准Fisher-Yates algorithm,我认为这会产生您期望的采样行为。为此,您可以按任意顺序从对象开始,然后从i1的{​​{1}}的每个值开始:

  • 选择n,从j开始的对象中的(加权)随机元素的索引,以及交换对象ii

为此,您需要维护连续较小后缀的CDF,您可以通过将对象保存在二叉树中来在O(log N)中执行此操作。 (或者你可以在O(N)中更简单地做,如果N很小的话。)

然而,我在点击Post按钮之前快速搜索了SO,并得出结论:brilliant answer实际上更好,因为它实现了O(N log N)而没有任何复杂的数据结构:对于每个对象,您从指数分布生成一个随机数,其速率是相应的权重。然后根据这些随机数对对象进行排序,结果是随机的随机数。