【问题标题】:c++ discrete distribution sampling with frequently changing probabilitiesc++ 离散分布抽样,概率频繁变化
【发布时间】:2014-08-07 18:18:31
【问题描述】:

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

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

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

问题:

第一季度。您对如何更快地实现它有更好的想法吗? Q2。最重要的部分:我正在寻找一个已经这样做的库。

说明:几年前我自己就这样做了,通过在向量中构建堆结构,但从那时起我学到了很多东西,包括发现库(:))和容器,如地图......现在我需要用更高的功能重写代码,这次我想把它改正:

所以 Q2.1 有一个很好的方法可以让 c++ 映射不是按索引排序和搜索,而是按其元素的累积总和(这就是我们的采样方式,对吧?...)。 (这是我目前的理论我想怎么做,但不一定要这样......)

Q2.2 也许有更好的方法来做同样的事情?我相信这个问题是如此频繁,以至于我很惊讶我找不到某种可以为我解决问题的库......

非常感谢,如果有人以其他形式提出这个问题,我很抱歉,请指导我,但我花了很长时间寻找......

-z

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

Edit2:权重通常是实数,我不得不考虑是否可以将它们设为整数...

【问题讨论】:

    标签: c++ statistics distribution probability sampling


    【解决方案1】:

    我实际上会使用一组哈希字符串(不记得它的 C++ 容器,但您可能需要实现自己的)。为每个 i 放置 wi 元素,其值为“w1_1”、“w1_2”、... 全部通过“w1_[w1]”(即 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 次,等等...,选择一个随机的固定元素只是选择一个随机数。

    【讨论】:

    • 您假设权重是整数。我阅读问题的方式是真实的。
    • 罗宾可能会说,神圣的高斯,蝙蝠侠,你是对的!
    • 谢谢大家,是的,这些数字是真实的,我认为我不能将它们近似为整数,因为仍有许多小概率事件可能发生。第二个建议很好,但非常混乱,即在某些时候我必须重新制作整个列表等。我认为二叉树仍然是最好的,但没有人为我提供一种简单的方法来实现它! ://
    【解决方案2】:

    在更改值时更新归一化因子是微不足道的。这可能会建议一种算法。

    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) 时间内计算总和所在的位置。这种数据结构有点像堆,但颠倒了。

    【讨论】:

    • 是的,这很明显,但是谢谢。问题是对分布进行采样 - 为此您需要更新 log(n) 总和以及最终的归一化常数。我提到标准化是不同的,因为它会改变所有 pi,因此我们无法使用其他非常有效的 Alias 方法。
    • 我在考虑您的问题,并用另外两个建议更新了我的答案。两者都不是很深,所以你很可能已经考虑过它们,但我想我最好提到它们以防它们有帮助。
    • 第二个想法是我几年前所做的,现在正在寻找完全一样但已经在实现的容器中完成的东西。 (你还需要通过每个级别的总和才能获得随机选择,所以它变成 O(log(N))。我没有得到第一个想法,它与位图有什么关系?
    • 希望能澄清我的意思。
    猜你喜欢
    • 1970-01-01
    • 2012-04-14
    • 1970-01-01
    • 1970-01-01
    • 2016-06-12
    • 1970-01-01
    • 1970-01-01
    • 2018-05-25
    • 2020-08-16
    相关资源
    最近更新 更多