scipy统计binom cdf返回nan



如果我理解正确,scipy.stats离散分布的cdf应该返回给定参数值的概率之和。

因此,scipy.stats.binom(7000000000, 0.5).cdf(6999999999)应该返回几乎正好为1的值,因为在70亿次试验中,有50/50的机会,在70亿减去1或更少的试验中成功的概率是非常确定的。相反,我得到了np.nan。事实上,对于提供给.cdf的任何值,除了70亿本身(或更多(,我都会得到np.nan

这是怎么回事?scipy.stats发行版可以处理的数量是否有文档中没有的限制?

TL;DR

内部计算过程中缺乏浮点精度。尽管scipy是一个Python库,但它的核心是用C编写的,并使用C数字类型。


让我给你看一个例子:

import scipy.stats
for i in range (13):
trials = 10 ** i
print(f"i: {i}tprobability: {scipy.stats.binom(trials, 0.5).cdf(trials - 1)}")

输出为:

i: 0    probability: 0.5
i: 1    probability: 0.9990234375
i: 2    probability: 0.9999999999999999
i: 3    probability: 0.9999999999999999
i: 4    probability: 0.9999999999999999
i: 5    probability: 0.9999999999999999
i: 6    probability: 0.9999999999999999
i: 7    probability: 0.9999999999999999
i: 8    probability: 0.9999999999999999
i: 9    probability: 0.9999999999999999
i: 10   probability: nan
i: 11   probability: nan
i: 12   probability: nan

原因在于二项分布的CDF公式(我不能嵌入图像,所以这里有wiki的链接:https://en.wikipedia.org/wiki/Binomial_distribution

在scipy源代码中,我们可以看到对该实现的引用:http://www.netlib.org/cephes/doubldoc.html#bdtr

在它的深处,它涉及到trials的划分(这里incbet.c, line 375: ai = 1.0 / a;被称为a,但nwm(。如果你的trials太大,这个除法的结果就太小了,以至于当我们把这个小数字加到另一个不是那么小的数字上时,它实际上不会改变,因为我们这里缺乏浮点精度(到目前为止只有64位(。然后,经过更多的算术运算,我们试图从一个数字中得到对数,但它等于零,因为它在应该改变的时候没有改变。并且没有定义log(0),这等于np.nan

最新更新