有谁知道 x<0 的标准正态 CDF 的对数的近似值?
我需要实现一个非常快速计算它的算法。当然,最直接的方法是首先计算 CDF(我可以在 Wikipedia 上找到合适的简单近似值),然后对其取对数。显然,我想避免计算两个特殊函数的时间成本,更不用说微小的中间值(尾部)排除了使用比浮点运算快得多的定点运算。
我知道各种统计函数有数百种近似值,但这是一个的对数这一事实使得找到一个变得更加困难。如果有人能给我指出一个,或者我可能找到的来源,我将不胜感激。
有谁知道 x<0 的标准正态 CDF 的对数的近似值?
我需要实现一个非常快速计算它的算法。当然,最直接的方法是首先计算 CDF(我可以在 Wikipedia 上找到合适的简单近似值),然后对其取对数。显然,我想避免计算两个特殊函数的时间成本,更不用说微小的中间值(尾部)排除了使用比浮点运算快得多的定点运算。
我知道各种统计函数有数百种近似值,但这是一个的对数这一事实使得找到一个变得更加困难。如果有人能给我指出一个,或者我可能找到的来源,我将不胜感激。
,即使是一个简单的最小二乘三次拟合到值似乎也足够了。
只是为了快速了解它,我在 -5 和 0 之间每隔 0.01 生成值,并尝试将最小二乘三次和五次(5 次)多项式拟合到。我想你可以像我一样轻松地做到这一点,所以我不会强调这一点。
对于五次方的最大绝对误差,它出现在零处。
[不完全清楚你所说的“在 0.2 + 10% 左右”是什么意思。如果您可以详细说明以明确您的标准,那么我可以详细说明这一点,并可能调整权重以更好地优化您的标准。]
在评估多项式时,如果速度很重要,您应该牢记霍纳的方法。
正如红衣主教所建议的那样,情节非常具有说明性。既然我已经生成了一个,我应该把它放在这里:
这是(有符号的)错误(日志中的绝对比例错误):
它看起来和我们期望的最小二乘拟合一样。不合身度相当适中;出于许多目的,这很好。
另一种方法是您可以将上尾的 Karagiannidis 和 Lioumpas 近似值(参见此处)翻转到下尾(通过替换为)并获取日志:
所以我们得到
要获得以 2 为底的日志,只需将结果乘以
这不如我提到的五次拟合准确,并且由于对数和求幂,评估可能更慢。不过,它又好又短,有一些优点。请注意,它不是为对数刻度设计的。
原始论文有 K&L 的公式 6:
对于值,他们建议和。
将除以以获得,这表明维基百科页面上的公式()
让我们看看对数尺度的近似质量。
紫色虚线是 K&L 近似值。现在让我们看看错误:
错误的大小比我们的五次要大得多。它在范围左半部分的中几乎是线性的这一事实或来改善误差 - 但这会使接近值的近似值更差 - 1. 是否会这样做取决于所需的特征。
这是神经网络用户的替代解决方案:
1 / (1 + 2*exp(-sqrt(2*pi)*x))
您可以使用(扩展此近似)来近似 CDF 。
并利用大多数深度学习框架具有log(1 + exp(x))
作为softplus激活函数的数值稳定实现这一事实。
得到的公式可以写成两行pytorch:
def log_standard_normal_cdf(x):
return -F.softplus(np.log(2) - x*np.sqrt(2*np.pi))
为了覆盖比最初要求的范围更广,我最终想出了这个有理近似值
它的绝对误差在 0.04 到 20 个标准偏差下,之后误差可能会超过该值,但仍低于该值的 0.04%(据我可以通过数值计算验证)。
我最近遇到了同样的问题,并找到了我认为更好的解决方案。Faddeeva包有一组用于计算 erf(z)、erfc(z) 等的精确函数。它们都从计算 Faddeeva 函数 w(z) 开始:
您可以显示正常 cdf 的日志是
所以现在我们可以计算三个表现良好的简单量,并得到对于非常小的 z 也表现良好。我验证了你得到的值与它有效的域 的常规值完全相同。normcdf
对于非常小的 z,我不知道“正确”的答案,但是对于 z=-100,你会得到 -5005.5242,它通常只会给你 -inf。这种方法的优点是使用现有的包来进行棘手的计算,因此您不必自己制作近似值,而且速度很快。
在 python 中,w可以作为. scipy.special.wofz