【发布时间】:2020-10-30 01:36:17
【问题描述】:
我已经进行了一些搜索,但似乎无法找到从截断的正态分布中采样的合理方法。
没有截断我在做:
samples = [np.random.normal(loc=x,scale=d) for (x,d) in zip(X,D)]
X 和 D 是浮点数列表。
目前我正在执行截断:
def truncnorm(loc,scale,bounds):
s = np.random.normal(loc,scale)
if s > bounds[1]:
return bounds[1]
elif s < bounds[0]:
return bounds[0]
return s
samples = [truncnorm(loc=x,scale=d,bounds=b) for (x,d,b) in zip(X,D,bounds)]
bounds 是一个元组列表(min,max)
这种方法感觉有点别扭,不知道有没有更好的方法?
【问题讨论】:
-
嗯,您所展示的并不是通常所说的截断正态分布。相反,它是截断法线与离散分布的混合,该分布在边界 [0] 处具有点质量,在边界 [1] 处具有另一个点质量。要获得截断的法线,您需要
if s > bounds[1]: return truncnorm(loc, scale, bounds),即,如果您掉到外面,请再试一次。根据界限,您可能必须尝试多次。如果大部分质量在界限之间,再试一次就可以了。但如果边界可能排除大部分质量,您可能需要一种不同的方法。 -
另一种方法是反转 cdf,cdf 是未截断 cdf 的缩放版本(缩放因子等于边界之间的质量)。这将是一些涉及 erf 的表达式。我不知道逆 erf 是否是 numpy/scipy 中可用的函数之一,但如果不是,你可以通过二分法或类似的简单方法来反转它。
-
你见过
scipy.stats.truncnorm吗?它与您实现的不完全相同,因为(正如@RobertDodier 指出的那样),您的分布在边界上有点质量。通常的truncated normal distribution 在边界处没有那些点质量。 -
@WarrenWeckesser 我查看了 scipy 函数,但不知道如何设置范围。