【问题标题】:Generate random number from custom distribution从自定义分布生成随机数
【发布时间】:2017-05-10 13:50:49
【问题描述】:

我正在尝试从自定义分布中生成随机数,我已经发现了这个问题: Simulate from an (arbitrary) continuous probability distribution 但不幸的是,它对我没有帮助,因为那里建议的方法需要一个分布函数的公式。我的分布是多个均匀分布的组合,基本上分布函数看起来像一个直方图。一个例子是:

f(x) = { 
    0     for  x < 1
    0.5   for  1 <= x < 2
    0.25  for  2 <= x < 4
    0     for  4 <= x
}

【问题讨论】:

    标签: r random distribution


    【解决方案1】:

    你只需要逆CDF方法:

    samplef <- function (n) {
      x <- runif(n)
      ifelse(x < 0.5, 2 * x + 1, 4 * x)
      }
    

    自己计算 CDF 以验证:

    F(x) = 0                 x < 1
           0.5 * x - 0.5     1 < x < 2
           0.25 * x          2 < x < 4
           1                 x > 4
    

    所以它的倒数是:

    invF(x) = 2 * x + 1      0 < x < 0.5
              4 * x          0.5 < x < 1
    

    【讨论】:

    • 谢谢,这很好用。你能解释一下为什么我需要反转 cdf 吗?
    • ohhhh 现在我明白了,x
    【解决方案2】:

    您可以结合使用从discrete distributions 采样的各种有效方法和连续均匀。

    也就是说,从变量的整数部分 Y=[X] 进行模拟,该变量具有离散分布,其概率等于处于每个区间的概率(例如通过表格方法 - 也称为别名方法),然后简单地添加一个随机统一 [0,1$, X = Y+U.

    在您的示例中,您让 Y 以 0.5,0.25 和 0.25 的概率取值 1,2,3(这相当于以相等的概率对 1,1,2,3 进行抽样),然后添加一个随机统一。

    如果您的“直方图”非常大,这可能是一种非常快速的方法。

    在 R 中,您可以通过

    做一个简单(如果不是特别有效)的版本
    sample(c(1,1,2,3))+runif(1)
    

    sample(c(1,1,2,3),n,replace=TRUE)+runif(n)
    

    更一般地,您可以使用sample 中的概率权重参数。

    如果您需要比这更快的速度(并且对于某些应用程序,您可能需要,特别是对于大直方图和非常大的样本量),您可以使用链接中提到的方法来加快离散部分的速度,并编程该函数的主力部分,使用较低级别的语言(例如 C 语言)。

    也就是说,即使只是使用上面的代码和一个相当“大”的直方图——几十到几百个箱——这种方法似乎——即使在我相当不起眼的笔记本电脑上——也能够很好地生成一百万个随机值不到一秒钟,所以对于许多应用程序来说,这会很好。

    【讨论】:

    • 谢谢,如果所有“bins”的宽度相同,您的方法似乎非常直观。我无法理解您的线路示例(c(1,1,2,3),n,replace=TRUE)+runif(n)
    • 顺便说一句,您可以将概率与示例函数一起使用,如下所示:sample(c(1, 2, 3), size=3000000, replace=TRUE, prob=c(0.5, 0.25, 0.25))那么你不需要使用两个 1 的解决方法:-)
    • (1,1, ... 部分是因为 1 个 bin 是常见的两倍;如果样本实施得很好,那么它应该比更一般的概率加权更快。... 2,3) 部分正在拆分 2-4 箱,因此它们的宽度都相同。同样,这是为了速度。如果箱的高度和宽度不是所有有理数(尽管问题中没有任何暗示),您将需要一种稍慢但更通用的方法,该方法仍然可以通过适当使用 samplerunif 函数来完成/跨度>
    • 感谢您的解释,这很有道理:-)