Floating point 朴素贝叶斯分类浮点下溢

Floating point 朴素贝叶斯分类浮点下溢,floating-point,naivebayes,underflow,Floating Point,Naivebayes,Underflow,在朴素贝叶斯中乘以大量概率可能会导致浮点下溢 P(x_1,….,x_n│c) = P(x_1│c).P(x_2│c).P(x_3│c)… … P(x_n |c) 使用下面给出的公式是否更可行/更好,而不是使用上述公式(导致浮点下溢)?还是会截断信息 log(xy) = log(x) + log(y) 在发生下溢或溢出之前,浮点乘法是表现最好的浮点运算。此外,在您的公式中,一旦达到下溢,就知道最终值很小,因为未处理的因子小于1.0,并且只能使最终结果更小 使用对数似乎只会降低总体精度,首先是

在朴素贝叶斯中乘以大量概率可能会导致浮点下溢

P(x_1,….,x_n│c) = P(x_1│c).P(x_2│c).P(x_3│c)… … P(x_n |c) 
使用下面给出的公式是否更可行/更好,而不是使用上述公式(导致浮点下溢)?还是会截断信息

log(xy) = log(x) + log(y)

在发生下溢或溢出之前,浮点乘法是表现最好的浮点运算。此外,在您的公式中,一旦达到下溢,就知道最终值很小,因为未处理的因子小于1.0,并且只能使最终结果更小

使用对数似乎只会降低总体精度,首先是因为对数本身,其次是因为不同大小的数字的浮点加法表现得不好

除非你关心2-1024的概率和0的概率之间的差异,因为你的问题没有说明原因,否则我不明白你为什么要把第一个公式中表现良好的乘法改成第二个公式中充满危险的加法


注意:对于IEEE 754的binary64格式,必须有大约20个因子,每个因子的数量级为2-50。如果这是你期望和想要精确处理的数据类型,如果编译器允许这种类型可用(例如,如果使用C,代码为<代码> long double < /代码>),则可以考虑使用80位双扩展格式,或者,我相信它用一个完整的词来表示指数。

假设所有的概率都在一个合理的范围内,比如说[2^{-63},2^{63},你可以这样累积乘积:

double prod(double *d, int n, int64_t *expo) {
  *expo = 0;
  double ans = 1;
  for (int i = 0; i < n; i++) {
    ans *= d[i];
    if (!(i % 16)) {
      int foo = 0;
      ans = frexp(ans, &foo);
      expo += foo;
    }
  }
}
double prod(double*d,int n,int 64_t*expo){
*expo=0;
双ans=1;
对于(int i=0;i
然后,产品在返回值乘以2^{
*expo
}的n/2ULP范围内。这段代码很容易矢量化,也很容易为这种特殊情况编写另一种更快的
frexp,这种特殊情况只需要稍微修改一下,就可以忽略NaN/无穷大/零/次正常值

如果您的平台支持补漏白浮点算法,并且已知您的输入位于合理但未知的范围内,则您可以通过为溢出和下溢添加补漏白处理程序,自适应地选择步幅,对大型
n
的性能影响最小。如果您用平台的汇编语言编写产品例程和陷阱处理程序,那么这可能是最容易做到的

如果你加上对数,你会损失相当大的精度,首先是取对数,其次是求和,你可能会关心,也可能不关心。更糟糕的是,计算这么多对数也会损失相当大的速度