将均匀分布转换为正态分布

Ter*_*rst 98 language-agnostic random algorithm normal-distribution

如何将均匀分布(大多数随机数生成器产生,例如介于0.0和1.0之间)转换为正态分布?如果我想要选择的平均值和标准偏差怎么办?

Tyl*_*ler 47

通灵塔的算法是这个相当有效,虽然箱穆勒变换更容易从头开始实现(而不是疯狂的慢).

  • 关于线性全等发生器的常见警告适用于这两种方法,因此使用适当的下层发生器.干杯. (7认同)
  • 如Mersenee Twister,或者您有其他建议吗? (3认同)

Ale*_* C. 44

有很多方法:

  • 千万不能用箱穆勒.特别是如果你绘制许多高斯数字.Box Muller产生的结果夹在-6和6之间(假设是双精度.浮子会恶化).它的效率确实低于其他可用方法.
  • Ziggurat很好,但需要一个表查找(由于缓存大小问题,还有一些特定于平台的调整)
  • 制服比例是我最喜欢的,只有少数加法/乘法和1/50的时间日志(例如看那里).
  • 反转CDF 有效的(并忽略了,为什么?),如果您搜索谷歌,您可以快速实现它.准随机数是强制性的.

  • @locster:反向CDF方法也共享这个不良属性.见http://www.cimat.mx/~src/prope08/randomgauss.pdf.这可以通过使用具有非零概率的均匀RNG来缓解,以产生非常接近零的浮点数.大多数RNG没有,因为它们生成一个(通常是64位)整数,然后映射到[0,1].这使得这些方法不适合对高斯变量的尾部进行采样(考虑在计算金融中定价低/高冲击选项). (7认同)
  • 我认为不使用Box Muller转换的建议会误导大部分用户.很高兴知道这个限制,但正如CrazyCasta所指出的那样,对于大多数并非严重依赖于异常值的应用程序,您可能不需要担心这一点.例如,如果您曾经依赖于使用numpy的法线采样,那么您依赖于Box Muller变换(极坐标形式)https://github.com/numpy/numpy/blob/c08d2647240555e730da7580374a61d8547a932e/numpy/random/ mtrand/randomkit.c#L619. (6认同)
  • @AlexandreC.为了清楚两点,使用64位数字,尾部变为8.57或9.41(较低的值对应于在记录之前转换为[0,1)).即使被限制在[-6,6],超出这个范围的几率大约是1.98e-9,对于大多数人来说甚至在科学上也是如此.对于8.57和9.41的数字,这变为1.04e-17和4.97e-21.这些数字非常小,以至于Box Muller采样和真正的高斯采样之间的差异几乎完全是学术性的.如果你需要更好,只需加上其中四个除以2. (5认同)
  • 你确定 [-6,6] 钳位?如果为真,这是一个非常重要的点(并且值得在维基百科页面上注明)。 (2认同)

Adi*_*Adi 28

将任何函数的分布更改为另一个函数涉及使用所需函数的反函数.

换句话说,如果你瞄准特定概率函数p(x),你可以通过积分得到分布 - > d(x)=积分(p(x))并使用它的逆:Inv(d(x)) .现在使用随机概率函数(具有均匀分布)并通过函数Inv(d(x))投射结果值.您应该根据您选择的函数获得随分布的随机值.

这是一般的数学方法 - 通过使用它,您现在可以选择任何概率或分布函数,只要它具有反向或良好的反向近似.

希望这有助于并感谢关于使用分布的小注释,而不是概率本身.

  • 请注意,您需要反转累积分布函数,而不是概率分布函数.亚历山大暗示了这一点,但我认为更明确地提及它可能不会受到伤害 - 因为答案似乎暗示了PDF (9认同)
  • +1这是一种用于生成非常好的高斯变量的被忽略的方法.在这种情况下,逆向CDF可以用牛顿法有效地计算(导数是e ^ { - t ^ 2}),初始近似很容易得到作为有理分数,因此你需要对erf和exp进行3-4次评估.如果你使用准随机数,这是必须的,你必须使用一个统一的数字才能获得高斯数. (4认同)
  • 这称为[逆变换采样](https://en.wikipedia.org/wiki/Inverse_transform_sampling) (2认同)
  • [这里](http://stats.stackexchange.com/questions/12953/generating-values-from-a-multivariate-gaussian-distribution) 是 SE 中的相关问题,有更概括的答案和很好的解释。 (2认同)

use*_*084 21

这是一个使用Box-Muller转换的极性形式的javascript实现.

/*
 * Returns member of set with a given mean and standard deviation
 * mean: mean
 * standard deviation: std_dev 
 */
function createMemberInNormalDistribution(mean,std_dev){
    return mean + (gaussRandom()*std_dev);
}

/*
 * Returns random number in normal distribution centering on 0.
 * ~95% of numbers returned should fall between -2 and 2
 * ie within two standard deviations
 */
function gaussRandom() {
    var u = 2*Math.random()-1;
    var v = 2*Math.random()-1;
    var r = u*u + v*v;
    /*if outside interval [0,1] start over*/
    if(r == 0 || r >= 1) return gaussRandom();

    var c = Math.sqrt(-2*Math.log(r)/r);
    return u*c;

    /* todo: optimize this algorithm by caching (v*c) 
     * and returning next time gaussRandom() is called.
     * left out for simplicity */
}
Run Code Online (Sandbox Code Playgroud)


Eri*_*sty 6

其中R1、R2是随机均匀数:

正态分布,SD 为 1:

sqrt(-2*log(R1))*cos(2*pi*R2)
Run Code Online (Sandbox Code Playgroud)

这是正确的......不需要做所有这些缓慢的循环!

参考:dspguide.com/ch2/6.htm

  • 这*是*许多其他答案中提到的 Box-Muller 变换,具有那里讨论的相同限制。请注意,您还可以通过计算正弦来获得 R1 和 R2 的第二个正态随机偏差。有关 Box-Muller 的更多详细信息[此处](https://www.baeldung.com/cs/uniform-to-normal-distribution)。 (2认同)

jil*_*wit 5

使用中心限制定理维基百科条目 mathworld条目对您有利.

生成n个均匀分布的数,求和,减去n*0.5,得到近似正态分布的输出,均值等于0,方差等于(1/12) * (1/sqrt(N))(参见上一个均匀分布的维基百科)

n = 10给你一些快速的东西.如果你想要超过一半的东西去做tylers解决方案(如正常发行版维基百科条目中所述)