2010-05-05 117 views
6

我找了一個隨機數發生器,可以有偏差。例如,假設我想1-5之間的隨機數,與概率之中:偏置隨機數發生器

1:出現20%的時間
2:出現10%的時間
3:出現40時間
4%:出現25%的時間
5:出現5%的時間

是否有標準庫什麼,或其他圖書館,在那裏,將做到這一點?或者,有沒有一種有效的方法來做到這一點?

+10

希望你不是在爲賭場寫軟件! – Alan 2010-05-05 18:01:01

+2

哈哈不,我敢肯定賭場會聘請一個更聰明的人。 – cmptrer 2010-05-05 18:05:02

+1

從昨天:http://stackoverflow.com/questions/2772882/c-picking-a-random-item-based-on-probabilities,這是一堆相同問題的早期版本的重複(我是懶得找)。您在搜索時可能缺少的詞是「離散的」,這一點很重要,因爲下面的一些答案更適用於連續分佈。 – dmckee 2010-05-05 20:06:46

回答

9

Boost隨機數字庫提供了爲您的生成器指定不同形狀分佈的能力。這是一個很棒的圖書館 - 見http://www.boost.org/doc/libs/1_42_0/libs/random/index.html

+1

是的,不要重新發明輪子! – 2010-05-05 18:18:24

+5

有一天我會開始使用Boost。有一天。 – 2010-05-05 18:20:32

+0

