Python 如何解决朴素贝叶斯分类中的数值下溢问题?

Python 如何解决朴素贝叶斯分类中的数值下溢问题?,python,python-3.x,machine-learning,naivebayes,Python,Python 3.x,Machine Learning,Naivebayes,我有一些函数来实现朴素贝叶斯分类器(对于我的数据集),而不使用任何ML库。 我想知道如何在这段代码中解决数值下溢问题。我知道我需要使用log来计算分类器中的概率,但我无法让它工作。当我打印p1和p0时,我当前得到0作为两者的输出。如何更改函数以使用log计算概率p0和p1 # build a naive bayes classifier def classifyNB0(vec2Classify, p0Vec, p1Vec, pAbusive): p1 = np.prod(np.power

我有一些函数来实现朴素贝叶斯分类器(对于我的数据集),而不使用任何ML库。 我想知道如何在这段代码中解决数值下溢问题。我知道我需要使用log来计算分类器中的概率,但我无法让它工作。当我打印p1和p0时,我当前得到0作为两者的输出。如何更改函数以使用log计算概率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]

我认为这实际上是一个数学问题,你的帖子可能更适合你

我同意@simon的观点,最好用一些“对数”来解决这个问题,但首先我建议用纸和笔来简化代码:

我对“朴素贝叶斯分类”一无所知,但就我从你的代码中所见,你基本上需要计算不等式,
p1>p0
。让我们做一些数学题

显然,我们可以等价地计算
log(p_1)>log(p_0)
。因此,让我们尝试重写
p1
p0
的两个表达式

在代码中,我们希望您需要迭代列表/向量以获得总和

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

根据您的数值,我希望这些计算不会受到下溢的影响,因此可以进行评估:
log\u p1>log\u 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
编辑: 当我查看您在稍后的编辑中添加到帖子中的数据时,您的数学变得微不足道。您不需要
power
log
。你可以一起避免它们。请注意

幂(x,0)=1

功率(x,1)=x

日志(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,y in zip(p1Vec,vec2Classify)])
如果出现下溢,请使用log重试

log_p1 = np.log(pA) + sum([np.log(x) if y else 0 for x,y in zip(p1Vec,vec2Classify)])
# ...
# and evaluate,
log_p1 > log_p0
EDIT2: 您实际上没有下溢问题。我试着输入您的数据,坦率地说,
p1
的计算结果正确到
0.0
。如果你仔细观察
vec2Classify
,你会发现它在三个不同的索引中只包含
1
,而
p1Vec
在完全相同的索引中是
0

如果
p1Vec
至少有一个索引
vec2Classify
1
,那么整个
p1=prod(…)
始终为零,因为您将使用
幂(0,1)=0进行乘法


可能您的输入数据(
p1Vec,vec2Classify
)输入错误?

请查看如何创建一个。我认为您最好使用对数来实现数值稳定性。你的求幂变成了乘法,乘积变成了和,这使得事情在数值上更加稳定。@simon
p1=sum(np.log(np.prod(p1Vec,vec2classive))+math.log(pAbusive)
我试过了,但我得到了错误
只有整数标量数组可以转换成标量索引。我是python新手,所以我可能犯了一个错误。这可能是因为math.log。改用np.log。在数学方面,你的公式也是不正确的。它应该是np.sum(vec2Classify*np.log(p1Vec))+np.log(pAbusive)实际上。。。仔细想想,这不应该是数学问题。。。它可能是np.prod,因为您将vec2Classify作为轴参数传递。谢谢,这使它更容易理解。@Miztory我很高兴我让您的数学更容易。然而,当我查看您在稍后的编辑中添加到帖子中的数据时,您的数学变得微不足道。请看一下我编辑过的答案。另外,既然你还没有接受答案,也许你可以详细说明什么东西仍然没有达到预期效果?