c ++具有频繁变化概率的离散分布采样

时间:2014-08-07 18:18:31

标签: c++ statistics distribution probability sampling

问题:我需要从由某些重量构成的离散分布中进行采样,例如{w1,w2,w3,..},因此概率分布{p1,p2,p3,...},其中pi = wi /(w1 + w2 + ...)。

有些wi的变化非常频繁,但只有非常低比例的所有wi。但是,每次发生时,分布本身都必须重新规范化,因此我认为Alias方法不能有效地工作,因为每次都需要从头开始构建整个分布。

我目前正在考虑的方法是二叉树(堆方法),其中所有wi都保存在最低级别,然后是两个级别在更高级别中的总和,依此类推。所有这些的总和将处于最高级别,这也是归一化常数。因此,为了在wi中更改后更新树,需要进行log(n)更改,以及从分发中获取样本的相同数量。

问题:

Q1。你对如何更快地实现它有更好的想法吗? Q2。最重要的部分:我正在寻找一个已经完成此工作的图书馆。

解释:几年前我自己做了这个,通过在向量中构建堆结构,但从那时起我学到了很多东西,包括发现库(:))和容器如map ...现在我需要重写具有更高功能的代码,我希望这次能够正确使用:

所以Q2.1有一种很好的方法可以使c ++地图不是通过索引进行排序和搜索,而是通过它的元素的累积和(这是我们的样本,对吧?)。 (这是我目前的理论,我想怎么做,但它不一定要这样......)

Q2.2也许还有一些更好的方法可以做到这一点?我会相信这个问题是如此频繁,我很惊讶我找不到某种能为我做这件事的图书馆......

非常感谢,如果有人以其他形式提出要求,我感到非常抱歉,请指导我,但我已经花了很长时间寻找......

-z

编辑:我可能需要删除或添加元素,但我认为我可以避免它,如果这会产生巨大的差异,因此只留下更改值权重。

Edit2:权重一般都是实数,我不得不考虑是否能让它们成为整数......

2 个答案:

答案 0 :(得分:1)

我实际上会使用一组哈希字符串(不记得C ++容器,你可能需要实现自己的)。为每个i添加wi元素,其值为" w1_1"," w1_2",...全部通过" w1_ [w1]" (即,以&#34开头的w1元素; w1 _")。

当您需要采样时,使用均匀分布随机选取一个元素。如果您选择了w5_ *,则说您选择了元素5.由于哈希中的元素数量,这将为您提供所需的分布。

现在,当wi从A变为B时,只需将B-A元素添加到散列(如果B> A),或删除wi的最后A-B元素(如果A> B)。

在这种情况下,添加新元素和删除旧元素是微不足道的。

显然问题是随机选择一个元素'。如果你的哈希是一个封闭的哈希,你随机选择一个数组单元格,如果它是空的 - 只需再次随机选择一个。如果你的哈希值比权重总和大3或4倍,那么你的复杂性将非常好:O(1)用于检索随机样本,O(| A-B |)用于修改权重。

另一种选择,因为只有一小部分重量发生变化,就是将重量分成两部分 - 固定部分和变化部分。然后,您只需要担心更改部件的更改,以及更改部件的总重量与未更改部件的总重量之间的差异。然后对于固定部分,你的哈希变成一个简单的数字数组:1出现w1次,2出现w2次等等,并且选择一个随机的固定元素只是选择一个随机数。

答案 1 :(得分:0)

更改值时更新标准化因子非常简单。这可能暗示了一种算法。

w_sum = w_sum_old - w_i_old + w_i_new;

如果将p_i作为计算属性p_i = w_i / w_sum,则应避免重新计算整个p_i数组,代价是每次需要时计算p_i。但是,您可以在不重新计算总和的情况下更新许多统计属性

expected_something = (something_1 * w_1 + something_2 * w_2 + ...) / w_sum;

通过一些代数,您可以通过减去旧权重的贡献来更新expected_something,并使用新权重添加贡献,并根据需要乘以和除以标准化因子。

如果您在采样期间跟踪哪些结果是样本的一部分,则可以传播概率如何更新为生成的样本。这是否可以让您更新而不是重新计算与样本相关的值?我认为位图可以提供一种有效的方法来存储用于构建样本的结果的索引。

将概率与总和一起存储的一种方法是从所有概率开始。在接下来的N / 2个位置,您可以存储货币对的总和。在那之后,总和所在的N / 4总和可以显然在O(1)时间内计算。这种数据结构有点堆,但是颠倒了。