偏置随机数发生器

时间:2010-05-05 17:56:08

标签: c++ random

我正在寻找一个可以有偏见的随机数发生器。例如,假设我想要1-5之间的随机数,概率为:

1:20%的时间出现 2:10%的时间出现
3:占40%的时间
4:25%的时间出现 5:5%的时间出现

标准库或其他库中是否有可以执行此操作的内容?或者,有没有一种有效的方法来做到这一点?

10 个答案:

答案 0 :(得分:16)

对于您的问题,只需从此列表中统一选择一个随机元素:

[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以生成此类数字等。

您可能还想查看包含比标准<random>库更多random distributions(和随机数生成器)的GSL。 (但请注意,GSL使用GPLv3。)

答案 1 :(得分: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 :(得分:8)

Boost随机数库提供了为发生器指定不同形状分布的功能。这是一个很棒的图书馆 - 请参阅http://www.boost.org/doc/libs/1_42_0/libs/random/index.html

答案 3 :(得分:5)

您所描述的是从特定概率分布中提取的随机数生成器的实现。例如,从高斯分布中绘制数字应该绘制随机数,使得特定绘制的概率 x alt text http://upload.wikimedia.org/math/1/8/4/184fa5540b76903b1653d9f83912265d.png成比例。

通常,方法是从均匀随机分布中提取,然后在该绘制位置选择所需分布的累积分布函数(CDF)的值。在普通高斯的情况下,从均匀分布中绘制一个随机数 x (这是标准随机数生成器应该给出的),然后选择alt text作为随机高斯分布值。对于您的情况,您描述的CDF是一个分段连续的阶梯式功能,可以使用您已经收到的许多(正确)答案中的任何一个来实现。

当然,这都是琐事。您应该正在做的是使用已经为您处理此问题的库。统计和随机数生成并非无足轻重,也无需重新发明轮子。请参阅Neil的答案(并查看Boost random number库)。

答案 4 :(得分: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

答案 5 :(得分:0)

为什么不使用一个返回0.0到1.0之间的数字的常规随机数生成器,并用另一个根据您的要求返回数字的函数包装它?

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

答案 6 :(得分:0)

在[0,1],if 0< x<0.2 return 1if 0.2<x <0.3 return 2等中输入随机实数x。

有关一般问题,请参阅here

答案 7 :(得分:0)

Kenny根据您的特定频率分布给出了适当的答案。

更一般的答案适用于CDF - 累积分布函数 - 用于数据,并使用统一的随机数来选择分布中的值。

答案 8 :(得分:0)

我正在做同样的事情,我发现了这个: http://eli.thegreenplace.net/2010/01/22/weighted-random-generation-in-python/

对于你说的目的来说似乎足够好。

答案 9 :(得分: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