简体   繁体   English

scipy 中的单边截断正态分布

[英]One-sided truncated normal distribution in scipy

In scipy, is there any way to sample from a normal distribution that has only been truncated on one side?在 scipy 中,有没有办法从仅在一侧截断的正态分布中进行采样?

Say I have a standard normal distribution, with the domain (-inf, 0] .假设我有一个标准正态分布,域为(-inf, 0]

The scipy.stats.truncnorm class provides utilities for distributions with a specific lower and upper bound, but is there a good way to do this if you only have one or the other, short of scipy.stats.truncnorm(a=-9999999, b=0, loc=0, scale=1) ? scipy.stats.truncnorm类为具有特定下限和上限的分布提供实用程序,但是如果您只有一个或另一个,缺少scipy.stats.truncnorm(a=-9999999, b=0, loc=0, scale=1) ?

Using np.inf (or -np.inf ) to set the bounds results in the distribution being unbounded on that side:使用np.inf (或-np.inf )设置边界会导致分布在该侧无界:

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

H/t to @warren-weckesser for the answer in comments.回复@warren-weckesser 以获取评论中的答案。

What you are describing is the Half-normal distribution (its mirror to the y-axis to be precise), a special case where the Folded Normal Distribution and the Truncated Normal Distribution are equivalent.您所描述的是半正态分布(准确地说是其镜像到 y 轴),这是折叠正态分布和截断正态分布等效的特殊情况。 scipy also provides that distribution: scipy.stats.foldnorm . scipy 还提供了该分布: scipy.stats.foldnorm The only reason I'm mentioning this is (not to be pedantic) because it is quite convoluted how scipy and numpy define these distributions (see below: mu & sigma vs. beta , scale , loc , a & b )我提到这一点的唯一原因是(不要迂腐)因为 scipy 和 numpy 如何定义这些分布非常复杂(见下文: mu & sigma vs. beta , scale , loc , a & b

Run this in a notebook and the differences become apparent:在笔记本中运行它,差异变得明显:

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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM