我有一个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循环可以循环多次,然后找到一个可接受的键值对来进行采样,这在我的应用程序中造成了相当大的瓶颈
修改
此外,我是否有必要对我的样品进行任何调整,因为它们偏向于此处?我知道在monte carlo集成中,你必须将样本的值除以该样本的PDF ...但我不确定这是否适用于此。如果它确实适用,我将如何找到PDF?
答案 0 :(得分:2)
如果您想要将样本与数值成比例地线性偏置,那么这很容易做到。
首先计算所有值的总和。
现在生成0和总和之间的单个随机浮点值。
遍历地图,随时对值进行求和。当总和大于先前计算的随机值时,您已找到样品。
如果你要在一个不变的地图上重复这样做,你可以创建一个总和矢量并对随机值进行二分搜索。
答案 1 :(得分:2)
拒绝抽样主要用于连续分发。你需要的是sample a discrete distribution。幸运的是,这是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
向量keys
和prob
分别包含地图的键和值(概率)。这是因为std::discrete_distribution
仅考虑了概率。
请注意,operator()
不能为const
,因为std::discrete_distribution
会自动更改每个样本的状态。
另请注意,即使您使用累积分布和二分搜索自己实施抽样(抽样是您域中大小的对数时间),也有更有效(恒定时间)的抽样方法,如{{3} }。我不确定使用什么方法
但是,std::discrete_distribution
。
答案 2 :(得分:0)
一种可能性是使用第二个map
(或set
)与未知 - 坏键(您将所有键放在那里,并且一旦拒绝了键,因为它是&#39; s大于初始随机变量,你将其从地图中删除 - 你在未知 - 坏集合中搜索密钥,而不是在整个地图中...