如何优化拒绝采样
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?
拒绝采样主要适用于连续分布。您需要的是对离散分布进行采样。幸运的是,这是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
在每个样本处(自然地)改变状态。
还要注意,即使您使用累积分布和二进制搜索(其中采样是域大小的对数时间)自己实现采样,也有更有效的(恒定时间)采样方法,如别名方法。我不知道用什么方法std::discrete_distribution
。
如果你想让你的样本与数值成比例线性偏差,这很容易做到。
首先计算所有值的总和。
现在生成一个介于0和和之间的随机浮点值。
在地图上进行迭代,边进行边求和。当总和大于前面计算的随机值时,您就找到了您的样本。
如果你要在不变的地图上重复这样做,你可以创建一个和的向量,并对随机值进行二进制搜索。
一种可能性是使用第二个具有未知坏键的map
(或set
- 访问被拒绝后,c++中的故障保护代码
- 如何用RISC-V GD32VF103CBT6开发板卸载精确的ADC过采样
- IpOpt拒绝解决不受约束的问题
- Termux权限被拒绝
- AWS Lambda C++运行时权限被拒绝
- WinSock2:connect() 提供"连接被拒绝"
- 为什么 KMS drmModeSetCrtc() 在 X11 会话中运行时会失败并被拒绝权限?
- 删除目录函数访问被拒绝
- 模板签名解析为 void(void) 被 GCC 拒绝;这是否有效C++?
- 为什么 Windows 拒绝访问某些进程的名称?
- std::stoi 的版本拒绝任何非数字
- 如何使用采样器立方体作为数组
- 我在执行任何程序时被拒绝在 devcpp 中访问
- Windows C++:文件夹移动访问被拒绝错误
- AWS AMI 中的 Windows DPAPI 失败,访问被拒绝
- 使用崇高文本 3 进行C++拒绝授予权限?
- 多重采样背景不显示
- 如何从wav文件中获取采样率?
- 将 Rcpp 与 C 代码链接,以实现自适应城域拒绝采样
- 如何优化拒绝采样