2013-08-26 3 views
15

IOK, поэтому я хочу иметь возможность выбирать значения из нормального распределения, которое только когда-либо падает между 0 и 1. В некоторых случаях я хочу иметь возможность в основном просто верните полностью случайное распределение, а в других случаях я хочу вернуть значения, которые попадают в форму гаусса.Как указать верхний и нижний пределы при использовании numpy.random.normal

На данный момент я использую следующую функцию:

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

Он выбирает значение из нормального распределения, а затем сбрасывает ее, если она выходит за пределы диапазона от 0 до 1, но я чувствую, что должен быть лучшим способом сделать это.

+0

Если вы «блок» значения < 0 and > 1, будет ли он по-прежнему будет гауссово распределение? –

+0

это не будет гауссовское распространение, но в некоторых случаях я не хочу гауссовского распространения. я хочу вернуть дистрибутив, который можно перестраивать между случайным распределением (сбор с очень широкого гауссова), до чего-то очень близкого к дельта-функции (где гауссов становится очень узким) –

ответ

21

Похоже, вы хотите получить truncated normal distribution. Используя 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.

+0

безупречное спасибо. –

5

Я наткнулся на это сообщение, ища способ вернуть ряд значений, выбранных из нормального распределения, усеченного между нулем и 1 (т. Е. Вероятностями). Чтобы помочь кому-либо, у кого такая же проблема, я просто хотел отметить, что scipy.stats.truncnorm имеет встроенную возможность «.rvs».

Итак, если вы хотите 100000 образцов со средним значением 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) 

Это дает поведение очень похоже на numpy.random.normal, но в пределах желаемого. Использование встроенного будет существенно быстрее, чем цикл для сбора образцов, особенно для больших значений N.

3

Я составил пример сценария следующим образом. В нем показано, как использовать 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

В случае, если кто-нибудь хочет решение, используя только NumPy, вот простая реализация с использованием normal функции и clip (подход МакГайвера в):

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

EDIT: НЕ используйте это! вот как вы не должны этого делать !!, например,
a = truncated_normal(np.zeros(10000), 1, -10, 10)
может выглядеть, как она работает, но
b = truncated_normal(np.zeros(10000), 100, -1, 1)
будет определенно не рисовать усеченный нормальный, как вы можете видеть в следующей гистограмме:

enter image description here

Sorry для этого, надеюсь, никто не пострадал!Я предполагаю, что урок, не пытайтесь подражать МакГайвера при кодировании ... Приветствия,
Andres