Как указать верхний и нижний пределы при использовании 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, но я чувствую, что должен быть лучший способ сделать это.
Ответы
Ответ 1
Похоже, вы хотите усеченное нормальное распространение.
Используя 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
.
Ответ 2
Я столкнулся с этим сообщением при поиске способа вернуть ряд значений, выбранных из нормального распределения, усеченного между нулем и 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)
Это дает поведение, очень похожее на numpy.random.normal, но в пределах желаемых границ. Использование встроенного будет значительно быстрее, чем цикл для сбора образцов, особенно для больших значений N.
Ответ 3
Если кто-то хочет решение только с использованием 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)
будет определенно не нарисовать усеченный нормальный, как вы можете видеть на следующей гистограмме:
![введите описание изображения здесь]()
Извините за это, надеюсь, никто не пострадал! Думаю, урок: не пытайтесь подражать MacGyver при кодировании...
Cheers,
Andres
Ответ 4
Я сделал пример script следующим. Он показывает, как использовать 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')
![введите описание изображения здесь]()