当'a'和'b'远离均值时,Python和R中的截断正态分布

2 投票
1 回答
950 浏览
提问于 2025-04-18 09:41

当尝试获取截断正态分布的概率密度函数(pdf)时:

from scipy.stats import truncnorm
truncnorm.pdf(-31, np.inf, -30, loc=0, scale=1)

这个过程运行得很好。但是如果上限离均值太远,分配给非截断部分(整体质量应该是1的地方)的样本概率会变成NaN:

# -41 is one of the points with highest probability. Why nan?
>truncnorm.pdf(-41, np.inf, -40, loc=0, scale=1)
nan

# 39 is impossible since it lays in the truncated side
>truncnorm.pdf(-39, np.inf, -40, loc=0, scale=1)
0.0

这是因为数值精度的问题还是其他什么原因导致的bug吗?有没有其他方法可以解决这个问题?

更新 1(使用R库“truncnorm”):

这似乎是一个常见的问题。在R的“truncnorm”库中也遇到了同样的问题:

 > dtruncnorm(-41, a=-Inf, b=-40, mean = 0, sd = 1)
 [1] NaN

更新 2(使用R库“msm”):

在他的博客中,Christian Robert 指出了“msm”库,它实现了他的论文

然而,在这种情况下它也出现了崩溃:

> dtnorm(-41, mean = 0, sd=1, lower=-Inf, upper=-40)
[1] NaN

1 个回答

3

truncnorm的计算是基于正态分布的累积分布函数(cdf)。

目前为止,在分布的尾部,无法用浮点数(双精度)精确表示这个累积分布函数。

>>> stats.norm.cdf(-37)
5.7255712225239266e-300
>>> stats.norm.cdf(-38)
0.0

>>> stats.norm.pdf(-37)
2.120006551524606e-298
>>> stats.norm.pdf(-38)
1.0972210519949712e-314
>>> stats.norm.pdf(-39)
0.0

>>> np.finfo(float).tiny
2.2250738585072014e-308

实现这个的唯一方法就是直接计算或近似这个截断分布,而不是通过正态分布的特殊函数。

我从来没有见过需要使用这个的情况。

撰写回答