浮点数的下溢一般是由很多很小的数的连乘造成的,读者可以在 Python 中尝试用很多很小的数相乘,最后四舍五入后会得到 0.
一种解决办法是对乘积取自然对数,在对数中有:
lna⋅b=lna+lnbln∑ixx=∑ilnxi
lna⋅b=lna+lnbln∑ixx=∑ilnxi
避免了太小的数之间的连乘,通过求对数可以避免浮点数的下溢或者浮点数舍入导致的错误。采取自然对数进行处理不会有任何损失。
def trainNB0(trainMatrix,trainCategory): #训练朴素贝叶斯模型 传入numpy数组类型 trainMatrix所有文档词汇向量矩阵(m*n矩阵 m个文档,每个文档都是n列,代表词汇向量大小),trainCategory每篇文档得标签
numTrainDoc = len(trainMatrix) #文档数量
pC1 = np.sum(trainCategory)/numTrainDoc #p(c1)得概率 p(c0)=1-p(c1)
wordVecNum = len(trainMatrix[0]) #因为每个文档转换为词汇向量后都是一样得长度
#初始化p1,p0概率向量---改进为拉普拉斯平滑
p1VecNum,p0VecNum = np.ones(wordVecNum),np.ones(wordVecNum)
p1Sum,p0Sum = 2.0,2.0 #N*1 N表示分类数
#循环每一个文档
for i in range(numTrainDoc):
if trainCategory[i] == 1: #侮辱性文档
p1VecNum += trainMatrix[i] #统计侮辱性文档中,每个单词出现频率
p1Sum += np.sum(trainMatrix[i]) #统计侮辱性文档中出现得全部单词数 每个单词出现概率就是单词出现频率/全部单词
else: #正常文档
p0VecNum += trainMatrix[i]
p0Sum += np.sum(trainMatrix[i])
p1Vect = np.log(p1VecNum / p1Sum) #统计各类文档中的单词出现频率
p0Vect = np.log(p0VecNum / p0Sum) #使用对数避免下溢
return p1Vect,p0Vect,pC1