scipy中的单侧截断正态分布

时间:2016-04-06 01:15:02

标签: python scipy statistics

在scipy中,是否有任何方法可以从仅在一侧被截断的正态分布中进行采样?

假设我有一个标准的正态分布,域名为(-inf, 0]

scipy.stats.truncnorm类为具有特定下限和上限的发行版提供实用程序,但是如果只有scipy.stats.truncnorm(a=-9999999, b=0, loc=0, scale=1)之外只有一个或另一个,那么有没有好办法呢?

2 个答案:

答案 0 :(得分:1)

使用np.inf(或-np.inf)设置边界会导致该侧的分布不受限制:

scipy.stats.truncnorm(a=-np.inf, b=0, loc=0, scale=1)

向@ warren-weckesser致以评论中的答案。

答案 1 :(得分:0)

您要描述的是Half-normal distribution(准确地说,它是y轴的镜像),在特殊情况下,Folded Normal Distribution和截断正态分布是相等的。 scipy还提供了该分布:scipy.stats.foldnorm。我要提及的唯一原因是(不要学究),因为它很难理解scipy和numpy如何定义这些分布(请参见以下内容:musigmabetascalelocab

在笔记本中运行此命令,差异显而易见:

import numpy as np
import scipy.stats as st
import matplotlib.pyplot as plt

resolution=10000

mu, sigma = 0.0, 0.2
normdist = lambda x: 1/(sigma * np.sqrt(2 * np.pi)) * np.exp( - (x - mu)**2 / (2 * sigma**2) )
f = np.random.normal(mu, sigma, resolution)

count, bins, ignored = plt.hist(f, 'auto', density=True)
plt.plot(bins, [normdist(x) for x in bins], 'r--', linewidth=2, label='(np)norm.dist')


beta=2.0
scale=1/np.sqrt(2)*(2*sigma)
nd = st.gennorm(beta, loc=mu, scale=scale)
x = np.linspace(nd.ppf(0.01), nd.ppf(0.99), resolution)
plt.plot(x, nd.pdf(x),'g-', lw=2, alpha=0.6, label='(sc)gennorm pdf')
print(f'mean: {nd.mean()}, std: {nd.std()}')

c=0.0
fnd = st.foldnorm(c, loc=0.0, scale=scale)

x = np.arange(-1.0, 5.0, 1/resolution)
plt.plot(x, fnd.pdf(x),'k-', lw=2, alpha=0.6, label='(sc)foldnorm pdf')
# count, bins, ignored = plt.hist(fnd.rvs(size=resolution), 'auto', density=True)

print(f'mean: {fnd.mean()}, std: {fnd.std()}')

a=0
b=np.inf
tnd = st.truncnorm(a=a, b=b, loc=0, scale=scale)
plt.plot(x, tnd.pdf(x),'b-', lw=1, alpha=0.6, label='(sc)truncnorm pdf')
# count, bins, ignored = plt.hist(tnd.rvs(size=resolution), 'auto', density=True)

plt.plot(x, [normdist(x) for x in x], 'r--', lw=1, label='(np)norm.dist')

print(f'mean: {fnd.mean()}, std: {fnd.std()}')
plt.legend()
plt.show()