根据分布生成随机数

22

我想根据一些分布生成随机数,该怎么做?


2
抛开计算机只能生成伪随机数这一事实,如果它们按照已知分布生成,那么它们根本不是随机的。您要为哪些分布生成样本数据? - Lazarus
最简单的方法是找到一个可以做到这一点的库。你有任何特定的语言想法吗? - Dan Dyer
如果你使用Java,可以尝试Dan Dyer的Uncommons Maths库请注意前面的评论),该库提供随机数生成器、概率分布、组合数学和统计学。 - hengxin
6个回答

21

您拥有的标准随机数生成器(在C语言中为rand()经过简单转换后,在许多其他语言中也有相应的等价物)是对区间[0,1]上均匀分布的相当好的近似。如果这正是您所需要的,那么您已经完成了。将其转换为生成范围稍大的整数的随机数也非常简单。

将均匀分布转换为正态分布已经在SO上进行了讨论,转换为指数分布也是如此。

[编辑]: 对于三角分布,将均匀变量转换相对简单(类似于C语言的某些东西):

double triangular(double a,double b,double c) {
   double U = rand() / (double) RAND_MAX;
   double F = (c - a) / (b - a);
   if (U <= F)
      return a + sqrt(U * (b - a) * (c - a));
   else
      return b - sqrt((1 - U) * (b - a) * (b - c));
}

那只是将维基百科页面上给出的公式转换而已。如果你想要其他公式,那就从这里开始找;通常情况下,你使用均匀变量来选择所需分布的累积密度函数上的垂直轴上的一个点(假设它是连续的),然后反演累积分布函数以获得具有所需分布的随机值。

不,我只需要一些指数、正常、三角形等类型的数字。Rockwell Arena输入分析器可以做到这一点,但我不知道如何使用它。 - Nilani Algiriyage
2
+1 我很欣赏这个 C 伪代码,因为我正在查看维基百科关于三角分布的文章,但无法将其转化为代码。有一个更正:rand() 返回从 0 到 RAND_MAX 的整数,所以我认为你想要 U = ((double)rand()) / RAND_MAX。否则,你的 sqrt((1 - U) ...) 将会是虚数。 - LarsH
@LarsH:该死!忘记了C语言是这样的奇怪。感谢您的纠正。 - Donal Fellows

11

正确的方法是将该分布拆分为n-1个二元分布。也就是说,如果您有以下这样的分布:

A: 0.05
B: 0.10
C: 0.10
D: 0.20
E: 0.55

你将其转换为4个二进制分布:

1. A/E: 0.20/0.80
2. B/E: 0.40/0.60
3. C/E: 0.40/0.60
4. D/E: 0.80/0.20

从 n-1 个分布中均匀地选择一个,然后根据二进制分布中每个符号的概率选择第一个或第二个符号。

这里有相关代码


1
你假设分布是离散的。 - pjs
我确实是这样的 - 这在编程中是典型的情况(例如概率转移表,隐马尔可夫模型等)。但是如果您注意到该方法是常数时间。这意味着生成大量分布没有时间性能惩罚。因此,对于连续分布,您可以将其离散化为所需的任意数量的箱以获得足够好的近似,并使用我的方法。 - Rafael Baptista
3
在你所从事的编程中,离散随机变量可能最为常见,但我们中的许多人需要高斯、指数、三角形、对数正态、贝塔、伽马、威布尔等分布来完成工作。即使是离散分布,它们也不能在无限范围内工作(如泊松分布、几何分布)。别名表可以在恒定时间内生成值,但大多数连续反演或组合也可以做到这一点。与此同时,使用表格近似连续分布需要巨大的设置和存储空间,而这些对计算方法并不需要。当适用时,别名表确实很好,但它们不是通用解决方案。 - pjs
一种非常聪明的方法可以在常数时间内生成非均匀随机数,如果分布无法通过函数表示或者您不知道如何表达它。如果您有一个尽可能细粒度的分布表,它可以很好地近似分布。谢谢您提供这个信息。 - RainSia

5

5

实际上这取决于分布。最常见的方法如下:设P(X)为根据您的分布生成的随机数小于X的概率。

首先,您需要生成介于零和一之间的均匀随机变量X。接着,您需要找到Y,使得P(Y) = X,并输出Y。您可以使用二分查找来找到这样的Y(因为P(X)是X的递增函数)。

这种方法并不是非常高效,但对于可以有效计算P(X)的分布而言,是可行的。


1
您可以使用插值将离散的数据转换为浮点数/双精度。简单的线性插值效果很好。如果您的表格内存受限,可以使用其他插值方法。-jlp

-1
这是一本标准教材的内容。点击这里查看一些代码,或者在第3.2节这里查看一些参考数学背景(实际上非常快速和简单易懂)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接