产生幂律分布的随机数生成器?

Posted

技术标签:

【中文标题】产生幂律分布的随机数生成器?【英文标题】:Random number generator that produces a power-law distribution? 【发布时间】:2010-10-29 10:59:21 【问题描述】:

我正在为 C++ 命令行 Linux 应用程序编写一些测试。我想生成一堆具有幂律/长尾分布的整数。意思是,我经常得到一些数字,但其中大多数相对不常见。

理想情况下,我可以将一些魔术方程式与 rand() 或 stdlib 随机函数之一一起使用。如果没有,一个易于使用的 C/C++ 块会很棒。

谢谢!

【问题讨论】:

【参考方案1】:

page at Wolfram MathWorld 讨论了如何从均匀分布(这是大多数随机数生成器提供的)中获得幂律分布。

简短答案(以上链接的推导):

x = [(x1^(n+1) - x0^(n+1))*y + x0^(n+1)]^(1/(n+1))

其中y是统一变量,n是分布幂,x0x1定义范围的分布,x 是你的幂律分布变量。

【讨论】:

额外的小细节:y 是 [0,1] 范围内的统一变量。 dmckee 的回答提供了理解 Wolfram 文章中推导所必需的缺失上下文。【参考方案2】:

如果您知道所需的分布(称为概率分布函数 (PDF))并对其进行了适当的归一化,则可以对其进行积分以获得累积分布函数 (CDF),然后反转 CDF(如果可能)以获得您需要从统一的[0,1] 分发到您想要的转换。

所以你首先定义你想要的分布。

P = F(x)

(for x in [0,1]) 然后积分得到

C(y) = \int_0^y F(x) dx

如果这可以反转,你会得到

y = F^-1(C)

所以调用rand()并将结果作为C插入最后一行并使用y。

这个结果称为抽样基本定理。由于规范化要求和分析反转函数的需要,这很麻烦。

或者,您可以使用拒绝技术:在所需范围内统一抛出一个数字,然后抛出另一个数字并在您第一次抛出指定的位置与 PDF 进行比较。如果第二次抛出超过 PDF,则拒绝。对于具有很多低概率区域的 PDF 往往效率低下,比如那些长尾的...

一种中间方法涉及通过蛮力反转 CDF:将 CDF 存储为查找表,然后进行反向查找以获得结果。


这里真正令人讨厌的是简单的x^-n 分布在[0,1] 范围内是不可归一化的,因此您不能使用采样定理。改用 (x+1)^-n...

【讨论】:

【参考方案3】:

我只是想进行一个实际的模拟,作为对(正确)接受的答案的补充。尽管在 R 中,代码是如此简单,以至于是(伪)伪代码。

接受答案中的Wolfram MathWorld formula 与其他可能更常见的方程之间的一个微小差异是 幂律指数 n(通常表示为 alpha)确实不带有明确的负号。所以选择的 alpha 值必须是负数,通常在 2 到 3 之间。

x0x1 代表分布的下限和上限。

原来是这样:

set.seed(0)
x1 = 5           # Maximum value
x0 = 0.1         # It can't be zero; otherwise X^0^(neg) is 1/0.
alpha = -2.5     # It has to be negative.
y = runif(1e7)   # Number of samples
x  = ((x1^(alpha+1) - x0^(alpha+1))*y + x0^(alpha+1))^(1/(alpha+1))
plot(density(x), ylab="log density x", col=2)

或以对数刻度绘制:

plot(density(x), log="xy", ylab="log density x", col=2)

以下是数据摘要:

> summary(x)
   Min.   1st Qu.  Median    Mean   3rd Qu.    Max. 
  0.1000  0.1208  0.1584    0.2590  0.2511   4.9388 

【讨论】:

不知道为什么你说指数必须在 -2 和 -3 之间(我认为自然界中观察到的许多幂律分布的 alpha 介于 1 和 2 之间)但是谢谢你的行R 代码! @SimonC。我是从page 4 left column of this paper 那里得到的。符号将始终为负(当公式带有减号时,alpha 表示为正值)。 是的,对不起,我的错,我完全同意负号,我只是问为什么将 alpha 限制为 [-2,-3]。【参考方案4】:

我无法评论生成幂律分布所需的数学(其他帖子有建议),但我建议您熟悉<random> 中的 TR1 C++ 标准库随机数工具。这些提供了比std::randstd::srand 更多的功能。新系统为生成器、引擎和发行版指定了一个模块化 API,并提供了一堆预设。

包含的分发预设是:

uniform_int bernoulli_distribution geometric_distribution poisson_distribution binomial_distribution uniform_real exponential_distribution normal_distribution gamma_distribution

当您定义幂律分布时,您应该能够将其插入现有的发电机和引擎。 Pete Becker 所著的The C++ Standard Library Extensions一书有一个关于<random> 的精彩章节。

Here is an article 关于如何创建其他分布(包括 Cauchy、卡方、Student t 和 Snedecor F 的示例)

【讨论】:

以上是关于产生幂律分布的随机数生成器?的主要内容,如果未能解决你的问题,请参考以下文章

如何产生满足二元正态分布的随机数点

matlab 如何产生power law分布的随机数

C++11随机数函数库random

随机数生成

怎么用matlab生成随机数,排序,取数排序前的位置?

如何用matlab生成高斯分布随机数