随机数发生器产生幂律分布?

时间:2009-05-28 01:13:20

标签: c++ math random power-law

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

理想情况下,我可以使用rand()或其中一个stdlib随机函数。如果没有,一个易于使用的C / C ++块就会很棒。

谢谢!

4 个答案:

答案 0 :(得分:34)

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

简短回答(从以上链接推导出来):

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

其中 y 是统一变量, n 是分配能力, x0 x1 定义范围分布, x 是你的幂律分布变量。

答案 1 :(得分:18)

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

所以你首先要定义你想要的发行版。

P = F(x)

(对于[0,1]中的x)然后积分给出

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而不是......

答案 2 :(得分:3)

我无法评论产生幂律分布所需的数学(其他帖子有建议),但我建议您熟悉<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撰写的 C ++标准库扩展一书对<random>有一个很好的章节。

Here is an article关于如何创建其他发行版(包含Cauchy,Chi-squared,Student t和Snedecor F的示例)

答案 3 :(得分:3)

我只想进行实际模拟,作为(正确)接受的答案的补充。虽然在R中,代码很简单,但是(伪)-pseudo-code。

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

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

所以这是:

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(1e5)   # Number of samples
x = ((x1^(alpha+1) - x0^(alpha+1))*y + x0^(alpha+1))^(1/(alpha+1))
hist(x, prob = T, breaks=40, ylim=c(0,10), xlim=c(0,1.2), border=F, 
col="yellowgreen", main="Power law density")
lines(density(x), col="chocolate", lwd=1)
lines(density(x, adjust=2), lty="dotted", col="darkblue", lwd=2)

enter image description here

或以对数标度绘制:

h = hist(x, prob=T, breaks=40, plot=F)
     plot(h$count, log="xy", type='l', lwd=1, lend=2, 
     xlab="", ylab="", main="Density in logarithmic scale")

enter image description here

以下是数据摘要:

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