代码之家  ›  专栏  ›  技术社区  ›  twk Mark Adler

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

  •  26
  • twk Mark Adler  · 技术社区  · 16 年前

    我正在编写C++命令行Linux应用程序的一些测试。我想生成一组具有幂律/长尾分布的整数。也就是说,我经常得到一些数字,但其中大部分相对较少。

    理想情况下,我可以用rand()或stdlib随机函数中的一个来使用一些神奇的公式。如果不是,一个易于使用的块C/C++将是伟大的。

    谢谢!

    4 回复  |  直到 16 年前
        1
  •  34
  •   gnovice    16 年前

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

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

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

    哪里 Y 是一个统一变量, n 是配电电源, X0 X1 定义分布的范围,以及 X 是幂律分布变量。

        2
  •  18
  •   dmckee --- ex-moderator kitten    16 年前

    如果你知道你想要的分布(称为概率分布函数(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,像那些具有长尾巴的pdf,往往效率低下。

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


    这里真正的臭味就是这么简单 x^-n 分布在范围内不可规范化 [0,1] 所以你不能用抽样定理。尝试(x+1)^-n代替…

        3
  •  3
  •   jwfearn    16 年前

    我不能评论产生幂律分布所需的数学(其他帖子有建议),但我建议您熟悉Tr1 C++标准库的随机数设施。 <random> . 这些功能比 std::rand std::srand . 新系统为发电机、发动机和发行版指定了一个模块化API,并提供了一系列预设。

    包括的分发预设为:

    • uniform_int
    • bernoulli_distribution
    • geometric_distribution
    • poisson_distribution
    • binomial_distribution
    • uniform_real
    • exponential_distribution
    • normal_distribution
    • gamma_distribution

    当你定义你的功率定律分布时,你应该能够用现有的发电机和引擎来连接它。这本书 C++标准库扩展 彼得·贝克尔写了一篇伟大的篇章 <随机的; .

    Here is an article 关于如何创建其他分布(以cauchy、chi squared、student t和snedecor f为例)

        4
  •  3
  •   Antoni Parellada    7 年前

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

    两者之间的一个微小差别 Wolfram MathWorld formula 在公认的答案和其他,也许更常见的,方程是事实上 幂律指数 n (通常表示为alpha)不带有明确的负号。所以选择的alpha值必须是负数,通常在2到3之间。

    x0 x1 代表分布的上下限。

    所以这里是:

    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