簡體   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