【问题标题】:Random number within a range based on a normal distribution基于正态分布的范围内的随机数
【发布时间】:2011-02-14 16:01:32
【问题描述】:

我想生成范围(n 到 m,例如 100 到 150)的随机数,但我希望结果基于正态分布,而不是纯随机数。

我的意思是,总的来说,我希望数字“聚集”在 125 左右。

我发现这个随机数包似乎有很多我需要的东西:http://codeproject.com/KB/recipes/Random.aspx

它支持多种随机生成器(包括mersiene twister),并且可以将生成器应用到一个发行版中。

但我很困惑,如果我使用正态分布生成器,随机数大约从 -6 到 +8(显然真实范围是 float.min 到 float.max)。

如何缩放到我需要的范围?

【问题讨论】:

    标签: .net


    【解决方案1】:

    标准正态分布的均值为 0,标准差为 1;如果您想进行均值m 和偏差s 的分布,只需乘以s,然后加上m。由于正态分布在理论上是无限的,因此您不能对您的范围设置硬上限,例如(100至150)没有明确拒绝落在它之外的数字,但是通过适当的偏差选择,您可以放心(例如)99%的数字将在范围内。

    大约 99.7% 的总体在 +/- 3 个标准差范围内,因此如果您选择大约 (25/3),它应该可以正常工作。

    所以你想要这样的东西:(normal * 8.333) + 125

    【讨论】:

    • 谢谢...这很有意义:)
    【解决方案2】:

    这对于您的需求来说可能过于简单,但是获得具有向中心加权分布的随机数的一种快速且廉价的方法是简单地添加 2 个(或更多)随机数。

    想想当你掷两个 6 面骰子并将它们相加时。总和最常见的是 7,然后是 6 和 8,然后是 5 和 9,等等,很少是 2 或 12。

    【讨论】:

    • 中心极限定理意味着添加制服将接近正态分布,但它很老套,而且很难跟踪方差。
    • 对于给定的正态分布近似值,它还需要任意大量的样本。
    【解决方案3】:

    tzaman 的答案是正确的,但是当使用您链接的库时,有一种比自己执行计算更简单的方法:NormalDistribution 对象具有可写属性Mu(意思是平均值)和Sigma(标准偏差) .所以按照 tzaman 的数字,将 Mu 设置为 125,将 Sigma 设置为 8.333。

    【讨论】:

    • 当然,直接设置会更方便。 :) +1
    【解决方案4】:

    为了感兴趣,从统一的 RNG 生成正态分布的随机数非常简单(尽管必须成对完成):

    Random rng = new Random();
    double r = Math.Sqrt(-2 * Math.Log(rng.NextDouble()));
    double θ = 2 * Math.Pi * rng.NextDouble();
    double x = r * Math.Cos(θ);
    double y = r * Math.Sin(θ);
    

    xy 现在包含两个独立的、正态分布的随机数,均值为 0,方差为 1。您可以根据需要缩放和转换它们以获得所需的范围(正如 interjay 解释的那样)。


    说明:

    此方法称为Box–Muller transform。它利用二维单位高斯的特性,即密度值本身 p = exp(-r^2/2) 均匀分布在 01 之间(为简单起见,删除了归一化常数)。

    由于您可以使用统一的 RNG 轻松生成这样的值,因此您最终会得到半径为 r = sqrt(-2 * log(p)) 的圆形轮廓。然后,您可以在02*pi 之间生成第二个均匀随机变量,为您提供一个角度θ,该角度定义了圆形轮廓上的唯一点。最后,您可以通过将极坐标(r, θ) 转换回笛卡尔坐标(x, y) 来生成两个i.i.d. 正态随机变量。

    这个属性 - p 是均匀分布的 - 不适用于其他维度,这就是为什么您必须一次恰好生成两个正态变量。

    【讨论】:

    • 有趣。这个方法有名字吗?我想阅读更多关于此的内容。这是一个近似值,对吧?
    • @Drew:称为 Box-Muller 变换:en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
    • 谢谢。我在此处 (stackoverflow.com/questions/2325472/…) 注意到建议您可以保留 u2 并将其用作 u1 以进行后续调用,作为优化。维基百科文章中没有提到这一点。你能评论一下这是否保持随机性吗?
    • Java 的 Random.nextGaussian() 的实现看起来更像另一个答案所指的 download.oracle.com/javase/1.4.2/docs/api/java/util/…——它也声称是 Box-Muller 变换,但代码看起来与你的答案。你在展示笛卡尔方法吗?
    • Drew:据我了解,生成的两个高斯随机数是完全独立的,但如果您需要确定,您应该查看更好的来源。 :-)
    【解决方案5】:

    这是另一个不需要计算 Sin/Cos 的算法,也不需要知道 Pi。不要问我理论背景。我曾经在某个地方找到它,从那以后我就一直在使用它。我怀疑这是@Will Vousden 提到的同一个Box-Muller 变换的某种标准化。它还成对产生结果。

    例子是VBscript;很容易转换成任何其他语言。

    Sub calcRandomGauss (byref y1, byref y2)
        Dim x1, x2, w
        Do
            x1 = 2.0 * Rnd() - 1.0
            x2 = 2.0 * Rnd() - 1.0
            w = x1 * x1 + x2 * x2
        Loop While w >= 1.0 Or w = 0  'edited this line, thanks Richard
    
        w = Sqr((-2.0 * Log(w)) / w )
        y1 = x1 * w
        y2 = x2 * w
    End Sub
    

    【讨论】:

    • “不要问我理论背景。我曾经在某个地方找到过”。不正确的知识就是这样传播的。这是 Marsaglia 极地方法的错误实现。您需要在 w>=1.0 OR w==0 时循环。否则,您可能会冒着使用log(0) 并炸毁您的程序的风险。
    • 我会说相反。诚实地说没有任何参考是为了防止不正确的知识传播。感谢您的参考和更正。
    【解决方案6】:

    解决此问题的另一种方法是使用 beta 分布(与正态分布不同,它确实有一个硬范围)并涉及选择适当的参数,使分布具有给定的均值和标准差(方差的平方根)。见this question

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-01
      • 1970-01-01
      • 2015-07-09
      • 2010-11-21
      • 2020-02-13
      • 1970-01-01
      • 1970-01-01
      • 2011-12-16
      相关资源
      最近更新 更多