它只是缺乏一個適當的文件...將很高興知道什麼引擎和分佈所需的概念,以便能夠自己設計,而無需逆向工程庫:( – 2010-05-05 18:26:45

15

對於您的問題,隨便挑一個隨機元素從這個名單一致:

[1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5] 

一般情況下,檢查這個答案:Weighted random numbers


在TR1和C++ 0x中,有<random> header其中包含discrete_distribution class以產生這些數字等等。

您可能還想查看GSL,其中包含比標準<random>庫更多的random distributions(和隨機數生成器)。 (但請注意,GSL使用GPLv3的。)

+2

也許我應該解釋我的實際情況好一點。我真正需要的是一個介於1-50,000之間的隨機數。創建一個很長的列表似乎是不必要的,並且不需要。對困惑感到抱歉。 – cmptrer 2010-05-05 18:01:35

+6

這就是爲什麼好的工程需要適當的一套要求。你問了簡單的情況,你得到了(正確的)簡單的答案。 – 2010-05-05 18:05:26

12

最好的辦法可能是隻取正常無偏隨機生成然後返回基於它的值落入區間。

只是一個if語句,讓1爲0:0.2,2爲0.2:0.3,3 0.3:0.7,4爲0.7:0.95和5 0.95:1。最好做出包含區間的上限或下限,以及其他排除。

int biasedRandom(){ 
double i = randomNumber(); 
if(i<= 0.2){return 1;} 
else if(i <= 0.3){return 2;} 
else if(i <= 0.7){return 3;} 
else if(i <= 0.95){return 4;} 
else{return 5;} 
} 

類似的東西。

+2

如果您有很多需要檢查的時間間隔,您應該做的是創建一個累積分佈數組(不知道該怎麼稱呼它),並且每次都進行二進制搜索以找到數字產生。 – 2010-05-05 18:07:48

+2

看起來像這個發電機總是會返回5。除非randomNumber()返回值0-1,否則需要雙/浮點數和其他一些數學運算。 – Xorlev 2010-05-05 18:25:59

+0

是的你是對的,它每次都會給5次,並不意味着讓我成爲一個整數,這是一個錯誤。感謝您指出。 – AaronM 2010-05-05 18:32:38

0

你爲什麼不只是使用普通的隨機數生成器0.0和1.0之間返回號碼,並與根據您的要求返回一個數字,另一個函數把它包裝?

double biased (double seed) { 
if (seed >= 0.0 && seed <0.2) return 1; 
else if ... 
} 
+2

我不會使用'seed'作爲一個隨機生成的數字的標識符,這是令人困惑的... – 2010-05-05 18:01:38

+0

爲什麼不呢? C rand函數也需要一個種子,大多數情況下是系統時間。所以有偏見是一個函數,它會根據種子生成一個隨機數。 – DaClown 2010-05-06 12:38:19

0

扔在[0,1]的隨機實數x,if 0< x<0.2 return 1if 0.2<x <0.3 return 2

here參見爲一般問題。

0

肯尼給爲您量身打造特定的頻率分配一個合適的答案。

更一般的答案適用於CDF - 累積分佈函數 - 用於數據,並使用統一的隨機數來選擇分佈內的值。

5

你所描述的是一個隨機數發生器,從一個特定的概率分佈繪製的實現。例如,來自高斯分佈的繪圖數字應繪製隨機數字,使得特定繪製的概率與alt text http://upload.wikimedia.org/math/1/8/4/184fa5540b76903b1653d9f83912265d.png成比例。

一般來說,該方法是從統一的隨機分佈中提取出來,然後在該位置選取期望分佈的累積分佈函數(CDF)的值。在正態高斯情況下,從均勻分佈(這是標準隨機數發生器應該給出的值)中繪製一個隨機數x,然後選擇alt text作爲隨機高斯分佈值。對於你的情況,你描述的CDF是一個分段連續的階梯函數,可以使用你已經收到的許多(正確的)答案中的任何一個來實現。

當然,這都是瑣事。 應該正在做的是使用一個已經爲你處理這個問題的庫。統計和隨機數字的生成並不是微不足道的,不需要重新發明輪子。查看Neil的答案(並查看Boost random number庫)。

4

晚會到這一方。這裏是C++ 0x中回答:

#include <iostream> 
#include <random> 
#include <iterator> 

int main() 
{ 
    // Set up distribution 
    double interval[] = {1, 2, 3, 4, 5, 6}; 
    double weights[] = { .2, .1, .4, .25, .05}; 
    std::piecewise_constant_distribution<> dist(std::begin(interval), 
               std::end(interval), 
               std::begin(weights)); 
    // Choose generator 
    std::mt19937 gen; // seed as wanted 
    // Demonstrate by pouring into avg[rand-1] 
    const unsigned N = 1000000; 
    double avg[sizeof(weights)/sizeof(weights[0])] = {0}; 
    for (unsigned i = 0; i < N; ++i) 
     avg[static_cast<unsigned>(dist(gen)) - 1]++; 
    // Comute averages 
    for (double* i = std::begin(avg); i < std::end(avg); ++i) 
     *i /= N; 
    // Display 
    for (unsigned i = 1; i <= sizeof(avg)/sizeof(avg[0]); ++i) 
     std::cout << "avg[" << i << "] = " << avg[i-1] << '\n'; 
} 

這對我來說輸出:

avg[1] = 0.199779 
avg[2] = 0.100002 
avg[3] = 0.400111 
avg[4] = 0.250257 
avg[5] = 0.049851 
+0

+1優秀的答案! – 2012-11-26 23:56:42

0
#include <boost/random/discrete_distribution.hpp> 
#include <boost/random/mersenne_twister.hpp> 
#include <boost/random/variate_generator.hpp> 

#include <iostream> 

int main() 
{ 

    unsigned int seed = 42; 
    boost::mt19937 generator(seed); 

    // return 0 with probability 10% 
    //  1     40% 
    //  2     50% 
    boost::random::discrete_distribution<int> custom_dist{1,4,5}; 

    boost::variate_generator<boost::mt19937&, 
    boost::random::discrete_distribution<int> > rndn(generator, custom_dist); 

    for (unsigned int i = 0; i<10000; i++) { 
    std::cout << rndn() << std::endl; 
    } 

    return 0; 

} 

這裏是結果的一個情節:

Output