繁体   English   中英

如何优化拒绝采样

[英]How to optimize rejection sampling

我有一个std :: map mymap,我试图根据每个键的值进行采样。 我已经建立了一个基于拒绝采样的算法,该算法似乎正在起作用,但是它非常慢(该算法在我的程序中被调用了数千次)。

所以我想知道这是否是最好的方法,或者是否有可以做的更快/更有效的方法。

这是我到目前为止的内容:

std::map<int, float> mymap; //My map that I am sampling

//These three floats are precomputed
int minKey;  //Min key in the map.  
int maxKey;  //Max key in the map.  
float maxValue; //Max value in the map.  

float x1, x2; //Two random variables;
int key;
float value;
do 
{
    x1 = (float)rand()/(float)RAND_MAX;
    x2 = maxValue * (float)rand()/(float)RAND_MAX;
    key = minKey*(1.0-x1) + maxKey*x1; //Linearly interpolate random value to get key;
    value = mymap[key]; //Get value;
} while(x2 > value) 


return std::pair<int, float)(key, value);

^因此,我在上面所做的就是统一随机地选择一个密钥。 然后创建另一个随机变量,并将其与该键的值进行比较。 如果较大,请重复该过程。 这样,具有较高值的​​键比具有较低值的键被采样的频率更高。 但是,do-while循环可能会循环很多次,然后才能找到可接受的键值对进行采样,这在我的应用程序中造成了很大的瓶颈

编辑

另外,由于样本存在偏差,我是否需要对样本进行任何调整? 我知道在蒙特卡洛积分中,您必须将样本的值除以该样本的PDF ...但是我不确定这是否适用于此。 如果适用,如何找到PDF?

如果要按比例线性偏移样本,则很容易做到。

首先计算所有值的总和。

现在生成一个介于0和总和之间的随机浮点值。

遍历地图,并在添加时对值求和。 当总和大于先前计算的随机值时,您就已经找到了样本。

如果要在不变的地图上重复进行此操作,则可以创建一个和向量,并对随机值进行二进制搜索。

拒绝采样主要用于连续分布。 您需要采样离散分布 幸运的是,这是C ++ 11中STL的一部分。 因此,根据std :: discrete_distribution的示例改编而成:

#include <iostream>
#include <map>
#include <random>

template <typename T>
class sampler
{
    std::vector<T> keys;
    std::discrete_distribution<T> distr;

public:
    sampler(const std::vector<T>& keys, const std::vector<float>& prob) :
        keys(keys), distr(prob.begin(), prob.end()) { }

    T operator()()
    {
        static std::random_device rd;
        static std::mt19937 gen(rd());
        return keys[distr(gen)];
    }
};

int main()
{
    using T = int;
    sampler<T> samp({19, 54, 192, 732}, {.1, .2, .4, .3});
    std::map<T, size_t> hist;

    for (size_t n = 0; n < 10000; ++n)
        ++hist[samp()];

    for (auto i: hist)
    {
        std::cout << i.first << " generated " <<
        i.second << " times" << std::endl;
    }
}

输出:

19 generated 1010 times
54 generated 2028 times
192 generated 3957 times
732 generated 3005 times

向量keysprob包含地图的键和值(概率)。 这是因为std::discrete_distribution仅考虑概率。

请注意, operator()不能为const因为std::discrete_distribution会在每个样本处自然改变状态。

还要注意,即使您使用累积分布和二进制搜索来实现抽样(抽样是域大小的对数时间),也存在更有效的(恒定时间)抽样方法,例如alias方法 我不确定std::discrete_distribution使用什么方法。

一种可能是使用带有未知坏键的第二个map (或set )(将所有键放在此处,一旦拒绝了某个键,因为它大于初始随机变量,则从映射中将其删除-然后您在未知坏集中而不是在整个地图中搜索密钥...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM