如何处理朴素贝叶斯分类中的数值下溢问题?

问题描述

我具有无需使用任何ML库即可实现Naive Bayes分类器(针对我的数据集)的功能。 我想知道如何在此代码解决数字下溢问题。我知道我需要使用日志来计算分类器中的概率,但是我无法使其正常工作。当我打印p1和p0时,当前我的输出均为0。如何更改函数以通过对数计算概率p0和p1。

# build a naive bayes classifier
def classifyNB0(vec2Classify,p0Vec,p1Vec,pAbusive):
    p1 = np.prod(np.power(p1Vec,vec2Classify)) * pAbusive
    print('p1 =',p1)
    # element-wise power computation
    p0 = np.prod(np.power(p0Vec,vec2Classify)) * (1.0 - pAbusive)
    print('p0 =',p0)
    if p1 > p0:
        return 1
    else:
        return 0
    

p1Vec中的值:

p1Vec = [0.05263158 0.15789474 0.05263158 0.         0.         0.05263158
 0.         0.05263158 0.         0.10526316 0.         0.
 0.         0.         0.05263158 0.05263158 0.05263158 0.05263158
 0.10526316 0.05263158 0.         0.         0.05263158 0.
 0.05263158 0.05263158 0.         0.         0.         0.
 0.         0.        ]

vec2Classify中的值:

vec2Classify = [0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0]

解决方法

我建议这实际上是一个数学问题,您的帖子可能更适合Math Exchange

我同意@simon,最好用一些“对数”解决,但首先我建议用笔和纸做一些工作以简化代码:

我对“朴素贝叶斯分类”一无所知,但是据我从您的代码中可以看到,您实际上需要评估不等式p1 > p0。让我们做一些数学..

很显然,我们可以等效地评估log (p_1) > log (p_0)。因此,让我们尝试重写p1p0的两个表达式。

The Math displayed is by compiled by LaTeX,then screenshotted and pasted here ..

在代码中,我们将需要遍历列表/向量以获取总和。

log_p1 = log(p1) = V[0]*log(U[0]) + ... + V[n]*log(U[n]) + log(pA)

根据您的数值,我希望这些计算不会出现下溢的情况,因此可以评估:log_p1 > log_p0

就python代码而言,总和为

import numpy as np

log_p1 = np.log(pAbusive)
log_p0 = np.log(1-pAbusive)
for i in range(len(p1Vec)):
  log_p1 += vec2Classify[i] * np.log(p1Vec[i])
  log_p0 += vec2Classify[i] * np.log(p0Vec[i])

然后评估,

log_p1 > log_p0

编辑: 当我查看您在以后的编辑中添加到帖子中的数据时,您的数学运算变得微不足道。您不需要powerlog。您可以一起避免它们。请注意,

power(x,0) = 1

power(x,1) = x

log(1) = 0

... 总是!

您可以简单地写

p1 = pAbusive
for x,y in zip(p1Vec,vec2Classify):
  if y: # == 1
    p1 *= x

或者,作为一种单列列表理解

p1 = pA * np.prod([x if y else 1 for x,vec2Classify)])

如果由此引起下溢,请使用日志重试

log_p1 = np.log(pA) + sum([np.log(x) if y else 0 for x,vec2Classify)])
# ...
# and evaluate,log_p1 > log_p0

EDIT2: 您确实没有下溢问题。我尝试输入您的数据,坦率地说,p1的评估结果正确为0.0。如果仔细研究vec2Classify,您会发现它仅在三个不同的索引处拥有1,而在完全相同的索引处p1Vec0

如果p1Vec在至少{em> 其中一个索引{{1}是vec2Classify的情况下为零,则整个1始终为零,因为您将与p1 = prod( ... ) 相乘。

也许您输入的数据(power(0,1) = 0)输入有误?