使用numpy.random.normal时如何指定上限和下限

Cat*_*gia 28 python random numpy gaussian scipy

IOK所以我希望能够从正常分布中选择只能介于0和1之间的值.在某些情况下,我希望能够基本上只返回一个完全随机的分布,而在其他情况下我想返回值落在高斯的形状.

目前我正在使用以下功能:

def blockedgauss(mu,sigma):
    while True:
        numb = random.gauss(mu,sigma)
        if (numb > 0 and numb < 1):
            break
    return numb
Run Code Online (Sandbox Code Playgroud)

它从正态分布中选取一个值,如果它超出0到1的范围,则丢弃它,但我觉得必须有更好的方法来做到这一点.

unu*_*tbu 32

听起来你想要一个截断的正态分布.使用scipy,您可以使用scipy.stats.truncnorm从这样的分布生成随机变量:

import matplotlib.pyplot as plt
import scipy.stats as stats

lower, upper = 3.5, 6
mu, sigma = 5, 0.7
X = stats.truncnorm(
    (lower - mu) / sigma, (upper - mu) / sigma, loc=mu, scale=sigma)
N = stats.norm(loc=mu, scale=sigma)

fig, ax = plt.subplots(2, sharex=True)
ax[0].hist(X.rvs(10000), normed=True)
ax[1].hist(N.rvs(10000), normed=True)
plt.show()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

上图显示了截断的正态分布,下图显示了具有相同均值mu和标准差的正态分布sigma.


小智 11

我在寻找一种方法来查找从零和1之间截断的正态分布(即概率)中采样的一系列值时遇到了这篇文章.为了帮助遇到同样问题的其他人,我只想注意scipy.stats.truncnorm具有内置功能".rvs".

因此,如果您想要100,000个样本,平均值为0.5,标准差为0.1:

import scipy.stats
lower = 0
upper = 1
mu = 0.5
sigma = 0.1
N = 100000

samples = scipy.stats.truncnorm.rvs(
          (lower-mu)/sigma,(upper-mu)/sigma,loc=mu,scale=sigma,size=N)
Run Code Online (Sandbox Code Playgroud)

这给出了一个非常类似于numpy.random.normal的行为,但是在所需的范围内.使用内置将比循环收集样本快得多,特别是对于大的N值.


Fly*_*ish 6

我通过以下方式制作了一个示例脚本。它展示了如何使用 API 来实现我们想要的功能,例如生成具有已知参数的样本,如何计算 CDF、PDF 等。我还附上了一张图片来展示这一点。

#load libraries   
import scipy.stats as stats

#lower, upper, mu, and sigma are four parameters
lower, upper = 0.5, 1
mu, sigma = 0.6, 0.1

#instantiate an object X using the above four parameters,
X = stats.truncnorm((lower - mu) / sigma, (upper - mu) / sigma, loc=mu, scale=sigma)

#generate 1000 sample data
samples = X.rvs(1000)

#compute the PDF of the sample data
pdf_probs = stats.truncnorm.pdf(samples, (lower-mu)/sigma, (upper-mu)/sigma, mu, sigma)

#compute the CDF of the sample data
cdf_probs = stas.truncnorm.cdf(samples, (lower-mu)/sigma, (upper-mu)/sigma, mu, sigma)

#make a histogram for the samples
plt.hist(samples, bins= 50,normed=True,alpha=0.3,label='histogram');

#plot the PDF curves 
plt.plot(samples[samples.argsort()],pdf_probs[samples.argsort()],linewidth=2.3,label='PDF curve')

#plot CDF curve        
plt.plot(samples[samples.argsort()],cdf_probs[samples.argsort()],linewidth=2.3,label='CDF curve')


#legend
plt.legend(loc='best')
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明


fr_*_*lio 6

如果有人只想使用numpy解决方案,这是一个使用常规函数和剪辑的简单实现(MacGyver的方法):

    import numpy as np
    def truncated_normal(mean, stddev, minval, maxval):
        return np.clip(np.random.normal(mean, stddev), minval, maxval)
Run Code Online (Sandbox Code Playgroud)

编辑:不要使用这个!这就是你不应该这样做的方法!例如,
a = truncated_normal(np.zeros(10000), 1, -10, 10)
可能看起来像它的工作原理,但
b = truncated_normal(np.zeros(10000), 100, -1, 1)
肯定不会得出一个截断正常的,因为你可以在下面的柱状图看:

在此处输入图片说明

抱歉,希望没人受伤!我想这课是,不要尝试在编码时模仿MacGyver ...干杯,
安德烈斯

  • 这个不应该删掉吗?这个警告非常明显——但这看起来仍然像是最多会产生误导的东西。 (3认同)
  • 最多可以阻止其他人犯同样的错误。我希望情况确实如此。而且情节也非常明显 (2认同)