正如几位 cmet 提到的,这两个要求相互冲突:
我想生成一个介于 -1000 和 1000 之间的随机数
和
生成的数字应符合标准正态分布,平均为 x
因为标准normal distribution 具有无限域。如果您从正态分布中选择数字,那么您得到的值可能会大于 1000 或小于 -1000。相反,如果您采取任何措施将范围限制为 [-1000,1000],那么您将不会从正态分布中绘图。
一种选择是根据截断正态分布生成数字,这就像标准正态分布一样,只是概率在 [-1000,1000] 范围之外设置为零。最简单的方法是根据正态分布选择一个数字,如果超出所需范围,请重新选择。
SIGMA=10.0 # you can pick this value to be pretty much anything
def generate_number(average):
x = random.normal_variate(average, SIGMA)
while x > 1000 or x < -1000:
x = random.normalvariate(average, SIGMA)
return x
这里SIGMA 是正态分布的标准差,它控制着值的分布程度。如果SIGMA 很小并且average 不接近1000 或-1000,或者更准确地说:如果(1000-average)/SIGMA 和(1000+average)/SIGMA 都大于2 或3,那么这种方法将相当有效,因为它会通常第一次命中所需范围 [-1000,1000] 内的数字。但是,如果其中一个比率很小,比如大约 1 或更少,那么算法有时必须循环一次或两次。那可能不会有什么大不了的。 (如果你想避免它,你可以使用一些先进的技术,但我认为它不值得这么复杂。)
另一个选项,也就是你在问题中的示例代码所做的,是完全放弃使用正态分布的要求,并使用其他一些自然限制在一定范围内的概率分布。您的示例代码,相当于
random.triangular(-1000,1000,mode)
使用概率从 -1000 到 mode 线性增加,然后从 mode 到 1000 线性减少的分布。不过,问题在于 mode 是最大的值被选中的概率。它与所选数字的平均值不同。实际平均值是(min+max+mode)/3.,或者在你的情况下,因为min+max = 1000-1000 = 0,只是mode/3,所以如果你想生成具有指定平均值的数字,你必须使用
def generate_number(average):
mode = 3*average
if mode < -1000 or mode > 1000:
raise ValueError('Average cannot be satisfied: %f' % average)
return random.normal_variate(-1000, 1000, mode)
请注意,使用此分布意味着您永远无法生成平均值小于-1000./3. 或大于1000./3. 的数字,除非您也相应地调整最小值或最大值。