如何在截断正态分布范围内生成随机数

How to generate random number in range of truncated normal distribution

我需要生成截断正态分布范围内的值,例如,在 python 中,您可以使用 scipy.stats.truncnorm() 来生成

def get_truncated_normal(mean=.0, sd=1., low=.0, upp=10.):
    return truncnorm((low - mean) / sd, (upp - mean) / sd, loc=mean, scale=sd)

如何描述here

是否有任何包可以在 go 中制作一些东西,还是我应该自己编写以下功能?

我试过按照 doc 的说法,但它使数字不在所需范围内:

func GenerateTruncatedNormal(mean, sd uint64) float64 {
    return rand.NormFloat64() * (float64)(sd + mean)
}
GenerateTruncatedNormal(10, 5)

为 16.61、-14.54,甚至 32.8,但我预计得到 15 的机会很小,因为 mean = 10 -> 10 + 5 = 15 是我们可以获得的最大值。这里有什么问题?

实现此目的的一种方法包括

  • 从正态分布生成一个数字x,具有所需的均值和标准差参数,
  • 如果它在范围[low..high]之外,那就扔掉它再试一次。

这尊重正态分布的Probability Density Function,有效地切掉了左右尾部。

func TruncatedNormal(mean, stdDev, low, high float64) float64 {
    if low >= high {
        panic("high must be greater than low")
    }

    for {
        x := rand.NormFloat64()*stdDev + mean
        if low <= x && x < high {
            return x
        }
        // fmt.Println("missed!", x)
    }
}

Playground

如果 [low..high] 区间很窄,那么计算时间会多一点,因为更多生成的数字会被丢弃。不过在实践中还是收敛的很快

我通过绘制其结果并将它们与 scipy's truncnorm 的结果进行比较来检查上面的代码,它们确实生成了等效的图表。