web-dev-qa-db-ja.com

numpy.random.normalを使用するときに上限と下限を指定する方法

IOKなので、0と1の間に収まる正規分布から値を選択できるようにしたい場合があります。場合によっては、基本的に完全にランダムな分布のみを返すことができるようにしたい場合もあれば、次のような値を返したい場合もあります。ガウスの形になります。

現時点では、次の関数を使用しています。

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

それは正規分布から値を選び、それが0から1の範囲外にある場合はそれを破棄しますが、これを行うより良い方法があるはずだと感じています。

30

切り捨てられた正規分布 が必要なようです。 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()

enter image description here

上の図は打ち切られた正規分布を示し、下の図は同じ平均muと標準偏差sigmaの正規分布を示しています。

30
unutbu

ゼロと1の間で切り捨てられた正規分布からサンプリングされた一連の値(つまり、確率)を返す方法を探しているときに、この投稿に出くわしました。同じ問題を抱えている他の人を助けるために、私はscipy.stats.truncnormに組み込み機能「.rvs」があることに注意したいだけです。

したがって、平均0.5で標準偏差0.1の100,000個のサンプルが必要な場合:

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)

これにより、numpy.random.normalと非常によく似た動作が得られますが、望ましい範囲内です。ビルトインを使用すると、特にNの値が大きい場合に、サンプルを収集するループよりもかなり高速になります。

11
Greg Alushin

誰かがnumpyだけを使用した解決策を望んでいる場合、 normal 関数と clip (MacGyverのアプローチ)を使用した簡単な実装を次に示します。

_    import numpy as np
    def truncated_normal(mean, stddev, minval, maxval):
        return np.clip(np.random.normal(mean, stddev), minval, maxval)
_

編集:これを使用しないでください!!これはあなたがそれをしてはいけない方法です!!たとえば、
a = truncated_normal(np.zeros(10000), 1, -10, 10)
動作するように見えるかもしれませんが、
b = truncated_normal(np.zeros(10000), 100, -1, 1)
次のヒストグラムからわかるように、切り捨てられた法線は描画されません

enter image description here

申し訳ありませんが、けが人がいないことを願っています!教訓は、コーディングでMacGyverをエミュレートしようとしないでください...乾杯、
アンドレス

6
fr_andres

以下でスクリプト例を作成しました。 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')

enter image description here

4
FlyFish